高可用系列二:绝对核心——服务请求幂等

服务请求幂等,简单地解释可以为同一次请求,因为各种原因重试时得到的结果一致或者可被识别,这里的结果一致指的是对于平台数据的变更影响,比如重复提交同一订单,会不会生成重复订单。从上一篇(高可用系列一:高可用问题是如何产生的)分析可以看出,请求幂等在高可用场景是非常重要的一环。

先从请求分析,一般请求可分为查询类、更新类和新增类:

  • 查询类:因为不存在数据变更,不存在幂等问题;
  • 更新类:更新虽然存在数据变更,但一般都通过特定条件,此时不存在单接口幂等问题,但可能存在ABA问题,不在本文讨论范围内;
  • 新增类:新增类存在幂等问题。

解决方案一:使用唯一索引

新增类场景,大多数情况下,数据都需要落库,此时最简单的方案则是,使用请求的必填字段,根据业务场景需要,设置数据库的唯一索引。当触发唯一索引异常时,表示为重复提交,此时可以选择返回正常成功或者数据已保存的标识。

优缺点:简单,且无需引入任何额外解决方案或第三方服务,但适用场景有限制

解决方案二:二次确认是否重复

有些情况下,使用请求的必填字段组合,从长期上无法生成为唯一索引,但是短期存在唯一性,此时可以采取查、锁、查的方式来解决:

  1. 查询是否已存在满足条件记录,已存在则说明为重复请求,否则继续
  2. 将关键字段作为锁key,申请分布式锁,加锁失败,则返回延后重试(此时可以考虑适当等待锁,减少重试次数),申请成功则继续
  3. 二次查询是否已存在满足条件记录,已存在则说明为重复请求,否则进行业务处理

ps:在处理有第三方依赖,且无法确认第三方是否已经做了幂等支持时,只要将查替换为查询第三方确认实际状态,也可以避免依赖第三方时因第三方系统造成的幂等问题。

优缺点:应用端引入分布式锁,所幸可以通过锁key减小锁竞争的范围,方案相对简单,但是多了两步查询消耗。

解决方案三:通过请求id

前端在发起请求时,可以提前生成一个请求id,在碰到重试场景是,使用相同的请求id来进行。这里需要注意一个坑,即需要保证生成请求id的服务本身的幂等请求id生成问题。说得比较绕,换个说法就是相同请求生成的请求id也需要相同。

使用请求id时,也有几种方案:

  1. 请求id 本身或者和其他参数共同组成唯一索引,这里其实是结合方案二来做,有时候会碰到请求的参数本身不存在唯一性,但可以与请求id组合形成唯一索引,组合的好处是对于请求id本身的唯一性要求降低了,毕竟生成的请求id根据不同的算法,两次生成也存在相同的可能性。
  2. 方案二基础上,使用请求id 本身或者和其他参数组合,作为分布式锁的key。

优缺点:大大降低了同请求判断对于业务参数的要求,对于请求id 的生成有一定要求(通常是故障引发点),另增加了请求id 本身的存储成本

解决方案四:提前生成主键

一般我们新增数据时,都存在一个单独的唯一主键,此时可以通过提前生成该唯一主键的方式,提交时将主键传入,利用主键存储时的主键重复异常来判断是否重复提交。

为了系统主键安全,一般采用如下步骤来使用该解决方案:

  1. 前端进入页面时,从系统请求一个令牌
  2. 后端在生成令牌时,将令牌放入分布式缓存
  3. 前端提交数据时,需同时提交令牌,和请求id类似(重试时使用与第一次相同的令牌,通常一个页面只请求一次令牌)
  4. 后端从分布式缓存中查询令牌对应主键,获取到主键则直接使用,未获取到则尝试生成主键
  5. 生成主键后,存入缓存时使用不存在则存入模式,存入成功则使用当前主键,否则说明主键已被其他线程/实例生成,直接重新从缓存中获取主键

优缺点:处理过程相对来说会更复杂一点,可以通过封装通用服务解决,业务侵入性更低,使用场景一般局限于前后端交互。

另外,还有一种串联的请求场景,即后置业务依赖前置业务信息的情况,比如下A订单送一次B权益,此时B权益的生成幂等,可以使用A订单的唯一索引通过特定规则转换后作为B权益的主键,或者使用该信息前面的方案一、方案二。

总结

不管哪个解决方案,本质在于相同的入参数下,如何区分两次请求为一次相同请求,并且该确认过程本身不存在高可用问题。以上每种方案都有其适用场景,没有绝对的优劣。

ps:有其他的方案欢迎留言讨论。

本作品的版权所有权归作者所有,受法律保护。未经作者书面许可,任何个人或组织均不得以任何形式使用、复制、修改、传播、展示或在未获得授权的情况下进行商业利用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/805934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

T527 Qt 触摸 ----- TSLIB

一、调试 1、驱动路径 bsp/drivers/input/ctp/gt9xx/gt9xx_ts.c 2、硬件接口 挂载在TWI0下 3、中断复位脚 4、设备树 &twi0 {clock-frequency <400000>;pinctrl-0 <&twi0_pins_default>;pinctrl-1 <&twi0_pins_sleep>;pinctrl-names &quo…

关于ansible的模块 ⑤

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 继《关于Ansible的模块 ①》、《关于Ansible的模块 ②》、《关于Ansible的模块 ③》与《关于Ansible的模块 ④》之后&#xff0c…

Redis(事务)

本篇博客中 Redis 事务是和 MySQL 事务对比来说的(要不我也不会了 …) Redis 事务是什么? Redis 事务的主要意义是 把命令打包在一起执行, 避免其他客户端在我执行一些命令的过程中 插队. ("秒杀"场景, "超卖"问题) Redis 事务 与 MySQL 事务 对比 相比较…

Spring Boot 切面的一种的测试方法,java中级开发面试

void afterReturnName() { Assertions.assertEquals(studentController.getNameById(123L).getName(), "测试姓名Yz");} } 但往往切面中的逻辑并非这么简单&#xff0c;在实际的测试中其实我们也完成没有必要关心在切面中到底发生了什么&#xff08;发生了什么应该在…

正则问题【蓝桥杯】/dfs

正则问题 dfs 刚开始用的是栈&#xff0c;没有想到dfs… #include<iostream> #include<stack> using namespace std; string s; int pos; int dfs() {//ans表示到当前位置最多的x数目//num表示暂存的x数目int num0,ans0;while(pos<s.size()){if(s[pos](){pos;…

HarmonyOS实战开发-如何实现文件管理相关的功能。

介绍 本示例主要展示了文件管理相关的功能&#xff0c;使用ohos.multimedia.medialibrary 、ohos.filemanagement.userFileManager 、ohos.fileio 、ohos.file.fs、ohos.app.ability.contextConstant 等接口&#xff0c;实现了增添文件、删除文件、查找指定类型文件文件、复制…

oracle恢复异常处理

问题现象&#xff1a; RMAN> 2> 3> 4> 5> 6> 7> 8> 9> 10> 11> 12> 13> 14> 15> 16> 17> 18> 19> 20> 21> 22> 23> 24> using target database control file instead of recovery catalog allocate…

软件测试定义和分类

什么是软件 软件是计算机程序&#xff0c;程序所用的数据以及有关文档资料的集合。 软件是计算机的灵魂&#xff0c;软件又可分为两大类&#xff1a;系统软件和应用软件。 系统软件&#xff1a;系统软件是生成&#xff0c;准备和执行其他程序所需要的一组文件和程序。如操作…

论文阅读--Conservative Q-Learning for Offline Reinforcement Learning

摘要 在强化学习( RL )中有效地利用以前收集的大量数据集是大规模实际应用的关键挑战。离线RL算法承诺从先前收集的静态数据集中学习有效的策略&#xff0c;而无需进一步的交互。然而&#xff0c;在实际应用中&#xff0c;离线RL是一个主要的挑战&#xff0c;标准的离线RL方法…

数字化浪潮下,制造业如何乘势而上实现精益生产

随着数字化技术的迅猛发展&#xff0c;制造业正迎来前所未有的变革机遇。本文将探讨如何利用数字化手段助推制造业实现精益生产&#xff0c;从而在激烈的市场竞争中脱颖而出。 1、构建智能化生产系统 借助物联网技术&#xff0c;实现设备之间的互联互通&#xff0c;构建智能化…

CODEFORCES --- 1676A. Lucky?

1676A. Lucky? 彩票是由六位数字组成的字符串。如果前三位数字之和等于后三位数字之和&#xff0c;则视为幸运彩票。给定一张彩票&#xff0c;输出它是否幸运。请注意&#xff0c;彩票可以有前导零。 输入 输入的第一行包含一个整数 t ( 1≤t≤103 ) - 测试用例的数量。 每…

腾讯云云原生数据库TDSQL-C mysql 以及项目怎么接入

要接入腾讯云的云原生数据库TDSQL-C的MySQL版本&#xff0c;并将它用于你的项目中&#xff0c;你需要按照以下步骤进行&#xff1a; 创建TDSQL-C的MySQL数据库实例&#xff1a; 登录腾讯云控制台。在产品搜索框中搜索TDSQL-C&#xff0c;然后选择它。在TDSQL-C的产品页面上&…

【爬虫】在Scrapy中配置随机User-Agent中间件

祝福这个快要漫出来的杯子吧&#xff0c;让杯里的水变得金光灿烂地流出&#xff0c;把反映你的喜悦的光送往各处! &#x1f3b5; 罗老师《查拉图斯特拉的前言_漾水》 在网络爬虫开发中&#xff0c;合理使用User-Agent&#xff08;UA&#xff09;是绕过服务…

Linux函数学习 select

1、Linux select 函数 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); nfds 最大文件fd 1 readfds 监听可读文件集合fd writefds 监听可写文件集合fd exceptfd 监听异常文件集…

数据结构--循环链表

一.循环链表的设计 1.循环链表的结构设计: typedef struct CNode{ int data; struct CNode* next; }CNode ,*CList; 2.循环链表的示意图: 3.循环链表和单链表的区别: 唯一区别,没有空指针,尾节点的后继为头,为循环之意. 二.循环链表的实现 //初始化free(q);return true; …

Pandas的测试关键词云

文章目录 前言一、pandas是什么&#xff1f; 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学…

git 拉取项目时切换账号密码

一般拉取线上代码的先 1.git clone 2.在输入用户名 3.输入密码 等三步操作,这样子太麻烦了 直接一步操作 git clone http://用户名:密码地址 1 例子 如果你用户叫123xxx 密码是mypassword 地址是git.xxx.com/www.git git clone http://123xxx:mypasswordgit.xxx.com/www.git注…

Spring boot 入门 ---(一),2024年最新java进阶训练营

spring-snapshots http://repo.spring.io/snapshot spring-milestones http://repo.spring.io/milestone spring-boot-starter-parent是使用Spring Boot的一种不错的方式&#xff0c;但它 并不总是最合适的。有时你可能需要继承一个不同的父POM&#xff0c;或只是不喜欢我…

集成sharding-jdbc实现分库分表

集成sharding-jdbc实现分库分表 sharding-jdbc是由当当捐入给apache的一款分布式数据库中间件&#xff0c;支持垂直分库、垂直分表、水平分库、水平分表、读写分离、分布式事务和高可用等相关功能。 1、ruoyi-framework\pom.xml模块添加sharding-jdbc整合依赖 <!-- shard…

自己写的组件中使用v-model双向绑定

这里的时间选择表单是我写的一个组件&#xff0c;我想用v-model获取到实时的ref值。 代码&#xff1a; //父组件<TimePickerModal v-model:value"time" label-text"计划客面时间" /> const time ref(2024-04-09 15:20:00);//子组件<template>…