Category Archives: Web

程序员必读的十篇文章

作为一个Java程序员和软件开发者,我从许多『关于某某每个程序员必知』这类文章中学到了很多东西,它们会就一个特定的话题给出很多有用有深度而且难以被发现的信息。我在求知的过程中遇到过一些很有用的文章,并将它们存为书签用于日后参考和重复阅读。

个人认为所有程序员都能从中受益,这也是我写这篇文章和跟大家分享所有这些文章的原因。这些都是从我个人书签里挑出来的。你将在本文中看到每个程序员都应该知道的经典话题,诸如内存、Unicode、浮点运算、网络、面对对象设计、时间、URL编码、字符串等等。因为初学者和新手的实际经验匮乏,所以本清单对他们来说非常重要。由于大部分文章其实是从实践中来的,所以初学者和中间件编程者可以从中获得很多知识。同时在职业生涯早期获得基础知识也有助于避免犯错,这些错误其他程序员和软件开发者在他们学习过程中都已经解决过了。

尽管仅仅通过一次阅读并没那么容易就汲取这些文章中给出的知识。你可能并不能理解浮点数的一些细节,或者被内存那些微妙的细节搞得头很大,但是手头留有这些文章列表并时不时联系上下文用作参考还是非常重要的。所以祝你们好运并希望你们可以享受阅读的乐趣。同时,请记得分享其他不在这个列表中的《关于某某,每个程序员必知》的文章。

关于内存,每个程序员必知

这是一篇很经典的文章,它展示了关于内存的方方面面,老的、新的、已知的、未知的。尽管内存问题相当普遍无处不在,也并不是每个程序员都足够了解它。如果你正在写高性能应用,关于现代系统中内存的知识尤显重要。硬件设计者会遇到更多复杂的内存处理和加速技术,比如CPU缓存,但是这些在没有程序员帮助的情况下并不能得到最优性能。我还在阅读这篇文章,我也无法告诉你从中我学到了多少关于诸如RAM、CPU缓存之类的知识。L1缓存和L2缓存、不同类型的内存、DMA、内存控制器涉及和通用内存。简而言之,这是一篇所有经验层次程序员都必读的文章。

关于浮点运算的每个计算机科学家必知

浮点运算是一个很微妙的东西,且并不容易掌控。甚至很多Java程序员都不知道当使用==运算符来做float或double类型的数值比较时会出什么错。我们中的很多人在用float和double类型做货币运算时都经常搞错。本文是此类文章中另一篇佳作,也是所有软件开发者和程序员必读文章。随着经验增长,你期望了解普通问题的细节,而浮点运算就是这些细节中的一个。作为一个高级Java程序员,你必须知道怎么用float、double或是BigDecimal类做货币运算,怎么对浮点数取整,等等。即使你知道浮点运算的基础,通过阅读本文你也会学到一些新的东西。

关于Unicode的每个开发者必知

字符编码是另一个让很多程序员纠结的领域,《每个软件开发者绝对必须要无理由知道的关于Unicode和字符集的最基本常识》一文旨在填补这个领域知识的空白。附注一下,没错,这就是这篇文章完整的标题。它的作者是statckoverflow.com的创建者之一————Joel Spolsky。Joel差不多在十年前就发表了这篇博文,而今看来它仍然适用于当前情况。本文将告诉你什么是Unicode,什么是字符编码,字符是如何用字节表示的,以及其他许多许多。这篇文章最赞的部分是它的表达方式(语言和流畅性),即使你对Unicode一无所知,你也可以无障碍阅读。总之,这是一篇对所有程序员、编程者和软件工程师而言更重要的必读文章。

关于时间,每个程序员都应了解的》(伯乐在线 2013年1月翻译)

在字符编码以外,时间和日期又是另一个让包括我自己在内的很多程序员纠结的领域。即使是高级开发者都会被GMT、UTC和夏令时,以及闰秒搞晕。坦白说,很难做到在处理时区问题时完全不犯错误,处理夏令时差以及它带来的影响同样也不容易。如果你用试错的方法时问题会更糟,因为这个办法永远无法帮你解决这个问题。有多少可能出错的地方,就有多少会发生误解的事。不管日期是否包含时区可以像地狱般把你搞混,将UNIX时间转化为其他时区会让你崩溃,从而忘记时钟同步和延时。我希望通过阅读这篇经典的文章可以消除你们对于时间的很多误解,可以打好关于时间的基础。

关于 URL 编码,每个开发者必须知道的

本文描述了一些大家对于URL编码的一般误解,在给出常见的问题及其解决方案前,先讲了HTTP的url编码。虽然本文并非针对某一具体的编程语言,它还是以Java来说明问题,并解释了如何在不同层次的Java web应用中解决URL编码的问题。你回学到URL语法基础,HTTP以及其他协议的通用URL语法。本文还阐述了URL的常见陷阱,比如字符编码、URL不同部分中的保留字符,以及URL编解码问题。如果你是一个Java程序员,你也将学会如何在Java应用中正确处理URL,如何构造URL和使用Apache CommonsHTTP客户端库。最后它还给出了最好的练习和处理URL的建议,比如应该在建URL的时候对URL编码,保证URL重写滤波器可以正确处理URL,以及其他很多很多。总之,这事一篇任何web开发者和程序员必读的文章。

关于Web开发的每个程序员必知

程序员和软件开发者必读文章。本文来自 stack exchange,是一篇每个程序员在发布站点前关于web应用需要学会的技术细节的文章。文章涉及接口设计、用户体验、安全、web标准、性能、搜索引擎优化、相关技术,还包含了一些重要资源。由于当今世界强烈依赖于互联网,程序员有个人网站和博客的现象很普遍,本文提供的经验不仅仅只对你的职业有帮助,也有助于你的私人工作。你将学到所有关键的技术,比如HTTP、HTML、XML、CSS、JavaScript、浏览器兼容性、降低网站载入时间的tips、XML地图、W3C规范和一些其他的关键细节。

关于SEO的每个程序员必知

这是另一篇对web开发者、程序员和博主来说非常重要的文章。SEO如此重要无法被忽视,因为很多程序员同时也是博客撰写者,所以学些搜索引擎优化基础来让Google搜到他们的文章并将文章展示给其他程序员很重要。在当今这个内联的世界,每个公司都必须将自己展示在网上才得以幸存,由此看来,SEO显得极其重要。如果你开办一个公司并开始销售商品,那么SEO就是你需要关心的东西。所有程序员,尤其是web开发者,都能从本文中受益良多。记住,搜索引擎优化是一个涉猎很广且变化迅速的课题,而且针对不同的搜索引擎差异很大,比如Google、Yahoo以及其他搜索引擎。所以为了掌握这门技术你将需要经常学习新知识。

关于未定义行为的每个C程序员需知

C语言有一个“未定义行为”的概念。未定义行为是一个有很多细微差别的很广泛的课题,这也是我喜欢Java语言的其中一个原因,Java的未定义行为少得多,混淆也很少,而且更加稳定和太平。C中很多看上去很合理的东西都有未定义行为,这也是程序里出bug的常见原因。此外,C中的任一未定义行为都允许实现方式(编译器和运行)来生成运行得很痛苦的代码,做一些完全不期望其发生的事,甚至更糟。这篇精彩的文章将带你在未定义行为的海洋中遨游。

关于网络,每个程序员需知

文中写道:“你是一个程序员,你是否曾想知道多人游戏是怎么运行的?这看起来似乎很神奇:两个以上的玩家通过网络分享同一段经历就像是在同一个虚拟世界里真正在一起一样。但是作为程序员,我们知道事实上发生的和看到的完全不一样。所有一切都是错觉。”

这是一篇关于网络的趣文,目标读者是游戏开发者,但我认为每个程序员和开发者都能从中受益。

关于String,每个Java开发者需知

这是我写的一篇关于java.lang.String的文章,我个人认为是每个Java程序员都需要了解的东西。String在每日的Java编程中很重要,所以任何Java开发者都必须了解这些。本文涉及了String的很多重要领域,包括string pool、string literal、用==和equals()比较String的区别、将字节转换为String、为什么String是不可变的、正确拼接String,等等。高级程序员可能已经知道所有这些情况,但是即使这样复习一下这些也是好的。

程序员都应该了解哪些安全知识》伯乐在线 2012年3月翻译

这个问题是StackOverFlow上的一个电脑编程的学生问的。就像我们学了很多常见的编程概念(比如操作系统、算法、数据结构、计算机架构等)一样,学一下安全相关的知识也很重要。虽然安全是一个很大的课题,它涉及加密/解密、SSL、网络安全、模糊处理、身份验证、证书授权等等,一些最基本的常识对每个程序员而言都是必需的。刚开始工作的时候,我个人对安全知之甚少,当开始写基于Java web应用的Servlet/JSP的时候,才开始了解网络安全和一些类似SQL注入、拒绝服务、XML注入、跨站脚本攻击等的安全威胁。作为一个Java开发者,现在我开始跟一些fortify、PMP和其他静态代码分析工具提供的安全Java编程经验。本文是非常好的安全主题集和链接集,不管你是否在编程,你肯定可以从中受益。

每个程序员都应知的延迟数字

这是一篇额外奖励的文章,但也是每个程序员必读之文。无论用哪种编程语言,如Java或C++,为了写出高性能的应用程序,你都应该了解基本的耗时数问题,比如,从内存、L1缓存、L2缓存、SSD随机读、硬盘中读取变量分别需要耗费多少时长。对互斥锁加解锁需要花多长时间,城市间传输一个数据包或是同一个数据中心循环传输一次需要花多长时间。这些耗时数与编程语言无关,属于内核知识的一部分,开发者必须写出高性能低耗时的应用。这篇文章好在它还提供了这些耗时数在多年来演变的对比分析。你可以看到这些耗时数在2006年和今天分别是什么样子的。

后话

以上是所有每个程序员必读文章清单。坦白说,程序员要学的东西太多了,学习一门编程语言,如Java,仅仅是冰山一角,但我们不都对学习充满热情的吗?编程是一项很有挑战的工作,在你的整个职业生涯中唯一能帮到你的就是基础知识,如内存、Unicode、浮点数、时间、安全相关对任何程序员都很重要。很少有什么是与特定的编程语言相关的,比如我那篇关于Java String和关于未定义行为每个C程序员需要些什么的文章,但对于初学者和开发者而言仍然是很好的学习材料。

from:http://blog.jobbole.com/71723/

知乎产品体验报告

1、产品概述

1.1 体验环境

体验机型:MI 5

系统版本:6.0.1MXB48T

App版本:4.11.0

体验时间:2016.12.3-2016.12.9

体验人:Grocery

1.2  产品简介

Logo:以代表诚实、信赖、知性的蓝色为底色,以“知”字作为产品标识,特别是对其右侧的“口”做了仿对话框的改动,点明知乎是汇聚智慧的知识交流平台。

Slogan:与世界分享你的知识、经验和见解——清晰易懂的平台功能介绍。

1.3 产品定位

以大学生、办公职场人士为主要对象的中文互联网最大的知识社交平台。

1.4 目标人群

“知乎的生态基于内容输出者、内容获取者以及第三方之间的价值关系。”——by 尼古拉斯 chaos 郭。

这样看来,知乎的用户主要有以下三种类型:

1、内容输出者——内容输出者分为两类。一类是各领域的专家级人物,以互联网领域居多,作为知乎的早期用户,这类专家级人物多是社区、移动互联网领域的CEO或者创始人,还有不少经理、总裁级别的专家。另一类是有相关从业经验但还称不上专家的学习型用户;

2、内容获取者——寻求高质量专业性解答,希望成为某领域专家的小白用户;

3、第三方——有广告、招聘等引流需求的用户。

1.5 产品功能

问答(包括付费语音问答“值乎”)、专栏、知乎书店(知乎周刊、一小时、知乎盐)、在线讨论(圆桌)、话题分享(知乎Live)

2、产品详情

2.1 需求及解决方案

1、问答

(1)需求分析

用户行为:搜索、提问和回答问题,对热门回答进行分享/投票/感谢/收藏/屏蔽/评论(包括拷贝、回复、踩、赞、举报评论等)

基本需求:获得专业解答,通过经验分享打造个人IP,问答双方需要信息反馈和良性互动的渠道

深层需求:主要满足小白用户的求知欲,以及专家和“中产阶级”对尊重和自我实现的需求

(2)关键因素分解

用户体验目标:针对特定问题能在最短时间内获得高质量的解答、能快速针对自己感兴趣或领域相关且有价值的问题作出回答

担忧:搜不到对应的问题、回答质量过低、得不到对方反馈和回应、低端问题(百度知道可以解决的问题)遍布、邀请信息过多等

障碍:用户基数不够大、问题覆盖面不全、不能对用户提问内容作过多限制、对回答质量进行筛选可能加大运营成本

(3)解决方案:

  1. 在扩大用户基数方面,知乎起初招募圈子精英先玩,然后开放公众注册,通过大V的口碑营销和名人光环效应进行社会化分享推广,用户量多了,问题覆盖面也逐渐扩大;
  2. 在减少低端问题和重复性问题方面,知乎虽不强行阻拦用户提交重复问题,但对问题进行聚类和重定向;
  3. 在保证问题和回答质量方面,知乎限制每人每日提问数及回答数,建立用户自筛选、举报和主页推送机制,优化算法,让好的答案排列靠前,对“没有帮助”的回答进行折叠;
  4. 建立回答邀请模式,同时鼓励用户修改题目以获得更多关注;
  5. 完善设置,让用户自行选择想接收的信息类型(例如用户可选择只允许自己关注的人给自己发私信)。

2、专栏

(1)需求分析

用户行为:写专栏(有@功能)、对专栏文章进行点赞/赞赏/评论/收藏/分享/关注等

基本需求:让用户可以撰写笔记、发表见解和分享经验(打造个人IP);自动推送特定主体的优质内容,降低搜索成本

深层需求:主要满足专家和“中产阶级”对尊重和自我实现的需求

(2)关键因素分解

用户体验目标:简便快捷地发布文章,能得到读者反馈、能找到感兴趣的话题

担忧:专栏内容支持格式过少编辑麻烦、写完专栏后没人看到没有反馈、找不到有趣的内容、无法保留优质内容

障碍:缺乏技术支持、“马太效应”即用户大多只关注大V、用户行业过于集中、专栏内容不够丰富、用户记性差

(3)解决方案:

  1. 从优化文字编辑开始,逐步对图片、语音和视频给予技术支持;
  2. 用户可利用@功能引起大V注意,同时知乎工作人员会定时筛选出普通用户的高质回答,放在首页推荐或知乎周刊中,增加曝光率;
  3. 邀请各行业的专业人士加入知乎专栏;
  4. 设置“收藏”和“浏览历史”功能,帮助用户轻松保留和找回优质内容。

3、知乎书店

(1)需求分析(整合价值,为优秀内容输出者提供变现渠道,以下仅考虑内容消费者)

用户行为:购买和下载电子书,进行阅读/书签/分享/点赞/评论

基本需求:找到感兴趣的电子书,阅读方便,能做标记和分享

深层需求:满足用户的求知欲、好奇心,让其获得将碎片时间都利用起来的充实感

(2)关键因素分解

用户体验目标:能找到感兴趣的书目并获得高效流畅的阅读体验

担忧:价格贵、内容不够丰富、篇幅过长、某些场景下使用不方便、买了之后才发现读不下去

障碍:用户对付费阅读有排斥心理;内容仅取自知乎问答和专栏,内容丰富度受限

(3)解决方法:

  1. 知乎周刊部分免费,收费部分定价多在3元左右,在多数人可承受范围之内;
  2. 推出“知乎周刊”、“知乎周刊Plus”“一小时”和“知乎盐”三种系列,丰富产品内容,篇幅有长有短;(注:“知乎周刊”多为时事和科技主题、“知乎周刊Plus”为结构化的技能经验合集、“一小时”为各行专业人士对一个问题的见解、“知乎盐”则属于深度行业介绍)
  3. 提供“试读”,允许用户阅览部分内容后再决定是否购买;
  4. 阅读体验方面,为用户提供“书签”和“评论”“分享”等实用功能。

4、在线讨论

(1)需求分析

用户行为:提问、回答或邀请参与活动的嘉宾回答,对动态和讨论进行关注/评论/感谢/分享/收藏/举报

基本需求:为用户和各专业领域的优质嘉宾提供和对方交流接触的途径

深层需求:满足用户的社交需求和品牌(主办方)的推广传播需求

(2)关键因素分解

用户体验目标:能与受邀嘉宾及其他用户展开高效有序的讨论和交流

担忧:提出的问题没有得到回答、讨论区变成“水区”、嘉宾都来自同一品牌、观点可能有失客观

障碍:受邀嘉宾参与积极性不高、讨论时用户言论不可预测、需要给予品牌一定的推广空间

(3)解决方法:

  1. 允许用户提问时邀请到场嘉宾或热门回答者回答问题,同时圆桌期间主持人也会将讨论区中较有价值的热门话题收录至圆桌中,提高曝光率;
  2. 在防止讨论区变成“水区”方面,主持人会做些引导,用户也可对不良内容进行举报;
  3. 邀请的嘉宾中包括来自同一领域但不同机构的专业人士。

5、话题分享

(1)需求分析(内容输出变现的新模式,以下同样只考虑内容消费者)

用户行为:赞助参与、赠送给好友、对知乎Live的内容进行赞赏/点赞/感谢/祝贺/鼓掌/收藏/评价/提问等

基本需求:高效专注的学习氛围,能有效地与播主进行实时互动交流

深层需求:满足用户的求知欲、归属感,以及尊重和自我实现的需求

(2)关键因素分解

用户体验目标:清晰、顺畅、反馈及时且无干扰的直播过程,支持多格式内容

担忧:价格贵、直播内容以语音为主不方便保存、主讲的解说容易被刷屏的问题淹没导致查找费力、提交的问题没得到答复、Live质量过低

障碍:技术问题无法支持多格式内容;问题过多主讲忙不过来

(3)解决方法:

  1. 功能刚起步,先做好语音和图文的分享,后续技术在逐步实现对PPT和小视频等格式的支持;
  2. 知乎Live最低1元起,高低由用户自选,不定时会有限时特价活动;
  3. 为用户提供“语音收藏”和“只看主讲”的功能;
  4. 知乎Live的所有听众可对直播中出现的问题表达“喜欢”,主讲根据问题“喜欢”次数的多少挑重点问题进行回答;
  5. 每场Live结束时都会邀请参与者进行评分和反馈,据此规范Live的质量。

2.2 产品分析

1、功能结构图

知乎 (2)

以下将从产品结构的清晰度和延展性两方面来评价知乎的功能结构。总体来看(左图),知乎的产品骨架比较清晰,底部共5个标签页:

  • “首页”的信息分为三种,顶部标签栏为搜索(重要功能)以及Live(热门子产品)的入口;中间卡片列表部分为内容推荐(包括关注人的动态、优质问答和热门Live);局部信息块为用户活动提供入口(写文章、提问、回答)。
  • “发现”是对各类细分内容的推荐。
  • “消息”是在用户收到“通知、赞与感谢、关注”时给予用户提醒。
  • “私信”方便用户与知友进行交流。
  • “更多”的信息也分为三种,上半部分属于用户信息的记录,下半部分为其他子产品提供入口(知乎书店、知乎Live、值乎),最后还有常规设置。

知乎从最初只做问答功能,到现在已成功添加“知乎书店、知乎Live、值乎”等多个子产品,界面结构仍保持清晰简洁,由此可见知乎产品结构的延展性还是很不错的。

关于知乎的产品功能结构,我有以下的一点想法:

相比于在首页有明显入口的“知乎Live”,知乎另外两个子产品“知乎书店”和“值乎”显然藏得较深,从推广付费内容的角度讲,建议将“私信”归到“消息”菜单下,同时将“更多”中与个人记录相关的内容提出来,放在一级菜单“我的”名下,效果如上面右图所示。

撤去“私信”菜单的理由有两个,一,尽管知乎想做的是知识社交,但大部分用户上知乎主要还是为了找答案,最常用的功能是搜索、问答、评论和写文章;二,很多时候在知乎上发“私信”会有去无回(对方觉得陌生人私信是种骚扰,选择屏蔽),且“私信”不配备表情包,实际体验一般。以上两者都会减少用户打开“私信”菜单的频率,因此建议撤去。

2、核心流程分析(注:以下用粗体标出对应的功能)

(1)提问

首先,对照线下经验,提问是“一对多”的业务流程,其过程大概如下:

找到同伴——我提出一个问题——每个人发表自己的看法(没有见解的会表示支持/反对/做出评论等)——讨论——总结起来得出结论——问题解决

由于app要做的是线上“一对多”的模式,所以区别会在哪呢?

【1】要怎么“召集同伴”:由于互不相识,所以相对比较被动,主动召集只有一种方式:“邀请”,那么这里需要做的就是推荐一些“可被邀请的人”。由于用户提问时默认面向所有对象,因此知乎定义,只要问题有人回答,就为公众所有。

【2】每个人发表看法阶段:就像线下讨论,总有几个意见领袖,有几个没想法的就对意见领袖的观点表示支持或反对,这里需要做的功能,一是让意见领袖的回答人人可见,二是允许非意见领袖们表达赞同、反对、举报等功能。

【3】讨论:参照线下,每人发表观点完毕,会发现存在分歧或有些值得深入探讨的点,这时候要给这群人提供的功能,一是能对每条回答都进行评论,二是更便捷的沟通方式像私信

【4】总结得出结论:提问是为了得到结果,与线下不同,在线提问的对象是所有用户,那么根据“一万个读者就有一万个哈姆雷特”法则,统一结论是困难且非必要的,因此这里只要提供类似投票的功能,如没有帮助,点赞,让用户自筛选高价值内容即可。

【5】最后问题解决:在现实生活中,找到一个难题的解决方法,你担心日后忘了所以你会找本东西把方法记下来,或者你会想把方法分享给朋友们。那么这里需要提供的,一个就是历史保存功能,像我的提问,一个是分享功能。

从以上整个提问的流程来看,由于在线问答不像线下,不是多人实时互动模式,所以也许你还需要一个消息提醒,像通知,这样就允许你转移精力做别的事同时在第一时间了解问题的动态。

(2)回答

相对于提问,回答是个“多对一”的模式,其流程可以参考学生课上老师的提问:

老师提出问题——学生主动回答/老师点名回答——学生回答问题——老师点评回答,问其他同学意见

【1】老师提出问题:对应地,线上有人提交了一个新问题。

【2】学生主动回答/老师点名回答:

一个是答主主动寻找问题来回答,这时候要给他提供获取途径,像搜索、推荐功能等。在线下,能引起学生回答兴趣的问题主要有两种,一种是有把握、能回答的问题,另一种是近期比较流行而自己也有点见解的话题。因此针对前一种我们要知道用户擅长的领域,对于后一种,考虑推荐最新的、热门的问题。另一个是答主被动受到邀请,这时要给答主提醒。

【3】学生回答问题:面对课堂上老师的提问,同学举手之前一般会打腹稿,有的可能会做点笔记。应用到线上,也可以给用户提供草稿的功能。

【4】老师点评同学回答,问其他同学意见:现实场景中,学生答完,老师会感谢同学站出来回答问题,其他同学如果还有想法会站起来补充,如果觉得他的回答很精彩,会用笔记下来,课后还会分享给其他人。这样看来,线上也可以允许用户对答主表达感谢,收藏或评论答主的回答。

(3)专栏

对应现实中给杂志写专栏的流程,知乎“专栏文章”的发布不需要经过审核,其流程大体如下:

打草稿——修改内容、排版——发布

【1】打草稿:用纸笔写作时草稿笔记不会突然消失,而线上用户如果不注意保存草稿就会丢失。要做到像笔纸一样自动留下草稿的痕迹,此处为用户提供自动保存的功能,同时让用户可以从随时查看草稿。

【2】修改内容、排版:杂志内容一般注重图文并茂,结构分明,类似的,线上专栏也应给支持用户上传图片,并能对图文的段落结构进行修改和排版

【3】发布:对于给杂志写专栏的作者来说,尽管文章在发布前会有审核,但偶尔出现错别字或信息错漏在所难免,读者反馈问题,杂志社一般会在下一期对问题声明修正。而在线写专栏无需经过审核,问题可能更多,应为作者提供更方便快捷的修改方式。对于杂志的读者来说,喜欢一个专栏,有人会持续订阅这本杂志,喜欢一篇专栏,有人会把它给剪下来收藏,还会在朋友间进行分享。类似的,我们也可以给用户提供订阅、收藏、分享的功能。

杂志订阅量高了,作为一种激励,作者的稿费价位也会相应提高。与之不同,在线专栏的发布没有“杂志社”作为中间人,为激励作者,可允许读者用户对优质内容进行评分和评价,因此应该提供点赞/赞赏/评论的功能。缺少像杂志这样拥有大量受众的载体,知乎上普通用户所写专栏一开始往往关注度低,曝光率不足,为激励用户可以为其提供@功能,让用户有机会引起大V注意从而借力传播。

总的来说,以上三个流程都具有目的性,刨去用户闲逛知乎的场景需求,以上各部分涉及的功能都能做到与业务需求一一对应,不过少也不冗余。

3、界面体验分析

(1)入口

捕获

左图为知乎首页,一眼看去有三个局部块特别显眼,一个是顶部搜索框,一个是旁边的闪电符号(用户起初不知道是知乎Live的入口,所以会去探索),以及用互补色突出的,位于右下角的黄色元件。点击黄色元件出现右边界面,该过程,元件旋转的同时,“写文章”“回答”“提问”的图标并列跳出,对应标签向左划出,同时卡片列表区出现白色遮罩层。

此处入口设计的巧妙在于:

【1】采用互补色突出元件,并将元件放置在移动端用户拇指容易触及之处,方便点击,一键找到入口。

【2】点击元件后,动态弹出入口捕捉用户视线,同时弱化背景提高对比度。

【3】受点击的黄色元件发生旋转,明确提示用户所处状态已发生变化。

(2)提问

捕获1

左图由首页黄色元件弹出的“提问”入口而来,为问题撰写页面。灰白搭配的页面风格清爽干净,在这类配色相对单调的背景上,自带阴影的弹出框对弹出内容起到了恰到好处的突出。该页面的元素非常简单:灰色提示文字、水平线、发布/设置/关闭元件,用法也一目了然。右图是在“问题”一栏输入关键字后出现的页面,为减少重复问题产生,该步骤会自动弹出“相关问题”列表,引导用户查看。

此处提问设计的优点在于:

【1】背景干净,能有效突出内容。

【2】结构清晰。页面顶部是编辑“问题”的位置,采用浅灰色背景突出层次,同时通过水平线提醒用户,“问题”和“话题”是必填项,“补充说明”可选填。

【3】为避免页面元素过于单调,采用飞机图形代替“发布”按钮,形象简洁;通过将灰色水平线变为蓝色来提示用户其所在位置。

缺点在于:弹出的“相关问题”列表中,由于排版问题文字有时会与数字重叠,导致用户看不清问题,同时影响美观。建议在重叠的地方对数字另起一行。

(3)回答

捕获5

左图由首页黄色元件弹出的“回答”入口而来,据前面核心流程分析,用户回答问题前要先确定擅长的领域。按照提示添加后出现中间页面,“推荐”中出现问题列表,点击“写回答”调转到第三页。前两个页面主题色采用知乎蓝,回答撰写页面采用浅灰/白色,与“提问”处保持一致。相较于“提问”页面,“撰写回答”一页的界面更为简洁,还多了@、上传图片功能以及禁止转载的设置。

此处设计的优点在于:

【1】思路清晰,用户撰写答案前要先确定擅长领域,找对问题。

【2】保持编辑页面风格前后一致,对于查找问题和撰写回答页的主题色,采用蓝色和灰色加以区分。

【3】有效地突出内容。上面前两张图都对重点信息(如“点击添加”、问题的内容和“写回答”)进行加粗或变色处理,以便突出。

需要说明的是,用户在成功提问和回答问题之后,都会默认关注该问题。因此用户有两条途径可查看提问和回答记录,一是:更多——个人主页——我的回答/提问,二是:更多——我的关注——问题。

(4)写文章

捕获7

左图由首页黄色元件弹出的“写文章”入口而来,可以发现“撰写文章”和“撰写回答”不仅风格一致,功能也十分相似。不同点在于“撰写文章”新增了导入草稿的功能,但从写作方便性来看,此页基本不具备排版功能。这会增大作者检查和读者阅读的难度。

此处写文章设计的建议是:

1、左侧键盘收起功能可去掉。目前主流输入法如讯飞、百度、搜狗等都自带该功能,如上图最右侧红框所示。

2、在技术允许的情况下,在界面底部可扩展一些基础的排版功能,如撤销键/字号/加粗/项目符号(尽管只有极少数用户会用app打长文,但不同字号的标题能帮助缕清文章的结构,这对中短文来说也同样重要)

3、 竞品分析

3.1 市场现状

1、行业分析

据易观数据今年12月2日发布的《中国知识付费行业发展白皮书2016》,近年来我国居民人均可支配收入快速增长,消费结构发生变化,人们对于“内容”和“知识”的付费意愿和消费逐渐发生改变,从不愿付费变得对于显著高质量、服务更好的类似产品愿意付费;同时随着移动互联网和移动支付的普及,人们的消费方式也发生了根本性的变化;人们获取信息的方式也从漫无目的地接受变为主动获取知识,信息的选择行为更为成熟。这些基础条件日渐成熟,推动知识付费行业成为新风口。

知识付费不同于出行和外卖行业“高频+刚需”的应用场景,知识交易的频率相对低且个性化程度高。但基于认知盈余分享的供给需求、用户对专业化和垂直化等优质内容的认知渴求,以及为有一技之长的个体提供闲置时间和知识技能的分享平台,知识付费行业仍存在巨大的潜在市场。

2、产品数据

2016年4月20日,ALEXA排名显示,zhihu.com成为中国第29大网站,此时距离2014年8月知乎在ALEXA中国区的排名143,仅仅过去20个月。而2016年12月8日,zhihu.com在ALEXA的排名已经晋升到23位。在移动端,根据appannie知乎iOS版本中国区排名显示,其在社交类app中国区下载量排名最近一年基本稳定在10到15位之间。知乎创始人兼CEO周源在2016年10月28日广州“知乎品牌开放日”上提到,截止至2016年9月,知乎已经拥有6000万注册用户,平均日活跃用户达1600万,人均访问时长达40分钟。目前,知乎已成为国内知识型社交的代表型产品。

3.2 竞品选择

本次选择百度知道(7.4.1版本)和简书作竞品分析对象,主要依据有两个:

  • 本次竞品分析目的是对比功能流程,寻找优化方向;
  • 知乎的老对手果壳目前只做了一个资讯类app,针对知乎的“问答”和“写文章”功能,分别选择同类典型产品“百度知道”和“简书”作对比分析。

3.3 竞品对比

捕获1

1、功能体验分析

(1)提问(知乎VS百度知道)

相对于知乎,百度知道的“提问”入口直接放在一级菜单,同时只需用户编辑题目(标签与补充内容可不填)即可提交,该过程无需用户判断提交的问题是否有重复,问题生成后会自动生成标签,最快1s内可完成该流程。在功能支持方面,两者都支持图片和匿名,但与知乎邀请制不同,百度知道采用悬赏的方式来激励用户回答问题。从亲身体验的角度看,我觉得后者是相对高效的,试过在知乎提了一个问题,邀请了15人回答,晾了一个月没有答复,而今天百度知道给我的反馈是1分钟。可见,相比知乎,百度知道在提问便捷度和反馈速度方面略胜一筹。

捕获

但百度知道对“提问”过程的简省也带来了信息冗余的问题。用户只有在成功提交问题后才能看到“已有答案”的相关问题,假如用户重复提交一样的问题,那他就会有两条同样的提问记录。此外,百度知道的信息同步还不及时,问题得到解答时应同步更新提问记录的状态。

知乎

具体到“提问”页面,百度知道采用虚线对“题目”和“补充说明”进行分隔,同时“提交”和“取消”按钮彼此对称,逻辑清晰,整体风格也清爽干净。

(2)回答(知乎VS百度知道)

由于百度知道将“问答”入口放在首页的顶部二级菜单中,因此知乎需要点击两次才到达的页面在百度知道一步即达。进入“问答”页后,用户会看到默认有“推荐”“最新”“悬赏”三个tab的二级菜单。与知乎让用户根据自身擅长领域来选择问题不同,百度知道是让用户选择感兴趣的问题,它不强制要求用户提交感兴趣的标签,但用户提交之后会扩展二级菜单,如图所示,这样给用户推荐问题会更加灵活且有更好的针对性。此外,百度知道还为用户提供“未答问题搜索框”,方便快捷。

捕获1

从答案呈现方面看,尽管百度知道也允许用户点赞,但并没有像知乎一样采用点赞筛选机制,也不会对没有帮助的答案进行折叠。用户上知乎app搜问题只会得到一个最高质量的解答,而百度知道默认呈现所有答案,对用户来说,后者的选择更多但耗时也多。因此知乎会显得更高效和专业。

具体到回答撰写页面,百度知道直接罗列所有支持功能,不提供“禁止转载”也不能自动保存,但会默认呈现题目,解决用户不想放弃作答又想看回题目的需求。(题目包含问题过多怕疏漏/答案太长怕跑题..)

webwxgetmsgimg (10)

此外,从结构层次来看,百度知道把“提问”放在一级菜单、“回答”放在首页的二级菜单,而知乎直接将两者置于一处,显然层次更为清晰;从社交体验上讲,相比百度知道,知乎允许其他用户在答主的回答下展开讨论,也允许答主在撰写答案时@其他用户,用户互动渠道更多。

(3)写文章(知乎VS简书)

简书“写文章”的入口在一级菜单中,尽管简书提供字数统计和比知乎强大得多的排版编辑功能,其界面风格仍能保持简洁。从个人体验来讲,明显简书“写文章”更为人性化。希望知乎日后能对“写文章”的体验再做一些改进。

捕获

4、 商业模式

Image

知乎自今年4月起先后推出了值乎、原生广告、知乎Live、知乎书店,并支持了付费授权和专栏赞赏功能,商业化加速,知乎正谋求从内容社区升级为服务平台。当前知乎的商业变现仍是以广告和付费内容服务为主。

5、 总结

总体来看,多年来知乎一直紧紧围绕自身的产品定位,通过有效的用户管理和激励机制、用户自筛选和主页推送机制打造高质量和专业化的知识社区氛围。其产品的功能流程逻辑清晰,结构层次简单清楚,界面简单自然。但在提高“问答”的有效互动频率和“写文章”的体验方面还有可优化的空间。

在变现路上,如今的知乎已成功打造商业闭环,当用户在知乎书店读完一本电子书后,不仅能通过社区问答进一步就书中内容进行拓展讨论,更可以浏览作者的专栏文章,或者参与作者的知乎Live,通过“值乎”进行一对一的个性化咨询。也许在未来,知乎还可以考虑切入专业招聘领域。

参考资料:

1.艾瑞咨询《2016年中国移动社交行业系列研究报告-产品篇》

2.艾瑞咨询《中国知识付费行业发展白皮书2016-V5》

from:http://www.woshipm.com/pmd/502718.html

HTTP requests Tools

1、Postman

A powerful GUI platform to make your API development faster & easier, from building API requests through testing, documentation and sharing.express-api-development

2、Fiddlerfiddler

3、CURL

curl -i -X GET http://rest-api.io/items
curl -i -X GET http:/ /rest-api.io/items/5069b47aa892630aae059584
curl -i -X DELETE http://rest-api.io/items/5069b47aa892630aae059584
curl -i -X POST -H ‘Content-Type: application/json’ -d ‘{“name”: “New item”, “year”: “2009”}’ http://rest-api.io/items
curl -i -X PUT -H ‘Content-Type: application/json’ -d ‘{“name”: “Updated item”, “year”: “2010”}’ http://rest-api.io/items/5069b47aa892630aae059584

4、For Chrome try one of extensions:
Advanced REST client
Postman – REST Client

5、For Firefox try one of add-ons:
REST Easy (has nice design)
RESTClient
Poster plugin (it runs on Firefox 33)
•Developer Tools (F12) ->[Network] ->[Edit and resend]

refer:http://stackoverflow.com/questions/4797534/how-do-i-manually-fire-http-post-requests-with-firefox-or-chrome

互联网后端基础设施

对于一个互联网企业,后端服务是必不可少的一个组成部分。抛开业务应用来说,往下的基础服务设施做到哪些才能够保证业务的稳定可靠、易维护、高可用呢?纵观整个互联网技术体系再结合公司的目前状况,个人认为必不可少或者非常关键的后端基础技术/设施如下图所示:

这里的后端基础设施主要指的是应用在线上稳定运行需要依赖的关键组件/服务等。开发或者搭建好以上的后端基础设施,一般情况下是能够支撑很长一段时间内的业务的。此外,对于一个完整的架构来说,还有很多应用感知不到的系统基础服务,如负载均衡、自动化部署、系统安全等,并没有包含在本文的描述范围内。

Continue reading 互联网后端基础设施

系统负载能力浅析

一. 衡量指标

用什么来衡量一个系统的负载能力呢?有一个概念叫做每秒请求数(Requests per second),指的是每秒能够成功处理请求的数目。比如说,你可以配置tomcat服务器的maxConnection为无限大,但是受限于服务器系统或者硬件限制,很多请求是不会在一定的时间内得到响应的,这并不作为一个成功的请求,其中成功得到响应的请求数即为每秒请求数,反应出系统的负载能力。

通常的,对于一个系统,增加并发用户数量时每秒请求数量也会增加。然而,我们最终会达到这样一个点,此时并发用户数量开始“压倒”服务器。如果继续增加并发用户数量,每秒请求数量开始下降,而反应时间则会增加。这个并发用户数量开始“压倒”服务器的临界点非常重要,此时的并发用户数量可以认为是当前系统的最大负载能力。

二. 相关因素

一般的,和系统并发访问量相关的几个因素如下:

  • 带宽
  • 硬件配置
  • 系统配置
  • 应用服务器配置
  • 程序逻辑
  • 系统架构

其中,带宽和硬件配置是决定系统负载能力的决定性因素。这些只能依靠扩展和升级提高。我们需要重点关注的是在一定带宽和硬件配置的基础上,怎么使系统的负载能力达到最大。

2.1 带宽

毋庸置疑,带宽是决定系统负载能力的一个至关重要的因素,就好比水管一样,细的水管同一时间通过的水量自然就少(这个比喻解释带宽可能不是特别合适)。一个系统的带宽首先就决定了这个系统的负载能力,其单位为Mbps,表示数据的发送速度。

2.2 硬件配置

系统部署所在的服务器的硬件决定了一个系统的最大负载能力,也是上限。一般说来,以下几个配置起着关键作用:

  • cpu频率/核数:cpu频率关系着cpu的运算速度,核数则影响线程调度、资源分配的效率。
  • 内存大小以及速度:内存越大,那么可以在内存中运行的数据也就越大,速度自然而然就快;内存的速度从原来的几百hz到现在几千hz,决定了数据读取存储的速度。
  • 硬盘速度:传统的硬盘是使用磁头进行寻址的,io速度比较慢,使用了SSD的硬盘,其寻址速度大大较快。

很多系统的架构设计、系统优化,最终都会加上这么一句:使用ssd存储解决了这些问题。

可见,硬件配置是决定一个系统的负载能力的最关键因素。

2.3 系统配置

一般来说,目前后端系统都是部署在Linux主机上的。所以抛开win系列不谈,对于Linux系统来说一般有以下配置关系着系统的负载能力。

  • 文件描述符数限制:Linux中所有东西都是文件,一个socket就对应着一个文件描述符,因此系统配置的最大打开文件数以及单个进程能够打开的最大文件数就决定了socket的数目上限。
  • 进程/线程数限制: 对于apache使用的prefork等多进程模式,其负载能力由进程数目所限制。对tomcat多线程模式则由线程数所限制。
  • tcp内核参数:网络应用的底层自然离不开tcp/ip,Linux内核有一些与此相关的配置也决定了系统的负载能力。

2.3.1 文件描述符数限制

  • 系统最大打开文件描述符数:/proc/sys/fs/file-max中保存了这个数目,修改此值
    1
    2
    3
    4
    临时性:
     echo 1000000 > /proc/sys/fs/file-max
    永久性:
    在/etc/sysctl.conf中设置 fs.file-max = 1000000
  • 进程最大打开文件描述符数:这个是配单个进程能够打开的最大文件数目。可以通过ulimit -n查看/修改。如果想要永久修改,则需要修改/etc/security/limits.conf中的nofile。

通过读取/proc/sys/fs/file-nr可以看到当前使用的文件描述符总数。另外,对于文件描述符的配置,需要注意以下几点:

  • 所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max
  • 单个进程打开的文件描述符数不能超过user limit中nofile的soft limit
  • nofile的soft limit不能超过其hard limit
  • nofile的hard limit不能超过/proc/sys/fs/nr_open

2.3.2 进程/线程数限制

  • 进程数限制:ulimit -u可以查看/修改单个用户能够打开的最大进程数。/etc/security/limits.conf中的noproc则是系统的最大进程数。
  • 线程数限制
    • 可以通过/proc/sys/kernel/threads-max查看系统总共可以打开的最大线程数。
    • 单个进程的最大线程数和PTHREAD_THREADS_MAX有关,此限制可以在/usr/include/bits/local_lim.h中查看,但是如果想要修改的话,需要重新编译。
    • 这里需要提到一点的是,Linux内核2.4的线程实现方式为linux threads,是轻量级进程,都会首先创建一个管理线程,线程数目的大小是受PTHREAD_THREADS_MAX影响的。但Linux2.6内核的线程实现方式为NPTL,是一个改进的LWP实现,最大一个区别就是,线程公用进程的pid(tgid),线程数目大小只受制于资源。
    • 线程数的大小还受线程栈大小的制约:使用ulimit -s可以查看/修改线程栈的大小,即每开启一个新的线程需要分配给此线程的一部分内存。减小此值可以增加可以打开的线程数目。

2.3.3 tcp内核参数

在一台服务器CPU和内存资源额定有限的情况下,最大的压榨服务器的性能,是最终的目的。在节省成本的情况下,可以考虑修改Linux的内核TCP/IP参数,来最大的压榨服务器的性能。如果通过修改内核参数也无法解决的负载问题,也只能考虑升级服务器了,这是硬件所限,没有办法的事。

1
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

使用上面的命令,可以得到当前系统的各个状态的网络连接的数目。如下:

1
2
3
4
5
6
7
LAST_ACK 13
SYN_RECV 468
ESTABLISHED 90
FIN_WAIT1 259
FIN_WAIT2 40
CLOSING 34
TIME_WAIT 28322

这里,TIME_WAIT的连接数是需要注意的一点。此值过高会占用大量连接,影响系统的负载能力。需要调整参数,以尽快的释放time_wait连接。

一般tcp相关的内核参数在/etc/sysctl.conf文件中。为了能够尽快释放time_wait状态的连接,可以做以下配置:

  • net.ipv4.tcp_syncookies = 1 //表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
  • net.ipv4.tcp_tw_reuse = 1 //表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
  • net.ipv4.tcp_tw_recycle = 1 //表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;
  • net.ipv4.tcp_fin_timeout = 30 //修改系統默认的 TIMEOUT 时间。

这里需要注意的一点就是当打开了tcp_tw_recycle,就会检查时间戳,移动环境下的发来的包的时间戳有些时候是乱跳的,会把带了“倒退”的时间戳的包当作是“recycle的tw连接的重传数据,不是新的请求”,于是丢掉不回包,造成大量丢包。另外,当前面有LVS,并且采用的是NAT机制时,开启tcp_tw_recycle会造成一些异常,可见:http://www.pagefault.info/?p=416。如果这种情况下仍然需要开启此选项,那么可以考虑设置net.ipv4.tcp_timestamps=0,忽略掉报文的时间戳即可。

此外,还可以通过优化tcp/ip的可使用端口的范围,进一步提升负载能力。,如下:

  • net.ipv4.tcp_keepalive_time = 1200 //表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
  • net.ipv4.ip_local_port_range = 10000 65000 //表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000。(注意:这里不要将最低值设的太低,否则可能会占用掉正常的端口!)
  • net.ipv4.tcp_max_syn_backlog = 8192 //表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
  • net.ipv4.tcp_max_tw_buckets = 5000 //表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参数可以控制TIME_WAIT的最大数量,避免Squid服务器被大量的TIME_WAIT拖死。

2.4 应用服务器配置

说到应用服务器配置,这里需要提到应用服务器的几种工作模式,也叫并发策略。

  • multi process:多进程方式,一个进程处理一个请求。
  • prefork:类似于多进程的方式,但是会预先fork出一些进程供后续使用,是一种进程池的理念。
  • worker:一个线程对应一个请求,相比多进程的方式,消耗资源变少,但同时一个线程的崩溃会引起整个进程的崩溃,稳定性不如多进程。
  • master/worker:采用的是非阻塞IO的方式,只有两种进程:worker和master,master负责worker进程的创建、管理等,worker进程采用基于事件驱动的多路复用IO处理请求。mater进程只需要一个,woker进程根据cpu核数设置数目。

前三者是传统应用服务器apache和tomcat采用的方式,最后一种是nginx采用的方式。当然这里需要注意的是应用服务器和nginx这种做反向代理服务器(暂且忽略nginx+cgi做应用服务器的功能)的区别。应用服务器是需要处理应用逻辑的,有时候是耗cup资源的;而反向代理主要用作IO,是IO密集型的应用。使用事件驱动的这种网络模型,比较适合IO密集型应用,而并不适合CPU密集型应用。对于后者,多进程/线程则是一个更好地选择。

当然,由于nginx采用的基于事件驱动的多路IO复用的模型,其作为反向代理服务器时,可支持的并发是非常大的。淘宝tengine团队曾有一个测试结果是“24G内存机器上,处理并发请求可达200万”。

2.4.1 nginx/tengine

ngixn是目前使用最广泛的反向代理软件,而tengine是阿里开源的一个加强版nginx,其基本实现了nginx收费版本的一些功能,如:主动健康检查、session sticky等。对于nginx的配置,需要注意的有这么几点:

  • worker数目要和cpu(核)的数目相适应
  • keepalive timout要设置适当
  • worker_rlimit_nofile最大文件描述符要增大
  • upstream可以使用http 1.1的keepalive

典型配置可见:https://github.com/superhj1987/awesome-config/blob/master/nginx/nginx.conf

2.4.2 tomcat

tomcat的关键配置总体上有两大块:jvm参数配置和connector参数配置。

  • jvm参数配置:
    • 堆的最小值:Xms
    • 堆的最大值:Xmx
    • 新生代大小: Xmn
    • 永久代大小: XX:PermSize:
    • 永久代最大大小: XX:MaxPermSize:
    • 栈大小:-Xss或-XX:ThreadStackSize

    这里对于栈大小有一点需要注意的是:在Linux x64上ThreadStackSize的默认值就是1024KB,给Java线程创建栈会用这个参数指定的大小。如果把-Xss或者-XX:ThreadStackSize设为0,就是使用“系统默认值”。而在Linux x64上HotSpot VM给Java栈定义的“系统默认”大小也是1MB。所以普通Java线程的默认栈大小怎样都是1MB。这里有一个需要注意的地方就是java的栈大小和之前提到过的操作系统的操作系统栈大小(ulimit -s):这个配置只影响进程的初始线程;后续用pthread_create创建的线程都可以指定栈大小。HotSpot VM为了能精确控制Java线程的栈大小,特意不使用进程的初始线程(primordial thread)作为Java线程。

    其他还要根据业务场景,选择使用那种垃圾回收器,回收的策略。另外,当需要保留GC信息时,也需要做一些设置。

    典型配置可见:https://github.com/superhj1987/awesome-config/blob/master/tomcat/java_opts.conf

  • connector参数配置
    • protocol: 有三个选项:bio;nio;apr。建议使用apr选项,性能为最高。
    • connectionTimeout:连接的超时时间
    • maxThreads:最大线程数,此值限制了bio的最大连接数
    • minSpareThreads: 最大空闲线程数
    • acceptCount:可以接受的最大请求数目(未能得到处理的请求排队)
    • maxConnection: 使用nio或者apr时,最大连接数受此值影响。

    典型配置可见:https://github.com/superhj1987/awesome-config/blob/master/tomcat/connector.conf

    一般的当一个进程有500个线程在跑的话,那性能已经是很低很低了。Tomcat默认配置的最大请求数是150。当某个应用拥有250个以上并发的时候,应考虑应用服务器的集群。

    另外,并非是无限调大maxTreads和maxConnection就能无限调高并发能力的。线程越多,那么cpu花费在线程调度上的时间越多,同时,内存消耗也就越大,那么就极大影响处理用户的请求。受限于硬件资源,并发值是需要设置合适的值的。

对于tomcat这里有一个争论就是:使用大内存tomcat好还是多个小的tomcat集群好?(针对64位服务器以及tomcat来说)

其实,这个要根据业务场景区别对待的。通常,大内存tomcat有以下问题:

  • 一旦发生full gc,那么会非常耗时
  • 一旦gc,dump出的堆快照太大,无法分析

因此,如果可以保证一定程度上程序的对象大部分都是朝生夕死的,老年代不会发生gc,那么使用大内存tomcat也是可以的。但是在伸缩性和高可用却比不上使用小内存(相对来说)tomcat集群。

使用小内存tomcat集群则有以下优势:

  • 可以根据系统的负载调整tc的数量,以达到资源的最大利用率,
  • 可以防止单点故障。

2.4.3 数据库

mysql

mysql是目前最常用的关系型数据库,支持复杂的查询。但是其负载能力一般,很多时候一个系统的瓶颈就发生在mysql这一点,当然有时候也和sql语句的效率有关。比如,牵扯到联表的查询一般说来效率是不会太高的。

影响数据库性能的因素一般有以下几点:

  • 硬件配置:这个无需多说
  • 数据库设置:max_connection的一些配置会影响数据库的连接数
  • 数据表的设计:使用冗余字段避免联表查询;使用索引提高查询效率
  • 查询语句是否合理:这个牵扯到的是个人的编码素质。比如,查询符合某个条件的记录,我见过有人把记录全部查出来,再去逐条对比
  • 引擎的选择:myisam和innodb两者的适用场景不同,不存在绝对的优劣

抛开以上因素,当数据量单表突破千万甚至百万时(和具体的数据有关),需要对mysql数据库进行优化,一种常见的方案就是分表:

  • 垂直分表:在列维度的拆分
  • 水平分表:行维度的拆分

此外,对于数据库,可以使用读写分离的方式提高性能,尤其是对那种读频率远大于写频率的业务场景。这里一般采用master/slave的方式实现读写分离,前面用程序控制或者加一个proxy层。可以选择使用MySQL Proxy,编写lua脚本来实现基于proxy的mysql读写分离;也可以通过程序来控制,根据不同的sql语句选择相应的数据库来操作,这个也是笔者公司目前在用的方案。由于此方案和业务强绑定,是很难有一个通用的方案的,其中比较成熟的是阿里的TDDL,但是由于未全部开源且对其他组件有依赖性,不推荐使用。

现在很多大的公司对这些分表、主从分离、分布式都基于mysql做了自己的二次开发,形成了自己公司的一套分布式数据库系统。比如阿里的Cobar、网易的DDB、360的Atlas等。当然,很多大公司也研发了自己的mysql分支,比较出名的就是姜承尧带领研发的InNoSQL

redis

当然,对于系统中并发很高并且访问很频繁的数据,关系型数据库还是不能妥妥应对。这时候就需要缓存数据库出马以隔离对mysql的访问,防止mysql崩溃。

其中,redis是目前用的比较多的缓存数据库(当然,也有直接把redis当做数据库使用的)。redis是单线程基于内存的数据库,读写性能远远超过mysql。一般情况下,对redis做读写分离主从同步就可以应对大部分场景的应用。但是这样的方案缺少ha,尤其对于分布式应用,是不可接受的。目前,redis集群的实现方案有以下几个:

  • redis cluster:这是一种去中心化的方案,是redis的官方实现。是一种非常“重”的方案,已经不是Redis单实例的“简单、可依赖”了。目前应用案例还很少,貌似国内的芒果台用了,结局不知道如何。
  • twemproxy:这是twitter开源的redis和memcached的proxy方案。比较成熟,目前的应用案例比较多,但也有一些缺陷,尤其在运维方面。比如无法平滑的扩容/缩容,运维不友好等。
  • codis: 这个是豌豆荚开源的redis proxy方案,能够兼容twemproxy,并且对其做了很多改进。由豌豆荚于2014年11月开源,基于Go和C开发。现已广泛用于豌豆荚的各种Redis业务场景。现在比Twemproxy快近100%。目前据我所知除了豌豆荚之外,hulu也在使用这套方案。当然,其升级项目reborndb号称比codis还要厉害。

2.5 系统架构

影响性能的系统架构一般会有这几方面:

  • 负载均衡
  • 同步 or 异步
  • 28原则

2.5.1 负载均衡

负载均衡在服务端领域中是一个很关键的技术。可以分为以下两种:

  • 硬件负载均衡
  • 软件负载均衡

其中,硬件负载均衡的性能无疑是最优的,其中以F5为代表。但是,与高性能并存的是其成本的昂贵。所以对于很多初创公司来说,一般是选用软件负载均衡的方案。

软件负载均衡中又可以分为四层负载均衡和七层负载均衡。 上文在应用服务器配置部分讲了nginx的反向代理功能即七层的一种成熟解决方案,主要针对的是七层http协议(虽然最新的发布版本已经支持四层负载均衡)。对于四层负载均衡,目前应用最广泛的是lvs。其是阿里的章文嵩博士带领的团队所研发的一款linux下的负载均衡软件,本质上是基于iptables实现的。分为三种工作模式:

  • NAT: 修改数据包destination ip,in和out都要经过lvs。
  • DR:修改数据包mac地址,lvs和realserver需要在一个vlan。
  • IP TUUNEL:修改数据包destination ip和源ip,realserver需要支持ip tunnel协议。lvs和realserver不需要在一个vlan。

三种模式各有优缺点,目前还有阿里开源的一个FULL NAT是在NAT原来的DNAT上加入了SNAT的功能。

此外,haproxy也是一款常用的负载均衡软件。但限于对此使用较少,在此不做讲述。

2.5.2 同步 or 异步

对于一个系统,很多业务需要面对使用同步机制或者是异步机制的选择。比如,对于一篇帖子,一个用户对其分享后,需要记录用户的分享记录。如果你使用同步模式(分享的同时记录此行为),那么响应速度肯定会受到影响。而如果你考虑到分享过后,用户并不会立刻去查看自己的分享记录,牺牲这一点时效性,可以先完成分享的动作,然后异步记录此行为,会提高分享请求的响应速度(当然,这里可能会有事务准确性的问题)。有时候在某些业务逻辑上,在充分理解用户诉求的基础上,是可以牺牲某些特性来满足用户需求的。

这里值得一提的是,很多时候对于一个业务流程,是可以拆开划分为几个步骤的,然后有些步骤完全可以异步并发执行,能够极大提高处理速度。

2.5.3 28原则

对于一个系统,20%的功能会带来80%的流量。这就是28原则的意思,当然也是我自己的一种表述。因此在设计系统的时候,对于80%的功能,其面对的请求压力是很小的,是没有必要进行过度设计的。但是对于另外20%的功能则是需要设计再设计、reivew再review,能够做负载均衡就做负载均衡,能够缓存就缓存,能够做分布式就分布式,能够把流程拆开异步化就异步化。

当然,这个原则适用于生活中很多事物。

三. 一般架构

一般的Java后端系统应用架构如下图所示:LVS+Nginx+Tomcat+MySql/DDB+Redis/Codis

web-arch

其中,虚线部分是数据库层,采用的是主从模式。也可以使用redis cluster(codis等)以及mysql cluster(Cobar等)来替换。

from:http://www.rowkey.me/blog/2015/09/09/load-analysis/