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

大厂最佳实践 | Stripe 如何防止重复付款

为什么扣了我两笔钱?

2010年,美国加利福尼亚州的两兄弟打算创办一家公司,但他们发现建立网上支付十分困难。于是,他们决定开发一款在线支付服务,并将其命名为Stripe。

随着用户数量的不断增长,重复付费问题逐渐显现。所谓的重复付费指的是对同一笔交易错误地向用户收取了两次甚至多次费用。可能造成重复付费的原因很多,下面看一种典型的场景。

当客户端发送一个请求后,服务器已成功处理该请求。但在返回响应给客户端之前,由于网络故障导致响应没有成功发送给客户端。

但是客户端不知道请求已被成功处理,它只要没收到响应,就当作请求处理失败,因此就会重试,这种情况下就会出现重复付款。

除此之外,框架的一些重试机制同样会导致重复付费。

幂等 API

为了解决重复付费问题,他们决定采用最简单也是最有效的解决方案:他们决定将API设计成幂等的。

幂等 API可以保证同一个请求可以重试多次且不会产生副作用。这意味着即使经过多次重试,这些请求也只会被处理一次。Stripe 实现幂等 API 的方式如下:

1.幂等key

幂等key是一个唯一的标识符,用来标识每一次请求。通过使用幂等key,服务器可以识别出同一个请求,即使这个请求被重复发送多次,也只会处理一次。

客户端(比如用户的浏览器或手机应用)发起支付请求时,会生成一个唯一的字符串作为幂等key。这个字符串通常是一个UUID(通用唯一标识符)。此后客户端发送请求时需要将这个key随请求的 HTTP 头部一起发送。

POST /pay
Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000
Content-Type: application/json
{"amount": 100,"currency": "USD","card_number": "4111111111111111","expiry_date": "12/23","cvv": "123"
}

服务端接收到请求后,先检查这个幂等key是否已经存在于数据库(或缓存)中,如果不存在,说明这是一个新的请求,服务器处理请求,并将幂等key和响应结果一起缓存在数据库中(如Redis)。如果幂等key存在于数据库中,说明这个请求之前已经被处理过了。服务器直接返回缓存中的处理结果,而不再重复处理。

如果服务器在处理请求时发生错误,他们会使用ACID数据库的事务回滚功能来撤销交易。幂等性key会在内存数据库中保留24小时(这个时间根据自己业务确定),以便在这个时间段内可以重试失败的请求。过了24小时后,幂等性key会被移除,这样可以减少存储成本,并允许在这个时间段后重复使用同一个key。

为了帮助您理解,我再举一个更具体的例子,假设你正在用Stripe支付一笔费用,但由于网络问题,没有响应回来,你以为付款失败了,于是你就重新点击了一次支付按钮。

  • 第一次请求:服务器生成一个幂等性键 12345,并处理这个请求。请求成功后,响应会被缓存,并且幂等性键 12345 被存储在内存数据库中。

  • 第二次请求:由于你不确定第一次是否成功,所以又发了一次请求。这次请求带着相同的幂等性键 12345。服务器查询内存数据库,发现这个请求已经处理过,因此直接返回缓存的响应,而不会再次处理请求。

2. 重试失败的请求

虽然使用幂等key之后,重试变的安全了,不会造成重复付费问题了,但是过多的重试请求可能会导致服务器过载。

因此系统重试使用了指数退避算法:每次重试之间的等待时间会逐次增加。

此外,为了防止大量客户端同时发起重试请求,导致服务器过载。还在指数退避的基础上给重试等待时间增加了随机时间,这称为抖动。

为了更好的理解指数退避算法和抖动,举两个例子来说明。

示例1:指数退避

第一个例子是用来解释指数退避算法,假如你在用Stripe支付,但服务器暂时不可用,导致请求失败。

  • 第一次请求失败:系统等待1秒后重试。
  • 第二次请求失败:系统等待2秒后重试。
  • 第三次请求失败:系统等待4秒后重试。
  • 依次类推,等待时间逐次增加。

示例2:抖动

这个例子是用来解释抖动。假设有很多用户同时在用Stripe支付,服务器暂时不可用。

  • 用户A的请求失败后,系统会根据指数退避算法等待一段时间,然后加上一个随机的额外等待时间。例如,第一次等待1秒加0.5秒的随机时间(总共1.5秒)。
  • 用户B的请求失败后,系统等待1秒加0.3秒的随机时间(总共1.3秒)。
  • 用户C的请求失败后,系统等待1秒加0.7秒的随机时间(总共1.7秒)。

由于加入了抖动,不同用户的重试时间就会有所不同,这样可以防止服务器在同一时间受到大量重试请求的冲击,从而减轻服务器的压力,防止过载。

幂等性对于可靠的在线支付至关重要。它给系统带来了安全性和更好的用户体验。Stripe,作为全球最大的在线支付服务提供商之一,正是通过这样的方法确保其支付系统的可靠性和稳定性。

相关文章:

大厂最佳实践 | Stripe 如何防止重复付款

为什么扣了我两笔钱? 2010年,美国加利福尼亚州的两兄弟打算创办一家公司,但他们发现建立网上支付十分困难。于是,他们决定开发一款在线支付服务,并将其命名为Stripe。 随着用户数量的不断增长,重复付费问题…...

Raspberry Pi Pico 2 上实现:实时机器学习(ML)音频噪音抑制功能

Arm 公司的首席软件工程师 Sandeep Mistry 为我们展示了一种全新的巧妙方法: 在 Raspberry Pi Pico 2 上如何将音频噪音抑制应用于麦克风输入。 机器学习(ML)技术彻底改变了许多软件应用程序的开发方式。应用程序开发人员现在可以为所需系统整…...

安全自动化和编排:如何使用自动化工具和编排技术来提高安全操作效率。(第二篇)

深入理解Kubernetes环境中的安全自动化与编排(第二篇) 1. 引言 Kubernetes作为现代容器编排平台的主流选择,正在被越来越多的企业用于部署和管理其容器化应用。在Kubernetes环境中实施安全自动化与编排,既能够提升系统的安全性&…...

HarmonyOS WebView

HarmonyOS WebView Web组件提供基础的前端页面加载的能力,包括加载网络页面、本地页面、html格式文本数据。Web组件提供丰富的页面交互的方式,包括:设置前端页面深色模式,新窗口中加载页面,位置权限管理,C…...

解决elementUI表格里嵌套输入框,检验时错误信息被遮挡

1.表格 自定义错误信息显示div <el-form-item label"租赁价格" prop"supplierId"><el-table-column prop"salePrice" label"销售价" align"center"><template slot-scope"scope"><el-form-…...

Unity读取Android外部文件

最近近到个小需求,需要读Android件夹中的图片.在这里做一个记录. 首先读写部分,这里以图片为例子: 一读写部分 写入部分: 需要注意的是因为只有这个地址支持外部读写,所以这里用到的地址都以 :Application.persistentDataPath为地址起始. private Texture2D __CaptureCamera…...

【5.3 python中的元组】

5.3 python中的元组 Python中的元组&#xff08;Tuple&#xff09;是一种用于存储多个项目&#xff08;可以是不同类型&#xff09;的序列数据结构&#xff0c;但它与列表&#xff08;List&#xff09;不同&#xff0c;主要区别在于元组是不可变的&#xff08;immutable&#…...

Debezium报错处理系列之第116篇:Caused by: java.lang.NumberFormatException: null

Debezium报错处理系列之第116篇:Caused by: java.lang.NumberFormatException: null 一、完整报错二、错误原因三、解决方法Debezium从入门到精通系列之:研究Debezium技术遇到的各种错误解决方法汇总: Debezium从入门到精通系列之:百篇系列文章汇总之研究Debezium技术遇到的…...

【启明智显技术分享】工业级HMI芯片Model3C/Model3A开发过程中问题记录笔记二

一、Model3C/Model3A芯片介绍 Model3C/Model3A是启明智显针对工业、行业以及车载产品市场推出的一款高性能、低成本的工业级HMI&#xff08;Human-Machine Interface&#xff0c;人机界面&#xff09;芯片。两颗芯片硬件PIN TO PIN&#xff1b;区别在于内置的PSRAM大小不同。该…...

Python 函数返回yield还是return?这是个问题

如果你刚入门 Python&#xff0c;你可能之前没有遇到过yield。虽然它看起来很奇怪&#xff0c;但它是你编码工具库中的一个重要工具。在成为 Python 大师的道路上&#xff0c;你必须掌握它。 返回列表的函数 假设有一个函数&#xff0c;它可以一次性生成一系列值&#xff0c;…...

Linux系统性能调优

Linux系统性能调优是一个复杂而细致的过程&#xff0c;涉及硬件、软件、内核参数、进程管理等多个方面。以下将从多个角度详细介绍Linux系统性能调优的技巧&#xff0c;旨在帮助用户提升系统的运行效率和稳定性。 一、硬件层面的调优 内存升级&#xff1a; 增加物理内存可以减…...

PHPStorm 环境配置与应用详解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; PHPStorm 是 JetBrains 出品的一款专业 PHP 集成开发环境&#xff08;IDE&#xff09;&#xff0c;凭借其智能的代码补全、调试功能、深度框架支持和前端开发工具&#xff0c;为用户提供了丰富的功能和工具…...

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载 各种文本文件预览&#xff08;pdf, xlsx, docx, cpp, java, sql, py, vue, html, js, json, css, xml, rust, md, txt, log, fa, fasta, tsv, csv 等各种文本文件&#xff09; 其中 除p…...

【Qt】QPluginLoader 类学习

文章目录 一、简介二、常用方法2.1 构造函数2.2 动态加载方法——load()2.3 检查是否加载成功——isLoaded()2.4 访问插件中的根组件——instance()2.5 卸载插件——unload() 一、简介 QPluginLoader 类在运行时加载插件。 QPluginLoader 提供对Qt插件的访问。Qt插件存储在共享…...

DataGear 企业版 1.2.0 发布,数据可视化分析平台

DataGear 企业版 1.2.0 已发布&#xff0c;欢迎体验&#xff01; http://datagear.tech/pro/ 企业版 1.2.0 修复严重漏洞&#xff0c;新增文件源管理模块&#xff0c;新增JWT统一登录支持&#xff0c;MQTT数据集主题支持通配符&#xff0c;具体更新内容如下&#xff1a; 新增…...

为啥https比http慢

Https有ssl的握手 HTTP没有 HTTPS TCP 和HTTP 的TCP 时间差不是很大 HTTPS请求中,ssl所占的时间比例是请求时间总和93.37%, HTTPS请求中,ssl的请求会是tcp请求的14倍,而HTTP中没有这个问题 建议:对安全要求不是很高的,不要使用https请求 图例...

软件测试需要具备的基础知识【功能测试】---后端知识(三)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 为了更好的学习软件测试的相关技能&#xff0c;需要具备一定的基础知识。需要学习的基础知识包括&#xff1a; 1、计算机基础 2、前端知识 3、后端知识 4、软件测试理论 后期分四篇文章进行编写&#xff0c;这是第三篇 …...

详解 Redis 队列 实现

Redis 是一个高性能的键值存储系统&#xff0c;它的多种数据结构使其能够以不同方式实现队列&#xff0c;包括普通队列、延时队列和异步队列的介绍和示例。 介绍 Redis 的 List 数据结构可以用来实现普通的队列。 生产者使用 LPUSH 或 RPUSH 命令将消息添加到列表的头部或尾部…...

分析SQL的count(*)并优化

最近优化过几个慢查询接口的性能&#xff0c;总结了一些心得体会拿出来跟大家一起分享一下&#xff0c;希望对你会有所帮助。 我们使用的数据库是Mysql8&#xff0c;使用的存储引擎是Innodb。这次优化除了优化索引之外&#xff0c;更多的是在优化count(*)。 通常情况下&#…...

Java学习日记(day18)

一、软件的结构 C/S (Client - Server 客户端-服务器端) 典型应用&#xff1a;QQ软件 &#xff0c;飞秋&#xff0c;印象笔记。 特点&#xff1a; 必须下载特定的客户端程序。服务器端升级&#xff0c;客户端升级。 B/S &#xff08;Broswer -Server 浏览器端- 服务器端&a…...

oh-my-prompt:模块化终端提示符引擎的设计、配置与性能优化

1. 项目概述&#xff1a;一个为现代终端量身定制的提示符引擎如果你和我一样&#xff0c;每天有超过一半的工作时间是在终端&#xff08;Terminal&#xff09;里度过的&#xff0c;那么一个高效、美观且信息丰富的命令行提示符&#xff08;Prompt&#xff09;绝对能让你事半功倍…...

蒙特卡洛方法赋能智能体决策:原理、实现与工程实践

1. 项目概述&#xff1a;一个为智能体注入“蒙特卡洛”思想的工具箱最近在探索智能体&#xff08;Agent&#xff09;开发时&#xff0c;我一直在思考一个问题&#xff1a;如何让智能体的决策过程不那么“一根筋”&#xff1f;我们常见的基于规则或简单LLM调用的智能体&#xff…...

程序员连夜带团队跑路,省了23万:这AI太贵,真的用不起了

好的&#xff0c;收到&#xff01;你说得对&#xff0c;之前的风格可能信息密度太高&#xff0c;有点“极客狂欢”的味道。 今天咱们换个姿势&#xff0c;用唠家常、说人话的方式&#xff0c;把5月11日AI圈最有趣、最魔幻的几件事儿聊明白。保证你在地铁上、蹲坑时&#xff0c;…...

【职业发展】程序员成长路径:从初级到架构师的进阶指南

【职业发展】程序员成长路径&#xff1a;从初级到架构师的进阶指南 引言 程序员的职业发展是一个持续学习和成长的过程。从初级程序员成长为技术架构师&#xff0c;需要经历多个阶段的积累和蜕变。本文将详细分析程序员成长的各个阶段&#xff0c;帮助你规划职业发展路径。 …...

Java开发者收藏 | 你的经验不是负担,而是转型AI应用开发的加速器!

本文为Java开发者提供了清晰的AI应用开发转型路径。强调Java后端经验在AI领域是宝贵财富而非负担&#xff0c;并介绍了拥抱AI的优势。文章提出了分阶段学习路线&#xff0c;涵盖基础概念、框架选型&#xff08;Spring AI、LangChain4j、Spring AI Alibaba&#xff09;、可视化工…...

LSP4J-MCP:连接语言服务器与AI的协议桥接器实践

1. 项目概述&#xff1a;当LSP遇上MCP&#xff0c;一场开发工具链的“协议融合”如果你是一名长期与IDE打交道的开发者&#xff0c;无论是写Java、TypeScript还是其他语言&#xff0c;大概率都听说过或者用过语言服务器协议。它让VS Code、IntelliJ IDEA这些编辑器能理解代码、…...

经验小波变换(EWT):从理论基石到信号分解实战

1. 经验小波变换&#xff08;EWT&#xff09;的前世今生 我第一次接触EWT是在处理一段轴承振动信号时。当时用传统EMD方法分解出的IMF分量里&#xff0c;高频噪声和故障特征频率完全混在一起&#xff0c;就像把咖啡和牛奶搅成了拿铁——虽然都是白色液体&#xff0c;但根本分不…...

从样式覆盖到版本升级:全面解析Antd表格固定列对齐问题的解决路径

1. 问题复现&#xff1a;当Antd表格固定列开始"跳舞" 第一次遇到Antd表格固定列错位问题时&#xff0c;我正喝着咖啡调试一个后台管理系统。突然发现表格右侧的固定列像被施了魔法——表头和内容列完全错开&#xff0c;活像跳着蹩脚的探戈。这种问题在Antd 3.x版本中…...

本地化AI编码助手codex-assistant:部署、实战与安全指南

1. 项目概述&#xff1a;一个本地化的AI编码助手最近在折腾一个挺有意思的开源项目&#xff0c;叫codex-assistant。简单来说&#xff0c;它就是一个能让你用自然语言直接驱动本地代码任务的工具。想象一下&#xff0c;你对着一个命令行窗口说“给我写个Python函数&#xff0c;…...

别再手动折腾了!用Stack Builder一键搞定PostGIS 2.1 for PostgreSQL 9.2 (Windows 64位)

告别繁琐配置&#xff1a;用Stack Builder轻松部署PostGIS空间数据库 在Windows环境下配置PostgreSQL的空间扩展PostGIS&#xff0c;传统方式往往需要手动下载安装包、配置环境变量、执行SQL脚本等一系列操作。对于刚接触空间数据库的开发者来说&#xff0c;这个过程既耗时又容…...