这位在阿里“救了八年火”的程序员讲了大型项目架构的演进过程。中间是业务运营服务体系,如会员服务、商品服务、店铺服务、交易服务等,还有共享服务,如分布式数据层、数据分析服务、配置服务、数据搜索服务等最底层是中间件服务,比如MQS或者队列服务,OCS或者缓存服务等,还有一些图片看不到的东西,比如高可用的一种体现,实现了容灾双机房、远程机房单元化部署,为淘宝业务提供稳定、高效、易维护的基础设施支持。这是一个含金量非常高的结构,也是一个非常复杂庞大的结构。当然,这也不是一两天就演变成这个样子的,也不是一上来就设计开发这么高大上的架构。说到这里,小公司应该怎么办?对于很多创业公司来说,前期很难预测十倍、一百倍、一千倍流量时网站结构会是什么样子。同时,如果在系统初期就设计出千万级并发流量的流量架构,任何公司都难以支撑这个成本。所以,一个大的服务体系是从一个小的一步一步来的。在每个阶段,找出该阶段网站架构面临的问题,然后不断解决这些问题。在这个过程中,整个架构会不断演进。那我们一起来看看吧。单一服务器-通常称为一体机。从一个小网站开始,一台服务器就够了。文件服务器、数据库、应用全部部署在一台机器上,俗称ALLINONE。随着用户越来越多,Access越来越大,硬盘、CPU、内存等开始吃紧,一台服务器已经不够用了。这个时候,我们就来看看下一步的进化。数据服务和应用服务是分离的。我们将数据服务和应用服务分开,配置更多的应用服务器。好的CPU,内存。并为数据服务器配置更好更大的硬盘。分离后,提高了一定的可用性。例如,如果文件服务器宕机了,我们仍然可以操作应用程序和数据库。随着访问qps越来越高,减少接口访问时间,提升服务性能和并发成为了我们下一个目标,同时我们发现有很多业务数据并不需要每次都从数据库中获取.使用缓存,包括本地缓存、远程缓存、远程分布式缓存,因为80%的业务访问集中在20%的数据上,也就是我们常说的28法则。如果我们能缓存这部分数据,性能会立马提升。缓存分为两种:本地缓存和远程缓存,远程分布式缓存。这里的远程缓存图展示了一个分布式缓存集群(Cluster)。思考点什么样的业务特征数据使用缓存?什么样的业务特征数据使用本地缓存?什么样的服务特性数据使用远程缓存?分布式缓存在扩容时会遇到哪些问题?怎么解决?分布式缓存的算法有哪些?各自的优点和缺点是什么?这时候随着访问qps的增加,服务器的处理能力就会成为瓶颈。虽然可以购买更强大的硬件,但总有一个上限,后期成本会成倍增长。这时候,我们就需要服务器集群。我们需要让我们的服务器水平扩展。这时候,我们就要添加一个新的东西:负载均衡调度服务器。使用负载均衡,服务器集群增加了负载均衡。服务器集群之后,我们可以对服务器进行横向扩展,解决了服务器处理能力的瓶颈。思考点负载均衡的调度策略有哪些?各自的优点和缺点是什么?分别适合什么场景?比如我们有轮询,权重,地址哈希,地址哈希分为原始ip地址哈希哈希,目标ip地址哈希哈希,最少连接数,加权最少连接数,还有很多继续升级的策略……我们来分析一个典型的负载均衡策略分析轮询:优点:实现简单,缺点:不考虑每台服务器的处理能力权重:优点:考虑服务器处理能力的不同地址散列:优点:同一个用户可以用最少的连接访问同一个服务器:优点:使集群中各个服务器的负载更加均匀最小连接加权:在最小连接的基础上给各个服务器增加一个权重。算法为(活跃连接数*256+非活跃连接数)/权重,计算出的值较小的服务器优先被选中。继续引出问题场景:我们登录的时候,登录到服务器A,session信息是存放在服务器A上的,假设我们使用的负载均衡策略是iphash,那么登录信息还是可以访问到的来自服务器A,但是这有可能会导致有的服务器压力太大,有的服务器压力不大。这时候压力太大的机器(包括网卡带宽)可能会成为瓶颈,请求不够分散。这时候我们使用轮询或者最小连接负载均衡策略,这就导致了第一个访问到服务器A的可能访问到第二个服务器。此时服务器A上保存的session信息在服务器B上是读取不到的。SessionManagement-SessionSticky粘性会话:比如我们每次吃饭都要保证用自己的餐具,而且只要我们把餐具放在饭店里,只要我们每次去这里吃饭就可以了一个餐厅。对于同一连接中的数据包,负载均衡器会将其转发到固定的后端服务器进行处理。它解决了我们session共享的问题,但是它的缺点是什么呢?某台服务器上运行的服务挂了或者重启了,上面的session就没了。负载均衡器变成了有状态的机器,给以后的容灾造成了羁绊。会话管理-会话复制就像我们在所有餐厅中一样。保留一份你自己的碗筷。我们可以随意去任何一家餐馆吃饭。不适合大规模集群,适合机器不多的情况。它解决了我们session共享的问题,但是它的缺点是什么呢?应用服务器之间的带宽问题,因为会话数据需要不断同步。当大量用户在线时,服务器占用内存过多。它解决了我们session共享的问题,但是它的缺点是什么呢?cookie的长度是有限的。cookie存储在浏览器中。安全是个问题。sessionmanagement-sessionserver比如我们的餐具就存放在一个巨大的柜子里。拿我们自己的碗和筷子。解决了我们session共享的问题,这个方案需要我们思考哪些问题呢?保证sessionserver的可用性,如何解决sessionserver的单点问题?我们在写应用的时候,需要调整存储session的业务逻辑。比如,为了提高sessionserver的可用性,我们可以在集群中间继续汇总sessionserver。因此,当网站架构遇到某些索引瓶颈时,在演进过程中,有哪些解决方案,它们的优缺点是什么?业务功能如何选择?如何做出选择?这个过程很重要。解决完水平扩展应用服务器,我们继续~~上面的技术我特地整理了一下。有很多技术不是三言两语能说清楚的,所以索性请了朋友录了一些视频。很多问题其实都有很好的答案。很简单,但背后的思维和逻辑并不简单。要知道它是什么,你还必须知道它为什么会这样。继续回到现在的架构图,数据库的读写操作还是要经过数据库。当用户数量达到一定数量时,数据库就会成为瓶颈。那我们怎么解决呢?数据库读写分离利用数据库提供的热备份功能,将所有读操作引入从服务器。因为数据库读写是分开的,所以我们的应用程序也必须做相应的改动。我们实现一个数据访问模块(图中的数据访问模块),让上层写代码的人不知道读写分离的存在。这样多数据源的读写分离,不会对业务代码造成侵扰。这就引出了代码层面演进的思考点。如何支持多数据源?如何在不侵入业务的情况下进行封装?如何利用现在的业务ORM框架来完成主从读写分离?ORM模型是否需要更换?每种ORM模型的优点和缺点是什么?如何选择?数据库读写分离会遇到以下问题:master和slave之间复制时,要考虑延迟问题,数据库支持,复制条件支持。当数据库为了提高可用性而划分到不同的机房,跨机房同步数据时,这就更成问题了。数据源的应用路由问题使用反向代理和CDN加速网站响应使用CDN可以解决不同地区的访问速度问题,反向代理将用户资源缓存在服务器机房。流量越来越大,我们的文件服务器也成了瓶颈。分布式文件系统思考点分布式文件系统如何做到不影响已经部署到线上的业务访问?你不能让某个图片突然变得无法访问。需要业务部门清洗数据吗?需要重新做域名解析吗?这时数据库又出现了瓶颈,将数据垂直拆分到数据库专用数据库中,如图Products、Users、Deal数据库。解决写入数据时并发量大的问题。思考点跨业务交易?怎么解决?使用分布式事务,去掉事务,或者不追求强事务应用。配置项比较多。如何跨数据库执行数据连接操作。这时候某个业务数据表的数据量或者更新量已经达到了单个数据库的瓶颈。数据层次拆分如图,我们将User拆分为User1和User2,将同一张表的数据拆分到两个数据库中,解决了单一数据库的瓶颈。思考点横向拆分的策略有哪些?各自的优点和缺点是什么?水平拆分时如何清理数据?SQL的路由问题需要知道某个User在哪个数据库上。主键策略会有所不同。假设我们的系统需要查询2017年4月下单的用户名的详情,这些用户分布在user1和user2上,那么我们的后台操作系统在显示的时候是怎么分页的呢?这时候公司引入了外部流量,我们应用里的搜索量猛增。我们不断进化,拆分搜索引擎,用搜索引擎解决数据查询问题。在某些场景下,可以利用NoSQL来提升性能,开发统一的数据访问模块,解决上层应用开发的数据源问题。如图所示,数据访问模块可以访问数据库、搜索引擎和NoSQL。最后,这只是一个示例演示。每个服务的技术架构都需要根据自己的业务特点进行优化演进,所以每个人的流程都不完全一样。最后一个并不完美。比如负载均衡还是单点,需要集群。我们的架构只是冰山一角,沧海一粟。在架构演进过程中,我们还需要考虑系统安全、数据分析、监控、反作弊等,在不断发展的同时,SOA架构、服务、消息队列、任务调度、多机房等..从刚才架构演进的讲解也可以看出,所有大型项目的架构和代码都是根据实际的业务场景和开发条件一步步开发演进的。在这个阶段,会采用不同的技术、不同的架构来解决实际问题。因此,高层次的项目技术架构和开发设计的落地,不是一蹴而就的。正所谓拔地而起。在架构演进的过程中,从核心模块代码到核心架构,都会不断演进。这个过程值得我们深入研究和思考。
