接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的, 不会因为多次点击而产生了影响。
比如说支付场景, 用户购买了商品支付扣款成功, 但是返回结果的时候网络异常, 此时钱已经扣了, 用户再次点击按钮, 此时会进行第二次扣款, 返回结果成功, 用户查询余额返发现多扣钱了, 支付记录也变成了两条,这就没有保证接口的幂等性。
1 用户多次点击按钮
2 用户页面回退再次提交
3 微服务互相调用, 由于网络问题, 导致请求失败。 feign 触发重试机制
1、 服务端提供了发送 token 的接口。 我们在分析业务的时候, 哪些业务是存在幂等问题的,
就必须在执行业务前, 先去获取 token, 服务器会把 token 保存到 redis 中。
2、 然后调用业务接口请求时, 把 token 携带过去, 一般放在请求头部。
3、 服务器判断 token 是否存在 redis 中, 存在表示第一次请求, 然后删除 token,继续执行业
务。
4、 如果判断 token 不存在 redis 中, 就表示是重复操作, 直接返回重复标记给 client, 这样
就保证了业务代码, 不被重复执行。
select * from xxxx where id = 1 for update;
悲观锁使用时一般伴随事务一起使用, 数据锁定时间可能会很长, 需要根据实际情况选用。
另外要注意的是, id 字段一定是主键或者唯一索引, 不然可能造成锁表的结果, 处理起来会
非常麻烦。
这种方法适合在更新的场景中,
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
根据 version 版本, 也就是在操作库存前先获取当前商品的 version 版本号, 然后操作的时候
带上此 version 号。 我们梳理下, 我们第一次操作库存时, 得到 version 为 1, 调用库存服务
version 变成了 2; 但返回给订单服务出现了问题, 订单服务又一次发起调用库存服务, 当订
单服务传如的 version 还是 1, 再执行上面的 sql 语句时, 就不会执行; 因为 version 已经变
为 2 了, where 条件就不成立。 这样就保证了不管调用几次, 只会真正的处理一次。
乐观锁主要使用于处理读多写少的问题。
如果多个机器可能在同一时间同时处理相同的数据, 比如多台机器定时任务都拿到了相同数
据处理, 我们就可以加分布式锁, 锁定此数据, 处理完成后释放锁。 获取到锁的必须先判断
这个数据是否被处理过
插入数据, 应该按照唯一索引进行插入, 比如订单号, 相同的订单就不可能有两条记录插入。
我们在数据库层面防止重复。
这个机制是利用了数据库的主键唯一约束的特性, 解决了在 insert 场景时幂等问题。 但主键
的要求不是自增的主键, 这样就需要业务生成全局唯一的主键。
如果是分库分表场景下, 路由规则要保证相同请求下, 落地在同一个数据库和同一表中, 要
不然数据库主键约束就不起效果了, 因为是不同的数据库和表主键不相关。
调用接口时, 生成一个唯一 id, redis 将数据保存到集合中(去重) , 存在即处理过。
可以使用 nginx 设置每一个请求的唯一 id;
proxy_set_header X-Request-Id $request_id;