1.0 简介:不可避免的分配法则
本系列的 1.0 版本奠定了基础,定义了后端工程的角色、工具和初始架构模式。 我们探索了单体应用和微服务、SQL 和 NoSQL、REST 和 GraphQL。 这些知识代表了构建功能应用程序的必要基础。 然而,本卷讲述的是当我们扩展这些应用程序时会发生什么; 当我们的单个服务器变成一个集群时,我们的单个数据库变成一个集群,我们的进程内调用变成网络跃点。 这是分布式系统的领域,它由一套不同的、更严格的规则管理。
从单机系统到分布式系统的转变并不是复杂性的线性增加; 这是一种范式转变。 在单台机器上成立的假设; 可靠组网、零延迟、即时操作; 都破碎了。 高级后端工程师的主要目标是构建即使底层环境固有的不可靠性也能正确可靠地运行的系统。
1.1 分布式计算的八个谬误
20 世纪 90 年代,L. Peter Deutsch 和 Sun Microsystems 的其他人编制了一系列谬误; 刚刚接触分布式应用程序的程序员总是会做出这样的假设,这会给他们带来危险。
CAUTION{title=“Eight Fallacies of Distributed Computing”}
- 网络可靠。(事实并非如此。)
- 延迟为零。(事实并非如此。)
- 带宽是无限的。(事实并非如此。)
- 网络是安全的。(事实并非如此。)
- 拓扑不会改变。(确实会改变。)
- 有一名管理员。(有很多。)
- 运输成本为零。(事实并非如此。)
- 网络是同质的。(事实并非如此。) :::在某种程度上,本卷中讨论的每种模式、协议和架构都是减轻这些谬论后果的策略。
1.2 高级后端工程路线图
在此基础上,我们探索定义现代系统架构的高级主题:
- 第 2 节:高级数据管理和一致性
- 第 3 节:弹性系统设计模式
- 第 4 节:高级异步通信
- 第 5 节:大规模性能工程
- 第 6 节:高级 API 和安全架构
2.0 高级数据管理和一致性
在具有一个数据库的单服务器应用程序中,数据一致性主要通过 ACID 事务来解决。 在分布式系统中,一致性成为最困难的挑战之一。
2.1 一致性谱和 PACELC 定理
CAP 定理描述了网络分区期间的行为,但 PACELC 定理 提供了更完整的情况:
NOTE{title=“PACELC Theorem”} “如果存在分区(P),分布式系统必须在可用性(A)和一致性(C)之间进行选择。否则(E),当系统正常运行时,必须在延迟(L)和一致性(C)之间进行选择。” :::这迫使人们进行细致入微的架构讨论。 系统在故障期间可能会为了可用性而牺牲一致性,但在正常操作期间优先考虑一致性而不是延迟。
2.2 分布式事务:Saga 模式
两阶段提交是同步的,不适合微服务。 Saga 模式通过本地事务和补偿操作来管理跨服务的数据一致性。
TIP{title=“Saga Pattern Example: E-commerce Order”}
Order Service:创建处于PENDING状态的订单,发布ORDER_CREATED事件Payment Service:处理付款,成功时发布PAYMENT_PROCESSEDInventory Service:更新库存,成功后发布INVENTORY_UPDATED4.“订单服务”:将订单更新为“已确认”失败处理: 如果库存失败,支付服务将通过退款进行补偿,订单服务将取消。 :::实施风格:
NOTE{title=“Saga Implementation Approaches”}
- 编排: 服务发布/订阅事件,无需中央协调员
- 编排: 中央编排器管理 saga 状态和补偿事务
2.3 事件溯源和 CQRS
这些模式构建了高度可扩展和可审计的系统。
- 事件溯源: 存储不可变事件而不是当前状态。 当前状态是通过重播事件得出的。
NOTE{title=“Event Sourcing Example”}
// 而不是存储余额:80// 存储事件序列:[{"type": "AccountCreated", "initialBalance": 0},{“类型”:“DepositMade”,“金额”:100},{“类型”:“提款”,“金额”:20}]// 当前余额 = 重播事件:::* CQRS(命令查询职责分离): 将写入模型与读取模型分开。
TIP{title=“CQRS Benefits”} *针对写入与读取进行优化的不同模型
- 命令和查询端的独立缩放
- 具有独立上下文的更好的领域建模
2.4 后端工程师的数据库内部结构
了解存储引擎和复制策略对于性能和可靠性至关重要。
NOTE{title=“MySQL Storage Engines”}
- InnoDB: 适用于 OLTP 工作负载的事务性、符合 ACID 的行级锁定
- MyISAM: 读取速度快,表级锁定,无事务(新应用程序已弃用) :::复制策略:
TIP{title=“Replication Models”}
- Leader-Follower: 所有写入领导者,从副本读取(最常见)
- Multi-Leader: 多个节点接受写入,必须解决复制冲突
- Leaderless(Cassandra 风格): 同时写入多个节点,仲裁读取 :::事务隔离级别 (SQL):
NOTE{title=“SQL Isolation Levels”}
- 读取未提交: 可以读取未提交的更改(脏读)
- 读已提交: 只读取已提交的更改(可能不可重复读取)
- 可重复读取: 事务内行值一致(可能存在幻读)
- **可串行化:**完全串行执行(一致性最高,性能最低)
3.0 弹性系统设计模式
弹性是指从故障中恢复并继续运作的能力; 优雅地处理故障而不是完全阻止它们。
3.1 断路器模式(深入)
断路器监视故障并防止分布式系统中的级联故障。
NOTE{title=“Circuit Breaker States”}
- 关闭: 正常运行,请求流经,监控失败
- 开放: 下游问题快速失败,重试前超时
- 半开放: 使用单个探测请求测试下游恢复
3.2 舱壁模式
将应用程序组件隔离到池中,以防止单一故障影响整个系统。
TIP{title=“Bulkhead Implementation”} 为每个下游服务使用单独的线程/连接池。 缓慢的服务 A 不会影响服务 B 的池,从而防止系统完全故障。
3.3 重试和超时模式
对于处理分布式系统中的瞬态故障至关重要。
CAUTION{title=“Retry Best Practices”}
- 超时: 积极的超时可防止资源耗尽
- 指数退避: 增加重试间隔(1s、2s、4s、8s)
- 抖动: 添加随机性以防止雷群问题
3.4 速率限制和减载
保护服务免于过载并实现优雅降级。
NOTE{title=“Rate Limiting Strategies”}
- 令牌桶: 请求时累积令牌,使用时删除
- 漏桶: 以固定速率处理请求,多余的被丢弃
- 甩负载: 在极端负载下拒绝低优先级请求
4.0 高级异步通信
异步模式是弹性、松散耦合的分布式系统的基础。
4.1 消息代理与事件日志
不同的消息传递方法具有不同的权衡。
TIP{title=“Message Broker Characteristics”}
- RabbitMQ: 智能路由、工作队列、消息代理模型
- Apache Kafka: 事件流、持久日志、多个消费者
4.2 幂等消费者
对于处理消息传递系统中的“至少一次”传递至关重要。
NOTE{title=“Idempotency Strategy”}
函数处理消息(消息){if (processedMessages.contains(message.id)) {返回; // 跳过重复}// 处理消息流程业务逻辑(消息);// 跟踪已处理的情况(具有业务逻辑的原子性)processedMessages.add(message.id);}
4.3 事务发件箱模式
解决事件驱动系统中的原子数据库更新和事件发布。
TIP{title=“Transactional Outbox Flow”}
- 更新业务实体并将事件插入单个本地事务中的发件箱 2.消息中继异步发布事件并标记为已发送
- 保证原子性,无需分布式事务
- 提供“至少一次”传递语义
5.0 大规模性能工程
识别和消除瓶颈的系统纪律。
5.1 缓存模式(深入)
超越基本缓存的高级缓存策略。
NOTE{title=“Caching Pattern Comparison”}
- Cache-Aside: 应用程序代码管理缓存、延迟加载
- Read-Through: 缓存处理从数据库加载的数据
- Write-Through: 缓存更新同步更新DB
- 写回: 缓存更新异步刷新到数据库 :::雷群缓解:
CAUTION{title=“Thundering Herd Problem”} 当缓存的项目过期时,数千个请求会同时错过缓存并淹没数据库。 解决方案:基于锁的重新获取,其中只有第一个请求加载数据,而其他请求则等待。
5.2 并发与并行
性能优化的基本概念。
TIP{title=“Workload Matching”}
- I/O 密集型工作负载: 异步模型(Node.js、asyncio)处理许多并发请求
- 受 CPU 限制的工作负载: 并行性(Go、Java)利用多个核心
5.3 分析和性能调优
你无法优化无法衡量的东西。
NOTE{title=“Performance Profiling”} 使用分析器生成火焰图来识别:
- 代码执行路径中的CPU热点
- 内存分配模式和泄漏
- I/O瓶颈和等待时间
6.0 高级 API 和安全架构
用于管理分布式环境中的复杂性的基础设施级解决方案。
6.1 API 网关模式
管理客户端和服务之间通信的单一入口点。
TIP{title=“API Gateway Responsibilities”}
- 路由: 将请求直接发送到适当的微服务
- 身份验证/授权: 在边缘验证凭据
- 速率限制: 强制执行使用策略和限制
- 请求转换: 调整下游服务的请求
- 可观察性: 集中记录和监控
6.2 服务网格
用于安全、快速、可靠的服务间通信的基础设施层。
NOTE{title=“Service Mesh Components”}
- Sidecar 代理: (Envoy) 处理每个服务的所有入站/出站流量
- 控制平面:(Istio、Linkerd)配置所有 sidecar 代理
- 功能: mTLS、流量管理、分布式跟踪、可观察性
6.3 零信任安全
分布式系统的“从不信任,总是验证”安全模型。
CAUTION{title=“Zero Trust Principles”}
- 基于身份的身份验证: 验证每个请求,无论来源如何
- 最低权限访问: 授予最低必要权限
- 假设违规: 设计预期内部妥协
6.4 JWT(深入):风险和缓解
了解 JWT 漏洞和安全实施。
CAUTION{title=“JWT Security Issues”}
- 算法混淆攻击: 欺骗服务器采用弱算法
- 缓解: 配置库仅接受强算法 (RS256)
- 令牌撤销: 无状态令牌无法失效
- 缓解: 在快速缓存中维护撤销拒绝列表
7.0 结论:有原则的工程师
2.0 版本已涉足分布式系统工程。 构建有弹性、可扩展的后端系统需要深入了解基本的权衡:延迟与一致性、可用性与正确性、速度与安全性。
高级后端工程师针对故障进行设计,假设网络敌意,并应用 Sagas、事件溯源、断路器和服务网格等模式。 最终的技能是对复杂性进行推理; 识别故障点、瓶颈和漏洞,以应用适当的缓解策略。