CloudNativeEra
  • Introduction
  • 名词解释
  • Computer Science
    • Computer Organization
      • CPU
      • 二进制、电路、加法器、乘法器
      • 编译、链接、装载
      • 存储器
      • IO
    • Operating System
      • 操作系统基础知识
      • 系统初始化
      • 进程管理
      • Everything about Memory
      • 文件系统
      • 并行编程
      • Linux
        • CPU
        • IO 多路复用
        • DMA IO and Linux Zero Copy
    • Computer Network
      • 网络相关命令
      • 评估系统的网络性能
      • 网络抓包
      • Linux 最多支撑的 TCP 连接
      • 网络虚拟化
      • DHCP 工作原理
    • Data Structure and Algorithm
      • 题目列表
      • Summarize
        • 方法总结
        • 二分思想
        • 树的演化
        • 算法思想总结
      • Data Structure
        • Data Struct - Array
        • Tree
        • Heap
        • Hash
        • 字符串
      • Algorithm
        • Sorting Algorithm
        • 查找
        • 贪心算法
        • 动态规划
        • 位运算
      • Practice Topics
        • Data Struct in SDK
        • Topic - Tree
        • Topic - Graph
        • Topic - 滑动窗口
        • 剑指 Offer 题解
    • 并发编程
      • 并发模式
      • 并发模型
  • 系统设计
    • 软件设计
      • 软件架构
      • 编程范式
      • 系统设计题
      • 设计原则
      • 计算机程序的构造和解释 SICP
    • 领域驱动设计
      • 应用:在线请假考勤管理
      • 应用: library
    • 微服务与云原生
      • Designing and deploying microservices
      • 容器技术
      • Docker
      • Etcd
      • Kubernetes
        • Kubernetes - Mapping External Services
      • Istio
      • 监控
    • 分布式系统
      • 分布式理论
      • 分布式事务
    • 后端存储设计
      • 缓存设计
      • 数据库架构设计
    • CI/CD
    • 设计最佳实践
    • 测试
    • 安全
    • 综合
      • 开发实践
      • 分布式锁
      • 分布式计数服务
      • 弹幕系统设计
      • 消息队列设计
      • 分布式ID生成算法
      • 限流设计
      • 网关设计
      • 通用的幂等设计
      • 分布式任务调度
        • Timer
        • ScheduledExecutorService
        • Spring Task
        • Quartz
      • 交易系统
      • 权限设计
  • 编程语言
    • 编程语言
    • C & C++
    • Java
      • JVM
        • JVM Bytecode
      • Java 核心技术
      • Java 8 新特性
      • Java 集合框架
      • Java NIO
      • 并发编程
        • 线程生命周期与线程中断
        • 三个线程交替打印
        • 两个线程交替打印奇偶
        • 优雅终止线程
        • 等待通知机制
        • 万能钥匙:管程
        • 限流器
        • 无锁方案 CAS
    • Java 源码阅读
      • Unsafe
      • 异步计算 Future
      • Java Queue
      • CoalescingRingBuffer 分析
      • Java Collections
        • PriorityQueue 分析
        • HashMap 分析
        • TreeMap
    • Golang
    • Python
  • 框架/组件/类库
    • Guava
      • Guava Cache
      • Guava EventBus
    • RxJava
    • Apache MINA
    • Netty
      • 网络 IO 模型
      • Netty 生产问题
    • Apache Tomcat
    • MyBatis
    • 限流框架
    • Spring Framework
      • Spring Core
      • Spring 事务管理
    • Spring Boot
    • Spring Cloud
      • Feign & OpenFeign
      • Ribbon
      • Eurake
      • Spring Cloud Config
    • FixJ
    • Metrics
    • Vert.x
  • 中间件
    • Redis
      • Redis 基础
        • Redis 数据结构设计与实现
        • Redis 高性能网络模型
      • Redis checklist
      • 应用案例 - Redis 数据结构
      • 应用案例 - Redis 缓存应用
      • 应用案例 - Redis 集群
      • Redis 客户端
      • Redis 生产案例
        • [译] 在 Redis 中存储数亿个简单键值对
    • MySQL
      • MySQL 基础
      • MySQL Index
      • MySQL Transaction
      • MySQL 优化
      • MySQL 内核
      • MySQL Command
      • MySQL Checklist
      • MySQL Analysis Tool
      • 实现 MySQL
    • State Machine
    • 数据库连接池
    • MQ
      • 高性能内存队列 Disruptor
      • Kafka
      • Pulsar
      • RocketMQ
        • Broker 的设计与实现
      • NSQ
  • 实际案例
    • 线上 Case
      • Request Aborted
      • MySQL - Specified key was too long
      • Java 应用 CPU 100% 排查优化
      • 频繁 GC 导致的 Java 服务不响应
      • 导出优化
  • 大数据
    • 流计算
    • Flink
  • 其他
    • 工具
    • 读书
      • 设计数据密集型应用
      • 实现领域驱动设计
      • 精通比特币
      • 提问的智慧
    • 论文
    • 工程博客
    • 阅读源码
    • 面试
      • 如何在最短的时间里对对方有个全面的了解
    • 分享
    • 软技能
    • Todo
  • Blog
    • #算法
      • 查找
      • 位运算
      • 树
    • #架构
      • 1- 通信
    • Design & Dev & Opt
      • High Performance Data structure Design
  • Tiny Project
    • A Simple WeChat-like Instant Messaging Platform
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 系统设计
  2. 综合

通用的幂等设计

如何设计一个具有通用性的幂等处理框架

一个操作如果多次任意执行所产生的影响,均与一次执行的影响相同,我们就称其为幂等。

幂等处理在一些关键的业务场景中非常重要,比如支付场景中的支付接口需要保证幂等:

当你给微信支付发送这个付款请求后,一个顺利的场景是不会有任何错误发生的,微信支付收到你的付款请求,处理所有转账,然后返回一个 HTTP 200 消息表示交易完成。

但是,当发送的支付请求并没有返回任何结果,那该怎么办?原因可能有很多:

发出去的请求可能就压根没有到达微信就超时了;可能请求达到了微信,微信进行处理,但是在收到回复前超时了;可能请求达到了微信,微信也处理了,也发了回复,但是这个时候网络中断,导致没有收到回复,等等

比如在 MQ 消费的场景中,需要保证消息消费的幂等性,在大部分的业务场景中是不允许消息重复的,MQ 的 Exactly Once 语义也是通过 At Least Once + 幂等 的方式实现的,可见幂等处理非常关键。

我们的应用一般都是:接口请求 + 超时重试,在正常情况下一切安好,当遇到超时时,客户端会执行请求重试,然而重试的原因多种多样,也是复杂度的来源。

幂等的实现有两个关键因素:

  1. 幂等令牌(Idempotency Key)。客户端和服务器端通过什么方式来识别,这实际上是同一个请求或是同一个请求的多次尝试。这往往需要双方有一个既定的协议,比如账单号或者交易令牌,这种在同一个请求上具备唯一标识的元素,这种元素通常由客户端生成。

  2. 确保唯一性(Uniqueness Guarantee)。服务器端用什么机制去确保同一个请求一定不会被处理两次,也就是微信支付如何确保,同一笔交易不会因为客户端发送两次请求就被处理多次。

实现幂等的方式有多种,但是需要根据自己的业务场景来选择何时的幂等处理方式:

  • 利用数据库,一般做法是幂等令牌所在的列添加唯一索引,防止数据重复插入;

  • 还有一种做法是使用状态管理(成功、失败、处理中),使用乐观锁的方式更新记录(update ... set ... where state="处理中"),或者使用版本号来控制等

  • 利用 Redis,Redis 的 setnx 具备实现幂等性的能力,但是使用 Redis 实现的幂等方案具备分布式系统的固有的问题,无法保证消息处理和幂等处理的原子性,这样会产生很多bug,所以使用 Redis 来实现幂等难度是最大的,而得到的好处是Redis的性能高(这个要看场景是否真的需要那么高的性能要求?)(2021.01 补充:Redis 做幂等处理真的性能高吗?这个要看业务场景,最近遇到一个问题:项目中有一个内部服务需要消费 MQ 的消息,但是我们需要保证幂等消费,最开始的做法是 redis + 数据库唯一索引,后来经过大量测试后发现,每次判断幂等时需要访问1次redis,基本要花费几ms的时间,然而在内部服务消费 MQ 时出现重复消息的概率是非常小的,为了这么小概率的事情引入了 Redis ,多了一次 Redis 访问却牺牲了性能(增加了几ms的访问延迟,会降低消息的消费速度),而且幂等 Key 占用了了大量的 Redis 内存,交易记录的 key 是很多的;后来直接去掉 Redis 这一层,直接利用唯一索引,重复数据直接丢弃,每秒消费消息的次数得到了提升)

  • 如果场景是类似于支付接口的场景,面向外部的 API,我们需要使用 Redis 来做幂等,Redis 缓存幂等 key

  • 在防止插入重复数据时,推荐的方案是(这是一种面向外部 API 的幂等解决方案,具体还要看场景):

    1. 使用 redis 作为接口锁,防止重复请求到达数据库,对数据库性能造成冲击(初步的幂等保证及数据库保护)

    2. 使用唯一键保证不插入重复数据(最后的兜底及最终保证)

幂等实现时容易出问题的地方:

  1. 幂等令牌谁来产生、什么时候产生、怎么产生,一般幂等令牌的产生可以使用分布式 ID 生成算法

  2. 幂等令牌有没有被误删的可能性

  3. 是否存在竞态条件

  4. 对请求重试的处理,一般可以考虑采用维护处理状态:成功、失败、处理中

  5. 多级幂等保证,如果存在多个系统调用,每个调用都需要保证幂等处理

分析了什么是幂等,幂等的要素,实现幂等的几种方式以及幂等处理易出现问题的地方,那么接下来就是如何实现一个通用的幂等处理框架,来简化幂等开发。

参考

其他

// WARN:使用 insert ignore 如果控制不好是会丢数据的
// https://www.yiibai.com/mysql/insert-ignore.html
// https://blog.csdn.net/ZYC88888/article/details/81741135
// 唯一索引冲突会抱的错
1062 - Duplicate entry 'yiibai.com@gmail.com' for key 'email' 
上一页网关设计下一页分布式任务调度

最后更新于4年前

这有帮助吗?

by 美团

GTIS 是美团使用的一种幂等解决方案 , . GTIS的实现思路是将每一个不同的业务操作赋予其唯一性。这个唯一性是通过对不同操作所对应的唯一的内容特性生成一个唯一的全局ID来实现的。基本原则为:相同的操作生成相同的全局ID;不同的操作生成不同的全局ID。

聊聊幂等
幂等性设计
如何处理消息消费过程中的消息重复
如何处理消息消费
RocketMQ 的消费幂等
分布式系统互斥性与幂等性问题的分析与解决
Talk is here