架构设计:对于微服务接口,幂等,并发的相关设计的一些设想
mhr18 2025-04-29 02:13 17 浏览 0 评论
我们微服务接口愈来愈庞大,那这里大概讲述一下我个人对于各种接口设计的一些看法和要点。
1、接口是否需要做幂等
如果是查询或者删除这些接口是不需要做幂等的,一般删除是根据ID来删除,第二次删除如果内容不存在,那么也相当于删除成功。
如果是新增或者修改操作,一般来说都会做幂等的,而做密等有如下两种。
1)业务逻辑上幂等
比如注册接口,这种根据用户填入信息,比如手机号这种来注册的,逻辑上一般都是如果发现表中有值,都会直接返回注册成功,不管用户调用多少次,所以这种业务逻辑上已经可以保证幂等了的。不管前端调用你的接口超时或者调用成功后本地操作失败造成客户端本地事务回滚,第二次调用后你直接返回成功,所以不会有数据上的问题。
2)接口调用流水号来保证幂等
有些接口比如权益领取,客户端调用权益领取接口,如果此时超时了,或者调用成功后本地业务逻辑操作失败了那怎么办,权益在接口那边是已经领取成功了的,如果再次发起可能会领取第二次,这种情况下靠业务逻辑来保证幂等就比较麻烦了,此时我们需要在接口上加上一个额外的接口调用流水号,比如如下输入参数:
{
"cstm_no":"会员号",
"award_id":"要领取的权益ID",
"call_sn":"接口调用流水号"
}
上面的接口调用流水号通常来说跟客户端的业务有关联,如果客户端调用接口成功后业务逻辑出错回滚,或者超时,第二次应该还是用相同流水号来,这样微服务业务处理逻辑就会根据流水号去查询该流水是否已经存在,存在则直接返回,不存在则做流水操作。
3)接口调用流水号来做异步解耦
还有一种业务逻辑是这样的,客户端或者第三方调用你的接口后,为了防止超时导致服务没返回,客户端会直接根据接口调用流水号来循环间隔的调用你提供的另一个接口来查询结果,比如支付宝的支付,因为支付逻辑耗时比较长,所以你调用完支付后,可以等着支付宝回调你的接口来告诉你结果,也可以你自己根据流水号去查询结果。又比如上面说的注册,如果我的注册逻辑比较复杂,如下流程:
获取接口输入信息
校验输入参数是否正确
调用身份验证接口校验用户是否满足注册条件
初始化用户相关信息
其中用身份验证接口和初始化用户相关信息耗时较长,如果客户端或者第三方调用我们的接口的话超时的概率很大,并且这个注册接口耗时时间较长,会较长时间占据一个http线程,对微服务的性能影响较大。此时我们通常会对该接口进行解耦。将”调用身份验证接口校验用户是否满足注册条件”和”初始化用户相关信息”这两部逻辑用消息队列比如RocketMQ让消费程序来执行,本注册接口就直接返回成功。最终注册结果需要通过另一个接口来查询,如下图:
那么客户端的调用逻辑将会变成图中所说的
- 1、调用注册接口,传入接口调用流失
{
"call_sn":"接口调用流水UUID等",
"userinfo":"用户注册信息"
}
- 2、不去管接口是否调用成功,因为可能超时,直接调用结果查询接口
{
"call_sn":"接口调用流水UUID等"
}
去根据流水号查询注册接口调用的结果,并且这里是轮询调用,比如两秒钟调用一次,总共调用10次,如果结果为生成就都叫做处理中。
查询接口可以通用出来,直接根据call_sn去redis查询结果,如果查询不到则代表处理中,如果查询得到则直接返回,让客户端自己去处理即可。
那么微服务的处理逻辑也很简单
- 1、获取接口输入信息,登记消息给消费程序。
{
"call_sn":"接口调用流水UUID等",
"userinfo":"用户注册信息"
}
消费程序的处理逻辑也很简单
- 1、做注册操作
- 2、把结果放入redis,key为call_sn.(或者加一些前缀)
一般来说,某个接口有做异步解耦的话,一定要传入接口调用流水,然后根据接口调用流水来查询本次的操作结果。
2、怎么保证接口同一个用户并发访问。
1)场景1:单个用户并发注册
比如我们有一个活动报名表,活动开始后用户首先要根据手机号注册,那么正常处理逻辑如下
1、根据用户手机号查询报名表查看用户是否已经注册
2、若用户已注册则返回用户注册成功
3、若用户未注册则做注册逻辑操作
伪代码如下
//1、获取用户报名信息
UserInfo userInfo = getUserInfoForUpdate(phone,activity_code)
if(userInfo==null){
//2、做注册操作
...
}else{
//3、用户已注册
return userInfo
}
正常逻辑是没有问题的,但是如果单个用户并发进来,在到第一步的时候两个线程都没有查询到userInfo,然后这里都跑去注册。
解决办法:这种情况下,通常我们可以子啊phone和activity_code加上唯一索引即可,如果用户并发进来,刚好同时查询用户信息都为空(正常情况下页面有做token或者防止重复点击的操作),那么会触发唯一索引报错,这样保证了业务数据的一致性。
2)场景2:单个用户并发登记
比如我们有一个玩游戏的活动,规定一个用户一天只能玩两次,也就是我们的提交分数接口处理逻辑要做如下操作。
1、用户提交分数
2、查看用户今天已经提交分数的次数
3、若没有超过2次,则允许提交
4、若超过超过2次,则不允许提交
正常流程是没问题的,并且第2步骤那里用户是行锁查询用户的当天提交分数记录,但是如果用户是第一次提交,四五个线程并发进来呢?
此时第2步骤因为一条记录都没有,所以都可以通过,然后用户就登记了四五条记录,违反了活动规则。
这种类似的情况还有很多,比如活动规定一个用户只能获取两个奖品,但是如果用户并发进来领取呢?活动规定以恶搞用户只能抢购两个商品,但是用户并发进来抢购呢?这种情况下行锁统计用户已经做的操作就没有太大意义了,那么该怎么解决呢?
解决方案如下:
方案1、借用redis的自增自减操作来防止用户并发
我们可以用redis的incr自增原子操作,如果incr后操过了规定则直接返回失败,然后回滚redis。并且设置该key的失效时间为几秒钟,反正只要数据库中有记录了的话
就不会出现都查询到是空,一条记录都不存在导致行锁失败的情况,几秒钟失效也可以不用浪费redis的内存。
方案2、借用数据库行锁来防止用户并发
奇怪,上面不是说数据库行锁在没有一条记录的情况下会失败么,这里我说的不是所没有记录的那个表,而是直接锁用户已经有记录的表,这里最好的就是报名表,报名表在场景一里可以保证一定有一条记录,所以这里可以行锁用户的记录,这样子后面统计用户的提交分数次数都不需要进行锁表了。这种情况会遇到的问题就是如果这个用户还有别的业务场景也都锁用户的报名表的话,会导致都等待。
上面两种方案都可以,具体采取哪一种,得看不同的项目架构是怎样的,如果没有引入redis组件,那肯定直接用第二种了。
3)场景3:多个用户并发登记
比如我们有一个奖品,一天只能派发10个,那么也会面临场景2的问题,如果是多个用户并发进来,此时表中一条记录都没有怎么办,又不可能全表锁,那么解决方案就只能够借用方案1来计数了,并且失效时间应该未活动期间内都有效,也许还有用户想直接用java的同步锁,这种方案在高并发的情况下是特别不可取的,不说对性能的影响极其大,如果是多个节点,那么同步锁只能锁JVM的特性就完全没有意义了。
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)