早期
最后更新于:2022-04-01 01:49:50
## Leo
和现在很多站点开始的时候一样, LinkedIn使用一个应用程序做所有的工作。 这个应用程序被称之为 "Leo"。它包含所有的Java Servlet页面, 处理业务逻辑, 连接少量的LinkedIn数据库。
[![*哈!早年网站的样式-简单实用*](http://colobu.com/2015/07/24/brief-history-scaling-linkedin/leo_arch.png)](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-30_55b9e34927a3a.png "*哈!早年网站的样式-简单实用*")
*哈!早年网站的样式-简单实用*
## Member Graph (会员关系图)
开始的工作之一就是管理会员之间关系的社交网络。我们需要一个系统通过图遍历(graph traversals)的方式来查询关系数据, 同时需要将数据驻留内存以便获得高效和性能。从这个不同的使用特征来看, 很明显这需要一个独立于Leo的系统以方便扩大规模,于是一个叫做"Clould"专门用于会员关系图(member graph)的独立系统诞生了。这是LinkedIn的第一个服务系统。为了和Leo系统分离,我们使用Java RPC来进行通讯。
也大约在此期间我们需要增加搜索服务的能力。我们的会员关系图服务也提供数据给一个基于[Lucene](https://lucene.apache.org/)的搜索服务。
## Replica read DBs (多个只读数据库副本)
随着站点的增长, Leo系统也在扩大, 增加了更多的角色和职能, 也更加复杂。 通过负载均衡可以运行多个Leo实例,但是新增的负载也影响到LinkedIn的最关键系统-会员信息数据库。
一个最容易的解决方案就是垂直扩展 - 在其上增加更多的CPU和内存。这虽然可以支撑一段时间,但是将来我们还是会遇到规模扩展的问题。会员信息数据库既处理读又处理写。 为了扩展,我们引入了复制从库(replica slave DB)。 复制数据库是会员数据库的一个拷贝, 使用 [databus](http://data.linkedin.com/blog/2012/10/driving-the-databus) (现已开源)的最早版本来进行同步。这些复制从库处理所有的读请求, 并且增加了保证主库和从库数据一致性的逻辑。
[![*主从读写分离的方案之后,我们转向了数据库分区的解决方案*](http://colobu.com/2015/07/24/brief-history-scaling-linkedin/arch_master_slave_0.png)](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-30_55b9e35579c93.png "*主从读写分离的方案之后,我们转向了数据库分区的解决方案*")
*主从读写分离的方案之后,我们转向了数据库分区的解决方案*
当站点遇到越来越多的流量时,单一的Leo系统经常宕机,而且很难排查和恢复, 发布新代码也很困难。 高可用性对LinkedIn至关重要, 很明显我们需要"干掉" Leo, 把它分解成多个小的功能模块和无状态的服务。
[![*"Kill Leo"这个咒语在内部传颂了好多年*](http://colobu.com/2015/07/24/brief-history-scaling-linkedin/leo-poster.jpg)](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-30_55b9e357d39e7.jpg "*")
*"Kill Leo"这个咒语在内部传颂了好多年*
## Service Oriented Architecture (面向服务的架构)
工程师开始抽取出一些微服务, 这些微服务提供API和一些业务逻辑, 如搜索,会员信息, 通讯和群组平台。接着我们的表现层也被抽取出来了,比如招聘产品和公共信息页。新产品,新服务都独立于Leo。 不久,各个功能区的垂直栈完成了。
我们构建了前端服务器, 可以从不同的域获取数据,处理展示逻辑以及生成HTML (通过JSP)。我们还构建了中间层服务提供API接口访问数据模型以及提供数据库一致性访问后端数据服务。到2010年,我们已经有超过150个独立的服务,而今天,我们已经有超过750个服务。
[![](http://colobu.com/2015/07/24/brief-history-scaling-linkedin/arch_soa_0.png)](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-30_55b9e358dee69.png)
因为无状态, 规模扩展可以通过堆叠任意服务的新实例以及在它们之间进行负载均衡来完成。我们给每个服务设定了警戒红线, 知道它的负载能力, 提供早期预警和性能监控。
## cache (缓存)
LinkedIn可预见的增长促使我们要进一步的扩展。我们知道通过添加更多的缓存层以减少负载压力。很多应用开始引入中间缓存层如 [memecached](https://en.wikipedia.org/wiki/Memcached) 或者 [couchbase](https://en.wikipedia.org/wiki/Couchbase_Server)。 我们还在数据层增加了缓存, 并且在适当的时候使用 [Voldemort](http://engineering.linkedin.com/tags/voldemort) 提供预先计算的结果。
之后,我们实际上去掉了中间缓存层。中间缓存层存储来自多个域的数据。虽然开始时缓存看起来是减少压力的一种简单方式,但是缓存数据失效的复杂性和调用图(call graph)变得无法控制。将缓存更可能地接近数据层可以降低延迟, 使我们可以水平扩展,降低可知的负载(cognitive load)。
## Kafka
为了收集日益增长的数据,LinkedIn开发了很多定制的数据通道来流水化和队列化数据(streaming and queueing)。 比如, 我们需要将数据放入数据仓库,我们需要将一批数据放入Hadoop工作流以便分析,我们从每个服务中中聚合了大量日志, 我们收集了很多用户追踪事件如页面点击, 我们需要队列化inMail消息系统中的数据, 我们需要保证用户更新完个人信息后搜索数据也是最新的等等。
随着网站还在壮大,更多的定制管道出现了。 因为网站规模需要扩展,每一个独立的管道也需要扩展, 有些东西不得不放弃。 结果就是Kafka开发出来了, 它是我们的分布式的发布订阅消息系统。Kafka成为一个统一的管道, 根据[commit log](http://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying)的概念构建, 特别注重速度和扩展性。 它可以接近实时的访问数据源,驱动Hadoop任务, 允许我们构建实时的分析,广泛地提升了我们的站点监控和报警能力, 也使我们能够可视化和跟踪调用图(call graph)。 今天, Kafka 每天处理超过[5千亿的事件](http://engineering.linkedin.com/kafka/kafka-linkedin-current-and-future)。
[![](http://colobu.com/2015/07/24/brief-history-scaling-linkedin/kafka.png)](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-30_55b9e35b43305.png)
## Inversion(反转)
扩展可以从很多维度来衡量,包括组织结构。 在2011年底, LinkedIn开始了一个内部创新,叫 “反转” ([Inversion](http://www.bloomberg.com/bw/articles/2013-04-10/inside-operation-inversion-the-code-freeze-that-saved-linkedin))。我们暂停了新功能的开发, 允许整个工程部门专注于提升工具,部署,基础架构和开发者生产力上。它成功地使我们可以敏捷地建立可扩展性新产品。