热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

知乎网站构架变迁

也许很多人还不知道,知乎在规模上是仅次于百度贴吧和豆瓣的中文互联网最大的UGC(用户生成内容)社区。知乎创业三年来,从0开始,到现在已经有了100多台服务器。
知乎是一个真实的网络问答社区,社区氛围友好与理性,连接各行各业的精英。用户分享着彼此的专业知识、经验和见解,为中文互联网源源不断地提供高质量的信息。

也许很多人还不知道,知乎在规模上是仅次于百度贴吧和豆瓣的中文互联网最大的UGC(用户生成内容)社区。知乎创业三年来,从0开始,到现在已经有了100多台服务器。目前知乎的注册用户超过了1100万,每个月有超过8000万人使用;网站每个月的PV超过2.2亿,差不多每秒钟的动态请求超过2500。

在ArchSummit北京2014大会上,知乎联合创始人兼 CTO 李申申带来了知乎创业三年多来的首次全面技术分享。

初期架构选型

在2010年10月真正开始动手做知乎这个产品时,包含李申申在内,最初只有两位工程师;到2010年12月份上线时,工程师是四个。

知乎的主力开发语言是Python。因为Python简单且强大,能够快速上手,开发效率高,而且社区活跃,团队成员也比较喜欢。

知乎使用的是Tornado框架。因为它支持异步,很适合做实时comet应用,而且简单轻量,学习成本低,再就是有FriendFeed 的成熟案例,Facebook 的社区支持。知乎的产品有个特性,就是希望跟浏览器端建立一个长连接,便于实时推送Feed和通知,所以Tornado比较合适。

最初整个团队的精力全部放在产品功能的开发上,而其他方面,基本上能节约时间、能省的都用最简单的方法来解决,当然这在后期也带来了一些问题。

最初的想法是用云主机,节省成本。知乎的第一台服务器是512MB内存的Linode主机。但是网站上线后,内测受欢迎程度超出预期,很多用户反馈网站很慢。跨国网络延迟比想象的要大,特别是国内的网络不均衡,全国各地用户访问的情况都不太一样。这个问题,再加上当时要做域名备案,知乎又回到了自己买机器找机房的老路上。

买了机器、找了机房之后又遇到了新的问题,服务经常宕掉。当时服务商的机器内存总是出问题,动不动就重启。终于有一次机器宕掉起不来了,这时知乎就做了Web和数据库的高可用。创业就是这样一个情况,永远不知道明早醒来的时候会面临什么样的问题。

这是当时那个阶段的架构图,Web和数据库都做了主从。当时的图片服务托管在又拍云上。 除了主从,为了性能更好还做了读写分离。为解决同步问题,又添加了一个服务器来跑离线脚本,避免对线上服务造成响应延迟。另外,为改进内网的吞吐量延迟, 还更换了设备,使整个内网的吞吐量翻了20倍。

在2011年上半年时,知乎对Redis已经很依赖。除了最开始的队列、搜索在用,后来像Cache也开始使用,单机存储成为瓶颈,所以引入了分片,同时做了一致性。

知乎团队是一个很相信工具的团队,相信工具可以提升效率。工具其实是一个过程,工具并没有所谓的最好的工具,只有最适合的工具。而且它是在整个过程中,随着整个状态的变化、环境的变化在不断发生变化的。知乎自己开发或使用过的工具包括Profiling(函数级追踪请求,分析调优)、Werkzeug(方便调试的工具)、Puppet(配置管理)和Shipit(一键上线或回滚)等。

日志系统

知乎最初是邀请制的,2011年下半年,知乎上线了申请注册,没有邀请码的用户也可以通过填写一些资料申请注册知乎。用户量又上了一个台阶,这时就有了一些发广告的账户,需要扫除广告。日志系统的需求提上日程。

这个日志系统必须支持分布式收集、集中存储、实时、可订阅和简单等特性。当时调研了一些开源系统,比如Scribe总体不错,但是不支持订阅。Kafka是Scala开发的,但是团队在Scala方面积累较少,Flume也是类似,而且比较重。所以开发团队选择了自己开发一个日志系统——Kids(Kids Is Data Stream)。顾名思义,Kids是用来汇集各种数据流的。

Kids参考了Scribe的思路。Kdis在每台服务器上可以配置成Agent或 Server。Agent直接接受来自应用的消息,把消息汇集之后,可以打给下一个Agent或者直接打给中心Server。订阅日志时,可以从 Server上获取,也可以从中心节点的一些Agent上获取。

具体细节如下图所示:

知乎还基于Kids做了一个Web小工具(Kids Explorer),支持实时看线上日志,现在已经成为调试线上问题最主要的工具。

Kids已经开源,放到了Github上。

事件驱动的架构

知乎这个产品有一个特点,最早在添加一个答案后,后续的操作其实只有更新通知、更新动 态。但是随着整个功能的增加,又多出了一些更新索引、更新计数、内容审查等操作,后续操作五花八门。如果按照传统方式,维护逻辑会越来越庞大,维护性也会 非常差。这种场景很适合事件驱动方式,所以开发团队对整个架构做了调整,做了事件驱动的架构。

这时首先需要的是一个消息队列,它应该可以获取到各种各样的事件,而且对一致性有很高的 要求。针对这个需求,知乎开发了一个叫Sink的小工具。它拿到消息后,先做本地的保存、持久化,然后再把消息分发出去。如果那台机器挂掉了,重启时可以 完整恢复,确保消息不会丢失。然后它通过Miller开发框架,把消息放到任务队列。Sink更像是串行消息订阅服务,但任务需要并行化处理, Beanstalkd就派上了用场,由其对任务进行全周期管理。架构如下图所示:

举例而言,如果现在有用户回答了问题,首先系统会把问题写到MySQL里面,把消息塞到Sink,然后把问题返回给用户。Sink通过Miller把任务发给 Beanstalkd,Worker自己可以找到任务并处理。

最开始上线时,每秒钟有10个消息,然后有70个任务产生。现在每秒钟有100个事件,有1500个任务产生,就是通过现在的事件驱动架构支撑的。

页面渲染优化

知乎在2013年时每天有上百万的PV,页面渲染其实是计算密集型的,另外因为要获取数据,所以也有IO密集型的特点。这时开发团队就对页面进行了组件化,还升级了数据获取机制。知乎按照整个页面组件树的结构,自上而下分层地获取数据,当上 层的数据已经获取了,下层的数据就不需要再下去了,有几层基本上就有几次数据获取。

结合这个思路,知乎自己做了一套模板渲染开发框架——ZhihuNode。

经历了一系列改进之后,页面的性能大幅度提升。问题页面从500ms 减少到150ms,Feed页面从1s减少到600ms。

面向服务的架构(SOA)

随着知乎的功能越来越庞杂,整个系统也越来越大。知乎是怎么做的服务化呢?

首先需要一个最基本的RPC框架,RPC框架也经历了好几版演进。

第一版是Wish,它是一个严格定义序列化的模型。传输层用到了STP,这是自己写的很 简单的传输协议,跑在TCP上。一开始用的还不错,因为一开始只写了一两个服务。但是随着服务增多,一些问题开始出现,首先是 ProtocolBuffer会 生成一些描述代码,很冗长,放到整个库里显得很丑陋。另外严格的定义使其不便使用。这时有位工程师开发了新的RPC框架——Snow。它使用简单的 JSON做数据序列化。但是松散的数据定义面对的问题是,比如说服务要去升级,要改写数据结构,很难知道有哪几个服务在使用,也很难通知它们,往往错误就 发生了。于是又出了第三个RPC框架,写RPC框架的工程师,希望结合前面两个框架的特点,首先保持Snow简单,其次需要相对严格的序列化协议。这一版 本引入了 Apache Avro。同时加入了特别的机制,在传输层和序列化协议这一层都做成了可插拔的方式,既可以用JSON,也可以用Avro,传输层可以用STP,也可以用 二进制协议。

再就是搭了一个服务注册发现,只需要简单的定义服务的名字就可以找到服务在哪台机器上。同时,知乎也有相应的调优的工具,基于Zipkin开发了自己的 Tracing系统。

按照调用关系,知乎的服务分成了3层:聚合层、内容层和基础层。按属性又可以分成3类:数据服务、逻辑服务和通道服务。数据服务主要是一些要做特殊数据类型的存储,比如图片服务。逻辑服务更多的是CPU密集、计算密集的操作,比如答案格式的定义、解析等。通道服务的特点是没有存储,更多是做一个转发,比如说Sink。

这是引入服务化之后整体的架构。

产品服务

知乎首页,大致有四个功能区。在左侧,是“最新动态”,大约占到首页70%版面,主要呈现用户所关注人的最新提问及回答等信息。用户在这一版块,除了查看最新问题及回答之外,也

可以通过“设置”、“关注问题”、“添加评论”“分享”、“感谢”和“收藏”等功能参与到自己感兴趣的问题中。如利用“设置”功能,用户可以选择屏蔽话题。在所关注用户关注问题下,也可以对该问题添加关注、添加评论等行为。

在首页右上方版面,是用户在知乎网相关行为管理信息。有“我的草稿”、“我的收藏”、“所有问题”、“我关注的问题”和“邀请我回答的问题”。 在右侧中间位置,是网外邀请功能——“邀请好友加入知乎”。在这个版块中,用户可以通过电子邮件和新浪微博邀请自己朋友加入到知乎社区中。 在右侧中下方,为用户关注或感兴趣话题或用户推荐板块。话题和用户推荐上,知乎运营方一方面可能根据用户关注话题信息汇总,一方面可能通过用户在知乎网络相关行为数据记录统计,达到相当准确推荐和汇总。同时,尤为一提的是,右下方的“话题广场”板块中,知乎网将所有话题分类标签呈现,为用户除搜索和导航之外,有一种不错的获取信息方式。

知乎话题页,可以分为两个板块,如图2所示,一个是“话题动态”,一个是“常去话题”。在左侧为“话题动态”信息,占到版面大约70%。在这一板块中,用户可以对所关注话题下问题(按时间顺序呈现)点击查看,也可以对所关注话题进行“固定”和“取消关注”操作。

在右下方,是“常去话题”版面。在这一版面中,用户可以了解到所关注话题具体诸如子话题、关注人数和动态等信息。

知乎通知页,可以分为四个版面,如图3所示。左侧“全部通知”为用户关注问题为其他用户回答信息(按时间先后顺序呈现)。右侧,用户行为数据汇总、“邀请好友加入知乎”、话题及话题推荐版面等,和首页介绍一样,这里不再赘述。

知乎个人主页大致分为5个版面:“个人资料”、“个人回答”、“个人主页”、“搜索用户问题和答案”、“关注人和被关注信息”和“关注话题”。具体如图4所示。

在“个人资料”版面,用户可以通过点击“查看详细资料”查看用户“个人成就”(包括获得“赞同”数量、“感谢”数量、“收藏”数量和“分享”数量)、“职业经历“、”居住信息“、”教育经历“、”擅长技能“5个方面信息。如果是知乎用户,可以通过点击”编辑我的资料“完善以上5个方面信息。

左下方,为“个人回答“版面,是用户对相关问题回答信息(按照赞同数量降序排列或按照回答时间顺序由近到远排列)。以上”个人资料“和”个人回答“两个版面能占到整个70%位置。

在右上方,为“个人主页“版面,是对知乎最新动态,用户提的问题、回答、收藏和日志信息汇总。

右侧中间位置,是一个搜索框。用户可以通过这个搜索框查询具体用户的问题和回答内容。

右侧中下方,分别是用户个人关注人或被关注和关注话题信息。用户可以通过点击相关图标,一键连接具体板块中。

知乎问题页面——是知乎最主要的页面。在这里用户可以了解、编辑、回答具体问题和信息,

知乎这一版面,按照功能大致可以分为六个部分,即“问题回答”、“关注功能”、“邀请功能”、“相关问题链接”、“分享功能”和“问题状态”。

在左侧位置,为“问题回答”版面,占到这一板块大约70%位置。在这一板块的版面中,用户可以对相关问题进行修改、评论、举报和管理投票。 用户可以对自己觉得不合适问题、问题标签和问题补充进行修改。同时,如果发现不合适或自己感兴趣问题,用户也可以评论或举报。在问题回答上,用户可以按照相当适合自己方式对问题回答进

行排序操作(知乎提供按投票排序、按时间排序和按用户关注人显示三种内容呈现方式)。

除此,值得一提的是每个回答左侧有分别代表赞同和反对一上一下两个三角形,如图6所示。用户可以根据自己知识理解角度或兴趣对问题回答进行个性化管理。

在这一板块右侧,由上到下首先是“关注”功能。这一功能板块中,用户可以对问题进行关注,这有点像新浪微博关注功能,不同的是,知乎关注主要针对具体问题,而新浪微博主要针对具体用户。

右侧再向下,是“邀请别人回答问题”版面。这和前面“知乎首页”和“知乎通知”板块介绍功能一样,这里不再赘述。

再向下,是与问题相关各个问题。这也是大多数网站系统推荐方式的一种。虽然这一种推荐方式在技术和经验上相对比较成熟,但效果上并不是达到毫无挑剔程度。知乎在问题相关问题链接方面,主要是针对具体问题特点,通过相应算法进行机器推荐,并没有做到针对不同用户爱好个性推荐效果(这也是未来互联网发展趋势,电子商务平台更为关注这一技术)。

再向下,便是问题分享功能。用户可以将知乎问题通过“微博“和”邮件“进行站外分享和通过“站内私信”进行站内分享。

在右侧最下方位置,便是问题状态。在这一版面中,用户可以了解问题最近活动发生时间,被浏览次数、相关话题关注者人数和该问题关注人数信息。

用户体验

1、 准确地讲,知乎更像一个论坛:用户围绕着某一感兴趣的话题进行相关的讨论,同时你可以关注和你兴趣一致的人。对于概念性的解释,网络百科几乎涵盖了你所有的疑问;但是对于发散思维的整合,却是知乎的一大特色。知乎鼓励在问答过程中进行讨论,以拓宽问题的发散性。鼓励答案的非针对性,鼓励答案的Wiki可参考性。

2、比论坛更加具有排他性,在知乎的每一个注册用户都有一个PR(Person Rank),你的每一个操作都将直接影响你个人的PR 值。在回答的时候,答案顺序按赞同票数排序,赞同票数相同的情况下按个人PR值排序,同时隐藏被认为无效的答案。这在一定程度上过滤了相当的垃圾信息。

3、知乎曾经坚持严格的邀请制度,一来是为了确保用户准实名身份的真实性,二来避免产生过多的垃圾信息。准实名可以方便用户有的放矢的向你感兴趣的人提出疑问,这是当初韩寒流产的《独唱团》中有一个相当有意思的栏目,“所有人问所有人”,换句话说,这就是现实版的知乎。同时,知乎严格的邀请制度也使知乎笼罩着浓郁的严谨氛围,以keso为代表,不言则已,一言服人。

自2013年3月起,知乎向公众开放注册。

4、以信用为基础的SNS关系。可能单纯作为SNS与问答的整合,国内人人网应该更能快速发展;但是正如前文所说,严格的邀请制度,排斥了相当一部分无效信息;如果人人网亦推出社会化问答,那必然会整合你原先的好友,而这部分好友显然不可能都是对你的关注点感兴趣的人。这也几乎否定了任何大型互联网公司进军Quora类问答的可能性。

因为大型互联网公司受众普遍广泛,而Quora类问答并不是单纯以人气为基础的,而是价值信息比(价值信息/总信息量),也就是精英信息产生量。

不过千橡旗下低调推出经纬网,作为垂直SNS聚集了相当数目的职业人,倘若千橡以此为契合点,整合类Quora问答,还是相当有潜力的。

5、与Quora相比,知乎以蓝色为基调。相比与Quora,知乎功能还是有待完善,比如某一话题下最佳话题。

推荐阅读
  • 精选10款Python框架助力并行与分布式机器学习
    随着神经网络模型的不断深化和复杂化,训练这些模型变得愈发具有挑战性,不仅需要处理大量的权重,还必须克服内存限制等问题。本文将介绍10款优秀的Python框架,帮助开发者高效地实现分布式和并行化的深度学习模型训练。 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • Kafka 是由 Apache 软件基金会开发的高性能分布式消息系统,支持高吞吐量的发布和订阅功能,主要使用 Scala 和 Java 编写。本文将深入解析 Kafka 的安装与配置过程,为程序员提供详尽的操作指南,涵盖从环境准备到集群搭建的每一个关键步骤。 ... [详细]
  • Requests库的基本使用方法
    本文介绍了Python中Requests库的基础用法,包括如何安装、GET和POST请求的实现、如何处理Cookies和Headers,以及如何解析JSON响应。相比urllib库,Requests库提供了更为简洁高效的接口来处理HTTP请求。 ... [详细]
  • Jupyter Notebook多语言环境搭建指南
    本文详细介绍了如何在Linux环境下为Jupyter Notebook配置Python、Python3、R及Go四种编程语言的环境,包括必要的软件安装和配置步骤。 ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 本文详细介绍了 Spark 中的弹性分布式数据集(RDD)及其常见的操作方法,包括 union、intersection、cartesian、subtract、join、cogroup 等转换操作,以及 count、collect、reduce、take、foreach、first、saveAsTextFile 等行动操作。 ... [详细]
  • 从0到1搭建大数据平台
    从0到1搭建大数据平台 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 本文整理了关于Sia去中心化存储平台的重要网址和资源,旨在为研究者和用户提供全面的信息支持。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 在当今的软件开发领域,分布式技术已成为程序员不可或缺的核心技能之一,尤其在面试中更是考察的重点。无论是小微企业还是大型企业,掌握分布式技术对于提升工作效率和解决实际问题都至关重要。本周的Java架构师实战训练营中,我们深入探讨了Kafka这一高效的分布式消息系统,它不仅支持发布订阅模式,还能在高并发场景下保持高性能和高可靠性。通过实际案例和代码演练,学员们对Kafka的应用有了更加深刻的理解。 ... [详细]
  • 在本地环境中部署了两个不同版本的 Flink 集群,分别为 1.9.1 和 1.9.2。近期在尝试启动 1.9.1 版本的 Flink 任务时,遇到了 TaskExecutor 启动失败的问题。尽管 TaskManager 日志显示正常,但任务仍无法成功启动。经过详细分析,发现该问题是由 Kafka 版本不兼容引起的。通过调整 Kafka 客户端配置并升级相关依赖,最终成功解决了这一故障。 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
author-avatar
邹昕明
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有