如何从零开始设计一套可以服务百万用户的系统。
这是本书第一章的内容,浅显易懂,把常见的套路组合了一下,没有具体的技术细节,过一遍也没什么负担。
俗话说:千里之行,始于足下。构建一个复杂系统也不例外,我们从单服务开始。
single server
画出整体的大框图,流程很简单。客户端先请求 DNS 拿到服务端的 IP 地址;客户端拿着 IP 地址请求服务端的接口;服务端返回 HTML;客户端渲染出页面。
这种是最简单的系统。但有个问题是:数据无法持久化。只能把状态存在内存中,一旦进程重启,数据就都丢失了。
因此,一般的服务都会加一个数据库:
add a database
具体是选择关系型数据库还是非关系型数据库,这里有一些需要考虑的点:
关系型数据库最出名的当属 MySQL,Oracle,PgSQL,互联网公司用得最多的还是 MySQL。它将数据存储在一张表的一行,可以在不同的表之间执行 join 操作。
非关系型数据库也叫 NoSQL,它有四种类型:k-v
,图数据库
,列存
,文档型
。
更多的时候当然还是选择老牌的关系型数据库,但有些场景还是更适合 NoSQL,尤其是在互联网蓬勃发展的今天。
下面这几个场景更适合使用 NoSQL:
现在很少有网站直接用 IP 地址+端口的地址访问,前面至少得挂个 Nginx。
后端服务也不能是单个 server,至少得挂个 2 台。当单个服务意外挂了,另一个服务得马上顶上,防止单点故障。
服务之间则是通过私有 IP 通信。
客户端通过 DNS 拿到的 IP 不再是服务器的 IP,而是前面的负载均衡器的 IP。请求到来之后,由负载均衡器将请求打到不同的 server 上。这一切对用户是透明的。
add lb
加上了负载均衡器后,服务层的可用性解决了。但是数据库层呢,我们还只有一个数据库服务器,一旦它挂了,服务同样是不可用的。
解决办法就是让数据库有更多的副本。
互联网绝大多数的场景是多读写少,可以采用经典的主从式架构模式,一般都会设置成一主多从。
所有的写操作,包括插入、删除、更新操作由主执行;而所有的读操作都由从执行。
database replication
采用主从架构的好处很多:
增加一个缓存层也是常规的做法。
缓存在内存中存储计算好的结果,等下次请求到来时,直接使用内存中的数据,系统响应时间会更短。
关于缓存,有这么几点需要考虑:
CDN 全称是 Content Delivery Network,内容分发网络。它是基于地理位置的服务,用来缓存静态内容,如图片、视频、CSS、JavaScript 文件等等。
下面这张图展示了 CDN 的工作流程,非常清晰:
cdn-workflow
使用 CDN 需要考虑的点有:
当我们增加了 CDN 之后,系统架构图如下:
add cdn
Web 层的水平扩展依赖无状态的设计:将状态(例如用户的 session)保存在外存,一般用 NoSQL。
当 Web 层无状态化后,流量上升就加机器,流量下降就减机器,扩展更容易。
auto scale
业务做起来后,用户会越来越多。为了更好的用户体验,需要建立多个数据中心。根据用户的地理位置决定由哪个数据中心提供服务。
当某个数据中心宕机了,流量自动或手动切到其他数据中心。
multi datacenter
消息队列让生产者和消费者解耦,对于构建可伸缩的服务架构是非常有用的。
生产者向消息队列发送消息,它不需要关心消费者是否在可用。消费者消费消息,它也不需要关心生产者是否可用。
对错误日志量的监控常常能快速发现和定位问题。
对业务信息、机器状态、进程状态进行打点和监控也是必不可少的。
当整个系统越来越大,我们还需要通过自动化工具来提升开发效率,CICD 就得搬到台前。
add tools
服务在线上正常运转,数据会越来越多。单机总有一天不能装下所有的数据,对数据库的扩展需求提上日程。
同样有两种扩展方式。
最简单的就是垂直扩展。换更大容量、更多核心,更大内存的机器,只要足够有钱,这都不是事。开始阶段,加机器的效率甚至更高。
更难的是水平扩展。说白了就是分 shard,将全量数据拆分到不同的机器上去。
分 shard 最关键的就是 key 的选取,它要能保证数据的平均分布。
数据分片并不容易,需要考虑下面这几点:
最后是一张考虑了以上所有的点之后的架构图:
overview
第一章感觉说了很多,又感觉什么都没说。整体看内容还是比较浅显的,不少都是点到即止。
不管怎么说,我们都已经上路了。