大数跨境
0
0

系统设计30个核心技能,每一个开发者都必须掌握

系统设计30个核心技能,每一个开发者都必须掌握 Spring全家桶实战案例
2025-10-08
0
导读:系统设计30个核心技能,每一个开发者都必须掌握
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!
图片

🎉🎉《Spring Boot实战案例合集》目前已更新180个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

系统设计会让人感到不知所措,尤其是当你刚刚开始工作,不知从何下手的时候。

但是,一旦你了解了核心概念和构建模块,无论是准备面试还是在工作中设计可扩展系统,它都会变得不再那么可怕。

在本文中,将带你了解每个开发人员都应该知道的 30 个最核心的系统设计概念(技能)。

2.实战案例

2.1 Client-Server架构

你所使用的几乎所有网络应用程序都是基于这一简单而强大的概念而构建的,即客户端-服务器架构。

一边是客户端,可以是网络浏览器、移动应用程序或任何其他前端应用程序。

另一侧是服务器  一台持续运行的机器,等待处理接收到的请求。

客户端发送存储、检索或修改数据的请求。

服务器接收请求,处理请求,执行必要的操作,然后发回响应。

这听起来很简单,但有一个大问题: 客户端如何知道服务器在哪里?

2.2 IP地址

客户端并不能神奇地知道服务器在哪里,它需要一个地址来定位并与之通信。

在互联网上,计算机通过 IP 地址相互识别,IP 地址就像服务器的电话号码。

每一台公开部署的服务器都拥有一个唯一的IP地址。当客户端想要与某个服务进行交互时,它必须将请求发送到正确的IP地址。

但这里存在一个问题:

  • 当我们访问一个网站时,我们并不会输入它的IP地址——我们只需输入网站名称即可

  • 我们无法期望用户(甚至系统)记住每个所连接服务的那一串随机数字形式的IP地址。

  • 而且,如果我们将服务迁移到另一台服务器上,其IP地址可能会发生变化——这会导致所有直接连接失效。

2.3 DNS

我们不再依赖难以记忆的IP地址,而是使用对人类更加友好的方式:域名。

但是,我们需要一种方法将域名映射到其对应的IP地址。

这时,DNS(即域名系统)就派上用场了。它将易于记忆的域名(如www.pack.com)映射到它们对应的IP地址。

以下是幕后发生的情况:

当你在浏览器中输入 pack.com 时,你的计算机会向 DNS 服务器询问该域名对应的 IP 地址。

一旦 DNS 服务器返回了 IP 地址,你的浏览器就会使用该地址与服务器建立连接并发出请求。

你可以使用 ping 命令查找任何域名的 IP 地址。只需打开终端,输入 ping 后跟域名即可。该命令将返回当前分配给该域名的 IP 地址。

2.4 代理 / 反向代理

当你访问一个网站时,您的请求并不总是直接进入服务器,有时会先通过代理或反向代理。

代理服务器是设备和互联网之间的中间人。

当你请求访问一个网页时,代理会将您的请求转发到目标服务器,检索响应并将其发送给你。

代理会隐藏你的 IP 地址,使你的位置和身份保密。

反向代理则相反。它拦截客户端请求,并根据预定义的规则将请求转发给后端服务器。

允许直接访问服务器会带来安全风险,使服务器面临黑客和 DDoS 攻击等威胁。

反向代理通过充当受控入口点来控制传入流量并隐藏服务器 IP,从而降低这些风险。

它还可以充当负载平衡器,在多个服务器之间分配流量。

2.5 延迟

每当客户端与服务器通信时,总会出现一些延迟。造成这种延迟的最大原因之一就是物理距离。

例如,如果我们的服务器在纽约,但印度的用户发送了一个请求,那么数据就必须穿越半个地球,然后响应也必须经过同样漫长的旅程才能返回。

这种往返延迟称为延迟,即数据在客户端和服务器之间传输所需的总时间。高延迟会让应用程序感觉缓慢、反应迟钝。

减少延迟的方法之一是在全球多个数据中心部署我们的服务。

这样,用户就可以连接到最近的服务器,而不用等待数据在全球范围内传输。

建立连接后,客户端和服务器如何进行实际通信?

2.6 HTTP / HTTPS

每次访问网站时,浏览器和服务器都会使用一套名为 HTTP(超文本传输协议)的规则进行通信。

这就是为什么大多数 URL 都以 http:// 或其安全版本 https:// 开头。

工作原理:

客户端向服务器发送请求。该请求包含一个请求头(其中包含请求类型、浏览器类型和 Cookie 等详细信息),有时还包含请求体(用于携带额外数据,如表单输入内容)。

服务器处理该请求,并返回一个 HTTP 响应——如果一切正常,则返回所请求的数据;如果出现问题,则返回错误信息。

HTTP 存在一个严重的安全缺陷,它以明文形式发送数据。这是一个严重的问题,特别是对于密码、信用卡详细信息和个人数据等敏感信息而言。

因此,现代网站都改用 HTTPS(超文本传输安全协议)。HTTPS 使用 SSL/TLS 对所有数据进行加密,确保即使有人拦截了请求,也无法读取或篡改请求内容。

不过,客户端和服务器并不会直接交换原始的 HTTP 请求和响应。

HTTP 只是一种数据传输协议,但它并未定义:

  • 请求应如何构建

  • 响应应采用何种格式

  • 或者不同客户端应如何与服务器进行交互

这时,API(即应用程序编程接口)就派上用场了。

2.7 APIs

将应用程序接口视为一个中间人,它允许客户端(如网络和移动应用程序)与服务器通信,而无需担心低级细节。

几乎你使用的每一项数字服务——社交媒体、电子商务、网上银行、网约车应用——都依赖于幕后协同工作的各类API。

其典型工作流程如下:

  • 客户端向API发送请求

  • API部署在服务器上,它会对请求进行处理,与数据库或其他服务进行交互,并准备响应内容。

  • API以结构化格式(通常是JSON或XML)将响应发送回客户端,客户端能够理解并展示这些内容。

API提供了一层抽象——客户端无需了解服务器如何处理请求,只需知道它能返回预期的数据即可。

2.8 Rest API

在不同的 API 风格中,REST(表征状态传输)是使用最广泛的一种。

REST API 遵循一系列规则,这些规则定义了客户端和服务器如何以结构化的方式通过 HTTP 进行通信。

REST的特点如下:

  • 无状态:每个请求都是独立的,服务器不存储客户端状态。

  • 基于资源:所有事物均被视为资源(例如,/users(用户)、/orders(订单)、/products(产品))。

  • 使用标准HTTP方法:客户端使用以下HTTP方法与资源进行交互:

  • GET → 检索数据(例如,获取用户资料)。

  • POST → 创建新数据(例如,添加新用户)。

  • PUT/PATCH → 更新现有数据(例如,更改用户设置)。

  • DELETE → 删除数据(例如,删除账户)。

REST API非常出色,因为它们简单、可扩展且易于缓存,但在处理复杂数据检索时存在局限性。

REST端点经常返回比所需更多的数据,导致网络使用效率低下。如果API不返回相关数据,客户端可能需要发起多个请求来检索所有必要信息。

为了应对这些挑战,Facebook 于 2015 年推出了 GraphQL。

2.9 GraphQL

与强制客户端获取固定数据集的REST不同,GraphQL允许客户端精确请求它们所需的数据——不多也不少。

使用REST API时,如果你需要用户详细信息、用户资料详细信息以及他们的最新帖子,你可能需要向不同的端点发起多个请求:

  • GET /api/users/123 → 获取用户详细信息

  • GET /api/users/123/profile → 获取用户资料

  • GET /api/users/123/posts → 获取用户的帖子

而使用GraphQL,你可以将这些请求合并为一个,并在单个查询中精确获取所需的数据:

服务器只响应所请求的字段,从而减少了不必要的数据传输,提高了效率。

不过,GraphQL 也有其局限性--它需要在服务器端进行更多处理,而且不像 REST 那样容易缓存。

更多GraphQL内容请查看下面链接:

Springboot整合GraphQL使你的API更易理解可读性更强

2.10 数据库

如果我们的应用程序要处理少量数据,我们可以将其存储在内存中。

但现代应用程序处理的数据量巨大,远远超出了内存所能有效处理的范围。

这就是为什么我们需要一个专门的服务器来存储和管理数据--数据库。

数据库是任何应用程序的支柱。它能确保数据的存储、检索和高效管理,同时保证数据的安全性、一致性和持久性。

当客户端请求存储或检索数据时,服务器会与数据库通信,获取所需的信息,并将其返回给客户端。

但并非所有数据库都是一样的。不同的应用程序有不同的可扩展性、性能和一致性要求,因此选择合适的数据库类型非常重要。

2.11 SQL vs NoSQL

SQL数据库以具有严格预定义架构的表形式存储数据,并遵循ACID特性。

  • 原子性: 事务具有全有或全无的特性(要么完全完成,要么完全不执行)

  • 一致性: 数据始终保持有效并遵循定义的规则

  • 隔离性: 事务之间不会相互干扰

  • 持久性: 数据一旦保存,即使系统崩溃也不会丢失

由于这些保证,SQL数据库非常适合需要强一致性和结构化关系的应用程序,例如银行系统。

流行的SQL数据库示例包括:MySQL和PostgreSQL

另一方面,NoSQL数据库旨在实现高可扩展性和高性能。

它们不需要固定的架构,并使用不同的数据模型,包括:

  • 键值存储: 用于简单键值对的快速查找(例如,Redis)

  • 文档存储: 存储灵活的、类似JSON的文档(例如,MongoDB)

  • 图数据库: 最适合高度连接的数据(例如,Neo4j)

  • 宽列存储: 针对大规模分布式数据进行了优化(例如,Cassandra)

那么,你应该使用哪一种呢?这取决于系统需求。

如果你需要具有强一致性的结构化关系数据→SQL是更好的选择。

如果你需要高可扩展性、灵活的架构或大规模下的快速读写→NoSQL是更好的选择。

许多现代应用程序同时使用SQL和NoSQL。

例如,一个电子商务平台可能会:

  • 在SQL中存储客户订单(因为它们需要严格的一致性)

  • 并在NoSQL中存储产品推荐(因为它们需要灵活且快速的查找)

2.12 垂直扩展

随着用户数量的增加,应用服务器收到的请求数量也在增加。

最初,一台服务器可能就足以处理负载。但是,随着流量的增加,单台服务器就会成为瓶颈,拖慢一切运行速度

最快的解决方案之一就是升级现有服务器,增加 CPU、内存或存储空间。

这种方法被称为垂直扩展(纵向扩展)——即提升单台机器的性能。

然而,这种方法存在一些重大局限性:

  • 硬件限制: 你不可能无限期地升级服务器。每台机器都有其最大容量。

  • 成本: 性能更强大的服务器,其成本会呈指数级增长。

  • 单点故障: 如果这台服务器崩溃,整个系统就会瘫痪。

因此,尽管垂直扩展是一种快速解决方案,但它并非应对高流量和确保系统可靠性的长期方案。

让我们来看看一种更好的方法——这种方法能让我们的系统更具可扩展性和容错能力。

2.13 水平扩展

与其升级一台服务器,不如增加更多服务器来分担负载,怎么样?

这种方法被称为水平扩展(横向扩展)——即通过将工作负载分散到多台机器上来实现扩展。

这种方法更为优越,原因如下:

  • 服务器更多 = 容量更大: 系统能够更有效地应对不断增长的流量

  • 无单点故障: 如果一台服务器出现故障,其他服务器可以接管其工作,从而提高系统的可靠性

  • 成本效益高: 我们无需投资于一台价格高昂的超级服务器,而是可以使用多台价格亲民的服务器

然而,水平扩展带来了一个新的挑战:客户端如何知道该连接到哪台服务器?这时,负载均衡器就派上用场了。

2.14 负载均衡

负载均衡器位于客户端与后端服务器之间,充当流量管理者,将请求分配到多台服务器上。

如果某台服务器崩溃,负载均衡器会自动将流量重定向到另一台正常运行的服务器。

那么,负载均衡器如何决定由哪台服务器处理下一个请求呢?

它使用负载均衡算法,例如:

  • 轮询(Round Robin): 按顺序将请求依次发送给各台服务器,循环往复

  • 最少连接数(Least Connections): 将请求发送给当前活跃连接数最少的服务器。

  • IP哈希(IP Hashing): 来自同一IP地址的请求始终发送到同一台服务器,这有助于保持会话一致性。

2.15 数据库索引

索引是加快数据库读取查询速度的最快捷、最有效的方法之一。

把它想象成一本书后面的索引页--无需翻阅每一页,而是直接跳转到相关部分。

数据库索引也是如此。它是一个超级高效的查找表,可以帮助数据库快速查找所需数据,而无需扫描整个表。

索引存储列值以及指向表中实际数据行的指针。

索引通常创建在经常被查询的列上,例如:

  • 主键

  • 外键

  • 在WHERE条件中使用的列

但需谨慎——虽然索引能加快读取速度,但会降低写入速度(INSERT、UPDATE、DELETE),因为每当数据发生变化时,索引都需要更新。

因此,我们只应为访问频率最高的列创建索引。

索引能显著提高读取性能,但如果连索引都不足以应对,数据库无法处理不断增长的读取请求,该怎么办?

这时,我们的下一个数据库扩展技术——复制(Replication)就派上用场了。

2.16 复制

就像我们增加更多应用服务器来处理流量一样,我们也可以通过在多个服务器上创建数据库副本来扩展数据库。

工作原理:

  • 我们设置一个主数据库(也称为“主副本”),负责处理所有写入操作(INSERT、UPDATE、DELETE)

  • 同时设置多个只读副本,负责处理读取查询(SELECT)。

  • 每当数据写入主数据库时,这些数据都会被复制到只读副本,以确保它们保持同步。

复制技术通过将读取请求分散到多个副本上,减轻了每个副本的负载,从而提高了读取性能。

此外,如果主副本发生故障,某个只读副本还可以接管成为新的主副本,这也提高了系统的可用性。

复制技术非常适合扩展读取密集型应用,但如果我们需要扩展写入能力或存储海量数据,该怎么办呢?

2.17 分片

比方说,我们的服务现在有数百万用户,我们的数据库已增长到 TB 级数据量。

单个数据库服务器最终将难以高效处理所有这些数据。

与其将所有数据集中在一个地方,我们不如将数据库拆分成更小、更易于管理的部分,并将它们分布在多个服务器上。

这种技术被称为分片(Sharding)

  • 我们将数据库拆分成更小的部分,称为分片

  • 每个分片包含总数据的一个子集

  • 数据根据分片键(如用户ID)进行分配

通过这种方式分配数据,我们可以:

  • 减轻数据库负载 → 每个分片仅处理部分查询

  • 加快读写性能 → 查询被分散到多个分片上,而不是集中在一个数据库上

分片也被称为水平分区,因为它是按行拆分数据的。

但如果问题不在于行数过多,而在于列数过多呢?

在这种情况下,我们使用垂直分区,即按列拆分数据库。接下来,我们将对此进行探讨。

2.18 垂直分区

想象一下,我们有一个用户表(User table),其中存储了以下信息:

  • 个人资料详情(姓名、电子邮箱、头像)

  • 登录历史(最后登录时间、IP地址)

  • 以及账单信息(账单地址、支付详情)

随着该表数据量的增长,查询速度会变慢,因为即使请求仅需要几个特定字段,数据库也必须扫描众多列。

为了优化这种情况,我们可以采用垂直分区(Vertical Partitioning)方法,根据使用模式将用户表拆分成更小、更聚焦的子表。

  • User_Profile → 存储姓名、电子邮箱、头像

  • User_Login → 存储登录时间戳

  • User_Billing → 存储账单地址、支付详情

这样可提升查询性能,因为每个请求只需扫描相关列,而无需扫描整个表。

这减少了不必要的磁盘I/O,使数据检索速度更快。

然而,无论我们对数据库进行多少优化,从磁盘检索数据总是比从内存检索数据慢。

如果我们能将频繁访问的数据存储在内存中,以实现极快的访问速度,那会怎样呢?

这就是缓存(caching)的作用。

2.19 缓存

缓存通过将频繁访问的数据存储在内存中,而不是从数据库中重复获取,从而优化系统性能。

最常见的缓存策略之一是缓存旁路模式(Cache Aside Pattern)。

工作原理:

  • 当用户请求数据时,应用程序首先检查缓存

  • 如果数据存在于缓存中,则立即返回该数据,无需访问数据库

  • 如果数据不在缓存中,应用程序会从数据库中检索该数据,将其存储在缓存中以备后续请求使用,然后将数据返回给用户

  • 下次请求相同数据时,数据将直接从缓存中提供,从而大幅加快请求速度

为防止提供过时数据,我们使用生存时间(TTL)——为缓存数据设置一个过期时间,这样数据在经过一定时间后会自动刷新。

流行的缓存工具包括Redis和Memcached。

接下来,我们来看下一种数据库扩展技术。

2.20 反规范化

大多数关系型数据库采用规范化(Normalization)方法,通过将数据拆分到不同的表中来高效存储数据。

例如,在一个电子商务系统中:

  • 用户表(Users)存储用户详细信息

  • 订单表(Orders)存储用户的订单

  • 产品表(Products)存储产品详细信息

虽然这种方法减少了数据冗余,但也引入了表连接(JOIN)操作。当需要从多个表中检索数据时,数据库必须使用JOIN操作将它们组合起来。随着数据集的不断增大,这种操作可能会导致查询速度变慢。

SELECT o.order_id, u.name, u.email, o.product, o.amount  FROM orders oJOIN users u ON o.user_id = u.user_id;

去规范化可将相关数据合并到一个表中,从而减少连接次数,即使这意味着某些数据会重复。

举例说明: 我们不再将用户和订单分别保存在不同的表中,而是创建了 UserOrders 表,用于存储用户详细信息及其最新订单。

现在,在检索用户的订单历史记录时,我们不需要进行连接操作--数据已经存储在一起,从而提高了查询速度和读取性能。

SELECT order_id, user_name AS name, user_email AS email, product, amount  FROM orders;

去规范化通常用于对速度要求较高的重读取应用中,但其缺点是会增加存储使用量和更复杂的更新请求。

2.21 CAP定理

当我们将系统扩展到多个服务器、数据库和数据中心时,我们就进入了分布式系统的世界。

分布式系统的基本原则之一是 CAP 定理,该定理指出: 任何分布式系统都无法同时实现以下三点:

  • 一致性 (C) : 每个节点总是返回最新数据

  • 可用性 (A) : 即使某些节点宕机,系统也始终响应请求(但数据可能不是最新的)

  • 分区容忍度 (P) : 即使节点之间出现网络故障,系统也能继续运行

由于网络故障 (P) 不可避免,我们必须在以下两者之间做出选择:

  • 一致性 + 分区容错 (CP) : 确保每个请求都能获得最新数据,但可能会在故障期间拒绝请求。例如:MySQL 等 SQL 数据库: MySQL 等 SQL 数据库

  • 可用性 + 分区容错(AP): 确保系统始终响应,即使某些数据已经过时。示例:Cassand 等 NoSQL 数据库: Cassandra 和 DynamoDB 等 NoSQL 数据库

在分布式 NoSQL 数据库中,在所有服务器之间实现即时一致性的速度太慢。

相反,我们使用 "最终一致性"--这意味着:

  • 并非所有节点都会立即更新,但只要有足够的时间,它们最终会同步并返回相同的数据

  • 这样,即使在极端负载情况下,系统也能保持高可用性和快速性

最终一致性如何发挥作用:

  • 用户更新数据库一个副本中的数据

  • 系统会立即确认更新,确保高可用性

  • 然后,更新会异步传播到其他副本

  • 经过短暂延迟后,所有副本都会拥有最新数据,从而确保了时间上的一致性

2.22 Blob存储

大多数现代应用程序不仅要存储文本记录,还需要处理图像、视频、PDF 和其他大型文件。

但问题是:传统数据库的设计无法高效地存储大型非结构化文件。

那么,解决方案是什么呢?

我们使用像亚马逊 S3 这样的 Blob 存储,这是一种在云中存储大型非结构化文件的高度可扩展且经济高效的方式。

Blob 是图像、视频或文档等单个文件。

这些 Blob 存储在云中的逻辑容器或桶中。

每个文件都有一个唯一的 URL,便于在网络上检索和提供服务。

使用 Blob 存储有以下几个优势:

  • 可扩展性: 可以毫不费力地存储 PB 级数据

  • 随用随付定价: 只需为实际使用的存储和检索付费

  • 自动复制: 数据在多个数据中心和可用区之间复制,以确保数据的持久性

  • 轻松访问: 可使用 REST API 或直接 URL 检索文件

一种常见的用例是将音频或视频文件实时流式传输到用户应用程序。

但直接从 blob 存储器流式传输速度可能会很慢,尤其是当数据存储在很远的地方时。

2.23 CDN

例如,假设您在印度试图观看托管在加利福尼亚州服务器上的 YouTube 视频。

由于视频数据必须在世界各地传输,这可能会导致缓冲和加载时间变慢。

内容分发网络(或 CDN)可以解决这个问题,它可以根据用户的位置更快地向其分发内容。

CDN 是由分布式服务器组成的全球网络,这些服务器协同工作,根据用户的地理位置向其传送网络内容(如 HTML 页面、JavaScript 文件、样式表、图像和视频)。

CDN 将静态内容缓存在遍布全球的多个边缘服务器上,而不是从单个数据中心提供内容。

当用户请求内容时,离其最近的 CDN 服务器就会提供内容,而不是一直传送到原始服务器。

由于内容是从最近的 CDN 节点提供的,因此用户可以体验到更快的加载时间和最小的缓冲。

2.24 WebSockets

大多数网络应用程序都使用 HTTP,它遵循请求-响应模式。

  • 客户端发送请求

  • 服务器处理请求并发送响应

  • 如果客户端需要新数据,则必须发送另一个请求

这种方式对于静态网页很有效,但对于实时应用程序(如即时聊天应用程序、股票市场仪表板和多人在线游戏)来说,速度太慢,效率太低。

使用 HTTP,获得实时更新的唯一方法是轮询--每隔几秒发送一次重复请求。

但轮询的效率很低,因为它会增加服务器负载并浪费带宽,因为大多数响应都是空的(当没有新数据时)。

WebSockets 解决了这个问题,它允许客户端和服务器之间通过单个持久连接进行连续的双向通信。

工作原理:

  • 客户端启动与服务器的 WebSocket 连接

  • 连接一旦建立,就会保持打开状态

  • 服务器可随时向客户端推送更新,无需等待请求

  • 客户端也可以即时向服务器发送信息

2.25 Webhooks

Webhooks 允许服务器在事件发生时立即向另一台服务器发送 HTTP 请求,而不是不断轮询 API 来检查事件是否发生。

工作原理:

  • 接收方(你的应用程序)向提供商(如 Stripe、GitHub、Twilio)注册一个 webhook URL

  • 事件发生时(如用户付款),提供商会向网络钩子 URL 发送 HTTP POST 请求,并提供事件详情

  • 你的应用程序会处理传入的请求并相应地更新数据

关于webhook详细应用,请查看下面文章:

告别轮询!Spring Boot+Webhook 构建实时响应系统

2.26 微服务

传统上,应用程序都是采用单片式架构构建的,即:

  • 所有功能(如身份验证、支付、订单、发货)都在一个大型代码库中

  • 如果系统的某个部分出现故障或需要扩展,整个系统都会受到影响

  • 部署是有风险的,一个错误的更新就可能导致整个应用程序瘫痪

举例说明: 想象一下,在一个电子商务应用程序中,订单、付款、库存和发货模块都在一个代码库中紧密相连。

如果库存系统崩溃,整个应用程序就会瘫痪。

单体系统对于小型应用程序来说很好用,但对于大型系统来说,就很难管理、扩展和部署了。

解决方案是将应用程序分解成更小的、独立的服务,这些服务被称为微服务,它们可以协同工作。

每个微服务:

  • 处理单一职责

  • 拥有自己的数据库和逻辑,因此可以独立扩展

  • 使用应用程序接口或消息队列与其他微服务通信

这样,服务就可以单独扩展和部署,而不会影响整个系统。

但是,当多个微服务需要通信时,直接调用 API 并不总是高效的,这就是消息队列的用武之地。

2.27 消息队列

在单体系统中,函数会直接互相调用并等待响应。

但在基于微服务的系统中,这种方法效率很低,因为:

  • 如果一项服务运行缓慢或出现故障,所有服务都将等待

  • 高流量会使单项服务超负荷

  • 同步通信(等待立即响应)无法很好地扩展

消息队列能让服务进行异步通信,从而在不阻塞其他操作的情况下处理请求。

工作原理:

  • 生产者(如结账服务)将信息放入队列(如 "处理付款")

  • 队列暂时保存消息,直到消费者(如支付服务)准备好处理它

  • 消费者检索信息并进行处理

利用消息队列,我们可以解耦服务,提高可扩展性和容错性。

常见的消息队列系统包括 Apache Kafka、RocketMQ 和 RabbitMQ。

2.28 速率限制(限流)

想象一下,一个机器人开始每秒向您的网站发出数千次请求。

如果不加限制,这可能:

  • 消耗所有可用资源,导致服务器崩溃

  • 由于过度使用 API 而增加云成本

  • 降低合法用户的性能

速率限制可限制客户端在特定时间内发送请求的数量。

工作原理:

  • 每个用户或 IP 地址都有一个请求配额(例如每分钟 100 个请求)

  • 如果超过这个限额,服务器会暂时阻止其他请求,并返回错误信息(HTTP 429 - 请求过多)

有各种速率限制算法,常用的有:

  • 固定窗口: 根据固定的时间窗口(如每分钟 100 个请求)限制请求

  • 滑动窗口: 更灵活的版本,可动态调整限制,以平滑处理突发请求

  • 令牌桶: 用户的请求会获得令牌,令牌会以固定比率随时间补充

2.29 API网关

API 网关是一种集中式服务,用于处理身份验证、速率限制、日志记录和监控以及请求路由。

想象一下,一个基于微服务的应用程序包含多个服务。

API 网关不是直接公开每个服务,而是充当所有客户端请求的单一入口。

工作原理:

  • 客户端向 API 网关发送请求

  • 网关验证请求(如身份验证、速率限制)

  • 它将请求路由到相应的微服务

  • 响应通过网关发回客户端

API 网关简化了 API 管理,提高了可扩展性和安全性。

2.30 幂等性

在分布式系统中,网络故障和服务重试很常见。如果用户不小心刷新了付款页面,系统可能会收到两个付款请求,而不是一个。

幂等性确保重复请求产生的结果与只请求一次的结果相同。

工作原理:

  • 每个请求都有一个唯一的 ID(如 request_1234)

  • 在处理之前,系统会检查该请求是否已被处理过

  • 如果是: 则忽略重复请求

  • 如果否: 正常处理该请求

幂等性可以防止重复事务,确保分布式系统的数据一致性。



以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

太强了!动态脚本引擎QLExpress,实现各种复杂的业务规则

Spring Boot 优雅处理 JSON动态属性

技术专家:零代码,Spring Boot存储加密解密,支持JDBC、MyBatis及JPA

一定要会!MySQL窗口函数太实用了,再也不怕复杂SQL查询了

别再写死了!Spring Boot 动态定时任务,支持实时更新

5种实现方式配置Spring Boot API接口超时时间

Java 25这是要逆天啊,新特性强的可怕

强大!基于Map优化缓存设计

强大!Spring Boot 通过事务感知解决数据库与缓存不一致问题

Spring Boot 一次性Token,此功能太实用了

性能提升!@Async与CompletableFuture优雅应用

图片
图片
图片
图片
图片
图片
图片
图片
图片

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读195
粉丝0
内容832