当前位置: 首页 > news >正文

亿级流量系统架构设计与实战(六)

微服务架构与网络调用

当某个业务从单体服务架构转变为微服务架构后,多个服务之间会通过网络调用形式形成错综复杂的依赖关系。

在微服务架构中 , 一个微服务正常工作依赖它与其他微服务之间的多级网络调用。

网络是脆弱的 , RPC 请求有较大的概率会遇到超时 、 抖动 、 断开连接等各种异常情况 , 这些都会直接影响微服务的可用性。

上游下游

当微服务 A 是微服务 B 的调用方时 , 我们称 B 是 A 的下游服务 , 而 A 是 B 的上游服务 。

  • 如上图,内容列表服务是个人页服务的下游服务,内容列表服务、内容服务、关系服务是计数服务的上游服务。

解决影响服务可用性的问题,从以下两方面考虑

  • 容错性设计
    • 要接受网络脆弱与下游服务质量不可靠的事实 , 并在进行服务设计时充分考虑相应故障产生时的容错方案 。
  • 流量控制
    • 既要对上游服务调用采取预防性策略,防止打垮我们的服务;
    • 也要对下游服务有感知与保护意识 , 当感知到下游服务的质量下滑甚至服务不可用时 ,及时通过自身保护下游服务。

重试与降级是容错性设计的具体表现形式。

熔断、隔离与限流则是流量控制的常见实现方式。

重试

对于服务间 RPC 请求遇到网络抖动的情况,最简单的解决办法就是重试。

幂等接口

超时可能出现在请求处理的多个阶段:

  • RPC 请求发送超时,此时下游服务并未收到 RPC 请求 。
  • RPC 请求处理超时,下游服务已经收到 RPC 请求,但是处理时间过长 。
  • RPC 响应报文超时,下游服务已经处理完 RPC 请求,但是响应报文超时未回复。

服务器是无法判断 RPC 请求是否被下游服务成功处理,只能假定最坏的情况:下游服务已经成功处理请求 ,但是我们的服务没有收到响应信息。

如果我们的服务要进行重试,那么下游服务必须保证再次处理同一请求的结果与用户预期相符。

怎样才算与用户预期相符呢 ?

举一个电商产品下单服务的例子。 用户选择购买价格为100 元的产品时 , 下单服务会调用用户账户服务的扣款接口 , 从用户的余额中扣除 100 元 。

假如用户账户服务已经成功从用户的余额中扣除 100 元,但是对下单服务请求的响应超时 ,这时下单服务将重试调用扣款接口 。 如果用户的余额再次被扣除 100 元 , 即用户实际支付200 元才下单了这个价格为 100 元的产品 , 那么这就不是与用户预期相符的情况 。

理论上 ,无论重试调用扣款接口多少次 , 用户的余额最终仅应该被扣除 100 元 。

幂等

幂等:幂等指的是对于某系统接口,无论同一请求被重复执行多少次,都应该与执行一次的结果相同

可以被重试调用的接口应该满足幂等性,只有幂等接口可以被安全地重试调用

  • 读性质的 RPC 接口 ( 即读接口 ) 天然都是幂等接口, 因为无论读接口执行多少次都不会改变数据 ;
  • 写性质的 RPC 接口 ( 即写接口 ) 会改变数据 , 所以需要查看多次改变数据的结果是否与一次改变数据的结果相同 。
    • 以 SQL 语句为例:
    • 覆盖操作:UPDATE table1 SET col1 = X WHERE col2 = Y,执行多次语句 col1 仍为 X,是幂等操作。
    • 更新操作:UPDATE table1 SET col1=col1 + 1 WHERE col2 = Y,每执行一次 col1 都会发生变化,不幂等。
    • 插入操作:INSERT INTO table1 (col1,col2) VALUES(X,Y),执行多次会插入多条数据,不幂等。

涉及非幂等写操作的接口可以通过幂等性被设计成幂等接口。

数据库操作设计幂等

插入操作:对数据库的相关数据表设置唯一键。重复调用此接口时,数据库会报出 “ 键重复 ” 错误 , 表示此数据已经被插入。

更新操作:借鉴 CAS ( Compare And Swap , 比较与替换)的思想 , 为行数据引入数据版本号 , 重写 SQL 语句如下 :UPDATE tablel SET col1 = col1 + l WHERE version = X AND col2 = Y

通用幂等设计

对于每个请求,使用分布式唯一 ID 作为 UUID,同时在接口侧保存已处理的请求记录

请求调用接口时,由接口侧根据请求的唯一标识查询已处理的请求记录,若找到,说明已经处理过,直接返回即可。

Redis 分布式锁

接口使用 Redis 的 SET 命令保存已处理请求的 UUID,并结合 NX 参数保证:当且仅当键不存在时才成功写入 , 否则不写入。

  1. 接口接收请求后 , 先尝试在 Redis 中执行 SET UUID NX 命令写入请求的 UUID 。
  2. 如果 Redis 写入成功 , 则说明此请求未被接口处理过 , 接口可以真正处理此请求

相关文章:

  • 【MySQL】事务(重点)
  • 【计算机视觉】OpenCV实战项目:FunnyMirrors:基于OpenCV的实时哈哈镜效果实现技术解析
  • PyTorch API 9 - masked, nested, 稀疏, 存储
  • Linux 阻塞和非阻塞 I/O 简明指南
  • 复习javascript
  • Python_day21
  • 基于大模型的新型隐球菌脑膜炎智能诊疗全流程系统设计与实现的技术方案文档
  • 青少年编程与数学 02-019 Rust 编程基础 05课题、复合数据类型
  • 【从零实现JsonRpc框架#1】Json库介绍
  • Edububtu 系统详解
  • ASCLL码(T^T
  • 前端进化论·JavaScript 篇 · 数据类型
  • Python面向对象编程:初识类与对象
  • 数据库故障排查指南:从连接问题和性能优化
  • 逆向学习笔记(代码)
  • leetcode504.七进制数
  • Java基础 5.10
  • JavaSE核心知识点02面向对象编程02-05(方法)
  • 《向上生长》读书笔记day5
  • Dockers部署oscarfonts/geoserver镜像的Geoserver
  • 2025上海十大动漫IP评选活动启动
  • 印方称所有敌对行动均得到反击和回应,不会升级冲突
  • 东方红资管官宣:41岁原国信资管董事长成飞出任新总经理
  • 央行:下阶段将实施好适度宽松的货币政策
  • 协会:坚决支持司法机关依法打击涉象棋行业的违法行为
  • 青年与人工智能共未来,上海创新创业青年50人论坛徐汇分论坛举办