幂等性
幂等性是数学概念,f(x)=f(f(x))。计算机领域,意为对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的.
该问题产生的一些场景
多次调用带来的是结果不一致和并发安全问题
- 浏览器多次调用.
- 业务调用超时或者没有接收到,重试
- mq重发
- 多次入库
解决方案
首先需要明确的是在一般场景中可以简单的解决或者忽略,在强一致性环境中必须校验,比如订单,支付
-
请求带token
页面每次刷新后端给前端提供一个token,每次点击只处理一个token.防止多次点击.这种情况前端优先处理
-
事务
简单粗暴
-
数据库乐观锁
查删没有影响,增改可能重复
save:对于业务中有唯一标志的,数据可以加唯一索引.没有唯一标志的,比如添了1条就是多1条的,在业务层就要判断.
update:在数据库加一个versionupdate t set a=a+1,version=version+1 where version=1;//成功了只有1次执行机会 -
去重表或redis去重
去重表:业务标志存入表去重.失败了删除.定期删除.优点是可以直接进事务回滚,缺点是每个业务都需要表,对数据库压力会随量级增加
insert ignore into log (user_id) value (#{userId})redis:存zset.分数为时间.失败了删除,另外起一个定时器定期删除.相对去重表,性能更好,操作更简单
之前做了一个数据增量统计,2种方式都试了下:
@Override public boolean haveExist(BusinessEnum businessEnum, String value) { Boolean flag = stringRedisTemplate.opsForZSet().add(PREFIX_REPEAT_KEY + businessEnum.code,value,System.currentTimeMillis()); return !(flag == null ? false : flag); } @Override public Long remove(BusinessEnum businessEnum, String value) { return stringRedisTemplate.opsForZSet().remove(PREFIX_REPEAT_KEY + businessEnum.code, value); } @Override public void clearCache() { BusinessEnum[] businessEnums = BusinessEnum.values(); long now = System.currentTimeMillis(); for (BusinessEnum biz : businessEnums) { stringRedisTemplate.opsForZSet().removeRangeByScore(PREFIX_REPEAT_KEY + biz.code, 0, now - biz.timeout); } } -
业务状态
根据状态操作,如订单
if(status==paid){ dosth.. } -
单机锁与分布式锁
-
mq
自带ack,保证消息百分百到达,性能优秀
谈谈分布式
分布式复杂性的原因有很多,很重要一点是网络的不可靠性.服务之间调用可能为成功,失败,超时. 要保证百分百成功,事务和重试是必不可少的.处理起来也要结合业务多种处理方式搭配起来用.比较推崇的一种方式是走mq,服务异步化和保证可靠性.

浙公网安备 33010602011771号