草庐IT

项目实战:并发下保证接口的幂等性

gezishan007 2023-04-18 原文

1.1 幂等性的概念

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

  • 多次请求一个资源时,应该有相同的结果(网络超时等问题除外)。 也就是说,一次请求被多次重复执行对资源自身的影响与第一次执行的影响相同。
  • 例如:用户查询结果多次扣款。 流水记录变成两个就是没有保证接口的幂等性。

1.2 防重设计和幂等设计

  • 防重设计和幂等设计在很多情况下是可以通用的,解决方案也比较类似,区别在于:
    • 防重设计:避免产生重复数据,对返回结果没有限制。
    • 幂等设计:避免产生重复数据,要求每次请求都返回同样的结果。

1.3 常见场景

  • FORM 表单,按钮重复点击,产生 ID 不一样的两条重复数据。
  • 浏览器页面返回按钮,此时数据依然存在,重复提交。
  • 接口重试机制(超时问题),重试过程中会产生重复数据。
  • 微服务调用,网络导致请求失败,feign 触发重复机制。
  • MQ 同一条消息重复读取。

1.4 汇总分析(数据库的角度

  • select 语句在数据不变的情况下,多次查询的结果相同,天然幂等操作。
  • insert 语句重复提交的情况下,会产生数据的重复。
  • delete 语句一次或者多次结果都是删除数据(已删除的数据不存在,返回0。 已删除的数据有多个,结果有多个。 删除操作也有乘方等属性)。
  • update 语句在大多数场景中的结果相同,但增量修改需要乘方等保证。例如表中存在 version 字段,此时更新时不是幂等。

1.5 保障幂等方式

1.5.1 唯一性索引

alter table xxx add UNIQUE KEY (key);
  • 异常精准捕获,以便返回数据。
  • DuplicateKeyException 异常。
  • MySQLIntegrityConstraintViolationException 异常。

1.5.2 单独表:防重复

  • 核心:防重表和业务表必须在同一个事务中。
  • 和唯一性索引的主要区别在于,并非所有的场景都不允许产生重复的数据。例如逻辑删除。

1.5.3 status 机制

  • 根据影响行数来判断是否更新成功。
update table set status = 1 where id = 1 and status=2;

1.5.4 数据库悲观锁

select * from table id = 1;
select * from table id = 1 for update;
  • 首先执行一遍查询,如果此时不满足条件,就直接返回了,无需锁住单条数据。
  • 悲观锁之后,再进行逻辑判断。
  • 执行业务操作。
  • 备注:mysql 存储引擎选用 innodb ,悲观锁字段最好是主键或唯一索引,不然可能会锁表。

1.5.5 数据库乐观锁(version )

select id,version,amount from table id = 1;
-- version 查询结果为 0
update table set amount = amount + 1,version = version + 1 
where id=1 and version = 0;
  • 根据sql的执行结果影响行数判断是否执行成功。

1.5.6 token机制

  1. 生成全局唯一的 token,token 放到 redis 中(注意设置过期时间),页面跳转时获取 token 。
  2. 请求时携带token ,执行提交逻辑。

1.5.7 分布式锁

  • 通过 setNx、set 命令或者 Redission 第三方的框架。

1.6 小结

  • 幂等不仅对一次(或多次)请求没有副作用,对资源也没有副作用。 例如,select 对数据库不会产生任何影响,因为没有被insert、update、delete。
  • 网络超时等问题不在幂等讨论范围内。
  • 幂等性是系统服务对外约定而不是实现的,约定如果接口调用成功,则外部多次调用对系统的影响是一致的。 声明为幂等的服务,认为外部调用失败是常态,失败后一定会有重试。
    更多精彩欢迎关注微信公众号《格子衫007》!

有关项目实战:并发下保证接口的幂等性的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  4. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  5. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  6. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  7. ruby - 如何在 Ruby 字符串中插入项目符号字符? - 2

    我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195

  8. ruby - 在 Rails 项目中测试本地版本的 gem - 2

    我的Rails站点使用了一个确实不是很好的gem。每次我需要做一些新的事情时,我最终不得不花费与向实际Rails项目添加代码一样多的时间来为gem添加功能。但我不介意,我将我的Gemfile设置为指向我的gem的GitHub分支(我尝试提交PR,但维护者似乎已经下台)。问题是我真的没有找到一种合理的方法来测试我添加到gem的新东西。在railsc中测试它会特别好,但我能想到的唯一方法是a)更改~/.rvm/gems/.../foo。rb,这看起来不对或者b)升级版本,推送到Github,然后运行​​bundleup,这除了耗时之外显然是一场灾难,因为我不确定我所做的promise是否正

  9. ruby-on-rails - 获取并发布相同匹配项的请求 - 2

    在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g

  10. ruby - 合并 nanoc 中的项目 - 2

    我一直在尝试使用nanoc用于生成静态网站。我需要组织一个复杂的排列页面,我想让我的内容保持干燥。包含或合并的概念在nanoc系统中如何运作?我已阅读文档,但似乎找不到我想要的内容。例如:我如何获取两个部分内容项并将它们合并到一个新的内容项中。在staticmatic您可以在您的页面中执行以下操作。=partial('partials/shared/navigation')类似的约定在nanoc中如何运作? 最佳答案 这里是nanoc的作者。在nanoc中,部分是布局。因此,您可以拥有layouts/partials/shared/

随机推荐