找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 73|回复: 9

[网站流量统计] 怎么判断服务器要多大带宽?

[复制链接]
  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
发表于 2024-12-10 22:22:49 | 显示全部楼层 |阅读模式
在选择服务器时,带宽是一个重要的考虑因素。带宽的大小直接影响到网站的加载速度和用户的访问体验。那么,如何判断服务器需要多大的带宽呢?本文将为你揭示这一关键问题的答案。
首先,我们需要了解带宽的基本概念。带宽是指服务器在单位时间内传输数据的能力。带宽越大,服务器在同一时间内处理的数据量就越大,网站的加载速度也就越快。
要判断服务器所需的带宽大小,我们需要考虑以下几个关键因素:
访问量:服务器的带宽需求与网站的访问量密切相关。如果你的网站流量大,比如每日有大量用户访问和数据交换,那么就需要更大的带宽来满足需求。

服务器
页面内容:服务器的带宽需求还与网站页面内容的大小有关。页面上的图片、视频、音频等媒体元素会占用大量数据空间,因此,如果网站包含大量媒体内容,就需要更高的带宽来确保流畅的加载速度。
地理位置:服务器的带宽需求还受到网站用户地理位置的影响。如果你的网站面向全球用户提供服务,并且用户分布广泛,那么带宽需求就会相应增加,以确保全球用户都能获得快速的访问速度。
在考虑以上因素的基础上,我们可以根据实际需求来评估所需的带宽大小。如果你不确定具体的需求,可以先选择一个合适的带宽配置,然后根据实际使用情况进行调整。一般来说,初创企业可以选择较低的带宽配置,然后随着业务的发展逐步增加带宽。
此外,为了确保最佳的网站性能和用户体验,建议定期监控服务器的带宽使用情况,以便及时调整配置或升级带宽。
判断服务器所需带宽需要考虑访问量、页面内容和地理位置等多个因素。通过合理的评估和调整,你可以选择合适的带宽配置,确保网站的流畅加载和优质的用户体验。
论坛免责声明
版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。
  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 22:24:23 | 显示全部楼层
抖音服务器带宽有多大,才能供上亿人同时刷?抖音,百度,阿里云,腾讯都是自建的数据中心,都是T级别出口带宽(总出口带宽),也就是达到1T=1024G/s的出口带宽,服务器总署基本都在20万台以上,甚至阿里云都超过了100万台。
字节跳动的数据中心总带宽,可能在10TB级别左右,预期突破15TB级别不远了。
一般情况下:总出口带宽1TB,实际机房出口带宽可能只有100G上下, 这是采用双(多)链路设计,双出口实现动态流量分担,总的出口带宽可以达到T级别。

想要同一时间有数亿人在线,TB级别带宽,CDN加速和多节点,负载均衡等等技术缺一不可。(这个设计技术过于复杂,有相关专业朋友,可以评论简要概述)

字节跳动有多少台服务器?根据网络数据整理,2017年2-3万台服务器,这个时候主要是租用服务器为主。2018年,字节跳动自己建设了数据中心,最大的数据中心在河北怀来官厅湖新媒体产业园,一期5万台服务器。二期9万台服务器。
2018年,租用+自建的服务器数量达到17万台服务器。
2020年,根据字节跳动招聘公告的数据,显示有42万台服务器。比2018年增长了1.5倍。(数据来自网络)

这部分服务器都是给中国区域使用,主要应用国内的抖音,西瓜视频,今日头条,飞书等产品。
在美国的TIKTOK是独立出来的运营,数据在美国当地存储和分发。
2020年TIktok在美国也租用了近10万台服务器据Business Insider公布数据,2020年上半年,字节跳动在美国弗吉尼亚州北部租用了能耗达53兆瓦的数据中心。可以容纳数十万台服务器,占地面积可达数十万平方英尺。
Tiktok在印度,新加坡都在投资建设数据中心。
聊完了服务器数量,那么咱们来点硬核的东西:字节跳动大型的数据中心出口带宽是多少?知识点:所谓的出口带宽,其实就是咱们普通人所说的下载带宽。就是服务器给每一个手机分发数据总速度。
一般情况下,小型的IDC公司自建机房,比如一些网站公司,租用联通,移动,电信的机房,可能总体出口带宽只有5G。超过30G那都是具备一定规模的企业。网络公司营收少说也是几千万的企业。
所以,经常能够看到,一些规模还不错的企业,基本上都不再自建机房,都是使用云主机。例如阿里云的ECS,腾讯云,百度云,AWS(亚马逊)。
一般一个企业网站(企业官网),20M带宽,4G内存,100G硬盘, 一年价格也就4000-5000块钱就足够了,赶上做活动价格可能更便宜。

这里面就是带宽最贵,当然增加带宽,达到一定等级,例如访问量增大,必须要增加内存和硬盘。相比来说,带宽增加的话,费用更贵一些。【这里就跟你说明一下:带宽比较昂贵,属于稀缺资源】
我们来看中国移动的一个机房:中国移动(河北石家庄)数据中心的数据:
占地面积174亩,总建筑面积13万平方米,规划10栋单体建筑,全部建成后可提供约3万个机架的装机能力3个IDC机房共可提供3.1万架机柜,15T带宽资源。
一个机柜,全1U设备部署数量一般不超过16台,全2U设备一般不超过12台,全4U设备一般4到7台。
我们取高性能的2U和4U服务器进行平均折中,各算一半(毕竟移动也算是有钱的大户,不能买低端的1U设备)。那么3.1万架机柜就可以安装,最多21-36万台服务器。
这里粗略取一个平均值:30万台服务器。享受15T的出口带宽资源。当然作为电信的干路网,移动拿带宽资源肯定是要比字节跳动更有优势的。
所以,我们粗略地估计字节跳动自建的17万台服务器的数据中心。总出口带宽可能在7Tb-10TB上下。基本上肯定会采用双出口流量设计,再加上多链路的部署方式:可以做到实际出口带宽在800G-1TG就可以实现10T左右的总出口带宽。【这是技术方式】[/b
T级别出口带宽是什么概念,如果我告诉你2009年,整个上海的出口带宽才1140G,也就是刚刚达到1TB。在短短的10年后,一个企业的数据中心的出口带宽就超过1Tb,这个速度真的不可想象。
要知道2009年,虽然智能手机不发达,但是个人PC销量已经非常庞大了。

CDN加速,让大众刷抖音,看视频都不在卡
知识点:CDN(Content Delivery Network,内容分发网络)
将服务端的内容发布到最接近用户的边缘节点,使用户可以就近取得所需的内容。
解决Internet网络拥塞状况,提高用户访问网站的响应速度。多种加速的方案集合。
用通俗的话解释CDN就是:会把一些页面,专门压缩,有的压缩为静态页面,静态页面直接分发速度快。用户可以在2s内看到内容,体验感更好。【这是静态传输】
对于动态视频,首先通过智能路由,寻找最佳路径,然后协议优化将长连接,内容进行压缩,去除冗余。【这就是动态压缩】
给你们看一下2015年腾讯5亿日活,集合了音乐,即时通讯等等产品的CDN的级别,达到了10TB带宽。每天请求万亿次。

因此,我这里说字节跳动整体服务器有10TB应该只少不多。毕竟抖音日活有6亿,西瓜视频+今日头条我们粗略算是2亿,总计有8亿的日活。
就是这么大的带宽和技术实力,才能让我们看视频这么顺畅。

  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 22:25:46 | 显示全部楼层
服务器托管带宽标准
1. 预期流量:首先,确定您的网站或应用程序预计会产生的流量。这可以通过分析历史数据、流量趋势和业务目标来确定。了解流量模式有助于您预测所需的带宽容量。
2. 并发用户数:了解同时访问您的网站或应用程序的用户数量。这有助于确定带宽需求,因为更多的并发用户可能会导致更高的带宽消耗。
3. 传输数据量:评估您的网站或应用程序每天传输的数据量。这包括文件、图片、视频、数据库等内容的传输。了解数据传输量可以帮助您确定所需的带宽大小。
4. 流量类型:了解您的流量类型,例如是否包含大量的小文件、大文件或流媒体内容。不同类型的流量对带宽的需求不同,因此了解流量类型有助于更准确地预测带宽需求。
5. 服务器性能:考虑服务器的性能,包括处理能力、存储容量和网络带宽。确保所选的服务器能够提供足够的带宽以满足业务需求。
6. 安全性和可靠性:考虑到网络安全和数据可靠性,您可能需要额外的带宽来支持这些功能。例如,可能需要更多的带宽来支持防火墙、负载均衡器和数据备份等安全措施。


1. 峰值带宽计算公式:峰值带宽(Mbps)=(平均页面大小(KB)+2*平均请求数*平均响应时间(秒))*并发用户数*在线用户比例/8
这个公式考虑了页面大小、请求数、响应时间、并发用户数和在线用户比例等因素,可以帮助您计算出所需的峰值带宽。
2. 持续带宽计算公式:持续带宽(Mbps)=页面浏览量(PV)/时间(小时)/页面大小(KB)/8
视频带宽计算公式
3.IDC视频带宽计算公式:
带宽 / (码流 * 8) = 同时在线人数
文件大小 = 时间×码率/8


比如爱奇艺视频
一个视频文件的大小为5.86M,播放时长为3分7秒
    该文件对应的码流就是 5.86 * 1024 * 1024 * 8 / (3 * 60 + 7) = 262872.95657754
10M独享带宽能支撑的同时在线人数
10* 1024 * 1024 / 262872.95657754 = 39.889078498294
支撑1000人同时在线的系统最少需要的带宽数为
262872 * 1000 / (1024 * 1024) = 250.69427490234M
一部电影90min,帧速25p每秒,像素1024*768,24bit,计算该视频文件的大小,单位为GB。
90*60*25*1024*768*24/8/1024/1024/1024=296.63GB
(每幅图像1024*768*24bit,1Byte=8bit,1GB=2^30B)
这个公式基于页面浏览量、时间和页面大小等因素来计算所需的持续带宽。
视频行业带宽选择
      请注意,这些公式仅作为估算带宽需求的工具,实际情况可能因各种因素而有所不同。因此,建议在实际部署服务器之前进行测试和验证,以确保所选的带宽能够满足业务需求。
       除了选择合适的带宽大小,还需要考虑IDC数据中心带宽的质量和可靠性。优质的带宽提供商可以提供更高质量的网络连接,减少丢包和延迟,确保数据传输的可靠性和稳定性。此外,考虑到业务发展的需要,您可能还需要具备扩展带宽的能力,以便在业务增长时能够轻松增加带宽容量。


对于PV,流量和带宽的理解,可以分成几个问题可能更加容易理解
问题1:首先什么是PV  
技术角度讲,1个PV是指从浏览器发出一个对网络服务器的Request ,网络服务器接到Request之后会开始把该Request对应的一个Page(Page就是一个网页)发送到客户端的浏览器上,恭喜,这就是一个Page View
对这个概念从业务上更加细化,就是一个访问者在24小时(0点到24点)内到底看了你网站几个页面,这里需要强调:同一个人浏览你网站同一个页面,不重复计算pv量,点100次也算1次
说白了,pv就是一个访问者打开了你的几个页面。
pv的计算:当一个访问者访问的时候,记录他所访问的页面和对应的IP,然后确定这个IP今天访问了这个页面没有,如果你的网站到了23点,单纯IP有60万条的话,每个访问者平均访问了3个页面,那么pv表的记录就要有180万条
问题2:假设一个网站流量是4000GByte/月
这到底是多少的带宽(单位是Mbit/s)?以及这4000GB流量可以支持多少IP访问呢?首先,你自己算一下你的网站有多少PV(页面访问量,1个独立IP可能有多个PV)
然后我们来算一算4000GB流量,可以支持多少个页面访问量:
假设每个页面请求平均大小是15KB(90%的网站所有页面平均请求大概是15KB),那么
访问10个页面,需要流量150KB
访问100个页面,需要流量1500KB(1.5MB)
访问1000个页面,需要流量15MB
访问1万个页面,需要流量150MB
访问10万个页面,需要流量1500MB(1.5GB)
访问100万个页面,需要流量15GB
访问200万个页面,需要流量30GB
访问2000万个页面,需要流量300GB
访问10000万个页面,需要流量1500GB
访问26000万个页面,需要流量4000GB,就是说,4000GB流量,1个月网站PV可以支持到2600万PV,每天800万PV
如果你的网站每个IP访问5个页面,那么4000GB流量,1个月网站可以支持26000/5=5200万IP访问量,即每天170万IP
当然,这还是假设页面平均大小有15KB的情况下,一般来说,我们的网页都会大量用到CSS,JS等缓存的文件
所以,平均一个页面一般在15K以下。比如您现在正在浏览的这个页面,经过gzip压缩处理,只有不到5KB
小技巧:如果PV很大,建议开启gzip压缩功能,这样可以使得平均页面大小在10KB以内。
以此类推(假设每个页面平均大小是15KB):
500GB流量,每个月可以支持320万PV页面访问量,即每天10万PV
1000GB流量,每个月可以支持660万PV页面访问量,即每天22万PV
2000GB流量,每个月可以支持1300万PV页面访问量,即每天44万PV


问题4:除了PV,网站流量还有哪些指标。
1.UV
UV(unique visitor),即独立访客数。指访问某个站点或点击某条新闻的不同访客人数。
一日内访问某个网站或者网页的不同用户数量。
同一个用户对一个网站或者一个网页的多次访问记为贡献一个uv。
2.IP
这里指的IP地址就是给每个连接在互联网上的计算机分配的一个32位ipv4地址。(现在已经有64位地址)
申请公网IP是需要钱的,因此出现了NAT(网络地址转换协议)。
局域网内的本地IP地址可以通过NAT转换为集体的公网的IP地址这样集体只需要申请少量IP地址
局域网内就可以拥有上百台机器。最典型的应用在公司、网吧,这些单位只有少量的公网IP地址。
3.PR
PR(即PageRank),即网页的级别技术,表示一个网页的重要程度。
级别从1到10级,10级为满分。PR值越高说明该网页越受欢迎(越重要)。
IP/UV/PV的区别与联系
(1)IP可以分析用户的地理位置。
(2)PV访问用户对网页的浏览数量。就行春节回家潮中是名词“人次”。
(3)UV统计不使用IP,因为通过由于NAT的原因
一个IP可能对应很多计算机,一个计算机可能有多个用户登录。可以使用用户名统计。
网站访问量和服务器带宽的选择
通常我们说当一个网站的访问量比较大时,可能会占用网络带宽,造成网络的拥挤,因而对于一些大型网站来说
他们选择的带宽不但要大,而且还以独享带宽为主。而很多站长在选择服务器空间时,往往也会根据网站具体的
访问量来选择,那么网站访问量和带宽有什么样的联系呢,网站的带宽又该如何根据访问量来选择呢

首先要知道影响在线人数的因素,1)访问量;2)网站类型。
  • 如果是出文字的网站(如小说站),1M带宽带动日均5000IP,还勉强。
  • 如果是普通网站有图片,有文字、论坛、新闻资讯类型网站大概1M能带一千IP。考虑到高峰期并发,1M高峰期还会卡。
下面根据影响因素计算下1M带宽能同时承受多少人在线。(以网络状况良好为前提)
  • 打开网站8秒原则;
  • 评判的只是:用户从服务器下载文件的速度;
  • 页面的标准尺寸大小为:60KB。
参考公式:支持连接个人 = 服务器带宽/页面尺寸大小,
通过计算大致结果是: 1Mbps的带宽(服务器的1M带宽最快上下速度能达到1M/s),跟一般家用的带宽稍有区别,支持的连接数为:17个。因此,N M带宽可以支持的同时在线人数大概为N*17个。所以,1M带宽的服务器,日均3000IP以下应该没问题。当然如果网站每个页面都比较大的话,那就没这么多了。具体多少,可以按照上面的算法算下。
同时在线访问数由几个方面决定:
  • 服务器的质量。
服务器分为高中低三种。不同型号品牌的服务器能够承受的流量是不同的,所以,这是影响同时在线访问数量的原因之一。
2、宽带的大小。
假若服务器保证的最大带宽是5M (即5Mbit/s),相应服务器的数据最高传输速度应为5Mbit/s x 1024/8=640KB,1分钟流量大约640 x 60=38400KB。假设毎个用户1分钟内始终占用10KB的流量,即该1分钟内支持占用这样的流量的同时在线访问人数为3840人(视频类大流量网站不在此例)。
但是,并不能保证每个用户在1分钟内只有一次到该站的链接,假如每个用户在1分钟内有两次或以上到该站的链接(每个链接始终占用10KB的流量),那么支持在线人数应该在2000以下。
综上所述,一台中低端服务器通常支持在线人数最高为2000人左右,而且只适合普通网站建设后的服务器和文字型论坛,不包括图片类、下载类、视频类等。如果是其他类型的网站,那就要考虑更高配置的服务器以及更大的带宽。

  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:17:17 | 显示全部楼层
你想建设一个能承受500万PV/每天的网站吗? 500万PV是什么概念?服务器每秒要处理多少个请求才能应对?如果计算呢?

PV是什么:

PV是page view的简写。PV是指页面的访问次数,每打开或刷新一次页面,就算做一个pv。

计算模型:
每台服务器每秒处理请求的数量=((80%*总PV量)/(24小时*60分*60秒*40%)) / 服务器数量 。
其中关键的参数是80%、40%。表示一天中有80%的请求发生在一天的40%的时间内。24小时的40%是9.6小时,有80%的请求发生一天的9.6个小时当中(很适合互联网的应用,白天请求多,晚上请求少)。


简单计算的结果:
((80%*500万)/(24小时*60分*60秒*40%))/1 = 115.7个请求/秒
((80%*100万)/(24小时*60分*60秒*40%))/1 = 23.1个请求/秒

初步结论:
现在我们在做压力测试时,就有了标准,如果你的服务器一秒能处理115.7个请求,就可以承受500万PV/每天。如果你的服务器一秒能处理23.1个请求,就可以承受100万PV/每天


留足余量:
以上请求数量均匀的分布在白天的9.6个小时中,但实际情况并不会这么均匀的分布,会有高峰有低谷。为了应对高峰时段,应该留一些余地,最少也要x2倍,x3倍也不为过。
115.7个请求/秒 *2倍=231.4个请求/秒
115.7个请求/秒 *3=347.1个请求/秒
23.1个请求/秒 *2=46.2个请求/秒
23.1个请求/秒 *3=69.3个请求/秒

最终结论:
如果你的服务器一秒能处理231.4--347.1个请求/秒,就可以应对平均500万PV/每天。
如果你的服务器一秒能处理46.2--69.3个请求,就可以应对平均100万PV/每天

说明:
这里说明每秒N个请求,就是QPS。因为我关心的是应用程序处理业务的能力。

实际经验:
1、根据实际经验,采用两台常规配置的机架式服务器,配置是很常见的配置,例如一个4核CPU+4G内存+服务器SAS硬盘
硬盘的性能很重要,由其是数据库服务器。一般的服务器都配1.5万转的SAS硬盘,高级一点的可以配SSD固态硬盘,性能会更好。最最最最重要的指标是“随机读写性能”而不是“顺序读写性能”。(本例还是配置最常见的1.5万转的SAS硬盘吧
4、一台服务器跑Tomcat运行j2ee程序,一台服务器跑MySql数据库,程序写的中等水平(这个真的不好量化),
5、以上软硬件情况下,是可以承受100万PV/每天的。(已留有余量应对突然的访问高峰)


首先,确认服务器硬件是否足够支持当前的流量。
服务器的负载过大,一个重要的原因是CPU负荷过大,降低服务器CPU的负荷,才能够有效打破瓶颈。而使用静态页面可以使得CPU的负荷最小化。前台实现完全的静态化当然最好,可以完全不用访问数据库,不过对于频繁更新的网站,静态化往往不能满足某些功能。
   缓存技术就是另一个解决方案,就是将动态数据存储到缓存文件中,动态网页直接调用这些文件,而不必再访问数据库, 第三,禁止外部的盗链。
   外部网站的图片或者文件盗链往往会带来大量的负载压力,因此应该严格限制外部对于自身的图片或者文件盗链,好在目前可以简单地通过refer来控制盗链
第四,控制大文件的下载。
   大文件的下载会占用很大的流量,并且对于非SCSI硬盘来说,大量文件下载会消耗CPU,使得网站响应能力下降。因此,尽量不要提供超过2M的大文件下载,如果需要提供,建议将大文件放在另外一台服务器上。目前有不少免费的Web 2.0网站提供图片分享和文件分享功能,因此可以尽量将图片和文件上传到这些分享网站。
  第六,使用流量分析统计软件。
   在网站上安装一个流量分析统计软件,可以即时知道哪些地方耗费了大量流量,哪些页面需要再进行优化,因此,解决流量问题还需要进行精确的统计分析才可以。


  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:18:51 | 显示全部楼层
1000W用户的问题分解
如何支撑1000W用户其实是一个非常抽象的问题,对于技术开发来说,我们需要一个非常明确的对于执行关键业务上的性能指标数据,比如,高峰时段下对于事务的响应时间、并发用户数、QPS、成功率、以及基本指标要求等,这些都 必须要非常明确,只有这样才能够指导整个架构的改造和优化。所以,如果大家接到这样一个问题,首先需要去定位到问题的本质,也就是首先得知道一些可量化的数据指标。
如果有过往的相似业务交易历史数据经验,你需要尽量参考,处理这些收集到的原始数据(日志),从而分析出高峰时段,以及该时段下的交易行为,交易规模等,得到你想要看清楚的需求细节
  • 当用户能够在2秒以内得到响应时,会感觉系统的响应很快;
  • 当用户在2-5秒之间得到响应时,会感觉系统的响应速度还可以;
  • 当用户在5-8秒以内得到响应时,会感觉系统的响应速度很慢,但是还可以接受;
  • 而当用户在超过8秒后仍然无法得到响应时,会感觉系统糟透了,或者认为系统已经失去响应,而选择离开这个Web站点,或者发起第二次请求。
另外一种情况,就是没有相关的数据指标作为参考,这个时候就需要经验来分析。比如可以参考一些类似行业的比较成熟的业务交易模型(比如银行业的日常交易活动或交通行业售检票交易活动)或者干脆遵循“2/8”原则和“2/5/8”原则来直接下手实践。  
在估算响应时间、并发用户数、TPS、成功率这些关键指标的同时,你仍需要关心具体的业务功能维度上的需求,每个业务功能都有各自的特点,比如有些场景可以不需要同步返回明确执行结果,有些业务场景可以接受返回“系统忙,请等待!”这样暴力的消息,以避免过大的处理流量所导致的大规模瘫痪,因此,学会平衡这些指标之间的关系是必要的,大多数情况下最好为这些指标做一个优先级排序,并且尽量只考察几个优先级高的指标要求。(SLA服务等级)
  SLA:Service-Level Agreement的缩写,意思是服务等级协议。服务的SLA是服务提供者对服务消费者的正式承诺,是衡量服务能力等级的关键项。服务SLA中定义的项必须是可测量的,有明确的测量方法。
   60a2215e297b6589a75d2ee5dd65afc5.png
并发中相关概念的解释
在分析上述问题之前,先给大家普及一下,系统相关的一些关键衡量指标。
TPS(Transaction Per Second)每秒处理的事务数。
站在宏观角度来说,一个事务是指客户端向服务端发起一个请求,并且等到请求返回之后的整个过程。从客户端发起请求开始计时,等到收到服务器端响应结果后结束计时,在计算这个时间段内总共完成的事务个数,我们称为TPS。
站在微观角度来说,一个数据库的事务操作,从开始事务到事务提交完成,表示一个完整事务,这个是数据库层面的TPS。
QPS (Queries Per Second)每秒查询数,表示服务器端每秒能够响应的查询次数。这里的查询是指用户发出请求到服务器做出响应成功的次数,可以简单认为每秒钟的Request数量。
针对单个接口而言,TPS和QPS是相等的。如果从宏观层面来说,用户打开一个页面到页面渲染结束代表一个TPS,那这个页面中会调用服务器很多次,比如加载静态资源、查询服务器端的渲染数据等,就会产生两个QPS,因此,一个TPS中可能会包含多个QPS。
  QPS=并发数/平均响应时间
  
   
11b2d4ac41aa50f4f41feef8d2777e88.png
RT(Response Time),表示客户端发起请求到服务端返回的时间间隔,一般表示平均响应时间。
并发数 并发数是指系统同时能处理的请求数量。
需要注意,并发数和QPS不要搞混了,QPS表示每秒的请求数量,而并发数是系统同时处理的请求数量,并发数量会大于QPS,因为服务端的一个连接需要有一个处理时长,在这个请求处理结束之前,这个连接一直占用。
举个例子,如果QPS=1000,表示每秒钟客户端会发起1000个请求到服务端,而如果一个请求的处理耗时是3s,那么意味着总的并发=1000*3=3000,也就是服务端会同时有3000个并发。
计算方法 上面说的这些指标,怎么计算呢?举个例子。
假设在10点到11点这一个小时内,有200W个用户访问我们的系统,假设平均每个用户请求的耗时是3秒,那么计算的结果如下:
  • QPS=2000000/60*60 = 556 (表示每秒钟会有556个请求发送到服务端)
  • RT=3s(每个请求的平均响应时间是3秒)
  • 并发数=556*3=1668
从这个计算过程中发现,随着RT的值越大,那么并发数就越多,而并发数代表着服务器端同时处理的连接请求数量,也就意味服务端占用的连接数越多,这些链接会消耗内存资源以及CPU资源等。所以RT值越大系统资源占用越大,同时也意味着服务端的请求处理耗时较长。
但实际情况是,RT值越小越好,比如在游戏中,至少做到100ms左右的响应才能达到最好的体验,对于电商系统来说,3s左右的时间是能接受的,那么如何缩短RT的值呢?
按照2/8法则来推算1000w用户的访问量
继续回到最开始的问题,假设没有历史数据供我们参考,我们可以使用2/8法则来进行预估。
  • 1000W用户,每天来访问这个网站的用户占到20%,也就是每天有200W用户来访问。
  • 假设平均每个用户过来点击50次,那么总共的PV=1亿。
  • 一天是24小时,根据2/8法则,每天大部分用户活跃的时间点集中在(24*0.2) 约等于5个小时以内,而大部分用户指的是(1亿点击 * 80%)约等于8000W(PV), 意味着在5个小时以内,大概会有8000W点击进来,也就是每秒大约有4500(8000W/5小时)个请求。
  • 4500只是一个平均数字。在这5个小时中,不可能请求是非常平均的,有可能会存在大量的用户集中访问(比如像淘宝这样的网站,日访问峰值的时间点集中在下午14:00、以及晚上21:00,其中21:00是一天中活跃的峰值),一般情况下访问峰值是平均访问请求的3倍到4倍左右(这个是经验值),我们按照4倍来计算。那么在这5个小时内有可能会出现每秒18000个请求的情况。也就是说,问题由原本的支撑1000W用户,变成了一个具体的问题,就是服务器端需要能够支撑每秒18000个请求(QPS=18000)
  
     
77e97613e240bfe72686c6a0d41579b8.png

326fd20f08c547e19e06da6c32cbadbe.png
服务器压力预估
大概预估出了后端服务器需要支撑的最高并发的峰值之后,就需要从整个系统架构层面进行压力预估,然后配置合理的服务器数量和架构。既然是这样,那么首先需要知道一台服务器能够扛做多少的并发,那这个问题怎么去分析呢?我们的应用是部署在Tomcat上,所以需要从Tomcat本身的性能下手。
下面这个图表示Tomcat的工作原理,该图的说明如下。
  • LimitLatch是连接控制器,它负责控制Tomcat能够同时处理的最大连接数,在NIO/NIO2的模式中,默认是10000,如果是APR/native,默认是8192
  • Acceptor是一个独立的线程,在run方法中,在while循环中调用socket.accept方法中接收客户端的连接请求,一旦有新的请求过来,accept会返回一个Channel对象,接着把这个Channel对象交给Poller去处理。   
        Poller 的本质是一个 Selector ,它同样也实现了线程,Poller 在内部维护一个 Channel 数组,它在一个死循环里不断检测 Channel 的数据就绪状态,一旦有 Channel 可读,就生成一个 SocketProcessor 任务对象扔给 Executor 去处理   
  • SocketProcessor 实现了 Runnable 接口,当线程池在执行SocketProcessor这个任务时,会通过Http11Processor去处理当前这个请求,Http11Processor 读取 Channel 的数据来生成 ServletRequest 对象。
  • Executor 就是线程池,负责运行 SocketProcessor 任务类, SocketProcessor 的 run 方法会调用 Http11Processor 来读取和解析请求数据。我们知道, Http11Processor 是应用层协议的封装,它会调用容器获得响应,再把响应通过 Channel 写出。
从这个图中可以得出,限制Tomcat请求数量的因素四个方面。
当前服务器系统资源TCP连接对于系统资源最大的开销就是内存。
因为tcp连接归根结底需要双方接收和发送数据,那么就需要一个读缓冲区和写缓冲区,这两个buffer在linux下最小为4096字节,可通过cat /proc/sys/net/ipv4/tcp_rmem和cat /proc/sys/net/ipv4/tcp_wmem来查看。
所以,一个tcp连接最小占用内存为4096+4096 = 8k,那么对于一个8G内存的机器,在不考虑其他限制下,最多支持的并发量为:810241024/8 约等于100万。此数字为纯理论上限数值,在实际中,由于linux kernel对一些资源的限制,加上程序的业务处理,所以,8G内存是很难达到100万连接的,当然,我们也可以通过增加内存的方式增加并发量。
Tomcat依赖的JVM的配置 我们知道Tomcat是Java程序,运行在JVM上,因此我们还需要对JVM做优化,才能更好的提升Tomcat的性能,
而在JVM中,要配置的几个核心参数无非是。
  • -Xms,Java堆内存大小
  • -Xmx,Java最大堆内存大小
  • -Xmn,Java堆内存中的新生代大小,扣除新生代剩下的就是老年代内存
    新生代内存设置过小会频繁触发Minor GC,频繁触发GC会影响系统的稳定性
  • -XX:MetaspaceSize,元空间大小, 128M
  • -XX:MaxMetaspaceSize,最大云空间大小 (如果没有指定这两个参数,元空间会在运行时根据需要动态调整。) 256M
       
        一个新系统的元空间,基本上没办法有一个测算的方法,一般设置几百兆就够用,因为这里面主要存放一些类信息。
       
  • -Xss,线程栈内存大小,这个基本上不需要预估,设置512KB到1M就行,因为值越小,能够分配的线程数越多。

JVM内存的大小,取决于机器的配置比如一个2核4G的服务器,能够分配给JVM进程也就2G左右,因为机器本身也需要内存,而且机器上还运行了其他的进程也需要占内存。而这2G还得分配给栈内存、堆内存、元空间,那堆内存能够得到的也就1G左右,然后堆内存还要分新生代、老年代。
Tomcat本身的配置
  • ccept-count: 最大等待数,当调用HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100。如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)
  • maxThreads:最大线程数,每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以同时处理多少个请求。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。线程数的经验值为:1核2g内存为200,线程数经验值200;4核8g内存,线程数经验值800。
  • maxConnections,最大连接数,这个参数是指在同一时间,tomcat能够接受的最大连接数。对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。对于Java 新的NIO模式,maxConnections 默认值是10000。对于windows上APR/native IO模式,maxConnections默认值为8192
    如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。
    maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。

服务器数量评估





  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:35:29 | 显示全部楼层
(1)单块架构
网站开始建立时,用户少 , 网站架构都是用单体架构设计,共部署3台服务器,1台应用,1台数据库,1台图片。
1、应用服务器上发布,可能是把应用服务器上的Tomcat给关掉,替换系统的代码war包,重新启动Tomcat。
2、数据库服务器,存全部核心数据。
3、网络文件系统(NFS)作图片服务器,存网站全部图片。应用服务器上代码会连接以及操作数据库以及图片服务器。
如下图所示:
v2-543ba8e40abf810b4aa751a4eab90291_1440w.jpg
但是这种纯单块系统架构下,有高可用问题存在,最大的问题就是应用服务器可能会故障,或者是数据库可能会故障
所以在这个时期,一般稍微预算充足一点的公司,都会做一个初步的高可用架构出来。
(2)初步的高可用架构
应用服务器而言,集群化部署,初期用户量少的情况下,一般就是部署两台应用服务器,前面会放一台服务器部署负载均衡设备,如说LVS(Linux虚拟服务器),均匀把用户请求打到两台应用服务器上去。
如此时某台应用服务器故障了,还有另外一台应用服务器是可以使用的,这就避免了单点故障问题。如下图所示:
v2-e393723248ae58002dcb89fcb811b15d_1440w.jpg
对于数据库服务器而言,此时一般也会使用主从架构,部署一台从库来从主库同步数据,这样一旦主库出现问题,可以迅速使用从库继续提供数据库服务,避免数据库故障导致整个系统都彻底故障不可用。如下图:
v2-f352832c222172f845eda0cdfa927c8b_1440w.jpg

(3)千万级用户量的压力预估
这个假设这个网站预估的用户数是1000万,那么根据28法则,每天会来访问这个网站的用户占到20%,也就是200万用户每天会过来访问。
通常假设平均每个用户每次过来会有30次的点击,那么总共就有6000万的点击(PV)。
每天24小时,根据28法则,每天大部分用户最活跃的时间集中在(24小时 * 0.2)≈ 5小时内,而大部分用户指的是(6000万点击 * 0.8 ≈ 5000万点击)
也就是说,在5小时内会有5000万点击进来。
换算下来,在那5小时的活跃访问期内,大概每秒钟会有3000左右的请求量,然后这5小时中可能又会出现大量用户集中访问的高峰时间段。
比如在集中半个小时内大量用户涌入形成高峰访问。根据线上经验,一般高峰访问是活跃访问的2~3倍。假设我们按照3倍来计算,那么5小时内可能有短暂的峰值会出现每秒有10000左右的请求。

(4)服务器压力预估
大概知道了高峰期每秒钟可能会有1万左右的请求量之后,来看一下系统中各个服务器的压力预估。
一般来说一台虚拟机部署的应用服务器,上面放一个Tomcat,也就支撑最多每秒几百的请求。
按每秒支撑500的请求来计算,那么支撑高峰期的每秒1万访问量,需要部署20台应用服务。
而且应用服务器对数据库的访问量又是要翻几倍的,因为假设一秒钟应用服务器接收到1万个请求,但是应用服务器为了处理每个请求可能要涉及到平均3~5次数据库的访问。
按3次数据库访问来算,那么每秒会对数据库形成3万次的请求。
按照一台数据库服务器最高支撑每秒5000左右的请求量,此时需要通过6台数据库服务器才能支撑每秒3万左右的请求。
图片服务器的压力同样会很大,因为需要大量的读取图片展示页面,这个不太好估算,但是大致可以推算出来每秒至少也会有几千次请求,因此也需要多台图片服务器来支撑图片访问的请求。
(5)业务垂直拆分
一般来说在这个阶段要做的第一件事儿就是业务的垂直拆分
因为如果所有业务代码都混合在一起部署,会导致多人协作开发时难以维护。在网站到了千万级用户的时候,研发团队一般都有几十人甚至上百人。
所以这时如果还是在一个单块系统里做开发,是一件非常痛苦的事情,此时需要做的就是进行业务的垂直拆分,把一个单块系统拆分为多个业务系统,然后一个小团队10个人左右就专门负责维护一个业务系统。如下
(6)分布式缓存扛下读请求
这个时候应用服务器层面一般没什么大问题,因为无非就是加机器就可以抗住更高的并发请求。
现在估算出来每秒钟是1万左右的请求,部署个二三十台机器就没问题了。
但是目前上述系统架构中压力最大的,其实是数据库层面 ,因为估算出来可能高峰期对数据库的读写并发会有3万左右的请求。
此时就需要引入分布式缓存来抗下对数据库的读请求压力了,也就是引入Redis集群。
一般来说对数据库的读写请求也大致遵循28法则,所以每秒3万的读写请求中,大概有2.4万左右是读请求
这些读请求基本上90%都可以通过分布式缓存集群来抗下来,也就是大概2万左右的读请求可以通过 Redis集群来抗住。
我们完全可以把热点的、常见的数据都在Redis集群里放一份作为缓存,然后对外提供缓存服务。
在读数据的时候优先从缓存里读,如果缓存里没有,再从数据库里读取。这样2万读请求就落到Redis上了,1万读写请求继续落在数据库上。
Redis一般单台服务器抗每秒几万请求是没问题的,所以Redis集群一般就部署3台机器,抗下每秒2万读请求是绝对没问题的。如下图所示
v2-2d55e26b16150b1c78288d7f44836631_1440w.jpg

(7)基于数据库主从架构做读写分离
此时数据库服务器还是存在每秒1万的请求,对于单台服务器来说压力还是过大。
但是数据库一般都支持主从架构,也就是有一个从库一直从主库同步数据过去。此时可以基于主从架构做读写分离
也就是说,每秒大概6000写请求是进入主库,大概还有4000个读请求是在从库上去读,这样就可以把1万读写请求压力分摊到两台服务器上去。
这么分摊过后,主库每秒最多6000写请求,从库每秒最多4000读请求,基本上可以勉强把压力给抗住。如下图:
v2-9d069d089faa8c204efdb7fa891d242f_1440w.jpg

(8)总结
本文主要是探讨在千万级用户场景下的大型网站的高并发架构设计,也就是预估出了千万级用户的访问压力以及对应的后台系统为了要抗住高并发,在业务系统、缓存、数据库几个层面的架构设计以及抗高并发的分析。但是要记住,大型网站架构中共涉及的技术远远不止这些,还包括了MQ、CDN、静态化、分库分表、NoSQL、搜索、分布式文件系统、反向代理,等等很多话题,但是本文不能一一涉及,主要是在高并发这个角度分析一下系统如何抗下每秒上万的请求。
如何降低RT的值 继续看上面这个图,一个请求只有等到tomcat容器中的应用执行完成才能返回,而请求在执行过程中会做什么事情呢?
  • 查询数据库
  • 访问磁盘数据
  • 进行内存运算
  • 调用远程服务
这些操作每一个步骤都会消耗时间,当前客户端的请求只有等到这些操作都完成之后才能返回,所以降低RT的方法,就是优化业务逻辑的处理。
数据库瓶颈的优化 当18000个请求进入到服务端并且被接收后,开始执行业务逻辑处理,那么必然会查询数据库。
每个请求至少都有一次查询数据库的操作,多的需要查询3~5次以上,我们假设按照3次来计算,那么每秒会对数据库形成54000个请求,假设一台数据库服务器每秒支撑10000个请求(影响数据库的请求数量有很多因素,比如数据库表的数据量、数据库服务器本身的系统性能、查询语句的复杂度),那么需要6台数据库服务器才能支撑每秒10000个请求。
除此之外,数据库层面还有涉及到其他的优化方案。
  • 首先是Mysql的最大连接数设置,大家可能遇到过MySQL: ERROR 1040: Too many connections这样的问题,原因就是访问量过高,连接数耗尽了。show variables like '%max_connections%'; 如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。
  • 数据表数据量过大,比如达到几千万甚至上亿,这种情况下sql的优化已经毫无意义了,因为这么大的数据量查询必然会涉及到运算。可以缓存来解决读请求并发过高的问题,一般来说对于数据库的读写请求也都遵循2/8法则,在每秒54000个请求中,大概有43200左右是读请求,这些读请求中基本上90%都是可以通过缓存来解决。分库分表,减少单表数据量,单表数据量少了,那么查询性能就自然得到了有效的提升读写分离,避免事务操作对查询操作带来的性能影响写操作本身耗费资源数据库写操作为IO写入,写入过程中通常会涉及唯一性校验、建索引、索引排序等操作,对资源消耗比较大。一次写操作的响应时间往往是读操作的几倍甚至几十倍。锁争用写操作很多时候需要加锁,包括表级锁、行级锁等,这类锁都是排他锁,一个会话占据排它锁之后,其他会话是不能读取数据的,这会会极大影响数据读取性能。所以MYSQL部署往往会采用读写分离方式,主库用来写入数据及部分时效性要求很高的读操作,从库用来承接大部分读操作,这样数据库整体性能能够得到大幅提升。
  • 不同类型的数据采用不同的存储库,MongoDB nosql 文档化存储Redis nosql key-value存储HBase nosql, 列式存储,其实本质上有点类似于key-value数据库。cassandra,Cassandra 是一个来自 Apache 的分布式数据库,具有高度可扩展性,可用于管理大量的结构化数据TIDB,是PingCAP公司自主设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品
  为什么把mysql数据库中的数据放redis缓存中能提升性能?
  Redis存储的是k-v格式的数据。时间复杂度是O(1),常数阶,而mysql引擎的底层实现是B+TREE,时间复杂度是O(logn)是对数阶的。Redis会比Mysql快一点点。Mysql数据存储是存储在表中,查找数据时要先对表进行全局扫描或根据索引查找,这涉及到磁盘的查找,磁盘查找如果是单点查找可能会快点,但是顺序查找就比较慢。而redis不用这么麻烦,本身就是存储在内存中,会根据数据在内存的位置直接取出。Redis是单线程的多路复用IO,单线程避免了线程切换的开销,而多路复用IO避免了IO等待的开销,在多核处理器下提高处理器的使用效率可以对数据进行分区,然后每个处理器处理不同的数据。
  • 池化技术,减少频繁创建数据库连接的性能损耗。每次进行数据库操作之前,先建立连接然后再进行数据库操作,最后释放连接。这个过程涉及到网络通信的延时,频繁创建连接对象和销毁对象的性能开销等,当请求量较大时,这块带来的性能影响非常大。
77f4b5abb33db0d43620147b8b9ed4b1.png
如何拆分服务 如何拆分服务,这个问题看起来简单,很多同学会说,直接按照业务拆分啊。
但是实际在实施的时候,会发现拆分存在一些边界性问题,比如有些数据模型可以存在A模块,也可以存在B模块,这个时候怎么划分呢?另外,服务拆分的粒度应该怎么划分?
一般来说,服务的拆分是按照业务来实现的,然后基于DDD来指导微服务的边界划分。领域驱动就是一套方法论,通过领域驱动设计方法论来定义领域模型,从而确定业务边界和应用边界,保证业务模型和代码模型的一致性。不管是DDD还是微服务,都要遵循软件设计的基本原则:高内聚低耦合。服务内部高内聚,服务之间低耦合,实际上一个领域服务对应了一个功能集合,这些功能一定是有一些共性的。比如,订单服务,那么创建订单、修改订单、查询订单列表,领域的边界越清晰,功能也就越内聚,服务之间的耦合性也就越低。
服务拆分还需要根据当前技术团队和公司所处的状态来进行。
如果是初创团队,不需要过分的追求微服务,否则会导致业务逻辑过于分散,技术架构太过负载,再加上团队的基础设施还不够完善,导致整个交付的时间拉长,对公司的发展来说会造成较大的影响。所以在做服务拆分的时候还需要考虑几个因素。
  • 当前公司业务所处领域的市场性质,如果是市场较为敏感的项目,前期应该是先出来东西,然后再去迭代和优化。
  • 开发团队的成熟度,团队技术能否能够承接。
  • 基础能力是否足够,比如Devops、运维、测试自动化等基础能力。 团队是否有能力来支撑大量服务实例运行带来的运维复杂度,是否可以做好服务的监控。
  • 测试团队的执行效率,如果测试团队不能支持自动化测试、自动回归、压力测试等手段来提高测试效率,那必然会带来测试工作量的大幅度提升从而导致项目上线周期延期
如果是针对一个老的系统进行改造,那可能涉及到的风险和问题更多,所以要开始着手改动之前,需要考虑几个步骤:拆分前准备阶段,设计拆分改造方案,实施拆分计划
  • 拆分之前,先梳理好当前的整个架构,以及各个模块的依赖关系,还有接口准备阶段主要是梳理清楚了依赖关系和接口,就可以思考如何来拆,第一刀切在哪儿里,即能达到快速把一个复杂单体系统变成两个更小系统的目标,又能对系统的现有业务影响最小。要尽量避免构建出一个分布式的单体应用,一个包含了一大堆互相之间紧耦合的服务,却又必须部署在一起的所谓分布式系统。没分析清楚就强行拆,可能就一不小心剪断了大动脉,立马搞出来一个 A 类大故障,后患无穷。
  • 不同阶段拆分要点不同,每个阶段的关注点要聚焦拆分本身可以分成三个阶段,核心业务和非业务部分的拆分、核心业务的调整设计、核心业务内部的拆分。第一阶段将核心业务瘦身,把非核心的部分切开,减少需要处理的系统大小;第二阶段。重新按照微服务设计核心业务部分;第三阶段把核心业务部分重构设计落地。拆分的方式也有三个:代码拆分、部署拆分、数据拆分。
另外,每个阶段需要聚焦到一两个具体的目标,否则目标太多反而很难把一件事儿做通透。例如某个系统的微服务拆分,制定了如下的几个目标:
  • 性能指标(吞吐和延迟):核心交易吞吐提升一倍以上(TPS:1000->10000),A 业务延迟降低一半(Latency:250ms->125ms),B 业务延迟降低一半(Latency:70ms->35ms)。
  • 稳定性指标(可用性,故障恢复时间):可用性>=99.99%,A 类故障恢复时间<=15 分钟,季度次数<=1 次。
  • 质量指标:编写完善的产品需求文档、设计文档、部署运维文档,核心交易部分代码 90%以上单测覆盖率和 100%的自动化测试用例和场景覆盖,实现可持续的性能测试基准环境和长期持续性能优化机制。
  • 扩展性指标:完成代码、部署、运行时和数据多个维度的合理拆分,对于核心系统重构后的各块业务和交易模块、以及对应的各个数据存储,都可以随时通过增加机器资源实现伸缩扩展。
  • 可维护性指标:建立全面完善的监控指标、特别是全链路的实时性能指标数据,覆盖所有关键业务和状态,缩短监控报警响应处置时间,配合运维团队实现容量规划和管理,出现问题时可以在一分钟内拉起系统或者回滚到上一个可用版本(启动时间<=1 分钟)。
  • 易用性指标,通过重构实现新的 API 接口既合理又简单,极大的满足各个层面用户的使用和需要,客户满意度持续上升。
  • 业务支持指标:对于新的业务需求功能开发,在保障质量的前提下,开发效率提升一倍,开发资源和周期降低一半。
当然,不要期望一次性完成所有目标,每一个阶段可以选择一个两个优先级高的目标进行执行。
9e411d3d3a64a3be2e4be7148574ccf4.png
整体架构图 基于上述从微观到宏观的整体分析,我们基本上能够设计出一个整体的架构图。
  • 接入层,外部请求到内部系统之间的关口,所有请求都必须经过api 网关。
  • 应用层,也叫聚合层,为相关业务提供聚合接口,它会调用中台服务进行组装。
  • 中台服务,也是业务服务层,以业务为纬度提供业务相关的接口。中台的本质是为整个架构提供复用的能力,比如评论系统,在咕泡云课堂和Gper社区都需要,那么这个时候评论系统为了设计得更加可复用性,就不能耦合云课堂或者Gper社区定制化的需求,那么作为设计评论中台的人,就不需要做非常深度的思考,如何提供一种针对不同场景都能复用的能力。你会发现,当这个服务做到机制的时候,就变成了一个baas服务。服务商客户(开发者)提供整合云后端的服务,如提供文件存储、数据存储、推送服务、身份验证服务等功能,以帮助开发者快速开发应用。
47c624e0066091a20988eece47d526aa.png
微观指标 性能指标
通过性能指标可以度量目前存在的性能问题,同时作为性能优化的评估依据。一般来说,会采用一段时间内的接口响应时间作为指标。
1、平均响应时间:最常用,但是缺陷很明显,对于慢请求不敏感。比如 1 万次请求,其中 9900 次是 1ms,100 次是 100ms,则平均响应时间为 1.99ms,虽然平均耗时仅增加了 0.99ms,但是 1%请求的响应时间已经增加了 100 倍。
2、TP90、TP99 等分位值:将响应时间按照从小到大排序,TP90 表示排在第 90 分位的响应时间, 分位值越大,对慢请求越敏感。
39ced36dc79eeb86b9006d0ffea0a87a.png
可用性指标
高可用性是指系统具有较高的无故障运行能力,可用性 = 平均故障时间 / 系统总运行时间,一般使用几个 9 来描述系统的可用性。
对于高并发系统来说,最基本的要求是:保证 3 个 9 或者 4 个 9。原因很简单,如果你只能做到 2 个 9,意味着有 1%的故障时间,像一些大公司每年动辄千亿以上的 GMV 或者收入,1%就是 10 亿级别的业务影响。
可扩展性指标
面对突发流量,不可能临时改造架构,最快的方式就是增加机器来线性提高系统的处理能力。
对于业务集群或者基础组件来说,扩展性 = 性能提升比例 / 机器增加比例,理想的扩展能力是:资源增加几倍,性能提升几倍。通常来说,扩展能力要维持在 70%以上。
但是从高并发系统的整体架构角度来看,扩展的目标不仅仅是把服务设计成无状态就行了,因为当流量增加 10 倍,业务服务可以快速扩容 10 倍,但是数据库可能就成为了新的瓶颈。
像 MySQL 这种有状态的存储服务通常是扩展的技术难点,如果架构上没提前做好规划(垂直和水平拆分),就会涉及到大量数据的迁移。
因此,高扩展性需要考虑:服务集群、数据库、缓存和消息队列等中间件、负载均衡、带宽、依赖的第三方等,当并发达到某一个量级后,上述每个因素都可能成为扩展的瓶颈点。
实践方案 通用设计方法
纵向扩展(scale-up)
它的目标是提升单机的处理能力,方案又包括:
1、提升单机的硬件性能:通过增加内存、CPU 核数、存储容量、或者将磁盘升级成 SSD 等堆硬件的方式来提升。
2、提升单机的软件性能:使用缓存减少 IO 次数,使用并发或者异步的方式增加吞吐量。
横向扩展(scale-out)
因为单机性能总会存在极限,所以最终还需要引入横向扩展,通过集群部署以进一步提高并发处理能力,又包括以下 2 个方向:
1、做好分层架构:这是横向扩展的提前,因为高并发系统往往业务复杂,通过分层处理可以简化复杂问题,更容易做到横向扩展。
2、各层进行水平扩展:无状态水平扩容,有状态做分片路由。业务集群通常能设计成无状态的,而数据库和缓存往往是有状态的,因此需要设计分区键做好存储分片,当然也可以通过主从同步、读写分离的方案提升读性能。
高性能实践方案 1、集群部署,通过负载均衡减轻单机压力。
2、多级缓存,包括静态数据使用 CDN、本地缓存、分布式缓存等,以及对缓存场景中的热点 key、缓存穿透、缓存并发、数据一致性等问题的处理。
3、分库分表和索引优化,以及借助搜索引擎解决复杂查询问题。
4、考虑 NoSQL 数据库的使用,比如 HBase、TiDB 等,但是团队必须熟悉这些组件,且有较强的运维能力。
5、异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理。
6、限流,需要先考虑业务是否允许限流(比如秒杀场景是允许的),包括前端限流、Nginx 接入层的限流、服务端的限流。
7、对流量进行削峰填谷,通过 MQ 承接流量。
8、并发处理,通过多线程将串行逻辑并行化。
9、预计算,比如抢红包场景,可以提前计算好红包金额缓存起来,发红包时直接使用即可。
10、缓存预热,通过异步任务提前预热数据到本地缓存或者分布式缓存中。
11、减少 IO 次数,比如数据库和缓存的批量读写、RPC 的批量接口支持、或者通过冗余数据的方式干掉 RPC 调用。
12、减少 IO 时的数据包大小,包括采用轻量级的通信协议、合适的数据结构、去掉接口中的多余字段、减少缓存 key 的大小、压缩缓存 value 等。
13、程序逻辑优化,比如将大概率阻断执行流程的判断逻辑前置、For 循环的计算逻辑优化,或者采用更高效的算法。
14、各种池化技术的使用和池大小的设置,包括 HTTP 请求池、线程池(考虑 CPU 密集型还是 IO 密集型设置核心参数)、数据库和 Redis 连接池等。
15、JVM 优化,包括新生代和老年代的大小、GC 算法的选择等,尽可能减少 GC 频率和耗时。
16、锁选择,读多写少的场景用乐观锁,或者考虑通过分段锁的方式减少锁冲突。
高可用实践方案 1、对等节点的故障转移,Nginx 和服务治理框架均支持一个节点失败后访问另一个节点。
2、非对等节点的故障转移,通过心跳检测并实施主备切换(比如 redis 的哨兵模式或者集群模式、MySQL 的主从切换等)。
3、接口层面的超时设置、重试策略和幂等设计。
4、降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。
5、限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。
6、MQ 场景的消息可靠性保证,包括 producer 端的重试机制、broker 侧的持久化、consumer 端的 ack 机制等。
7、灰度发布,能支持按机器维度进行小流量部署,观察系统日志和业务指标,等运行平稳后再推全量。
8、监控报警:全方位的监控体系,包括最基础的 CPU、内存、磁盘、网络的监控,以及 Web 服务器、JVM、数据库、各类中间件的监控和业务指标的监控。
9、灾备演练:类似当前的“混沌工程”,对系统进行一些破坏性手段,观察局部故障是否会引起可用性问题。
高可用的方案主要从冗余、取舍、系统运维 3 个方向考虑,同时需要有配套的值班机制和故障处理流程,当出现线上问题时,可及时跟进处理。
高扩展的实践方案 1、合理的分层架构:比如上面谈到的互联网最常见的分层架构,另外还能进一步按照数据访问层、业务逻辑层对微服务做更细粒度的分层(但是需要评估性能,会存在网络多一跳的情况)。
2、存储层的拆分:按照业务维度做垂直拆分、按照数据特征维度进一步做水平拆分(分库分表)。
3、业务层的拆分:最常见的是按照业务维度拆(比如电商场景的商品服务、订单服务等),也可以按照核心接口和非核心接口拆,还可以按照请求去拆(比如 To C 和 To B,APP 和 H5)。


  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:38:48 | 显示全部楼层
对于一个支撑日活百万用户的高并系统,他的数据库架构应该如何设计?
看到这个题目,很多人第一反应就是:分库分表啊!但是实际上,数据库层面的分库分表到底是用来干什么的,他的不同的作用如何应对不同的场景,我觉得很多同学可能都没搞清楚。
用一个创业公司的发展作为背景引入
假如我们现在是一个小创业公司,注册用户就 20 万,每天活跃用户就 1 万,每天单表数据量就 1000,然后高峰期每秒钟并发请求最多就 10。
天哪!就这种系统,随便找一个有几年工作经验的高级工程师,然后带几个年轻工程师,随便干干都可以做出来。
因为这样的系统,实际上主要就是在前期快速的进行业务功能的开发,搞一个单块系统部署在一台服务器上,然后连接一个数据库就可以了。
接着大家就是不停的在一个工程里填充进去各种业务代码,尽快把公司的业务支撑起来。
如下图所示:
oroizgla1p.jpeg


结果呢,没想到我们运气这么好,碰上个优秀的 CEO 带着我们走上了康庄大道!
公司业务发展迅猛,过了几个月,注册用户数达到了 2000 万!每天活跃用户数 100 万!每天单表新增数据量达到 50 万条!高峰期每秒请求量达到 1 万!
同时公司还顺带着融资了两轮,估值达到了惊人的几亿美金!一只朝气蓬勃的幼年独角兽的节奏!
好吧,现在大家感觉压力已经有点大了,为啥呢?因为每天单表新增 50 万条数据,一个月就多 1500 万条数据,一年下来单表会达到上亿条数据。
经过一段时间的运行,现在咱们单表已经两三千万条数据了,勉强还能支撑着。
但是,眼见着系统访问数据库的性能怎么越来越差呢,单表数据量越来越大,拖垮了一些复杂查询 SQL 的性能啊!
然后高峰期请求现在是每秒 1 万,咱们的系统在线上部署了 20 台机器,平均每台机器每秒支撑 500 请求,这个还能抗住,没啥大问题。但是数据库层面呢?
如果说此时你还是一台数据库服务器在支撑每秒上万的请求,负责任的告诉你,每次高峰期会出现下述问题:
  • 你的数据库服务器的磁盘 IO、网络带宽、CPU 负载、内存消耗,都会达到非常高的情况,数据库所在服务器的整体负载会非常重,甚至都快不堪重负了。
  • 高峰期时,本来你单表数据量就很大,SQL 性能就不太好,这时加上你的数据库服务器负载太高导致性能下降,就会发现你的 SQL 性能更差了。
  • 最明显的一个感觉,就是你的系统在高峰期各个功能都运行的很慢,用户体验很差,点一个按钮可能要几十秒才出来结果。
  • 如果你运气不太好,数据库服务器的配置不是特别的高的话,弄不好你还会经历数据库宕机的情况,因为负载太高对数据库压力太大了。
多台服务器分库支撑高并发读写
首先我们先考虑第一个问题,数据库每秒上万的并发请求应该如何来支撑呢?
要搞清楚这个问题,先得明白一般数据库部署在什么配置的服务器上。通常来说,假如你用普通配置的服务器来部署数据库,那也起码是 16 核 32G 的机器配置。
这种非常普通的机器配置部署的数据库,一般线上的经验是:不要让其每秒请求支撑超过 2000,一般控制在 2000 左右。
控制在这个程度,一般数据库负载相对合理,不会带来太大的压力,没有太大的宕机风险。
所以首先第一步,就是在上万并发请求的场景下,部署个 5 台服务器,每台服务器上都部署一个数据库实例。
然后每个数据库实例里,都创建一个一样的库,比如说订单库。此时在 5 台服务器上都有一个订单库,名字可以类似为:db_order_01,db_order_02,等等。
然后每个订单库里,都有一个相同的表,比如说订单库里有订单信息表,那么此时 5 个订单库里都有一个订单信息表。
比如 db_order_01 库里就有一个 tb_order_01 表,db_order_02 库里就有一个 tb_order_02 表。
这就实现了一个基本的分库分表的思路,原来的一台数据库服务器变成了 5 台数据库服务器,原来的一个库变成了 5 个库,原来的一张表变成了 5 个表。
然后你在写入数据的时候,需要借助数据库中间件,比如 sharding-jdbc,或者是 mycat,都可以。
你可以根据比如订单 id 来 hash 后按 5 取模,比如每天订单表新增 50 万数据,此时其中 10 万条数据会落入 db_order_01 库的 tb_order_01 表,另外 10 万条数据会落入 db_order_02 库的 tb_order_02 表,以此类推。
这样就可以把数据均匀分散在 5 台服务器上了,查询的时候,也可以通过订单 id 来 hash 取模,去对应的服务器上的数据库里,从对应的表里查询那条数据出来即可。
依据这个思路画出的图如下所示,大家可以看看:
ya9omplsvh.jpeg


做这一步有什么好处呢?第一个好处,原来比如订单表就一张表,这个时候不就成了 5 张表了么,那么每个表的数据就变成 1/5 了。
假设订单表一年有 1 亿条数据,此时 5 张表里每张表一年就 2000 万数据了。
那么假设当前订单表里已经有 2000 万数据了,此时做了上述拆分,每个表里就只有 400 万数据了。
而且每天新增 50 万数据的话,那么每个表才新增 10 万数据,这样是不是初步缓解了单表数据量过大影响系统性能的问题?
另外就是每秒 1 万请求到 5 台数据库上,每台数据库就承载每秒 2000 的请求,是不是一下子把每台数据库服务器的并发请求降低到了安全范围内?
这样,降低了数据库的高峰期负载,同时还保证了高峰期的性能。
大量分表来保证海量数据下的查询性能
但是上述的数据库架构还有一个问题,那就是单表数据量还是过大,现在订单表才分为了 5 张表,那么如果订单一年有 1 亿条,每个表就有 2000 万条,这也还是太大了。
所以还应该继续分表,大量分表。比如可以把订单表一共拆分为 1024 张表,这样 1 亿数据量的话,分散到每个表里也就才 10 万量级的数据量,然后这上千张表分散在 5 台数据库里就可以了。
在写入数据的时候,需要做两次路由,先对订单 id hash 后对数据库的数量取模,可以路由到一台数据库上,然后再对那台数据库上的表数量取模,就可以路由到数据库上的一个表里了。
通过这个步骤,就可以让每个表里的数据量非常小,每年 1 亿数据增长,但是到每个表里才 10 万条数据增长,这个系统运行 10 年,每个表里可能才百万级的数据量。
这样可以一次性为系统未来的运行做好充足的准备,看下面的图,一起来感受一下:
mowrkgla5h.jpeg


全局唯一 id 如何生成
在分库分表之后你必然要面对的一个问题,就是 id 咋生成?因为要是一个表分成多个表之后,每个表的 id 都是从 1 开始累加自增长,那肯定不对啊。
举个例子,你的订单表拆分为了 1024 张订单表,每个表的 id 都从 1 开始累加,这个肯定有问题了!
你的系统就没办法根据表主键来查询订单了,比如 id = 50 这个订单,在每个表里都有!
所以此时就需要分布式架构下的全局唯一 id 生成的方案了,在分库分表之后,对于插入数据库中的核心 id,不能直接简单使用表自增 id,要全局生成唯一 id,然后插入各个表中,保证每个表内的某个 id,全局唯一。
比如说订单表虽然拆分为了 1024 张表,但是 id = 50 这个订单,只会存在于一个表里。
那么如何实现全局唯一 id 呢?有以下几种方案:
方案一:独立数据库自增 id
这个方案就是说你的系统每次要生成一个 id,都是往一个独立库的一个独立表里插入一条没什么业务含义的数据,然后获取一个数据库自增的一个 id。拿到这个 id 之后再往对应的分库分表里去写入。
比如说你有一个 auto_id 库,里面就一个表,叫做 auto_id 表,有一个 id 是自增长的。
那么你每次要获取一个全局唯一 id,直接往这个表里插入一条记录,获取一个全局唯一 id 即可,然后这个全局唯一 id 就可以插入订单的分库分表中。
这个方案的好处就是方便简单,谁都会用。缺点就是单库生成自增 id,要是高并发的话,就会有瓶颈的,因为 auto_id 库要是承载个每秒几万并发,肯定是不现实的了。
方案二:UUID
这个每个人都应该知道吧,就是用 UUID 生成一个全局唯一的 id。
好处就是每个系统本地生成,不要基于数据库来了。不好之处就是,UUID 太长了,作为主键性能太差了,不适合用于主键。
如果你是要随机生成个什么文件名了,编号之类的,你可以用 UUID,但是作为主键是不能用 UUID 的。
方案三:获取系统当前时间
这个方案的意思就是获取当前时间作为全局唯一的 id。但是问题是,并发很高的时候,比如一秒并发几千,会有重复的情况,这个肯定是不合适的。
一般如果用这个方案,是将当前时间跟很多其他的业务字段拼接起来,作为一个 id,如果业务上你觉得可以接受,那么也是可以的。
你可以将别的业务字段值跟当前时间拼接起来,组成一个全局唯一的编号,比如说订单编号:时间戳 + 用户 id + 业务含义编码。
方案四:SnowFlake 算法的思想分析
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。
这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
3yr1glb6c8.jpeg


给大家举个例子吧,比如下面那个 64 bit 的 long 型数字:
  • 第一个部分,是 1 个 bit:0,这个是无意义的。
  • 第二个部分是 41 个 bit:表示的是时间戳。
  • 第三个部分是 5 个 bit:表示的是机房 id,10001。
  • 第四个部分是 5 个 bit:表示的是机器 id,1 1001。
  • 第五个部分是 12 个 bit:表示的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,0000 00000000。
①1 bit:是不用的,为啥呢?
因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。
②41 bit:表示的是时间戳,单位是毫秒。
41 bit 可以表示的数字多达 2^41 - 1,也就是可以标识 2 ^ 41 - 1 个毫秒值,换算成年就是表示 69 年的时间。
③10 bit:记录工作机器 id,代表的是这个服务最多可以部署在 2^10 台机器上,也就是 1024 台机器。
但是 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2 ^ 5 个机房(32 个机房),每个机房里可以代表 2 ^ 5 个机器(32 台机器)。
④12 bit:这个是用来记录同一个毫秒内产生的不同 id。
12 bit 可以代表的最大正整数是 2 ^ 12 - 1 = 4096,也就是说可以用这个 12 bit 代表的数字来区分同一个毫秒内的 4096 个不同的 id。
简单来说,你的某个服务假设要生成一个全局唯一 id,那么就可以发送一个请求给部署了 SnowFlake 算法的系统,由这个 SnowFlake 算法系统来生成唯一 id。
这个 SnowFlake 算法系统首先肯定是知道自己所在的机房和机器的,比如机房 id = 17,机器 id = 12。
接着 SnowFlake 算法系统接收到这个请求之后,首先就会用二进制位运算的方式生成一个 64 bit 的 long 型 id,64 个 bit 中的第一个 bit 是无意义的。
接着 41 个 bit,就可以用当前时间戳(单位到毫秒),然后接着 5 个 bit 设置上这个机房 id,还有 5 个 bit 设置上机器 id。
最后再判断一下,当前这台机房的这台机器上这一毫秒内,这是第几个请求,给这次生成 id 的请求累加一个序号,作为最后的 12 个 bit。
最终一个 64 个 bit 的 id 就出来了,类似于:
3yr1glb6c8.jpeg


这个算法可以保证说,一个机房的一台机器上,在同一毫秒内,生成了一个唯一的 id。可能一个毫秒内会生成多个 id,但是有最后 12 个 bit 的序号来区分开来。
下面我们简单看看这个 SnowFlake 算法的一个代码实现,这就是个示例,大家如果理解了这个意思之后,以后可以自己尝试改造这个算法。
总之就是用一个 64 bit 的数字中各个 bit 位来设置不同的标志位,区分每一个 id。
因为大家可以考虑一下,我们在生成唯一 id 的时候,一般都需要指定一个表名,比如说订单表的唯一 id。
所以上面那 64 个 bit 中,代表机房的那 5 个 bit,可以使用业务表名称来替代,比如用 00001 代表的是订单表。
因为其实很多时候,机房并没有那么多,所以那 5 个 bit 用做机房 id 可能意义不是太大。
这样就可以做到,SnowFlake 算法系统的每一台机器,对一个业务表,在某一毫秒内,可以生成一个唯一的 id,一毫秒内生成很多 id,用最后 12 个 bit 来区分序号对待。
读写分离来支撑按需扩容以及性能提升
这个时候整体效果已经挺不错了,大量分表的策略保证可能未来 10 年,每个表的数据量都不会太大,这可以保证单表内的 SQL 执行效率和性能。
然后多台数据库的拆分方式,可以保证每台数据库服务器承载一部分的读写请求,降低每台服务器的负载。
但是此时还有一个问题,假如说每台数据库服务器承载每秒 2000 的请求,然后其中 400 请求是写入,1600 请求是查询。
也就是说,增删改的 SQL 才占到了 20% 的比例,80% 的请求是查询。此时假如说随着用户量越来越大,又变成每台服务器承载 4000 请求了。
那么其中 800 请求是写入,3200 请求是查询,如果说你按照目前的情况来扩容,就需要增加一台数据库服务器。
但是此时可能就会涉及到表的迁移,因为需要迁移一部分表到新的数据库服务器上去,是不是很麻烦?
其实完全没必要,数据库一般都支持读写分离,也就是做主从架构。
写入的时候写入主数据库服务器,查询的时候读取从数据库服务器,就可以让一个表的读写请求分开落地到不同的数据库上去执行。
这样的话,假如写入主库的请求是每秒 400,查询从库的请求是每秒 1600。
那么图大概如下所示:
keinuyhnm7.jpeg


写入主库的时候,会自动同步数据到从库上去,保证主库和从库数据一致。
然后查询的时候都是走从库去查询的,这就通过数据库的主从架构实现了读写分离的效果了。
现在的好处就是,假如说现在主库写请求增加到 800,这个无所谓,不需要扩容。然后从库的读请求增加到了 3200,需要扩容了。
这时,你直接给主库再挂载一个新的从库就可以了,两个从库,每个从库支撑 1600 的读请求,不需要因为读请求增长来扩容主库。
实际上线上生产你会发现,读请求的增长速度远远高于写请求,所以读写分离之后,大部分时候就是扩容从库支撑更高的读请求就可以了。
而且另外一点,对同一个表,如果你既写入数据(涉及加锁),还从该表查询数据,可能会牵扯到锁冲突等问题,无论是写性能还是读性能,都会有影响。
所以一旦读写分离之后,对主库的表就仅仅是写入,没任何查询会影响他,对从库的表就仅仅是查询。
高并发下的数据库架构设计总结
从大的一个简化的角度来说,高并发的场景下,数据库层面的架构肯定是需要经过精心的设计的。
尤其是涉及到分库来支撑高并发的请求,大量分表保证每个表的数据量别太大,读写分离实现主库和从库按需扩容以及性能保证。
这篇文章就是从一个大的角度来梳理了一下思路,各位同学可以结合自己公司的业务和项目来考虑自己的系统如何做分库分表。
另外就是,具体的分库分表落地的时候,需要借助数据库中间件来实现分库分表和读写分离,大家可以自己参考 Sharding-JDBC 或者 MyCAT 的官网即可,里面的文档都有详细的使用描述。
  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:54:25 | 显示全部楼层
对于一个拥有100万IP(Internet Protocol)的网站,需要一个强大的服务器配置来应对庞大的访问量和数据处理需求。以下是一个可能的服务器配置推荐:
    处理器(CPU):至少需要一颗高性能的多核心CPU。推荐选择英特尔(Intel)的至少16核心的Xeon系列或AMD的系列。
    内存(RAM):对于处理大量用户请求,推荐至少128GB的RAM。内存容量越大,可以缓存更多的数据,提高网站的响应速度。
    存储(Storage):对于大型网站来说,需要足够的存储空间来存储数据库、静态文件、日志等。推荐使用SSD(固态硬盘)作为主要存储设备,以提高数据读取和写入速度。
    网络带宽(Bandwidth):网络带宽的大小决定了网站可以同时处理的用户数量。对于100万IP的网站,需要至少10Gbps的带宽来保证流畅的访问体验。
    加载均衡(Load Balancing):为了分担服务器的负载,建议使用负载均衡技术,将访问请求均匀地分配到多台服务器上。这可以提高整体性能和可用性。
    高可用性(High Availability):为了确保网站的稳定运行,建议配置冗余的服务器、网络和存储设备,并使用故障转移和备份技术,以备份服务器故障或数据丢失。
    安全性(Security):对于一个拥有大量用户数据的网站来说,保护用户隐私和数据安全非常重要。配置防火墙、DDoS(分布式拒绝服务攻击)防护和安全审计等软件、硬件措施是必要的。
除了以上的硬件配置,还需要相应的软件配置和优化,如使用高效的Web服务器(如Nginx或Apache)、数据库服务器(如MySQL或PostgreSQL)、缓存服务器(如Redis或Memcached)等。
请注意,以上只是一个大致的服务器配置推荐,具体配置需根据网站的实际情况、访问量和预算来确定。同时,随着网站的发展和用户量的增加,还可能需要进一步升级服务器配置。
你的系统如何支撑高并发?
大多数同学被问到这个问题压根儿没什么思路去回答,不知道从什么地方说起,其实本质就是没经历过一些真正有高并发系统的锤炼罢了。
因为没有过相关的项目经历,所以就没法从真实的自身体会和经验中提炼出一套回答,然后系统的阐述出来自己复杂过的系统如何支撑高并发的。
所以,这篇文章就从这个角度切入来简单说说这个问题,用一个最简单的思路来回答,大致如何应对。
当然这里首先说清楚一个前提:高并发系统各不相同。比如每秒百万并发的中间件系统、每日百亿请求的网关系统、瞬时每秒几十万请求的秒杀大促系统。
他们在应对高并发的时候,因为系统各自自身特点的不同,所以应对架构都是不一样的。
另外,比如电商平台中的订单系统、商品系统、库存系统,在高并发场景下的架构设计也是不同的,因为背后的业务场景什么的都不一样。
所以,这篇文章主要是给大家提供一个回答这类问题的思路,不涉及任何复杂架构设计,让你不至于在面试中被问到这个问题时,跟面试官大眼瞪小眼。
具体要真能在面试的时候回答好这个问题,建议各位参考一下本文思路,然后对你自己手头负责的系统多去思考一下,最好做一些相关的架构实践。
(2)先考虑一个最简单的系统架构
假设刚刚开始你的系统就部署在一台机器上,背后就连接了一台数据库,数据库部署在一台服务器上。
我们甚至可以再现实点,给个例子,你的系统部署的机器是4核8G,数据库服务器是16核32G。
此时假设你的系统用户量总共就10万,用户量很少,日活用户按照不同系统的场景有区别,我们取一个较为客观的比例,10%吧,每天活跃的用户就1万。
按照28法则,每天高峰期算他4个小时,高峰期活跃的用户占比达到80%,就是8000人活跃在4小时内。
然后每个人对你的系统发起的请求,我们算他每天是20次吧。那么高峰期8000人发起的请求也才16万次,平均到4小时内的每秒(14400秒),每秒也就10次请求。
好吧!完全跟高并发搭不上边,对不对?
然后系统层面每秒是10次请求,对数据库的调用每次请求都会好几次数据库操作的,比如做做crud之类的。
那么我们取一个一次请求对应3次数据库请求吧,那这样的话,数据库层每秒也就30次请求,对不对?
按照这台数据库服务器的配置,支撑是绝对没问题的。
上述描述的系统,用一张图表示,就是下面这样:



(3)系统集群化部署
假设此时你的用户数开始快速增长,比如注册用户量增长了50倍,上升到了500万。
此时日活用户是50万,高峰期对系统每秒请求是500/s。然后对数据库的每秒请求数量是1500/s,这个时候会怎么样呢?
按照上述的机器配置来说,如果你的系统内处理的是较为复杂的一些业务逻辑,是那种重业务逻辑的系统的话,是比较耗费CPU的。
此时,4核8G的机器每秒请求达到500/s的时候,很可能你会发现你的机器CPU负载较高了。
然后数据库层面,以上述的配置而言,其实基本上1500/s的高峰请求压力的话,还算可以接受。
这个主要是要观察数据库所在机器的磁盘负载、网络负载、CPU负载、内存负载,按照我们的线上经验而言,那个配置的数据库在1500/s请求压力下是没问题的。
所以此时你需要做的一个事情,首先就是要支持你的系统集群化部署。
你可以在前面挂一个负载均衡层,把请求均匀打到系统层面,让系统可以用多台机器集群化支撑更高的并发压力。
比如说这里假设给系统增加部署一台机器,那么每台机器就只有250/s的请求了。
这样一来,两台机器的CPU负载都会明显降低,这个初步的“高并发”不就先cover住了吗?
要是连这个都不做,那单台机器负载越来越高的时候,极端情况下是可能出现机器上部署的系统无法有足够的资源响应请求了,然后出现请求卡死,甚至系统宕机之类的问题。
所以,简单小结,第一步要做的:
  • 添加负载均衡层,将请求均匀打到系统层。
  • 系统层采用集群化部署多台机器,扛住初步的并发压力。
此时的架构图变成下面的样子:



(4)数据库分库分表 + 读写分离
假设此时用户量继续增长,达到了1000万注册用户,然后每天日活用户是100万。
那么此时对系统层面的请求量会达到每秒1000/s,系统层面,你可以继续通过集群化的方式来扩容,反正前面的负载均衡层会均匀分散流量过去的。
但是,这时数据库层面接受的请求量会达到3000/s,这个就有点问题了。
此时数据库层面的并发请求翻了一倍,你一定会发现线上的数据库负载越来越高。
每次到了高峰期,磁盘IO、网络IO、内存消耗、CPU负载的压力都会很高,大家很担心数据库服务器能否抗住。
没错,一般来说,对那种普通配置的线上数据库,建议就是读写并发加起来,按照上述我们举例的那个配置,不要超过3000/s。
因为数据库压力过大,首先一个问题就是高峰期系统性能可能会降低,因为数据库负载过高对性能会有影响。
另外一个,压力过大把你的数据库给搞挂了怎么办?
所以此时你必须得对系统做分库分表 + 读写分离,也就是把一个库拆分为多个库,部署在多个数据库服务上,这是作为主库承载写入请求的。
然后每个主库都挂载至少一个从库,由从库来承载读请求。
此时假设对数据库层面的读写并发是3000/s,其中写并发占到了1000/s,读并发占到了2000/s。
那么一旦分库分表之后,采用两台数据库服务器上部署主库来支撑写请求,每台服务器承载的写并发就是500/s。每台主库挂载一个服务器部署从库,那么2个从库每个从库支撑的读并发就是1000/s。
简单总结,并发量继续增长时,我们就需要focus在数据库层面:分库分表、读写分离
此时的架构图如下所示:



(5)缓存集群引入
接着就好办了,如果你的注册用户量越来越大,此时你可以不停的加机器,比如说系统层面不停加机器,就可以承载更高的并发请求。
然后数据库层面如果写入并发越来越高,就扩容加数据库服务器,通过分库分表是可以支持扩容机器的,如果数据库层面的读并发越来越高,就扩容加更多的从库。
但是这里有一个很大的问题:数据库其实本身不是用来承载高并发请求的,所以通常来说,数据库单机每秒承载的并发就在几千的数量级,而且数据库使用的机器都是比较高配置,比较昂贵的机器,成本很高。
如果你就是简单的不停的加机器,其实是不对的。
所以在高并发架构里通常都有缓存这个环节,缓存系统的设计就是为了承载高并发而生。
所以单机承载的并发量都在每秒几万,甚至每秒数十万,对高并发的承载能力比数据库系统要高出一到两个数量级。
所以你完全可以根据系统的业务特性,对那种写少读多的请求,引入缓存集群。
具体来说,就是在写数据库的时候同时写一份数据到缓存集群里,然后用缓存集群来承载大部分的读请求。
这样的话,通过缓存集群,就可以用更少的机器资源承载更高的并发。
比如说上面那个图里,读请求目前是每秒2000/s,两个从库各自抗了1000/s读请求,但是其中可能每秒1800次的读请求都是可以直接读缓存里的不怎么变化的数据的。
那么此时你一旦引入缓存集群,就可以抗下来这1800/s读请求,落到数据库层面的读请求就200/s。
同样,给大家来一张架构图,一起来感受一下:


按照上述架构,他的好处是什么呢?
可能未来你的系统读请求每秒都几万次了,但是可能80%~90%都是通过缓存集群来读的,而缓存集群里的机器可能单机每秒都可以支撑几万读请求,所以耗费机器资源很少,可能就两三台机器就够了。
你要是换成是数据库来试一下,可能就要不停的加从库到10台、20台机器才能抗住每秒几万的读并发,那个成本是极高的。
好了,我们再来简单小结,承载高并发需要考虑的第三个点:
  • 不要盲目进行数据库扩容,数据库服务器成本昂贵,且本身就不是用来承载高并发的
  • 针对写少读多的请求,引入缓存集群,用缓存集群抗住大量的读请求
(6)引入消息中间件集群
接着再来看看数据库写这块的压力,其实是跟读类似的。
假如说你所有写请求全部都落地数据库的主库层,当然是没问题的,但是写压力要是越来越大了呢?
比如每秒要写几万条数据,此时难道也是不停的给主库加机器吗?
可以当然也可以,但是同理,你耗费的机器资源是很大的,这个就是数据库系统的特点所决定的。
相同的资源下,数据库系统太重太复杂,所以并发承载能力就在几千/s的量级,所以此时你需要引入别的一些技术。
比如说消息中间件技术,也就是MQ集群,他是非常好的做写请求异步化处理,实现削峰填谷的效果。
假如说,你现在每秒是1000/s次写请求,其中比如500次请求是必须请求过来立马写入数据库中的,但是另外500次写请求是可以允许异步化等待个几十秒,甚至几分钟后才落入数据库内的。那么此时你完全可以引入消息中间件集群,把允许异步化的每秒500次请求写入MQ,然后基于MQ做一个削峰填谷。比如就以平稳的100/s的速度消费出来然后落入数据库中即可,此时就会大幅度降低数据库的写入压力。
ps:关于MQ削峰填谷的概念,在讲消息中间件的文章中已详细阐述,如果大伙儿忘记了,可以回顾一下。

此时,架构图变成了下面这样:



大家看上面的架构图,首先消息中间件系统本身也是为高并发而生,所以通常单机都是支撑几万甚至十万级的并发请求的。
所以,他本身也跟缓存系统一样,可以用很少的资源支撑很高的并发请求,用他来支撑部分允许异步化的高并发写入是没问题的,比使用数据库直接支撑那部分高并发请求要减少很多的机器使用量。
而且经过消息中间件的削峰填谷之后,比如就用稳定的100/s的速度写数据库,那么数据库层面接收的写请求压力,不就成了500/s + 100/s  = 600/s了么?
大家看看,是不是发现减轻了数据库的压力?
到目前为止,通过下面的手段,我们已经可以让系统架构尽可能用最小的机器资源抗住了最大的请求压力,减轻了数据库的负担。
  • 系统集群化
  • 数据库层面的分库分表+读写分离
  • 针对读多写少的请求,引入缓存集群
  • 针对高写入的压力,引入消息中间件集群
初步来说,简单的一个高并发系统的阐述是说完了。

我觉得单单凭借几篇文章是绝对不可能真的让你完全回答好这个问题的,这里有很多原因在里面。
首先,高并发这个话题本身是非常复杂的,远远不是一些文章可以说的清楚的,他的本质就在于,真实的支撑复杂业务场景的高并发系统架构其实是非常复杂的。
比如说每秒百万并发的中间件系统、每日百亿请求的网关系统、瞬时每秒几十万请求的秒杀大促系统、支撑几亿用户的大规模高并发电商平台架构,等等。
为了支撑高并发请求,在系统架构的设计时,会结合具体的业务场景和特点,设计出各种复杂的架构,这需要大量底层技术支撑,需要精妙的架构和机制设计的能力。最终,各种复杂系统呈现出来的架构复杂度会远远超出大部分没接触过的同学的想象。如果大家想要看一下有一定发复杂度的系统的架构设计和演进过程,可以看一下之前写的一个系列专栏《亿级流量系统架构演进》。
但是那么复杂的系统架构,通过一些文章是很难说的清楚里面的各种细节以及落地生产的过程的。
其次,高并发这话题本身包含的内容也远远不止本文说的这么几个topic:分库分表、缓存、消息。
一个完整而复杂的高并发系统架构中,一定会包含各种复杂的自研基础架构系统、各种精妙的架构设计(比如热点缓存架构设计、多优先级高吞吐MQ架构设计、系统全链路并发性能优化设计,等等)、还有各种复杂系统组合而成的高并发架构整体技术方案、还有NoSQL(Elasticsearch等)/负载均衡/Web服务器等相关技术。
所以大家切记要对技术保持敬畏之心,这些东西都很难通过一些文章来表述清楚。
最后,真正在生产落地的时候,高并发场景下你的系统会出现大量的技术问题。
比如说消息中间件吞吐量上不去需要优化、磁盘写压力过大性能太差、内存消耗过大容易撑爆、分库分表中间件不知道为什么丢了数据,等等吧。
诸如此类的问题非常多,这些也不可能通过文章给全部说清楚。
当然,也是因为毕竟没真的做过高并发系统,没相关经验,确实很难理解好这个问题。
所以本文就是让很多没接触过的同学有一个初步的感知,这个高并发到底是怎么回事儿,到底对系统哪里有压力,要在系统架构里引入什么东西,才可以比较好的支撑住较高的并发压力。
而且你可以顺着本文的思路继续思考下去,结合你自己熟悉和知道的一些技术继续思考。
比如说,你熟悉Elasticsearch技术,那么你就可以思考,唉?在高并发的架构之下,是不是可以通过分布式架构的ES技术支撑高并发的搜索?
上面所说,权当抛砖引玉。大家自己平时一定要多思考,自己多画图,盘点盘点自己手头系统的请求压力。计算一下分散到各个中间件层面的请求压力,到底应该如何利用最少的机器资源最好的支撑更高的并发请求。
这才是一个好的高并发架构设计思路。
剩下的,还是建议各位同学结合自己手头负责的系统多做思考。
比如当前业务场景下,你的系统有多大的请求压力?如果请求压力增长10倍你的架构如何支撑?如果请求压力增长100倍,你的架构如何支撑?如果请求压力增长1000倍,你的架构如何支撑?
平时一定多给自己设置一些技术挑战,敦促自己去思考自己的系统,最好多做写架构上的演练、落地和实践,自己实际操作一下,才有更好的感知。
然后在面试的时候,起码自己做过一定深度的思考,结合自己负责的系统做过一些实践,可以跟面试官有一个较为清晰和系统的阐述。





  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-10 23:58:12 | 显示全部楼层
阿里双 11 高并发系统架构设计核心技术全解开源给大家,希望对大家有所帮助~阿里双 11 高并发系统架构设计核心技术全解
  • 基础知识

2ad79f59722e3a2f14e0c912ddf05715.png


f4465fffd6dd9338a6a28caf4960b647.png


  • 数据库

617146b1c16d01e340012423d0b22499.png


d606fd22b4f0d17255bd8e301d18e6d5.png


  • 缓存

785e04f8e37c0185d5182a5093cb965d.png


e3bfb8edbddbb0d402d8b2c5409df390.png


  • 消息队列

d2d6398c9eb294f3d6b81e7b47f51539.png


22f83cd2c46c7b15504101b41e78506f.png


  • 分布式服务

da723c4a71902ec95f9d01713599c6d6.png


d2ce6c914aa5b2435e49b5b9751f2c7f.png


  • 维护篇

aaf9083dd6bdd3da9e4d538c10e39eb0.png


091a8b4379325fd0b7453c78c6012a58.png


  • 实战

ea0884dab9be86a368d0fa80bd040a93.png


db218fa8f579f85484904eaf35f00c08.png


其他相关资料分享
亿级流量网站系统架构设计全解
  • 互联网三高核心解决方案汇总

e879aee38f9352d8064bc7d6280b583b.png


7b2d66c2e3f09587ba44d10df907e924.png


秒杀系统架构设计揭秘
  • 秒杀业务场景与微服务架构解析

5d6fc15c1259819f7444fcf8a42f86ab.png


d47cc7a2fc9023cd8f3a8093ac40ab4d.png


最后
今天与高并发系统设计相关的文档笔记一共分享了三份,篇幅限制就不继续截图拉长篇幅了,感兴趣的小伙伴 +v:bjmsb0606006 即可~

  • 打卡等级:热心大叔
  • 打卡总天数:245
  • 打卡月天数:2
  • 打卡总奖励:7719
  • 最近打卡:2025-12-05 20:56:49

350

主题

557

回帖

1万

积分

管理员

积分
10407
 楼主| 发表于 2024-12-11 00:00:53 | 显示全部楼层
每到节假日期间, 一二线城市返乡、外出游玩的人们几乎都面临着一个问题:抢火车票! 虽然现在大多数情况下都能订到票, 但是放票瞬间即无票的场景,相信大家都深有体会。尤其是春节期间,大家不仅使用 12306,还会考虑 “智行” 和其他的抢票软件, 全国上下几亿人在这段时间都在抢票。“12306 服务”承受着这个世界上任何秒杀系统都无法超越的 QPS, 上百万的并发再正常不过了!笔者专门研究了一下 “12306” 的服务端架构, 学习到了其系统设计上很多亮点,在这里和大家分享一下并模拟一个例子:如何在 100 万人同时抢 1 万张火车票时,系统提供正常、稳定的服务。
  github 源码地址:
  https://github.com/GuoZhaoran/spikeSystem
  1、大型高并发系统架构  高并发的系统架构都会采用分布式集群部署,服务上层有着层层负载均衡,并提供各种容灾手段 (双火机房、节点容错、服务器灾备等) 保证系统的高可用, 流量也会根据不同的负载能力和配置策略均衡到不同的服务器上。下边是一个简单的示意图:
   c9a0f58dce7b2201087a1438f7b7fb59.png
  1.1 负载均衡简介  上图中描述了用户请求到服务器经历了三层的负载均衡,下边分别简单介绍一下这三种负载均衡:
  1、OSPF(开放式最短链路优先) 是一个内部网关协议 (Interior Gateway Protocol, 简称 IGP)。OSPF 通过路由器之间通告网络接口的状态来建立链路状态数据库,生成最短路径树,OSPF 会自动计算路由接口上的 Cost 值,但也可以通过手工指定该接口的 Cost 值,手工指定的优先于自动计算的值。OSPF 计算的 Cost,同样是和接口带宽成反比,带宽越高,Cost 值越小。到达目标相同 Cost 值的路径,可以执行负载均衡,最多 6 条链路同时执行负载均衡。
LVS (Linux VirtualServer),它是一种集群 (Cluster) 技术,采用 IP 负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。  3、Nginx 想必大家都很熟悉了, 是一款非常高性能的 http 代理 / 反向代理服务器, 服务开发中也经常使用它来做负载均衡。Nginx 实现负载均衡的方式主要有三种: 轮询、加权轮询、ip hash 轮询,下面我们就针对 Nginx 的加权轮询做专门的配置和测试
  1.2 Nginx 加权轮询的演示  Nginx 实现负载均衡通过 upstream 模块实现,其中加权轮询的配置是可以给相关的服务加上一个权重值,配置的时候可能根据服务器的性能、负载能力设置相应的负载。下面是一个加权轮询负载的配置,我将在本地的监听 3001-3004 端口, 分别配置 1,2,3,4 的权重:
  1. #配置负载均衡
  2.     upstream load_rule {
  3.        server 127.0.0.1:3001 weight=1;
  4.        server 127.0.0.1:3002 weight=2;
  5.        server 127.0.0.1:3003 weight=3;
  6.        server 127.0.0.1:3004 weight=4;
  7. }
  8. ...
  9.     server {
  10.     listen       80;
  11.     server_name  load_balance.com www.load_balance.com;
  12.     location / {
  13.        proxy_pass http://load_rule;
  14. }
复制代码

2、秒杀抢购系统选型  回到我们最初提到的问题中来:火车票秒杀系统如何在高并发情况下提供正常、稳定的服务呢?
  从上面的介绍我们知道用户秒杀流量通过层层的负载均衡,均匀到了不同的服务器上,即使如此,集群中的单机所承受的 QPS 也是非常高的。如何将单机性能优化到极致呢?要解决这个问题,我们就要想明白一件事:通常订票系统要处理生成订单、减扣库存、用户支付这三个基本的阶段,我们系统要做的事情是要保证火车票订单不超卖、不少卖,每张售卖的车票都必须支付才有效,还要保证系统承受极高的并发。这三个阶段的先后顺序改怎么分配才更加合理呢? 我们来分析一下:
  2.1 下单减库存
当用户并发请求到达服务端时,首先创建订单,然后扣除库存,等待用户支付。这种顺序是我们一般人首先会想到的解决方案,这种情况下也能保证订单不会超卖,因为创建订单之后就会减库存,这是一个原子操作。但是这样也会产生一些问题,第一就是在极限并发情况下,任何一个内存操作的细节都至关影响性能,尤其像创建订单这种逻辑,一般都需要存储到磁盘数据库的,对数据库的压力是可想而知的;第二是如果用户存在恶意下单的情况,只下单不支付这样库存就会变少,会少卖很多订单,虽然服务端可以限制 IP 和用户的购买订单数量,这也不算是一个好方法。
   99589d28fe965c04974c300f93f8a376.png
  2.2 支付减库存

  如果等待用户支付了订单在减库存,第一感觉就是不会少卖。但是这是并发架构的大忌,因为在极限并发情况下,用户可能会创建很多订单,当库存减为零的时候很多用户发现抢到的订单支付不了了,这也就是所谓的 “超卖”。也不能避免并发操作数据库磁盘 IO
   0f958cfafa5b07f1a10ee1d5951799ce.png
  2.3 预扣库存
从上边两种方案的考虑,我们可以得出结论:只要创建订单,就要频繁操作数据库 IO。那么有没有一种不需要直接操作数据库 IO 的方案呢,这就是预扣库存。先扣除了库存,保证不超卖,然后异步生成用户订单,这样响应给用户的速度就会快很多;那么怎么保证不少卖呢?用户拿到了订单,不支付怎么办?我们都知道现在订单都有有效期,比如说用户五分钟内不支付,订单就失效了,订单一旦失效,就会加入新的库存,这也是现在很多网上零售企业保证商品不少卖采用的方案。订单的生成是异步的, 一般都会放到 MQ、kafka 这样的即时消费队列中处理, 订单量比较少的情况下,生成订单非常快,用户几乎不用排队。
   d2a4ba50dc35892764a38c0ee79bc513.png
  3、扣库存的艺术  从上面的分析可知,显然预扣库存的方案最合理。我们进一步分析扣库存的细节,这里还有很大的优化空间,库存存在哪里?怎样保证高并发下,正确的扣库存,还能快速的响应用户请求?
  在单机低并发情况下,我们实现扣库存通常是这样的:
   d7c27735dc152eb3aafdd83ff3d2612c.png
  为了保证扣库存和生成订单的原子性,需要采用事务处理,然后取库存判断、减库存,最后提交事务,整个流程有很多 IO,对数据库的操作又是阻塞的。这种方式根本不适合高并发的秒杀系统。
  接下来我们对单机扣库存的方案做优化:本地扣库存。我们把一定的库存量分配到本地机器,直接在内存中减库存,然后按照之前的逻辑异步创建订单。改进过之后的单机系统是这样的:
   106f8ce9f449b43262cc98487943390d.png
  这样就避免了对数据库频繁的 IO 操作,只在内存中做运算,极大的提高了单机抗并发的能力。但是百万的用户请求量单机是无论如何也抗不住的,虽然 nginx 处理网络请求使用 epoll 模型,c10k 的问题在业界早已得到了解决。但是 linux 系统下,一切资源皆文件,网络请求也是这样,大量的文件描述符会使操作系统瞬间失去响应。上面我们提到了 nginx 的加权均衡策略,我们不妨假设将 100W 的用户请求量平均均衡到 100 台服务器上,这样单机所承受的并发量就小了很多。然后我们每台机器本地库存 100 张火车票,100 台服务器上的总库存还是 1 万,这样保证了库存订单不超卖, 下面是我们描述的集群架构:
   8927f18d69c097f0f28033e7f8262489.png
  问题接踵而至,在高并发情况下,现在我们还无法保证系统的高可用,假如这 100 台服务器上有两三台机器因为扛不住并发的流量或者其他的原因宕机了。那么这些服务器上的订单就卖不出去了,这就造成了订单的少卖。要解决这个问题,我们需要对总订单量做统一的管理,这就是接下来的容错方案。服务器不仅要在本地减库存,另外要远程统一减库存。有了远程统一减库存的操作,我们就可以根据机器负载情况,为每台机器分配一些多余的 “buffer 库存” 用来防止机器中有机器宕机的情况。我们结合下面架构图具体分析一下:
   da20f7ce9ea5bab3829da0b310a34e3d.png
  我们采用 Redis 存储统一库存,因为 Redis 的性能非常高,号称单机 QPS 能抗 10W 的并发。在本地减库存以后,如果本地有订单,我们再去请求 redis 远程减库存,本地减库存和远程减库存都成功了,才返回给用户抢票成功的提示, 这样也能有效的保证订单不会超卖。当机器中有机器宕机时,因为每个机器上有预留的 buffer 余票,所以宕机机器上的余票依然能够在其他机器上得到弥补,保证了不少卖。buffer 余票设置多少合适呢,理论上 buffer 设置的越多,系统容忍宕机的机器数量就越多,但是 buffer 设置的太大也会对 redis 造成一定的影响。虽然 redis 内存数据库抗并发能力非常高,请求依然会走一次网络 IO, 其实抢票过程中对 redis 的请求次数是本地库存和 buffer 库存的总量,因为当本地库存不足时,系统直接返回用户 “已售罄” 的信息提示,就不会再走统一扣库存的逻辑,这在一定程度上也避免了巨大的网络请求量把 redis 压跨,所以 buffer 值设置多少,需要架构师对系统的负载能力做认真的考量。



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Discuz! X

GMT+8, 2025-12-7 08:45 , Processed in 0.043924 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表