服务端高并发分布式结构演进之路

发布于:2025-07-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

概述

在进行技术学习过程中,由于大部分读者没有经历过一些中大型系统的实际经验,导致无法从全局理解一些概念。因此,本文以一个“电子商务”应用为例,介绍从一百个到千万级并发情况下服务端的架构演进过程。同时,列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知,方便大家在后续深入学习时有一定的整体视野。

架构演进

关于后端架构的演进,最初往往是从一个单机架构来去进行的!

单机架构

单机架构就是只有一台服务器,这个服务器负责所有的工作

初期,我们需要利用我们精干的技术团队,快速将业务系统投入市场进行检验,并且可以迅速响应变化要求。但好在前期用户访问量很少,没有对我们的性能、安全等提出很高的要求,而且系统架构简单,无需专业的运维团队,所以选择单机架构是合适的。

下图假设是一个电商网站:最少要包含 --- 应用服务(HTTP)和存储服务器(MySQL)

用户在浏览器中输入 www.XXX.com 首先经过 DNS 服务将域名解析成 IP 地址 10.102.41.1,随后浏览器访问该 IP 对应的应用服务。

对于单机程序,能不能将数据库服务器去掉,光一个应用服务器又负责业务,又负责数据存储?

在单机架构中,通常所有服务(包括应用服务和数据库服务)都运行在同一台服务器上。这意味着应用逻辑、数据存储以及用户请求的处理都在同一台机器上完成。这种架构的特点是简单、部署成本低,适合用户量较少、业务逻辑相对简单的初期项目。

绝大部分的公司的产品可都是单机架构哦!!!因为硬件发展太快了!!!性能好!!!

如果业务进一步增长,用户量和数据量都水涨船高,一台主机难以应付的额时候,就需要引入更多的主机,更多的硬件资源!这时候也就自然而然的过渡到了分布式系统了!

一台主机的硬件(主要指的是:CPU,内存,硬盘,网络......)资源是有上限的,服务器每次收到一个请求,都是需要消耗这些资源来处理请求。同一时刻请求多了,此时就可能导致某一个硬件资源不够用了!进而导致服务器处理请求的时间变长,甚至处理出错!

我们该如何处理呢?

  1. 开源 --- 简单粗暴,增加更多的硬件资源。一台主机扩展到极限了,只能引入多台主机了!不是说买一个新的机器买来就可以解决问题了,也是需要软件上做出对应的调整和适配的!一旦引入多台主机了,咱们的系统就可以称为是“分布式系统”了!--- 引入分布式,是万不得已的!
  2. 节流 --- 软件上优化(各凭本事,需要通过性能测试,找到是哪一个环节出现了性能瓶颈,再去对症下药)解决是相对比较困难的。

相关软件

  • Web 服务器软件:Tomcat、Netty、Nginx、Apache 等

  • 数据库软件:MySQL、Oracle、PostgreSQL、SQL Server 等

💡 我们目前的训练大多针对该阶段的业务系统,包括本科毕业设计的系统实现。


应用服务集群架构

我们的系统受到了用户的欢迎,并且出现了爆款,单台应用服务器已经无法满足需求了。我们的单机应用服务器首先遇到了瓶颈,摆在我们技术团队面前的有两种方案,大家针对方案的优劣展开了热烈的讨论:

  • 垂直扩展 / 纵向扩展(Scale Up):通过购买性能更优、价格更高的应用服务器来应对更多的流量。这种方案的优势在于完全不需要对系统软件做任何的调整;但劣势也很明显:硬件性能和价格的增长关系是非线性的,意味着选择性能 2 倍的硬件可能需要花费超过 4 倍的价格,其次硬件性能提升是有明显上限的。

应用服务器:里面可能会包含很多的业务逻辑,可能会吃 CPU 和内存;

数据库服务器:需要更到的硬盘空间,更快的数据访问速度,可以配置更大硬盘的服务器,甚至还可以上 SSD 硬盘!

这样就可以最大层度解决硬件不足的问题,也即是上面提到的问题。


  • 水平扩展 / 横向扩展(Scale Out):通过调整软件架构,增加应用层硬件,将用户流量分担到不同的应用层服务器上,来提升系统的承载能力。这种方案的优势在于成本相对较低,并且提升的上限空间也很大。但劣势是带给系统更多的复杂性,需要技术团队有更丰富的经验。

经过团队的学习、调研和讨论,最终选择了水平扩展的方案,来解决该问题,但这需要引入一个新的组件 —— 负载均衡为了解决用户流量向哪台应用服务器分发的问题,需要一个专门的系统组件做流量分发。实际中负载均衡不仅仅指的是工作在应用层的,甚至可能是其他的网络层之中。同时流量调度算法也有很多种,这里简单介绍几种较为常见的:

  • Round-Robin 轮询算法:即非常公平地将请求依次分给不同的应用服务器。

  • Weight-Round-Robin 加权轮询算法:为不同的服务器(比如性能不同)赋予不同的权重(weight),能者多劳。

  • 一致性哈希散列算法:通过计算用户的特征值(比如 IP 地址)得到哈希值,根据哈希结果做分发,优点是确保来自相同用户的请求总是被分给指定的服务器。也就是我们平时遇到的专项客服经理服务。


应用服务器可能会吃 CPU 和内存,如果把 CPU 或者内存吃没了,此时应用服务器就顶不住了,这时候,引入更多的应用服务器,就可以有效解决该问题!

用户的请求就可以先去访问负载均衡器,然后由负载均衡器对这个请求进行分发!负载均衡器对于请求量的承担能力,要远超过应用服务器的。

负载均衡器是领导:分配工作。

应用服务器是组员:执行任务。

那是否可能会出现,请求量大到负载均衡器也扛不住了呢???这是有可能的!

我们可以引入更多的负载均衡器~~~(引入多个机房) 


相关软件

  • 负载均衡软件:Nginx、HAProxy、LVS、F5 等


可是就一个存储服务器,所有的应用服务器都要访问数据库,就会有很大的压力,而且相比之下,数据库对于压力是更加敏感的!增加应用服务器,确实能够处理更高的请求量,但是随之存储服务器,要承担的请求量也就更多了!!!

我们一样的可以使用开源和节流来解决问题:

读写分离/主从分离架构

读写分离/主从分离架构是一种用于缓解数据库压力的解决方案。在之前的架构中,用户请求通过负载均衡分发到不同的应用服务器后,虽然可以并行处理,但所有请求最终都会从数据库读写数据,导致数据库成为系统承载能力的瓶颈。数据库服务的特殊性在于数据一致性要求很高,例如银行账户金额,如果数据分散到多台服务器,数据一致性将无法保障。

为了解决这个问题,采用主从分离架构:保留一个主数据库用于处理所有写入请求,其他从数据库用于读取请求。从库的数据全部来自主库,通过数据同步保持与主库一致。由于大部分系统中读请求远多于写请求,将读请求分散到从库可以有效减轻数据库压力。虽然主库到从库的数据同步存在一定的时间成本,但可以通过数据库中间件(如 MyCat、TDDL、Amoeba、Cobar 等)来实现读写请求的分离处理,从而优化整个系统的性能。

本来的服务器即是写又是读,现在分成两个了,一个主(master)用来写数据和做同步,一个从(slave) 用来读数据!


因为读的频率是比较高的,我们就可以设计一个主服务器,然后多个从服务器,也就是一主多从,然后这些从服务器通过负载均衡的方式,让应用服务器进行访问! 

引入缓存 --- 冷热分离架构 

数据库有一个天然的问题,响应速度是很慢的!因为在磁盘上存放,我们可以将数据进行"冷热"区分,热点数据放到缓存中,缓存的访问速度往往比数据库要快很多!

随着访问量的增加,业务中出现了读取频率远高于其他数据的热点数据,以及相对的冷数据。为了提升热点数据的读取响应时间,引入了缓存机制,包括本地缓存(如 Memcached)和分布式缓存(如 Redis),缓存热门商品信息或热门商品的 HTML 页面等。通过缓存可以拦截绝大多数请求,从而大大降低数据库的压力。同时,需要解决缓存一致性、缓存穿透/击穿、缓存雪崩以及热点数据集中失效等问题。

引入缓存是可以提高效率,但是修改就不是一件容易事!修改了就需要进行主从数据库的数据同步,还要考虑主的改对了,从的缓存有没有对等等一系列问题!这些问题等我们后续Redis的学习,会进一步展开! 


我们引入分布式系统,不光要去应对更多的请求量(并发量),同时也要能应对更大的数据量!是否会出现一台服务器已经存不下数据了呢???当然会存在的!!! 

一台主句存不下,我们就需要多台主机来解决 --- 进行分库分表!

垂直分布

本来一个数据库服务器,这个数据库服务器上有多个数据库(指的是逻辑上的数据集合,create database 库名 创建的东西),现在就可以引入多个数据库服务器,每一个数据库服务器存储一个或一部分数据库!--- 分库!

如果某一个表特别大,大到一台主机都存不下,也可以针对表进行拆分!--- 分表!

为了进一步应对业务数据量的增大,可以采用垂直分库的方式,将数据按照业务逻辑进行拆分。例如,评论数据可以根据商品 ID 进行 hash 路由到对应的表中存储;支付记录可以根据小时创建表,并进一步根据用户 ID 或记录编号拆分为小表。通过将数据分散到多个小表中,可以实现数据库的水平扩展,从而提高性能。这种架构显著增加了数据库运维的难度,对 DBA 的要求较高。此时的数据库已经可以称为分布式数据库,但其内部组件是通过不同的工具实现的,例如分库分表管理和请求分发由 Mycat 实现,SQL 解析由单机数据库实现,读写分离可能由网关和消息队列实现,查询结果汇总可能由数据库接口层实现等。这种架构是 MPP(大规模并行处理)架构的一种实现。

相关软件包括 Memcached、Redis 等缓存软件,以及 Greenplum、TiDB、Postgresql XC、HAWQ 等分布式数据库软件,商业产品如南大通用的 GBase、睿帆科技的雪球 DB、华为的 LibrA 等。

业务拆分 --- 微服务架构

之前的应用服务器,一个服务器程序里面做了很多的业务。这就可能会导致这一个服务器的代码变得越来越复杂!

为了方便于代码的维护,就可以把这样的一个复杂的服务器,拆分成更多的,功能更单一,但是更小的服务器!这就是微服务!--- 服务器的种类和数量就增加了!

随着人员增加和业务发展,业务被拆分给不同的开发团队进行维护,每个团队独立实现自己的微服务。团队之间通过隔离数据直接访问,利用 Gateway、消息总线等技术实现相互调用和关联。同时,可以将用户管理、安全管理、数据采集等通用业务提取为公共服务。

引入微服务,解决了人的问题,付出的代价???

1. 系统性能下降: 

拆出来更多的服务,多个功能之间要更依赖网络通信,网络通通信的速度可能还比访问硬盘还慢!!!

想要保证性能不下降太多,只能引入更多的机器,更多的硬件资源 --- 充钱!!!

2. 系统复杂程度提高,可用性收到影响:

服务器更多了,问题出现的概率就会更大了!

这就需要一系列的手段,来保证系统的可用性!更丰富的报警系统,以及配套的运维人员!

尾声

在架构上,形成了多个子系统集群,例如用户子系统集群、商品子系统集群、交易子系统集群等,每个集群都包含应用集群、缓存和存储集群。公共服务包括安全中心、监控预警中心等。

电商系统的架构演变是一个逐步优化的过程。以上所述的架构演变顺序只是针对某个侧面的单独改进。在实际场景中,可能同时面临多个问题,或者瓶颈可能出现在其他方面。例如,在政府类场景中,业务可能很丰富但并发量不大,此时高并发不是重点,而解决复杂需求的方案更为关键。

对于单次实施且性能指标明确的系统,架构设计应满足系统性能指标要求,并预留扩展接口以备不时之需。对于持续发展的系统,如电商平台,应设计到满足下一阶段用户量和性能指标要求的程度,并根据业务增长不断迭代升级架构,以支持更高的并发和更丰富的业务。

“大数据”是一个统称,涵盖了海量数据采集、清洗转换、存储、分析和服务等场景的解决方案。每个场景都有多种技术可供选择,例如数据采集有 Flume、Sqoop、Kettle 等,数据存储有分布式文件系统 HDFS、FastDFS,NoSQL 数据库 HBase、MongoDB 等,数据分析有 Spark 技术栈、机器学习算法等。大数据架构根据业务需求整合各种组件,提供分布式存储、计算、多维分析、数据仓库和机器学习算法等能力。而服务端架构更多关注应用组织层面,底层能力通常由大数据架构提供。



在正式引入架构演进之前,为避免读者对架构中的概念完全不了解导致低效沟通,优先对其中一些比较重要的概念做前置介绍:

基本概念

应用(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)这个非量化目标简要表达系统的追求。

分布式系统小结

单机架构:采用应用与数据库同机部署的简单架构模式。这种架构适用于初期业务量较小、访问量低的场景,具有部署和维护简单的优点。例如个人博客、小型企业官网等系统常采用此架构。但随着业务发展,这种架构容易导致资源竞争,性能瓶颈明显。

应用与数据库分离:将应用服务器和数据库服务器分别部署在不同主机上,实现资源隔离。这种分离可以解决CPU、内存和IO资源的竞争问题,提高系统整体性能。例如电商网站将商品展示应用和用户数据库分离部署后,可以有效避免数据库查询影响前端响应速度。

负载均衡:通过负载均衡器(如Nginx、HAProxy等)将请求均匀分发到多台应用服务器,提升系统吞吐量。常见的负载均衡策略包括轮询、加权轮询、最少连接等。例如在秒杀活动中,负载均衡可以将大量并发请求分摊到多个服务器节点处理。

读写分离架构:

  • 采用主从数据库结构
  • 主库负责写入操作,确保数据一致性
  • 多个从库负责读取请求,分担查询压力
  • 主库通过binlog复制等数据同步机制保持从库数据一致性 这种架构特别适合读多写少的业务场景,如新闻网站、社交平台等。

缓存优化:引入Redis、Memcached等缓存机制实现冷热数据分离,显著提升系统响应能力(符合二八原则)。热点数据如商品详情、用户信息等可缓存在内存中,降低数据库访问压力。例如电商平台将热门商品信息缓存后,查询响应时间可从数百毫秒降至毫秒级。

数据分片:通过分库分表策略(如水平分片、垂直分片)扩展数据库容量,有效缓解存储压力。分片策略可以根据业务特点选择,如按用户ID哈希分片、按时间范围分片等。大型社交平台通常采用分片策略来处理海量用户数据。

微服务化:将单体应用拆分为多个功能单一、轻量化的服务集群,每个服务独立开发、部署和扩展。例如电商系统可拆分为用户服务、商品服务、订单服务等。这种架构通过服务注册中心(如Nacos)和服务网关(如Spring Cloud Gateway)实现服务治理,大幅提升系统可维护性和扩展性。


网站公告

今日签到

点亮在社区的每一天
去签到