高并发问题的通用设计方法

        “⾼并发”是后端领域的技术圣杯,是⼀种可遇⽽不可求的特殊业务需求。 对于每⼀名后端⼯程师来说,实现⾼并发的系统都是⼀项颇具挑战性的任务。为了应对这⼀挑战,你需要对 ⽹络、缓存、并发、并⾏、分布式计算以及数据库优化等技术有深⼊的理解和实际经验。在这个领域,没有 虚假的掩饰,只有真实的实⼒。

1.1 概述

        我们都知道,互联⽹服务的核⼼价值在于流量,流量越⼤,平台的盈利机会和发展空间就越⼤,这也是为何 ⼤⼚总是倾向于招聘拥有⾼并发经验的研发⼈员。2007 年,中国电⼦商务总和交易额突破⼀万亿⼈民币, ⽹民数量快速增加,中国互联⽹正式进⼊了⾼并发时代。之后,⼤⼚与创业公司之间的技术壁垒不断加强。如今,掌握⾼并发技术已成为⼤⼚技术⼈员的基本要求。

        当然,⼤⼚可以为我们提供⾼并发系统架构设计的实践机会。然⽽,如果你没有相关的架构设计经验,⼤⼚ 的⼤门⼜怎会向你敞开呢?这就形成了⼀个逻辑悖论。

        难道我们只能⼀直陷在这个困境中吗?实际上,我们⾃⼰也是这些⾼并发应⽤的⽤户,例如使⽤微信、使⽤ 搜索引擎、刷微博、刷短视频。我们只需要将⾃⼰从⽤户⾓⾊转换为设计者的⾓⾊,想象⾃⼰成为这些⼤⼚ 的架构师,设⾝处地思考:如果我来设计这个系统,我该怎么做。

         尽管我们都知道⾼并发的重要性,并学习了许多⾼并发系统设计的技术资料,但仍然会感到困惑:为什么我 们仍然缺乏对设计⼀个完整的⾼并发系统的了解?

        这是因为你缺乏真实业务场景中的架构设计经验。没有亲⾃接触过真实的业务需求,就⽆法感受到⾯对压⼒ 、迎接挑战以及完成任务后的喜悦和轻松。只有通过真实的现场感受,我们学到的各种技术才能真正融会贯 通,⽽不只是⼀堆零碎知识的杂乱集合。就像那句著名的“我听过很多道理,却仍然过不好这⼀⽣”。归根 结底,还是缺乏实践。

         你可以“化⾝”为那个真的需要解决⾼并发问题的⼈,借助一些真实⾼并发处理经验,⾝临其境地站在架构师的⾓度,深⼊理解⾼并发系统设计的哲学原理。

找出单点,进行拆分

开门见⼭,先说结论,⾼并发的哲学原理就是——找出单点,进⾏拆分。要将每⼀个“⼤单点”都拆成“⼀ 个⼩单点 + 多个资源并⾏”的形式。

“单点”的定义

       单点指的是⼀个 Web 系统中,⼏乎所有流量都必须经过的特定部分,如果它出现瓶颈或故障,将导致整个 系统的性能下降或不可⽤。单点是⼀个逻辑概念,在系统架构层⾯它可能指代各种不同层⾯的软件、硬件实 体。在传统的单体式应⽤中,可以说遍地都是单点。

        在解决⾼并发问题的过程中,我们会不断地遇到各种单点:Web Server、单个操作系统、虚拟化/容器技术 、编程语⾔运⾏架构、⽹络、Unix 进程模型、数据库等。每遇到⼀个单点,我们都要见招拆招,使⽤架构⼯ 具拆掉它。计算机的虚拟化程度⾮常⾼,理论上每个单点都是可以继续往下拆分的。

1.2 设定目标:每秒一百万次 HTTPS 请求

是⾼并发原理与实战,那就要先设定⼀个⾼并发的⽬标:每秒⼀百万次 HTTPS 请求,即 1, 000,000 QPS(Queries Per Second)。某些场景中,也称为:1,000,000 TPS(Transactions Per Se cond)。

性能问题要靠架构解决在正式展开之前,我们需要明确⾼并发问题的基本解决思路:系统的性能问题需要通过架构设计来解决。

⾯对⾼并发技术需求时,在架构上进⾏优化是最为简单、对系统稳定性影响最低且最容易获得收益的⽅法。 即便在我们专注于单个资源的性能优化时,例如 MySQL 单机性能优化(软件优化)或 x86 CPU 多核性能 提升(硬件优化),从微观⾓度来看,这些优化措施实际上也是在进⾏架构优化——通过调整软件或硬件的 运⾏架构,提升总体性能。

“没有银弹”是计算机世界的第⼀准则,你想获得性能收益,就⼀定要拿出⼀些东西,和“信息之神”交换。架构优化的本质就是拿其它资源或者指标来交换性能,系统总体性能的提升必然需要伴随着某种资源的更多消耗或者某个⾮关键指标的劣化,像我们常说的“时间换空间”“空间换时间”都是这个道理的实际体现。

我们讨论哪个高并发?

“Web 服务⾼并发”问题,典型场景为电商秒杀:同⼀个时刻,数万⼈抢同⼀个低价商品,会 给系统的每⼀个层⾯都造成显著的性能瓶颈,每年的双 11 ⼤促就是这⼀场景的极致体现。

接下来,请⼤家跟着笔者⼀起,沿着 计算高并发 -> 网络高并发 -> 数据库(存储)高并发 的道路⼀步⼀步将系统性 能的上限从单机 100 QPS 提升到 1,000,000(⼀百万)QPS。

1.3 动态、静态资源分开部署

动静分离是⾼并发架构设计的第⼀步,部分场景下还是收益最⼤的那⼀步,因为我们可以把 99% 的流量压 ⼒都转移出去。

一个 Nginx 软件竟然还能减少 CPU 和内存占用?

如果你的应⽤现在还在⽤ Apache 承载全部流量,那只需要在前⾯加⼀个 Nginx,承载静态资源的分发,动态请求可以原封不动地使⽤ http 协议发送给 Apache,只需要这样⼀个⼩操作,便可以在服务器配置不变的情况下把系统容量提升⼀倍以上。此时的系统架构图如图 1-1 所⽰。

此外,由于 Nginx 针对新图⽚格式(如 .webp)和视频流式传输等进⾏了专门的优化,在增加了⼀个软件后 ,服务器的 CPU 和内存资源消耗反⽽会明显下降。在如今流量越来越便宜的时代,静态资源的体积和流量 呈指数级增长,Nginx 的性能优势还在持续扩⼤。

使用云服务 如果你在⽤云服务的话,那么把静态资源全部交给云服务商的 CDN 来承载,还可以再获得 90% 的 CPU 节 省。同时,CDN 的流量费还⽐云主机的流量费更便宜,时⾄今⽇中国 CDN 市场已经卷的不像样⼦了。此时 的系统架构图如图 1-2 所⽰。

 

1.4 数据库独立部署 

在使⽤ Nginx 承载全部静态资源以后,如果你的低配云主机还是扛不住流量,该怎么办呢?这个时候就需要 引⼊第⼆台云主机了:专门⽤来跑数据库。

将后端代码和数据库部署在同一台机器上是“灾难架构”

出于节省成本的需要,把后端代码和数据库部署在同⼀台机器上确实是⼀个⽆奈的选择。但是,我们要清楚 的是,这是⼀种错误的架构设计⽅案,它只适合超低流量的系统。

⼀旦系统承受的压⼒稍⼤,便会⾯临“债股双杀”的局⾯:

  • CPU 被耗尽导致 MySQL 响应变慢;
  •  应⽤代码需更长时间等待,虽不额外消耗 CPU 资源,却占⽤⼤量内存;
  • 系统内存被占⽤导致 InnoDB 缓存被系统回收,进⼀步降低了 MySQL 的运⾏速度;
  • 最终形成“内卷”和“踩踏”,系统性能急剧下降,服务可能完全崩溃。

MySQL 单独部署时性能非常出色

只要你将 MySQL 与后端代码的 CPU 进⾏隔离,数据库的极限性能就能达到够⽤的⽔平。根据笔者的实测 结果,即使是⼀台1 核 2G 的 MySQL 服务器,也能够达到 200QPS(Query Per Second,每秒执⾏的 S QL 语句数) 的每秒执⾏ SQL 语句数,⾜以⽀撑⼀个每天⼀百万 PV 的⼩⽹站。

MySQL 单独部署架构图 应⽤服务器和 MySQL 数据库服务器分为两台机器部署时,系统架构图如图 1-3 所⽰。

运维哲学初探 

在这个⼩⼩的例⼦中,我们已经在不经意间窥探到了过去数⼗年运维技术圈的基本哲学:从物理机到虚拟机 ,从虚拟主机到云主机,再从云主机到 Kubernetes,虽然推动运维架构演进的是越来越复杂的软件架构和 越来越多的计算资源需求,但是运维的基本哲学是不变的:

运维的核⼼价值不在于资源的扩充,⽽在于资源的隔离。

1.5 真实业务经历:CMS 网站 

⼀个⾯向 SEO 的 CMS(内容管理系统)⽹站,该⽹站每⽇ PV 达到两百万。 这类⽹站往往有很多的“相关内容”需求,需要进⾏类似于搜索引擎的“相关查询”,导致页⾯相应⼗分缓 慢。由于内容的独特性,经常受到爬⾍和采集机器⼈的关注,导致频繁被爬取,给运维⼯作带来了很⼤压⼒.

随着⽹站内容的逐渐丰富,除了被正规蜘蛛访问外,某⼀天还突然遭遇了每秒 100 次 HTTP 请求的采集机 器⼈袭击,当时的配置是可怜的 1 核 2G 云主机和 1 核 1G 的 MySQL 数据库,⽹站瞬间就宕机了。后来 ,在⽹站恢复以后,测试了⼀下,由于页⾯的复杂度⾮常⾼,当 QPS 达到 7 以后,数据库就会满载, 随后云主机也会满载,⽹站就挂了。

那么,是如何解决这个问题的呢?

动静分离 ⾸先,实施了动静分离的策略。将静态资源全部使⽤ CDN 进⾏分发,由于 CDN 节点具备强缓存的特 点,只需⽂件名不变,即可维持长时间的缓存效果。这⼀举措显著降低了静态资源对服务器的负载,使系统的总 CPU 消耗下降了 80%。

利用 Elasticsearch 提升网页响应速度

当时,这个⽹站使⽤关键词 like 的⽅法来实现“类似⽂章推荐”功能。具体来说,我们预设了⼀个关键词库 ,然后根据页⾯上的⽂章标题和内容进⾏匹配,匹配到的第⼀个关键词就会被⽤于各个表中的 SQL 查询语句 ,以获取相关内容。然⽽,这种⽅法在数据量庞⼤的情况下会出现显著的性能问题。

为了解决这个问题,笔者采购了⼀台 8 核 32GB 的云主机,并在其上安装了⼀个单节点的 Elasticsearch。 通过将搜索任务交由 Elasticsearch 处理,不仅成功降低了单页⾯的响应时间,从 300-500ms 降⾄约 20 0ms 左右,同时推荐内容的精准性也得到了显著提升。

MySQL 索引优化

在绝⼤多数情况下,为关系型数据库添加索引都是⾸选的性能优化策略。这种⽅法通常可以带来数⼗倍到数 万倍的性能提升,尽管需要增加明显的磁盘消耗和略微的内存消耗作为代价。 例如,为⼀张主要的⼤表增加了⼀些简单的单字段索引,结果页⾯的响应时间就从 200ms 降低到了⼤ 约 150ms,效果显著。

利用 Redis 缓存

在页⾯展⽰的过程中,有很多很难被优化的⾼耗时操作,是⽆法利⽤索引来做性能优化的,例如⼤表 的 select count(*)。于是,本着“解决不了问题就解决提问题的⼈”的思想,将⼤表的总数统计⼯作 利⽤后台定时任务来承载,强制压制了业务需求:每个页⾯⽆法实时地获取⽂章总数了,只能获取到⼀分钟 之前的数据。

每分钟,笔者会统计⼀次那⼏个内容表的总数,存⼊ Redis,⽽页⾯如果需要使⽤,直接读 Redis 中的数字 即可。经过这⼀步的优化,笔者把页⾯的响应时间从 150ms 降低到了 120ms。

网络请求并行化

由于每个页⾯都会获取多个其他表的“类似⽂章推荐”,所以每个页⾯对 Elasticsearch 的 HTTP 请求都有多个,⽽ PHP 默认是⼀个⼀个阻塞运⾏的:上⼀个不回来,PHP 进程就等待。笔者将这个阻塞操作并⾏化 了:虽然 PHP 是⼀种阻塞语⾔,但是⼀次性发送多个 HTTP 请求的能⼒还是有的,等到所有请求都返回了 数据之后,再继续阻塞地运⾏ PHP 代码。

这个系统平均每个页⾯请求了五次 Elasticsearch,每次 15ms。并⾏化之前,这五个请求总共需要消耗 75 ms。并⾏化之后,总时间从 75ms 减少到了 25ms。

经过上述的优化措施,将单个页⾯的平均响应时间压缩到了 70ms,这个数字和之前的 300~500ms ⽐ 是⼀个飞跃,在同样后端计算资源的情况下,系统容量提升了五倍左右,我们 1 核 2G 的⼩云主机也能顶住 100 QPS 的压⼒了。

为什么不做静态化?

这个时候可能有⼈会问了,既然是内容⽹站,为什么不静态化呢?因为数据量太⼤了,500 万个页⾯,⼀个 页⾯ 100KB,就是 476GB 的磁盘容量,这个量级太⼤了。

在这个规模下,和缓慢但可⽤的数据库相⽐,这么多静态资源的管理和刷新反⽽是个更⼤的问题,不如选择 做数据库和架构优化,问题会更少。在百万量级下,数据库绝对是更好的数据存储解决⽅案,远⽐⾃⼰管理 ⽂件要更简单更稳定。如果我们从头观察数据库的发展史,就会发现数据库就是为了处理单靠读写⼀堆磁盘⽂件已经⽆法满⾜需求的场景⽽被发明出来的。

反爬措施

做了那么多,还是不乏有⼀些爬⾍愣头青在学习了 Swoole 和 Go 协程之后,对⽹站发动数 千 QPS 的死亡冲锋,这个时候再怎么性能优化都是没⽤的,需要掏出倒数第⼆个⼯具:限流。

者做了三道限流关卡才最终顶住采集机器⼈的 DOS:

1. 针对单个 ip 做请求频率限制

2. 针对整个 “123.123.123.123/24” ip 段做请求频率限制(很多爬⾍采⽤同⼀段内的多个 ip 绕过限流 )

3. 针对每个 UA 做请求频率限制

对了,既然限流是倒数第⼆个⼯具,肯定有⼈好奇最后⼀个⼯具是什么?那就是熔断,熔断属于系统鲁棒性⼯具,是善后⽤的。

1.6 高并发实战:虚拟电商平台“静山”

静⼭是我国境内最矮的⼭,它仅仅⾼出地⾯ 0.6 ⽶,如图 1-4 所⽰,但却是⼀座货真价实的⼭,⽤来给我们 的虚拟电商平台命名正合适。

假设我们拥有⼀个电商平台,名为静⼭,它以 APP 的形式对外服务,没有 Web 端,官⽹域名为 js.com。 静⼭平台的初始架构如图 1-5 所⽰。

静态资源云服务化

作为⼀个 2023 年的电商平台,静态资源必须全部云服务化,这已经是最新的业界技术标准了。为了实现云 服务化,可以采取以下步骤:

  • 存储层:使⽤对象存储服务(如阿⾥云 OSS 和亚马逊 S3)来存储静态资源。
  • 前端接⼊层:通过 CDN(内容分发⽹络)域名直接对接对象存储服务,实现静态资源的⽆缝访问和负载 均衡。CDN 将静态资源副本分布在全国各个节点,让每个地⽅的⽤户都能⽤最快的速度访问静态资源。
  • 减轻后端压⼒:将静态资源独⽴出后端系统,减轻后端系统的负担,提⾼系统的性能和可伸缩性。后端系 统可专注于业务逻辑处理,⽽⽆需关⼼静态资源的管理和访问。 

GraphQL 协议 

GraphQL 是最佳的客户端数据交互协议,它能在很⼤程度上避免后端⼯程师的低 级错误。笔者⼗分推荐⼤家尝试这个新技术。

GraphQL 是最佳的客户端数据交互协议

GraphQL 是⼀种⽤于客户端与服务器之间进⾏数据交互的协议,它是⼀种灵活且⾼效的数据传递⽅式。相⽐ 于传统的 RESTful API,GraphQL 具有更好的可扩展性和性能优势。使⽤ GraphQL,前端可以直接请求所 需的数据,⽽⽆需经过繁琐的中间件或模板引擎处理。这种直接的数据获取⽅式可以减少⽹络传输的数据量 ,提⾼应⽤的性能。

避免后端工程师的低级错误

通过使⽤ GraphQL,后端⼯程师可以将更多的注意⼒集中在业务逻辑上,⽽不是处理底层的数据请求细节。 GraphQL 提供了⼀种类型安全的⽅式来定义数据模型和查询,减少了潜在的数据⼀致性问题和错误。这使得 后端⼯程师可以更加专注于编写⾼质量的代码,减少低级错误的发⽣。

GraphQL 可以被看作是一种编程语言的“Java 化”

从软件⼯程的⾓度来看,GraphQL 可以被看作是⼀种编程语⾔的“Java 化”。Java 是⼀种⼴泛使⽤的编 程语⾔,以其严谨的语法规则和强⼤的⽣态系统⽽闻名。类似地,GraphQL 通过增加繁复⽽严密的规范,使 得编程语⾔可以更加健壮和可靠。这有助于提⾼软件的整体质量,并减少了由于低级错误⽽导致的问题。

可以只依靠架构师的个人能力来保证软件质量

通过引⼊ GraphQL,相当于给灵活的编程语⾔(如 PHP、Go)引⼊了规范的严格,软件的质量可以得到保 证。通过使⽤这些规范严格的语⾔和框架,架构师可以更好地管理和控制整个软件开发过程,从⽽保证软件 的质量⽔平。同时,这也使得⾮⾼级⼯程师能够更容易地写出可⽤的代码,提⾼了整个团队的开发效率。

数据库分开部署

如果预算有限,我们可以选择基于云主机⾃建数据库并⾃⼰进⾏数据备份。这种⽅式的优点是灵活性⾼,可 以根据⾃⼰的需求进⾏定制和优化。但是缺点也很明显,那就是需要投⼊⼤量的时间和精⼒进⾏运维,⽽且 数据备份和恢复的过程也可能会遇到各种问题。

如果预算充⾜,我们强烈建议⼤家直接使⽤云服务商提供的云数据库服务。云数据库是云服务商最核⼼的“ 软件服务”之⼀,也是最具⽤户价值和⽤户粘性的云产品。它的优点在于稳定性⾼,安全性好,⽽且可以随 着业务的发展进⾏弹性扩展。此外,云数据库还可以提供丰富的数据分析和处理功能,对于我们未来的⾼并 发系统建设⾮常重要。

需要注意的是,虽然云主机、对象存储、CDN 都很容易迁移,但云数据库⼏乎⽆法在云服务商之间迁移,在 选择云数据库服务时,我们需要考虑到这⼀点。

云数据库的价值

云数据库绝不只是“不⽤⾃⼰做运维”那么简单,它拥有很多额外价值:

  • 云数据库拥有完善的数据备份和恢复机制。这不仅可以保证数据库的安全,还能提供⾃建数据库⽆法 做到的“闪回到任意时刻”的能⼒。在实际的业务运⾏过程中,这种需求其实是相当常见的。例如,可能需 要从过去的某个时间点恢复数据来进⾏数据分析或者修复错误。云数据库通常提供了多种备份和恢复策略, 可以满⾜不同的需求。
  • 云数据库的性能更⾼。⼀旦你对数据库的需求超过了 1000QPS,⾃建数据库就很难⽀撑了。开源的 MySQL 在低配机器上性能很强,但是即便给它 32 核 64GB 内存,它的性能也不会好到哪⾥去。如果招聘 研发团队⾃建数据库集群,那就太复杂了,⼩公司完全不值得,每年投⼊数百万成本养活运维和开发⼩团队 ,可能数据库集群还是会经常宕机。相⽐之下,云数据库可以提供⾼性能的数据库服务,可以轻松应对⾼并 发的访问请求。
  • 云数据库具有极佳的弹性。⼤部分互联⽹业务的流量都拥有显著的波动性,除了每天每周的业务⾼峰 期之外,电商⾏业每年还有超级⼤促⽇。所以,数据库的弹性⾮常重要,按需付费可以节约⼤量⾦钱。云数 据库可以根据实际的业务需求进⾏资源的动态调整,避免了资源的浪费。

1.7 现实世界中的高并发场景

高并发场景之——电商大促

"⼤促"是现如今电商平台最常见的营销模式,双 11 和 618 可以说每⼀个中国⼈都有所⽿闻。

在电商⼤促期间,由于⽤户访问流量和交易量在短时间内会快速增加,就导致了⼀系列⾼并发问题的出现:

系统响应慢

⽤户访问量突然增⼤,系统规模⽆法短时间内扩⼤,导致页⾯加载缓慢,⽤户体验差。 我们可以采取以下技 术⼿段来提升系统的总容量:

  • 静态资源缓存:将静态资源如图⽚、CSS 和 JavaScript ⽂件缓存到 CDN(内容分发⽹络)上,减少⼤ 促开始时服务器的带宽需求,加快页⾯加载速度。
  • 弹性伸缩:通过⾃动或⼿动调整服务器的数量和配置,根据实时负载情况动态分配计算资源,以满⾜⽤户 访问的需求。
  • 负载均衡:将⽤户请求分发到多个服务器上,避免单个服务器过载,提⾼系统的吞吐能⼒。

订单提交失败

订单量突然增加,系统可能⽆法及时处理订单,导致订单提交失败,甚⾄重复提交订单等问题。常⽤解决⽅案:

  • 异步处理:将订单处理过程异步化,即时返回排队中的状态,避免单个⽹络请求的时间过长影响⽤户体验 和服务器总容量。
  • 消息队列:使⽤消息队列来存储和处理订单,确保订单的顺序和可靠处理。
  • 幂等性设计:为订单处理接⼝设计幂等性,在前端加⼊订单唯⼀ UUID,防⽌重复提交订单和重复⽀付。

 库存超售

在电商⼤促中,多个⽤户可能在同⼀时刻购买同⼀款商品,极有可能导致超出库存数量的售卖⾏为,给经营 带来损失。为了解决这个严重的问题,可以采取以下措施:

  • 预售和抢购限制:提前设置商品的预售数量或限购数量,减少在明确⽆库存的情况下对库存扣减系统的额 外压⼒。
  • 使⽤队列进⾏库存扣减:使⽤消息队列来存储和处理订单,确保库存的顺序扣减。我们假设每次扣减库存 需要 20ms 的处理时间,那单线程队列就可以完成每秒 50 单的需求,这个容量其实是不⼩的,我们假 设客单价为 1000 元,则单个队列处理器可以承担每秒 5 万元,每分钟 300 万元的压⼒,这个交易额其 实已经很⼤了,全国能达到每分钟 300 万的电商平台应该也没有很多。
  • 订单超卖记录:在极限情况下,为了保证系统的总容量能满⾜⼤促的要求,我们不会极端严格地限制超卖 。如果真的超卖了,需要及时地反映在管理后台,让客服等运营⼈员介⼊处理。

支付超时

⽀付系统具有天然的单点性。在电商⼤促期间,由于⽤户购买⾏为集中,⽀付系统可能⾯临⼤量的并发⽀付 请求,难以及时处理所有订单的⽀付请求,导致⽤户⽀付超时,有货卖不出去。这时我们可以做如下处理: 

  • 多节点部署:由于⽀付系统具有天然的单点性,单个线程经常需要等待,所以我们要尽量地多节点部署, 以利⽤尽量多的 CPU 核⼼数来提升系统总容量。
  • 异步⽀付处理:将⽀付处理过程异步化,把和⽤户操作相关的前序步骤和后续步骤都进⾏异步拆分,只在 最核⼼的地⽅设置同步等待,减少对⽤户体验的阻滞。
  • 合理设置⽀付超时时间:根据实际情况,合理设置⽀付超时时间,可以减少单个⽤户的⽀付容量以及系统 总容量,极端场景下的订单可以在系统⾃动侦测到了之后进⾏⼿动改库修正。

举个例⼦:⽤户唤起了⽀付,但是停留在输⼊密码的页⾯⼀个⼩时,但是最后依然⽀付成功了,此 时该订单很有可能已经被系统⾃动取消了。 

 恶意攻击

电商⼤促期间,由于系统流量集中,使得此时成为了恶意攻击的最佳时机。为了保护系统的安全和稳定,我 们可以采取以下措施:

  • 防⽕墙和⼊侵检测系统:部署硬件防⽕墙和⼊侵检测系统,它们可以抵挡住低级的基于⽹络协议漏洞的低 端流量攻击。
  • 限制访问频率:通过限制单个 IP 地址、单个 UUID、单个⽤户 ID 的访问频率和请求次数,防⽌恶意攻击 者通过⼤量伪造请求或者是利⽤机器⼈抢购造成的系统瘫痪。
  • 安全加密通信:使⽤ SSL/TLS 等安全协议对⽤户和服务器之间的通信进⾏加密,防⽌信息泄露和篡改。 这⼀步在 2023 年应该已经全⾯普及了,如果你的系统还在⽤ HTTP 协议,需要赶紧升级。

高并发场景之——社交网络

虽然电商⼤促的问题已被阿⾥等公司解决。然⽽,社交⽹络的⾼并发问题是⽬前仍待解决的难点之⼀。⼀个 典型的案例是微博明星感情突发事件。

2017 年 10 ⽉ 8 ⽇中午,微博⼯程师丁振凯正在举⾏婚礼,⿅晗突然宣布与关晓彤的恋情,导致微博客户 端⽆法正常刷新、评论以及多个页⾯⽆法正常显⽰等问题。这次事件导致丁振凯中断婚礼,穿着西装戴着⼤ 红花坐在电脑前处理问题,成了⿅晗关晓彤事件的余波之⼀。事后统计,⿅晗公布恋情的微博,被转发了 33 万次,最终覆盖了 8.4 亿⼈次的微博⽤户。

在社交⽹络出现突发热点时,系统需要处理⼤量的实时数据更新、⽤户交互和内容传播动作,这些操作同时 发⽣就给系统带来了巨⼤的压⼒。我们可以采取如下⼏个⼿段:

缓存优化: 利⽤缓存技术来减轻数据库的压⼒,提⾼读取性能。将热门的⽤户信息、动态内容等存储在缓存中,加快数 据的访问速度。在微博场景下,最⼤的挑战就是热点数据的及时识别:在某条微博、某个账号突然流量暴增 时,能够在多短的时间内将该账号、该条微博缓存化,就成了决定系统是否会崩溃的最重要的因素。

数据库优化: 对热点数据和⾮热点数据分⽽治之,减少热点数据所在表的长度,可以最⼤限度地利⽤数据库本⾝的性能特 定和内存缓存,极⼤地提升数据库查询和更新的性能。

水平扩展: ⽔平扩展是通过增加服务器数量和实施负载均衡来应对⾼并发访问的策略。通过将系统拆分为多个服务实例 ,可以同时处理更多请求,提⾼系统的吞吐量。系统能够以多快的速度进⾏⽔平扩展,直接影响普通⽤户的 感受。只要扩容⾜够快,⼤多数⽤户⼏乎⽆法察觉到系统曾经宕机过。

资源预估和监控: 在活动⾼峰期前,进⾏系统资源的预估和规划,确保系统能够承受预期的并发流量。同时,实时监控系统的 运⾏状态,及时发现和解决潜在的性能问题。这⼀条只适⽤于节假⽇,明星们不按套路出牌,本条在明星场 景下没什么⽤。

1.8 相关面试题

你遇到过哪些高并发系统?

  • 1. 电商平台:例如淘宝、京东等,这些平台需要处理⽤户浏览商品、添加购物车、下单、⽀付等⼤量请求, ⽽且需要在同⼀时间处理⼤量的并发请求。
  • 2. 社交⽹络:例如微信、微博等,这些平台需要处理⽤户发布动态、点赞、评论、聊天等⼤量请求,⽽且需 要在同⼀时间处理⼤量的并发请求。
  • 3. 游戏服务器:游戏需要实时处理玩家的输⼊指令,同时还需要处理⼤量的图形渲染和数据计算等任务,因 此需要⾼并发的处理能⼒。
  • 4. 云计算平台:例如AWS、阿⾥云等,这些平台需要为⽤户提供计算、存储、数据库等服务,需要处理⼤ 量的并发请求。

高并发系统的通用设计方法是什么?

⾼并发系统遇到性能瓶颈,⼀定是某个单点资源达到了极限,例如数据库、后端云服务器、⽹络带宽等,需 要找到这个瓶颈资源,拆分它,提升整个系统的容量。具体来说,有如下⼏个设计⽅向:

  • 1. 负载均衡:这是解决⾼并发问题的最基本和最直接的⽅式。负载均衡可以将请求分散到多个服务器上,从 ⽽使得每个服务器的负载保持在⼀个相对较低的⽔平,提⾼了系统的整体处理能⼒。
  • 2. 缓存技术:缓存是提⾼系统性能的⼀种重要⼿段。通过将经常访问的数据存储在内存中,可以⼤⼤减少对 数据库的访问,从⽽提⾼系统的响应速度。
  • 3. 异步处理:异步处理是⼀种将耗时的操作转化为后台任务进⾏处理的⽅式,这样主线程就可以⽴即返回, 不需要等待这些操作完成。这种⽅式可以提⾼系统的并发处理能⼒。
  • 4. 消息队列:消息队列是⼀种⽤于处理⼤量并发请求的技术。通过将请求放⼊消息队列中,然后由专门的服 务进程来处理这些请求,可以避免主线程被阻塞,从⽽提⾼系统的并发处理能⼒。
  • 5. 数据库优化:对于数据库来说,优化SQL语句、合理设置索引、使⽤数据库集群等都可以提⾼数据库的处 理能⼒,从⽽提⾼整个系统的性能。
  • 6. ⽔平扩展:当系统的负载达到⼀定程度时,可以通过增加更多的服务器来扩展系统的能⼒。这通常需要对 系统进⾏微服务化改造,每个服务都可以独⽴地部署和扩展。
  • 7. 服务隔离:在⾼并发系统中,通常会有多个服务同时运⾏。为了保证服务的独⽴性和稳定性,需要将不同 的服务隔离开来,避免⼀个服务的故障影响到其他服务。

 

高并发系统的拆分顺序是什么样的?

⾼并发系统的拆分顺序应该从静态资源拆分开始,逐步进⾏到数据库和后端计算的机器分离,然后是设计负 载均衡和分布式计算架构,接着是利⽤数据库集群和分布式数据库提升数据库性能,最后可以考虑基于地域 进⾏数据库拆分。展开如下:

  • 1. 静态资源拆分:⾸先,将系统中的静态资源(如图⽚、CSS ⽂件、JavaScript ⽂件等)进⾏拆分。这样 可以避免在⾼并发情况下,静态资源的加载成为系统性能瓶颈。可以将静态资源放在专门的 CDN 上,提 ⾼访问速度。
  • 2. 数据库和后端计算的机器分离:将负责处理业务逻辑的服务器与负责存储数据的数据库服务器分离。这样 可以降低数据库的压⼒,提⾼数据处理速度。同时,可以将不同的业务逻辑部署在不同的服务器上,提⾼ 系统的可扩展性和容错能⼒。
  • 3. 设计负载均衡和分布式计算架构:通过负载均衡技术,将⽤户请求分发到多台服务器上进⾏处理。这样可 以充分利⽤多台服务器的资源,提⾼系统的处理能⼒。同时,可以采⽤分布式计算架构,利⽤多台服务器 同时进⾏服务,进⼀步提⾼系统的并发处理能⼒。
  • 4. 数据库集群和分布式数据库:为了提升数据库的性能,可以采⽤数据库集群和分布式数据库技术。数据库 集群是将多个数据库实例分布在不同的服务器上,通过数据同步和故障转移机制,保证数据库的⾼可⽤性 。分布式数据库是将数据分散在多个节点上,每个节点只负责部分数据的存储和查询,从⽽提⾼整个系统 的读写性能。
  • 5. 基于地域进⾏数据库拆分:如果已经是⼀个全国性系统,可以考虑基于地域进⾏数据库拆分。将全国分成 ⼏个区域,每个区域的机房只为地理位置在本区的⽤户提供热数据。这样可以避免跨区域的数据传输,降 低⽹络延迟,提⾼系统响应速度。对于外区的⽤户,可以将请求转发回原来的⼤区,获得终极的系统容量 提升。

静态资源如何加速?

为了加速静态资源的加载,可以采取以下⼏种⽅法:

1. 使⽤⾼性能的 Web 服务器:如 Nginx,适合处理⼤量并发请求,提⾼应⽤性能。

2. 利⽤ CDN 服务:将⽹站内容复制到全球多个服务器,⽤户从最近的服务器获取信息,减少延迟,提⾼加 载速度。CDN 特别适⽤于静态资源的分发,可以有效地加速图⽚、CSS、JavaScript 等静态资源的加载 。

3. 进⾏格式转换、压缩和 HTTP/2 header 重⽤:可以将 PNG、BMP 图⽚转换为 WebP 或 JPEG 格式 ,以减⼩⽂件体积。此外,利⽤压缩算法如 gzip 对⽂件进⾏压缩,可以进⼀步减⼩⽂件⼤⼩,提⾼传输 效率。另外,HTTP/2 协议⽀持 header 重⽤功能,可以减少⽹络传输时间。

相关推荐

  1. 并发系统中面临问题 及 解决方案

    2024-07-15 09:46:02       27 阅读
  2. 基于Flask并发部署方案

    2024-07-15 09:46:02       56 阅读
  3. 3.架构设计系列:并发系统设计目标

    2024-07-15 09:46:02       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 09:46:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 09:46:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 09:46:02       58 阅读
  4. Python语言-面向对象

    2024-07-15 09:46:02       69 阅读

热门阅读

  1. 对AAC解码的理解

    2024-07-15 09:46:02       22 阅读
  2. 【Karapathy大神build-nanogpt】Take Away Notes

    2024-07-15 09:46:02       24 阅读
  3. C的分文件编写与动态库

    2024-07-15 09:46:02       26 阅读
  4. Spring Boot中的安全配置与实现

    2024-07-15 09:46:02       20 阅读
  5. 设计模式--抽象工厂模式

    2024-07-15 09:46:02       23 阅读
  6. 【C++ 】类与对象 -- 纯虚函数与抽象类

    2024-07-15 09:46:02       22 阅读
  7. 设计模式--简单(抽象)工厂模式

    2024-07-15 09:46:02       24 阅读
  8. python中停止线程的方法

    2024-07-15 09:46:02       19 阅读
  9. 【前端】fis框架学习

    2024-07-15 09:46:02       19 阅读