2_【Redis】服务端高并发分布式系统架构演进
「前言」文章的大致内容是对服务端高并发分布式系统架构演进之路进行介绍。
一、单机架构
前期,用户访问量很少,没有对性能、安全等提出很高的要求,而且系统架构简单,无需专业的运维团队,所以选择单机架构是合适的。
单机架构:只有一台服务器,这台服务器负责所有的工作,应用服务和数据库服务是在同一台主机上的。(单机架构也是当前主流,绝大部分的互联网产品(中小公司)都是单机架构)
用户通过网络访问我们所写的 HTTP 服务器,然后 HTTP 服务器返回用户所需要的数据。
注:现在的计算机硬件发展速度很快,哪怕只有一台主机,这一台主机的性能也是很高的,可以支持非常的的并发和非常大的数据存储。

相关软件:
- Web 服务器软件:Tomcat、Netty、Nginx、Apache 等。
- 数据库软件:MySQL、Oracle、PostgreSQL、SQL Server 等。
如果业务进一步增长,用户量和数据量都大大增加,一台主机就难以应付了,需要引入更多的主机,也就是引入更多的硬件资源,也就过度到了分布式系统。
二、分布式系统
由于一台计算机的硬件资源是有限的。即使再怎么发展硬件,一台计算的硬件终究有上限。
硬件资源:CPU、内存、网络、硬盘...
服务器每收到一个请求,都是需要消耗一些硬件资源的。如果同一时刻,处理的请求多了,此时就会导致某个硬件资源不够用了。无论是哪一个硬件资源不够用了,都会带导致服务器处理请求的时间变长,甚至是处理出错。
那么如何处理呢?进行开源或者节流。
- 开源:简单粗暴,就是增加更多的硬件资源(一个主机上面可以增加的硬件资源取决去主板的扩展能力,能扩展的硬件资源也是有限的。)一台主机扩展到极限了,但是还是不够用,就只能引入更多的主机了,即增加服务器的数量。但是不是说买来的主句就可以解决问题了,也需要软件上面作出调整和适配。一旦引入了多台主机,该系统就称之为“分布式系统”。
- 节流:在软件上进行优化,比如优化数据结构,优化存储结构,优化网络协议等等。(需要通过性能测试,看看是哪个环节出了问题,找到是哪个环节出现了瓶颈,再对症下药。此方法对程序员水平要求很高,并且是很难。)
引入分布式系统,是万不得已的,分布式系统会给系统的复杂程度会大大提高。复杂程度随着引入主机的数量形成指数级增长。也就是说分布式系统出现 Bug 的概率会大大增加。
所以能单机架构就使用单机架构,万不得已的情况下再使用分布式系统。
三、应用数据分离架构
应用数据分离架构:是一种将应用程序(应用层)和数据存储(数据层)分别部署在不同服务器中的软件架构设计。
- 对于应用服务器,会包含很多的业务逻辑,可能会吃 CPU 和内存,就可以单独配置给这台主机更多的 CPU 资源和内存资源。
- 对于存储数据的服务器,只用来储存数据,不吃 CPU,就可以给存储数据的服务器配置更大的硬盘,或者也可以上 SSD 硬盘(固态硬盘)。
机械硬盘:便宜,速度慢。
固态硬盘:贵,速度快。

虽然这样的架构可以处理更高的并发,但是也是有上限的。并发过高也会扛不住(本质是 CPU 和内存资源没有了),就可以引入更多的应用服务器了(本质是引入更多的 CPU 资源和内存资源),用来提高并发量。
四、应用服务集群架构
应用服务集群架构:在应用数据分离架构的基础上,引入更多的应用服务器(对应用服务器进行水平扩展,Scale Out)。

在这个架构中引入一个负载均衡器。负载均衡器负责接收外部请求,并根据一定的策略(如轮询、最少连接数等)将请求分发到集群中的各个应用服务器上。
负载均衡器也是一个独立分的服务器,用户的请求会先到达负载均衡器(或者叫网关服务器)。
比如来了 9000 个请求,负载均衡器就可以通过某种算法分配给不同的应用服务器。比如有三台应用服务器,负载均衡器就给每台应用服务器分配 3000 个请求,这样就可以提高整体的并发量,降低每一台应用服务器的并发量。
常见的负载均衡算法有:
- Round-Robin 轮询算法:Round-Robin 轮询算法是一种非常公平地将请求依次分给不同应用服务器的负载均衡策略。它按照固定的顺序轮流将请求分配给集群中的服务器,确保了每台服务器都能获得等量的处理机会。
- Weight-Round-Robin 轮询算法:Weight-Round-Robin 轮询算法为不同的服务器(比如性能不同的服务器)赋予不同的权重(weight)。根据这些权重,算法能够智能地将更多的请求分配给处理能力更强的服务器,实现了“能者多劳”的负载均衡效果。
- 一致哈希散列算法:一致哈希散列算法通过计算用户的特征值(比如 IP 地址)得到哈希值,并根据这个哈希结果来进行请求的分发。其优点在于能够确保来自相同用户的请求总是被分给指定的服务器,类似于我们平时遇到的专项客户经理服务,提高了系统的缓存命中率和用户体验。
对于负载均衡器来说,对于请求量的承受能力是要远远超过应用服务器的,因为每个请求都要经过负载均衡器。即负载均衡器负责分配任务(时间短),应用服务器负责执行任务(时间长)。
如果流量大到负载均衡器也不能抗住了,就需要引入更多的负载均衡器,即引入更多的机房,每个机房都有自己的负载均衡器。
负载均衡软件:Nginx、HAProxy、LVS、F5 等。
注意:当机器变多了,管理成本就会变高,出现问题的概率就会变高。
五、读写分离/主从分离架构
上面的架构虽然可以抗住更高的并发量,但是对于存储服务器来说,要承担的请求量也就变多了。
例如有三台应用服务器,一台数据存储服务器,有 9000 个请求到来,给每台应用服务器分配 3000 个请求,但是数据存储服务器依旧要承担 9000 个请求。并发量过高,数据存储服务器也会处理不过来。

如何解决?也是开源、节流。
- 开源:引入更多的存储服务器(简单),对数据库进行读写分离。
- 节流:对数据库进行调优(门槛高,难)。
但是不可以像扩展应用服务器一样扩展数据库服务器,因为数据库服务有其特殊性:如果将数据分散到各台服务器之后,数据的一致性将无法得到保障。所谓数据的一致性,此处是指针对同一个系统,无论何时何地,我们都应该看到一个始终维持统一的数据
解决办法是这样的:保留一个主要的数据库作为写入数据库(主库),其他的数据库则作为从属数据库(从库) -- 一主多从。
从库的所有数据全部来自主库的数据,经过同步后,从库可以维护着与主库一致的数据。然后,为了分担数据库的压力,我们可以将写数据(增删改)请求全部交给主库处理,但读请求则分散到各个从库中。由于大部分的系统中,读写请求的比例都是不成正比的,例如常见的 100 次读请求对应 1 次写请求,所以只要将读请求由各个从库分担之后,数据库的整体压力就会显著减轻。这就是数据库读写分离。

应用中需要对读写请求做分离处理,所以可以利用一些数据库中间件,将请求分离的职责托管出去。
相关软件:MyCat、TDDL、Amoeba、Cobar 等类似数据库中间件等。
六、冷热分离架构(引入缓存)
随着访问量持续增加,业务中逐渐显现出一种现象:部分数据的读取频率远超过其他数据,我们将这部分数据定义为热点数据,而相对不常被访问的数据则称为冷数据。
为了优化热点数据的读取响应时间,可以采取一系列缓存策略。具体而言,可以在应用层面增加本地缓存,以快速响应高频访问请求。同时,为了进一步扩展缓存能力和提升系统可用性,还可以在外部部署分布式缓存系统,比如商品系统,用于缓存热门商品信息、热门商品的 HTML 页面等内容。
通过这种缓存机制,能够在数据库层面之前拦截并处理绝大多数的请求,从而显著减轻数据库的负担,提升整体系统的响应速度和性能。
热点数据 -- 二八原则:20% 的数据能够支持 80% 的访问量(根据实际场景,略有差异)。
其中主数据库和从数据库存储的依旧是完整的数据。

而 Redis 用处就是在这里,用作缓存。请求数据库时,会先去缓存服务器里面查找是否有该数据,有就直接返回,不再去查询数据库;如果没有,再去存储服务器中的数据库中查询。
缓存服务器相关软件:Memcached、Redis 等缓存软件。
但是想要提高访问速度,就得付出代价。使用 Redis 作为分布式缓存,会涉及缓存一致性、缓存穿透/击穿、缓存雪崩、热点数据集中失效等问题,这些后面学习 Redis 再谈。
七、垂直分库架构
随着业务数据量的增大,将大量数据存储在同一个数据库中已经显得力不从心(并发量不成问题了,但是数据存储出现了问题)。为了应对这一挑战,可以按照业务逻辑,将数据分别存储在不同的数据库中或表结构中。例如电商系统,针对评论数据,可以采用商品 ID 进行哈希处理,根据哈希结果将评论数据路由到对应的表中存储;而对于支付记录,则可以按照小时为单位创建表,每个小时表内部再进一步拆分为更小的表,使用用户 ID 或记录编号来路由数据。
只要确保实时操作的表数据量足够小,且请求能够均匀分发到多台服务器上的小表,那么数据库就能通过水平扩展的方式来提升性能。这种分库分表策略不仅提高了数据处理的效率,还增强了系统的可扩展性和灵活性。
在此过程中,可能会使用到如 Mycat 这样的中间件来支持大表拆分为小表情况下的访问控制。然而,这种做法也显著增加了数据库运维的难度,对数据库管理员(DBA)的要求较高。
当数据库设计到这种结构时,已经可以被称为分布式数据库系统。但值得注意的是,这仍然是一个逻辑上的数据库整体,其内部不同的组成部分可能由不同的组件单独实现。例如,分库分表的管理和请求分发可能由 Mycat 这样的中间件负责,SQL 的解析则可能由单机数据库完成,读写分离可能通过网关和消息队列来实现,而查询结果的汇总则可能由数据库接口层来完成。
这种架构实际上是MPP(Massively Parallel Processing,大规模并行处理)架构的一种实现方式,它通过并行处理多个数据库实例或表来显著提高数据处理能力和查询性能。
简单来说,一台存储服务器已经存储数据满了,存不下了。既然一台存储服务器存不下,就需要多台存储服务器进行存储。即对原来的数据库进行拆分,进行分库分表操作。然后每个数据库存储服务器就可以存储一个数据库或者存储一部分数据库。
具体如何分库分表,需要结合实际的业务场景展开。

相关软件:Greenplum、TiDB、Postgresql XC、HAWQ 等,商用的如南大通用的 GBase、睿帆科技的雪球 DB、华为的 LibrA 等
八、微服务架构(业务拆分)
上面的应用服务器,一个应用服务器里面包含了很多业务,这会导致一个应用服务器上的代码变得越来越复杂。为了方便代码的维护,可以把一个复杂的服务器里面的业务,拆分为更多的、功能单一的、更小的服务,对应应用服务器种类就增加了。
微服务架构:是一种将复杂的单体应用拆分成一组小而自治的服务的架构风格。每个微服务都围绕着特定的业务领域进行构建,可以独立部署、独立扩展,并遵循单一职责原则。
例如:电商系统,可以把系统拆分为用户子系统、商品子系统、交易子系统等。

将业务分给不同的开发团队去维护,每个团队独⽴实现⾃⼰的微服务,然后互相之间对数据的直接访问进行隔离,可以利用 Gateway、消息总线等技术,实现相互之间的调用关联。甚至可以把⼀些类似用户管理、安全管理、数据采集等业务提成公共服务。
微服务本质是在解决人的问题。当应用服务器变得复杂了,就需要招聘更多的人去维护应用服务器。但是人多了,就需要配套的分工和管理,用于把人组织好。如何组织好相关的人员?进行划分组织结构,分成更多的组,每个组配备组长进行管理。
应用服务器按照功能拆分成多组微服务,就可以有利于上述人员的组织结构分配了。
拆分微服务一般都是大厂才弄的,并且拆分微服务会导致系统的性能下降。因为微服务之间的通信需要依靠网络进行通信,网络通信的速度比访问磁盘的速度还要慢。
但是随着硬件发展,已经有万兆网卡,万兆网卡读写的速度已经超过硬盘的读写速度了,不会导致微服务系统的性能下降太多。
微服务还会让系统的复杂程度提高,可用性受到影响。微服务增加了大量的服务器,结构就会导致出现问题的概率大大增加。这就需要一系列手段来保证系统的可用性,比如更丰富的监控报警系统,进行配套的运维人员。
微服务的优势:
- 解决了人的问题。
- 实现功能复用。
- 可以给不同的服务进行不同的部署。
所谓的分布式系统实际上就是为了引入更多的硬件资源。
九、分布式系统常见的概念
应用(Application)/ 系统(System):为了完成一整套服务的一个程序或者一组相互配合的程序群。生活例子类比:为了完成一项任务,而搭建的由一个人或者一群相互配合的人组成的团队。
模块(Module)/ 组件(Component):当应用较复杂时,为了分离职责,将其中具有清晰职责的、内聚性强的部分,抽象出概念,便于理解(即将系统/应用进行功能拆分)。生活例子类比:军队中为了进行某据点的攻克,将人员分为突击小组、爆破小组、掩护小组、通信小组等。
分布式(Distributed):系统中的多个模块被部署于不同服务器之上,即可以将该系统称为分布式系统。如 Web 服务器与数据库分别工作在不同的服务器上,或者多台 Web 服务器被分别部署在不同服务器上。生活例子类比:为了更好的满足现实需要,一个在同一个办公场地的工作小组被分散到多个城市的不同工作场地中进行远程配合工作完成目标。跨主机之间的模块之间的通信基本要借助网络支撑完成。
集群(Cluster):被部署于多台服务器上的、为了实现特定目标的一个/组特定的组件,整个整体被称为集群。比如多个 MySQL 工作在不同服务器上,共同提供数据库服务目标,可以被称为一组数据库集群。生活例子类比:为了解决军队攻克防守坚固的大城市的作战目标,指挥部将大批炮兵部队集中起来形成一个炮兵打击集群。
分布式 vs 集群:通常不用太严格区分两者的细微概念,细究的话,分布式强调的是物理形态,即工作在不同服务器上并且通过网络通信配合完成任务;而集群更在意逻辑形态,即是否为了完成特定服务目标。
主(Master)/ 从(Slave):集群中,通常有一个程序需要承担更多的职责,被称为主;其他承担附属职责的被称为从。比如 MySQL 集群中,只有其中一台服务器上数据库允许进行数据的写入(增/删/改),其他数据库的数据修改全部要从这台数据库同步而来,则把那台数据库称为主库,其他数据库称为从库。
中间件(Middleware):一类提供不同应用程序用于相互通信的软件,即处于不同技术、工具和数据库之间的桥梁,比如缓存,消息队列。生活例子类比:一家饭店开始时,会每天去市场挑选买菜,但随着饭店业务量变大,成立一个采购部,由采购部专职于采买业务,称为厨房和菜市场之间的桥梁。
评价指标(Metric):
- 可用性(Availability):考察单位时间段内,系统可以正常提供服务的概率/期望。例如: 年化系统可用性 = 系统正常提供服务时长 / 一年总时长。这里暗含着一个指标,即如何评价系统提供是否正常,我们就不深入了。平时我们常说的 4 个 9 即系统可以提供 99.99% 的可用性,5 个 9 是 99.999% 的可用性,以此类推。我们平时只是用高可用(High Availability, HA)这个非量化目标简要表达我们系统的追求。
- 响应时长(Response Time, RT):指用户完成输入到系统给出用户反应的时长,用于衡量服务器性能。例如点外卖业务的响应时长 = 拿到外卖的时刻 - 完成点单的时刻。通常我们需要衡量的是最长响应时长、平均响应时长和中位数响应时长。这个指标原则上是越小越好,但很多情况下由于实现的限制,需要根据实际情况具体判断。
- 吞吐(Throughput) vs 并发(Concurrent):这两个用于衡量系统处理请求的能力,也是衡量系统性能的一种方式。吞吐考察单位时间段内,系统可以成功处理的请求的数量。并发指系统同一时刻支持的请求最高量。例如一条车辆道高速公路,一分钟可以通过 20 辆车,则并发是 2,一分钟的吞吐量是 20。实践中,并发量往往无法直接获取,很多时候都是用极短的时间段(比如 1 秒)的吞吐量做代替。我们平时用高并发(High Concurrent)这个非量化目标简要表达系统的追求。
--------------- END ---------------
「 作者 」 枫叶先生
「 更新 」 2024.7.18
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
或有谬误或不准确之处,敬请读者批评指正。
2_【Redis】服务端高并发分布式系统架构演进
http://114.132.213.38:6250/archives/26000eb5-a7f8-42d9-88e8-f53266c190bd
评论