<audio id="audio" title="09 | 架构设计原则案例" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/60/87/60b1d7e351735aff7a85743284e82687.mp3"></audio>

周二，我给你介绍了架构设计的三条核心原则，先复习一下：合适原则、简单原则和演化原则。我们在架构设计实践中，应该时刻谨记这三条设计原则，指导我们设计出合适的架构，即使是代表中国互联网技术最顶尖水平的BAT，其架构的发展历程也同样遵循这三条原则。

今天我就以大家耳熟能详的淘宝和手机QQ作为案例，来简单分析一下。

## 淘宝

注：以下部分内容摘自《淘宝技术发展》。

淘宝技术发展主要经历了“个人网站”→“Oracle/支付宝/旺旺”→“Java时代1.0”→“Java时代2.0”→“Java时代3.0”→“分布式时代”。我们看看每个阶段的主要驱动力是什么。

1.个人网站

> 
2003年4月7日马云提出成立淘宝，2003年5月10日淘宝就上线了，中间只有1个月，怎么办？淘宝的答案就是：买一个。


> 
估计大部分人很难想象如今技术牛气冲天的阿里最初的淘宝竟然是买来的，我们看看当初决策的依据：


> 
当时对整个项目组来说压力最大的就是时间，怎么在最短的时间内把一个从来就没有的网站从零开始建立起来？了解淘宝历史的人知道淘宝是在 2003 年 5 月 10 日上线的，这之间只有一个月。要是你在这个团队里，你怎么做？我们的答案就是：买一个来。


淘宝当时在初创时，没有过多考虑技术是否优越、性能是否海量以及稳定性如何，主要的考虑因素就是：快！

因为此时业务要求快速上线，时间不等人，等你花几个月甚至十几个月搞出一个强大的系统出来，可能市场机会就没有了，黄花菜都凉了。

同样，在考虑如何买的时候，淘宝的决策依据主要也是“快”。

> 
买一个网站显然比做一个网站要省事一些，但是他们的梦想可不是做一个小网站而已，要做大，就不是随便买个就行的，要有比较低的维护成本，要能够方便地扩展和二次开发。


> 
那接下来就是第二个问题：买一个什么样的网站？答案是：轻量一点的，简单一点的。


**买一个系统是为了“快速可用”，而买一个轻量级的系统是为了“快速开发”**。因为系统上线后肯定有大量的需求需要做，这时能够快速开发就非常重要。

从这个实例我们可以看到：淘宝最开始的时候业务要求就是“快”，因此反过来要求技术同样要“快”，业务决定技术，这里架构设计和选择主要遵循的是“合适原则”和“简单原则”。

第一代的技术架构如图所示。

<img src="https://static001.geekbang.org/resource/image/36/yd/369c79010ebbdea7fbc787a9f8388yyd.jpg" alt="" />

2.Oracle/支付宝/旺旺

淘宝网推出后，由于正好碰到“非典”，网购很火爆，加上采取了成功的市场运作，流量和交易量迅速上涨，业务发展很快，在2003年底，MySQL已经撑不住了。

一般人或者团队在这个时候，可能就开始优化系统、优化架构、分拆业务了，因为这些是大家耳熟能详也很拿手的动作。那我们来看看淘宝这个时候怎么采取的措施：

> 
技术的替代方案非常简单，就是换成Oracle。换Oracle的原因除了它容量大、稳定、安全、性能高，还有人才方面的原因。


可以看出这个时候淘宝的策略主要还是“买”，买更高配置的Oracle，这个是当时情况下最快的方法。

除了购买Oracle，后来为了优化，又买了更强大的存储：

> 
后来数据量变大了，本地存储不行了。买了NAS（Network Attached Storage，网络附属存储），NetApp的NAS存储作为了数据库的存储设备，加上Oracle RAC（Real Application Clusters，实时应用集群）来实现负载均衡。


为什么淘宝在这个时候继续采取“买”的方式来快速解决问题呢？我们可以从时间上看出端倪：此时离刚上线才半年不到，业务飞速发展，最快的方式支撑业务的发展还是去买。如果说第一阶段买的是“方案”，这个阶段买的就是“性能”，这里架构设计和选择主要遵循的还是“合适原则”和“简单原则”。

换上Oracle和昂贵的存储后，第二代架构如图所示。

<img src="https://static001.geekbang.org/resource/image/c7/2e/c735c053a4765c0739e2c5b3ef1b962e.jpg" alt="" />

3.脱胎换骨的Java时代1.0

> 
淘宝切换到Java的原因很有趣，主要因为找了一个PHP的开源连接池SQL Relay连接到Oracle，而这个代理经常死锁，死锁了就必须重启，而数据库又必须用Oracle，于是决定换个开发语言。最后淘宝挑选了Java，而且当时挑选Java，也是请Sun公司的人，这帮人很厉害，先是将淘宝网站从PHP热切换到了Java，后来又做了支付宝。


这次切换的最主要原因是因为技术影响了业务的发展，频繁的死锁和重启对用户业务产生了严重的影响，从业务的角度来看这是不得不解决的技术问题。

但这次淘宝为什么没有去“买”呢？我们看最初选择SQL Relay的原因：

> 
但对于PHP语言来说，它是放在Apache上的，每一个请求都会对数据库产生一个连接，它没有连接池这种功能（Java语言有Servlet容器，可以存放连接池）。那如何是好呢？这帮人打探到eBay在PHP下面用了一个连接池的工具，是BEA卖给他们的。我们知道BEA的东西都很贵，我们买不起，于是多隆在网上寻寻觅觅，找到一个开源的连接池代理服务SQL Relay。


不清楚当时到底有多贵，Oracle都可以买，连接池买不起 ？所以我个人感觉这次切换语言，更多是为以后业务发展做铺垫，毕竟当时PHP语言远远没有Java那么火、那么好招人。淘宝选择Java语言的理由可以从侧面验证这点：

> 
Java是当时最成熟的网站开发语言，它有比较良好的企业开发框架，被世界上主流的大规模网站普遍采用，另外有Java开发经验的人才也比较多，后续维护成本会比较低。


综合来看，这次架构的变化没有再简单通过“买”来解决，而是通过重构来解决，架构设计和选择遵循了“演化原则”。

从PHP改为Java后，第三代技术架构如图所示。

<img src="https://static001.geekbang.org/resource/image/95/2c/9558b5cbb1yyf77154e4172ceb66b92c.jpg" alt="" />

4.坚若磐石的Java时代2.0

Java时代2.0，淘宝做了很多优化工作：数据分库、放弃EJB、引入Spring、加入缓存、加入CDN、采用开源的JBoss。为什么在这个时候要做这些动作？原文作者很好地概括了做这些动作的原因：

> 
这些杂七杂八的修改，我们对数据分库、放弃EJB、引入Spring、加入缓存、加入CDN、采用开源的JBoss，看起来没有章法可循，其实都是围绕着提高容量、提高性能、节约成本来做的。


我们思考一下，为什么在前面的阶段，淘宝考虑的都是“快”，而现在开始考虑“容量、性能、成本”了呢？而且为什么这个时候不采取“买”的方式来解决容量、性能、成本问题呢？

简单来说，就是“买”也搞不定了，此时的业务发展情况是这样的：

> 
随着数据量的继续增长，到了2005年，商品数有1663万，PV有8931万，注册会员有1390万，这给数据和存储带来的压力依然很大，数据量大，性能就慢。


原有的方案存在固有缺陷，随着业务的发展，已经不是靠“买”就能够解决问题了，此时必须从整个架构上去进行调整和优化。比如说Oracle再强大，在做like类搜索的时候，也不可能做到纯粹的搜索系统如Solr、Sphinx等的性能，因为这是机制决定的。

另外，随着规模的增大，纯粹靠买的一个典型问题开始成为重要的考虑因素，那就是**成本**。当买一台两台Oracle的时候，可能对成本并不怎么关心，但如果要买100台Oracle，成本就是一个关键因素了。这就是“量变带来质变”的一个典型案例，业务和系统发生质变后，架构设计遵循“演化原则”的思想，需要再一次重构甚至重写。

Java架构经过各种优化，第四代技术架构如图所示。

<img src="https://static001.geekbang.org/resource/image/84/5b/84818454a50bc4ca97fdf3d152cbb45b.jpg" alt="" />

5.Java 时代3.0和分布式时代

> 
<p>Java时代3.0我个人认为是淘宝技术飞跃的开始，简单来说就是淘宝技术从商用转为“自研”，典型的就是去IOE化。<br />
分布式时代我认为是淘宝技术的修炼成功，到了这个阶段，自研技术已经自成一派，除了支撑本身的海量业务，也开始影响整个互联网的技术发展。</p>


到了这个阶段，业务规模急剧上升后，原来并不是主要复杂度的IOE成本开始成为了主要的问题，因此通过自研系统来降低IOE的成本，去IOE也是系统架构的再一次演化。

## 手机QQ

注：以下部分内容摘自《QQ 1.4亿在线背后的故事》。

手机QQ的发展历程按照用户规模可以粗略划分为4个阶段：十万级、百万级、千万级、亿级，不同的用户规模，IM后台的架构也不同，而且基本上都是用户规模先上去，然后产生各种问题，倒逼技术架构升级。

1.十万级IM 1.X

最开始的手机QQ后台是这样的，可以说是简单得不能再简单、普通得不能再普通的一个架构了，因为当时业务刚开始，架构设计遵循的是“合适原则”和“简单原则”。

<img src="https://static001.geekbang.org/resource/image/4f/85/4f43b7902c343a95bbc04f2ddf44c085.jpg" alt="" />

2.百万级IM 2.X

随着业务发展到2001年，QQ同时在线人数也突破了一百万。第一代架构很简单，明显不可能支撑百万级的用户规模，主要的问题有：

<li>
以接入服务器的内存为例，单个在线用户的存储量约为2KB，索引和在线状态为50字节，好友表400个好友 × 5字节/好友 = 2000字节，大致来说，2GB内存只能支持一百万在线用户。
</li>
<li>
CPU/网卡包量和流量/交换机流量等瓶颈。
</li>
<li>
单台服务器支撑不下所有在线用户/注册用户。
</li>

于是针对这些问题做架构改造，按照“演化原则”的指导进行了重构，重构的方案相比现在来说也还是简单得多，因此当时做架构设计时也遵循了“合适原则”和“简单原则”。IM 2.X的最终架构如图所示。

<img src="https://static001.geekbang.org/resource/image/f7/14/f7286a0fd79c61cdfd55eec957276d14.jpg" alt="" />

3.千万级IM 3.X

业务发展到2005年，QQ同时在线人数突破了一千万。第二代架构支撑百万级用户是没问题的，但支撑千万级用户又会产生新问题，表现有：

<li>
同步流量太大，状态同步服务器遇到单机瓶颈。
</li>
<li>
所有在线用户的在线状态信息量太大，单台接入服务器存不下，如果在线数进一步增加，甚至单台状态同步服务器也存不下。
</li>
<li>
单台状态同步服务器支撑不下所有在线用户。
</li>
<li>
单台接入服务器支撑不下所有在线用户的在线状态信息。
</li>

针对这些问题，架构需要继续改造升级，再一次“演化”。IM 3.X的最终架构如下图，可以看到这次的方案相比之前的方案来说并不简单了，这是业务特性决定的。

<img src="https://static001.geekbang.org/resource/image/59/27/5933a11358bbeb12ab62ec18a23ff827.jpg" alt="" />

4.亿级IM 4.X

业务发展到2010年3月，QQ同时在线人数过亿。第三代架构此时也不适应了，主要问题有：

<li>
灵活性很差，比如“昵称”长度增加一半，需要两个月；增加“故乡”字段，需要两个月；最大好友数从500变成1000，需要三个月。
</li>
<li>
无法支撑某些关键功能，比如好友数上万、隐私权限控制、PC QQ与手机QQ不可互踢、微信与QQ互通、异地容灾。
</li>

除了不适应，还有一个更严重的问题：

> 
IM后台从1.0到3.5都是在原来基础上做改造升级的，但是持续打补丁已经难以支撑亿级在线，IM后台4.0必须从头开始，重新设计实现！


这里再次遵循了“演化原则”，决定重新打造一个这么复杂的系统，不得不佩服当时决策人的勇气和魄力！

重新设计的IM 4.0架构如图所示，和之前的架构相比，架构本身都拆分为两个主要的架构：存储架构和通信架构。

- 存储架构

<img src="https://static001.geekbang.org/resource/image/10/a2/103006ae445b6623f6c6eaa18295e4a2.jpg" alt="" />

- 通信架构

<img src="https://static001.geekbang.org/resource/image/c9/d5/c9febc2c26c2088332c31eae451b36d5.jpg" alt="" />

## 小结

今天我给你讲了淘宝和手机QQ两个典型互联网业务的架构发展历程，通过这两个案例我们可以看出，即使是现在非常复杂、非常强大的架构，也并不是一开始就进行了复杂设计，而是首先采取了简单的方式（简单原则），满足了当时的业务需要（合适原则），随着业务的发展逐步演化而来的（演化原则）。罗马不是一天建成的，架构也不是一开始就设计成完美的样子，然后可以一劳永逸一直用下去。

这就是今天的全部内容，留一道思考题给你吧。搜索一个互联网大厂（BATJ、TMD等）的架构发展案例，分析一下其发展过程，看看哪些地方体现了这三条架构设计原则。

欢迎把你的答案写到留言区，和我一起讨论。相信经过深度思考的回答，也会让你对知识的理解更加深刻。（编辑乱入：精彩的留言有机会获得丰厚福利哦！）
