去重:是对请求或者消息在一定时间内进行去重
幂等:实在保证请求或者消息在任意时间内进行处理,都需要保证它的结果是一致的
去重和幂等的本质:唯一Key + 存储
不同的业务场景,唯一Key是不一样的,由业务决定
存储选择挺多的,比如本地缓存、redis、MySQL、HBase等等,具体选取什么,也和业务有关。比如在消息管理平台这个场景下,存储选择redis(读写优越),redis也有过期时间,方便解决一定时间内的问题,而唯一Key自然就是根据不同的业务构建不同的。
比如 5分钟相同内容消息去重,我直接MD5请求参数作为唯一Key 1小时则是模板ID+userId作为唯一Key。
布隆过滤器的底层数据结构可以理解为bitmap,bitmap也可以简单理解为一个数组,元素只存储0和1,所以它占用的空间相对较小。
当一个元素要存入bitmap时,其实是要去看存储到bitmap的哪个位置,这时一般用的就是哈希算法,存进去的位置标记为1,标记为1的位置表示存在,标记为0的位置表示不存在。
布隆过滤器时可以以较低的空间占用来判断元素是否存在而用于去重,但是它也有缺点:只要使用哈希算法离不开哈希冲突,导致有存在误判的情况。在布隆过滤器中,如果元素判定存在,那该元素未必真实存在。如果元素判定为不存在,那就肯定是不存在的。布隆过滤器也不能删除元素,也是哈希算法的局限性,在布隆过滤器中是不能准确定位一个元素的。如果要用的话,布隆过滤器的实现可以直接上Guava已经实现好的,不过这个是单机的,而分布式下的布隆过滤器,一般现在会用Redis,但也不是每个公司都会部署布隆过滤器的Redis版(还是有局限)。
如果去重的开销比较大,可以考虑建立多层过滤的逻辑。比如,先看看本地缓存能不能过滤一部分,剩下强校验交由远程存储(Redis或者DB),进行二次过滤。
一般我们需要对数据强一致性校验,就直接上MySQL,毕竟有事务支持,本地缓存如果业务合适,那也可以作为一个前置判断,Redis高性能读写,前置判断和后置均可,而HBase则一般用于庞大数据量的场景下(Redis内存太贵了,BD也不够灵活适合单表存储大量数据)
至于摩幂等,一般的方案下存储还是Redis和数据库
最常见的就是i数据库唯一索引,来实现幂等,构建唯一Key是业务相关的事,一般事用自己的业务ID进行拼接,生成一个有意义的唯一Key
也有用Redis和Mysql实现分布式锁来实现幂等的
但是Redis分布式锁事不能完全保证安全的,而MySQL实现分布式锁(乐观锁和悲观锁),不过还是看业务把,暂时还没用到过
网上也有很多实现幂等的方案,本质上是围绕着存储和唯一Key做了变种