MQ实现消息的幂等性

1、什么是幂等性
能够参考数据库乐观锁机制,好比执行一条更新库存的 SQL 语句,在并发场景,为了性能和数据可靠性,会在更新时加上查询时的版本,而且更新这个版本信息。可能你要对一个事情进行操做,这个操做可能会执行成百上千次,可是操做结果都是相同的,这就是幂等性。
html

2、消费端的幂等性保障
在海量订单生成的业务高峰期,生产端有可能就会重复发生了消息,这时候消费端就要实现幂等性,这就意味着咱们的消息永远不会被消费屡次,即便咱们收到了同样的消息。java

业界主流的幂等性有两种操做:
1.惟一 ID + 指纹码 机制,利用数据库主键去重
2.利用redis的原子性去实现redis

3、惟一 ID + 指纹码 机制
你们确定懂惟一 ID 的,就很少说了,为何须要指纹码呢?这是为了应对用户在一瞬间的频繁操做,这个指纹码多是咱们的一些规则或者时间戳加别的服务给到的惟一信息码,它并不必定是咱们系统生成的,基本都是由咱们的业务规则拼接而来,可是必定要保证惟一性,而后就利用查询语句进行判断这个id是否存在数据库中。算法

好处:实现简单,就一个拼接,而后查询判断是否重复。
坏处:在高并发时,若是是单个数据库就会有写入性能瓶颈
解决方案 :根据 ID 进行分库分表,对 id 进行算法路由,落到一个具体的数据库,而后当这个 id 第二次来又会落到这个数据库,这时候就像我单库时的查重同样了。利用算法路由把单库的幂等变成多库的幂等,分摊数据流量压力,提升性能。数据库

4、redis的原子性去实现
咱们都知道redis是单线程的,而且性能也很是好,提供了不少原子性的命令。好比可使用 setnx 命令。缓存

在接收到消息后将消息ID做为key执行 setnx 命令,若是执行成功就表示没有处理过这条消息,能够进行消费了,执行失败表示消息已经被消费了。并发

使用 redis 的原子性去实现主要须要考虑两个点异步

第一:咱们是否要进行数据落库,若是落库的话,关键解决的问题是数据库和缓存如何作到原子性?
采用延时双删策略函数

伪代码以下:高并发

public void write(String key,Object data){
        redis.delKey(key);
        db.updateData(data);
        Thread.sleep(1000);
        redis.delKey(key);
    }

转化为中文描述就是
(1)先淘汰缓存
(2)再写数据库(这两步和原来同样)
(3)休眠1(根据业务本身设定)秒,再次淘汰缓存
这么作,能够将1秒内所形成的缓存脏数据,再次删除。

url:http://www.javashuo.com/article/p-ftdcqtnl-cx.html

第二:若是不进行落库,那么都存储到缓存中,如何设置定时同步的策略(同步到关系型数据库)?缓存又如何作到数据可靠性保障呢 关于不落库,定时同步的策略, 目前主流方案有两种: 第一种为双缓存模式,异步写入到缓存中,也能够异步写到数据库,可是最终会有一个回调函数检查,这样能保障最终一致性,不能保证100%的实时性。 第二种是定时同步,好比databus同步。

相关文章
相关标签/搜索