网站建设阶段推广策略,推销产品的万能句子,响应式布局的原理,asp网站的缺点文章目录 一、防重与幂等的区别二、幂等性的应用场景三、幂等性与防重关系四、处理流程 一、防重与幂等的区别
防重与幂等是在 Web 应用程序和分布式系统中重要而又非常常见的问题。
防重 防重是指在多次提交同样的请求过程中#xff0c;系统会检测和消除重复的数据#xf… 文章目录 一、防重与幂等的区别二、幂等性的应用场景三、幂等性与防重关系四、处理流程 一、防重与幂等的区别
防重与幂等是在 Web 应用程序和分布式系统中重要而又非常常见的问题。
防重 防重是指在多次提交同样的请求过程中系统会检测和消除重复的数据确保相同的数据只会被处理一次从而避免不必要的重复操作或产生错误的结果。防重通常指人为多次提交请求、系统超时等原因数据重复处理防止重复处理产生错误。
幂等 幂等是指对同一操作进行多次执行所产生的结果和执行一次的结果是相同的。换句话说无论进行多少次相同的操作最终的结果都是一致的。在计算中幂等操作不会因为重复执行而导致状态的变化。幂等性通常在设计和实现API、网络通信等场景中具有重要意义因为它保证了对同一资源或操作的多次请求不会产生意外的副作用。
举例HTTP的幂等性 • HTTP GET 方法用于获取资源不应有副作用所以是幂等的。比如GET http://www.bank.com/account/123456不会改变资源的状态不论调用一次还是 N 次都没有副作用。请注意这里强调的是一次和 N 次具有相同的副作用而不是每次 GET 的结果相同。 GET http://www.news.com/latest-news这个 HTTP 请求可能会每次得到不同的结果但它本身并没有产生任何副作用因而是满足幂等性的。
• HTTP POST 方法用于创建资源所对应的 URI 并非创建的资源本身而是去执行创建动作的操作者有副作用不满足幂等性。比如POST http://www.forum.com/articles的语义是在http://www.forum.com/articles下创建一篇帖子HTTP 响应中应包含帖子的创建状态以及帖子的 URI。两次相同的 POST 请求会在服务器端创建两份资源它们具有不同的 URI所以POST 方法不具备幂等性。
二、幂等性的应用场景
幂等性在分布式系统和网络通信中广泛应用。以下是一些常见的应用场景 交易处理 在金融系统中交易处理通常需要保证幂等性以防止重复执行交易或产生不一致的结果。 支付系统 支付操作需要保证幂等性确保多次支付请求不会导致用户重复支付或多次扣款。 订单处理 在电商平台中订单处理需要具有幂等性以避免订单重复创建或多次处理。 消息处理 消息队列系统中消费者需要确保处理消息的幂等性防止消息重复处理或丢失。 API设计 在设计RESTful API时应该考虑接口的幂等性以防止客户端多次提交相同的请求。 数据库更新 数据库操作中更新操作需要具有幂等性确保多次更新不会产生重复结果或破坏数据一致性。
三、幂等性与防重关系
总结起来防止重复处理是为了避免相同请求或操作的重复执行而幂等性是一种特性保证相同的操作在多次执行时会得到相同的结果并且不会对系统状态产生副作用从而能够帮助实现防止重复处理的目标。
举例来说一个更新用户信息的操作如果是幂等的那么多次执行相同的更新操作不会产生副作用用户信息也不会发生额外的改变。因此防止重复处理的一个常见策略是将更新用户信息的操作设计成幂等的这样即使多次收到相同的更新请求也不会对用户信息产生重复的更新。
看起来防重与幂等似乎在说同一件事情但其实又有不同的区分。 幂等性强调一个操作的重复执行不会改变最终结果而防重则关注于避免在处理过程中重复处理相同的数据或操作防重对接口处理结果没有要求。虽然它们是不同的概念但在分布式场景下组合使用防重与幂等设计可以更好地保证系统的可靠性和正确性。特别是在面对高并发请求的场景下合理有效的设计对于系统的正常运行非常重要。
下面我们看下如何设计通用的防重幂等系统。
四、处理流程
常见web请求包含客户端接口请求、服务调用请求、MQ消费等场景我们把这些请求方统称为客户端对应的处理方称为服务端。
对于幂等性的处理流程来说这样来看防重主要分三步 确定唯一请求标识通过唯一标识服务端根据标识判断是否重复请求。 客户端控制避免重复请求 服务端幂等性处理说白了就是要过滤一下已经收到的请求。要做到这个事我们需要一个存储来记录收到的请求唯一标识。当收到交易请求的时候我们就会到这个存储中去查询。如果查找到了那么就不再做查询了并把上次做的结果返回。如果没有查到那么我们就记录下来。
大概流程如下 上面流程有个问题如果让 100% 的请求都到这个存储里去查一下这会导致处理流程变得很慢。所以最好是当这个存储出现冲突的时候会报错。也就是说我们收到交易请求后直接去存储里记录这个 ID相对于数据的 Insert 操作如果出现 ID 冲突了的异常那么我们就知道这个之前已经有人发过来了所以就不用再做了。比如数据库中你可以使用 insert into … values … on DUPLICATE KEY UPDATE … 这样的操作。对于更新的场景来说如果只是状态更新可以使用如下的方式。如果出错要么是非法操作要么是已被更新要么是状态不对总之多次调用是不会有副作用的。
update table set status “paid” where id xxx and status “unpaid”;
网上还有 乐观锁、版本号等其他方式这些都不标准我们希望我们有一个标准的方式来做这个事所以最好还是用一个 ID。因为我们的幂等性服务也是分布式的所以需要这个存储也是共享的。这样每个服务就变成没有状态的了。但是这个存储就成了一个非常关键的依赖其扩展性和可用性也成了非常关键的指标。
对此一般的幂等性的设计如下。
1. 确定唯一请求标识 有唯一标识的需要把唯一标识带上 唯一标识通常是业务的唯一ID这种情况通常用于状态变更操作。比如取消订单场景订单ID就是唯一标识 无业务唯一ID但是有操作记录的操作记录可以充当唯一标识。这种情况通常是调用下游时先生成本地操作记录然后调用下游将操作记录ID充当唯一标识。 没有唯一标识的我们创造唯一标识 在表单中添加一个隐藏的字段或在请求头中添加一个特定的标识token分布式ID。服务端在处理请求时根据请求标识来判断是否为重复请求如果请求标识已经存在或已被使用则拒绝处理该请求。 通过其他字段串行化处理服务端生成唯一标识。比如商品购买可以通过userIdproductId加锁以用户、商品维度加锁串行化处理服务端接收请求时先加锁然后生成订单ID进行业务处理业务处理完成后释放锁。
2.客户端防止重复提交 前端页面可以在提交后页面控制按钮禁止点击防止多次点击 上游服务接口避免重复调用下游对于超时场景可以让下游提供查询接口判断处理状态避免重复调用。 MQ尽量符合exactly once 语义
3.服务端幂等处理 为了实现幂等性可以采用以下处理流程
虚线非必须 获取唯一标识 在每个请求中添加唯一标识例如通过隐藏字段或请求头。 客户端向服务端请求带上唯一标识 并发控制分布式锁 服务端收到请求后根据标识判断是否为重复请求。同时记录已处理的请求标识。 通过分布式锁 通过分布式锁Redis防止重复请求如果并发请求可以拒绝重复请求。 乐观锁和版本号 在数据库中使用乐观锁机制来实现幂等性。在每次请求之前先读取数据的版本信息并在更新数据时检查版本号是否匹配。如果版本号不匹配说明数据已被其他请求修改可以拒绝重复请求。 业务数据处理 我们先根据唯一标识去存储中去查询。如果查找到了那么就不再做查询了并把上次做的结果返回。如果没有查到那么我们就进行业务处理并把唯一标识记录下来。 如果有操作流水建议基于操作流水做幂等并将幂等号作为唯一性约束确保唯一性。如果没有流水那么基于状态机也是可以的。 不管怎么样数据库的唯一性约束都要加好这是系统的最后一道防线。万一前面的锁失效了这里也能控制得住不会产生脏数据。