1.设置缓存的时候,要考虑多容器加锁的场景。

(1)场景,短信回执场景,会有二次回执的情况,但是我们只处理一次回执的消息体,如何不处理二次回执呢?

// 队列中有数据且容量未达到100,可继续放入队列数据if (viberReceiptQueue.size() > 0 && (dlvViberReceiptMap.size() + fldViberReceiptMap.size()) <= 100) {while (viberReceiptQueue.size() > 0&& (dlvViberReceiptMap.size() + fldViberReceiptMap.size()) <= 100) {ViberReceipt viberReceipt = viberReceiptQueue.take();logger.info("HandlerRunnable viberReceipt take:{}", JSONObject.toJSONString(viberReceipt));if (Objects.isNull(viberReceipt.getPartId())) {MccContact mccContact = mccContactMapper.selectByPrimaryKey(viberReceipt.getMessageId());viberReceipt.setPartId(Long.parseLong(mccContact.getPartId().toString()));// 这里做一个二次回执业务过滤,判断contact表的状态是否已经被修改,如果已经被修改,则不处理if (!CmsStateDef.CONTACT_STATE_CSD.equals(mccContact.getContactState())) {continue;}}//failed 发送失败  pending mmgw发送成功   success 发送成功  ceg一次成功回执pending 但一次失败回执failed 去重if ("failed".equals(viberReceipt.getResult())) {String key = viberReceipt.getMessageId() + "-" + viberReceipt.getResult();String value = RedisUtil.getValue(RedisUtil.FUNTYPE1, key);logger.info("qry FLD cache key:{}, is repeat flag:{}", key, value);if (StringUtils.isEmpty(value)) {fldViberReceiptMap.put(viberReceipt.getMessageId(), viberReceipt);RedisUtil.setValue(RedisUtil.FUNTYPE1, key, "2", 3600);}else {RedisUtil.delKey(RedisUtil.FUNTYPE1, key);}}else if ("success".equals(viberReceipt.getResult())) {dlvViberReceiptMap.put(viberReceipt.getMessageId(), viberReceipt);}}

这里我们通过RedisUtil.setValue(RedisUtil.FUNTYPE1, key, “2”, 3600);方法。将一次回执之后的key设置到缓存中去,这样二次回执过来的时候,会去查看缓存中是否有值,有值,则一次回执已经处理,该消息体为二次回执。不处理。

(2)上面这种解决方法看起来好像没有什么问题,但是Redis一般都是分布在多容器的,如果两个容器的两个消息同时getValue,这样既取不到数据,并且两条消息都进行了处理,显然与我们要求的不符合。
解决方法:使用RedisUtil的单线程处理方法incr

 // 队列中有数据且容量未达到100,可继续放入队列数据if (viberReceiptQueue.size() > 0 && (dlvViberReceiptMap.size() + fldViberReceiptMap.size()) <= 100) {while (viberReceiptQueue.size() > 0&& (dlvViberReceiptMap.size() + fldViberReceiptMap.size()) <= 100) {ViberReceipt viberReceipt = viberReceiptQueue.take();logger.info("HandlerRunnable viberReceipt take:{}", JSONObject.toJSONString(viberReceipt));MccContact mccContact = mccContactMapper.selectByPrimaryKey(viberReceipt.getMessageId());viberReceipt.setPartId(Long.parseLong(mccContact.getPartId().toString()));// 这里做一个二次回执业务过滤,判断contact表的状态是否已经被修改,如果已经被修改,则不处理if (!CmsStateDef.CONTACT_STATE_CSD.equals(mccContact.getContactState())) {continue;}//failed 发送失败  pending mmgw发送成功   success 发送成功  ceg一次成功回执pending 但一次失败回执failed 去重if ("failed".equals(viberReceipt.getResult())) {String key = viberReceipt.getMessageId() + "-" + viberReceipt.getResult();int incr = RedisUtil.incr(RedisUtil.FUNTYPE1, key, 1,  3600l);logger.info("qry FLD cache key:{}, is repeat flag:{}", key, incr);if (incrValue != incr) {fldViberReceiptMap.put(viberReceipt.getMessageId(), viberReceipt);}}else if ("success".equals(viberReceipt.getResult())) {dlvViberReceiptMap.put(viberReceipt.getMessageId(), viberReceipt);}}

(3)为什么使用incr:(自增计数器)

1.Redis自增key 的好处

  1. 原子性(atomicity):一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都做,要么都不做。
  2. Redis所有单个命令的执行都是原子性的,这与它的单线程机制有关;
  3. Redis命令的原子性使得我们不用考虑并发问题,可以方便的利用原子性自增操作

(4)为什么不使用加锁的方式(不选择Redis锁的原因:)

  1. 它获取锁的方式简单粗暴,获取不到锁直接不断尝试获取锁,比较消耗性能。
  2. 另外来说的话,Redis 的设计定位决定了它的数据并不是强一致性的,在某些极端情况下,可能会出现问题。锁的模型不够健壮。
  3. 即便使用 Redlock 算法来实现,在某些复杂场景下,也无法保证其实现 100% 没有问题,关于 Redlock 的讨论可以看 How to do distributed locking。
    Redis 分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。

(5)其他使用场景:。

限流可以使用redis原子计数器incr.但是除了限流以外,很多系统会在一些节日的时候搞一些活动,当然,这些活动是有奖品的,并且奖品的数量也是有限的。为了防止在高并发的时候,出现多个人中奖的情况,那么可以使用分布式锁,比如redis的分布式锁,zookeeper的分布式锁。当然,我们也可以采用简单一点的方案,就是使用redis原子计数器incr来统计。

Redis多容器高并发场景 , 设置缓存的时候,要考虑多容器加锁的场景。(incr计数和redis分布式锁区别)相关推荐

  1. SpringBoot+Redis+Cookies实现高并发的购物车

    案例实战:SpringBoot+Redis+Cookies实现高并发的购物车 步骤1:代码逻辑 /*** 添加购物车*/@PostMapping(value = "/addCart" ...

  2. java redis队列_redis队列实现高并发怎么用?Java如何使用redis队列解决高并发?

    小伙伴们大家好,不知道你们有没有在Java开发中遇到redis队列高并发,这个问题让你很头疼,今天小编就来讲解一下在Java中遇到redis队列高并发了,到底该怎么办. 高并发的业务场景: 我们做商品 ...

  3. SpringBoot +Redis +RabbitMQ 实现高并发限时秒杀

    SpringBoot +Redis +RabbitMQ 实现高并发限时秒杀 提示:以下是本篇文章正文内容,下面案例可供参考 一.软件安装 1.安装RabbitMQ docker安装:docker安装R ...

  4. 面试官:为什么单线程的Redis可以实现高并发访问

    背景 上回说到小枫在接受面试官的拷打,所幸第一个问题回答的还不错,因此面试官对于小枫的初步印象还行.我们接着来看看小枫是怎么和面试官继续过招的吧,他还能扛得住面试官几个连环炮呢? 面试官考察目的分析 ...

  5. Redis与Zookeeper实现分布式锁区别

    1.分布式锁解决方案  1.采用数据库 不建议 性能不好 jdbc  2.基于Redis实现分布式锁(setnx)setnx也可以存入key,如果存入key成功返回1,如果存入的key已经存在了,返回 ...

  6. 高并发用redis还是mysql_高并发架构系列:Redis缓存和MySQL数据一致性方案详解

    需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...

  7. 91免费视频Redis+Lua解决高并发场景在线秒杀问题

    为何要使用Lua脚本解决商品超卖的问题呢? Redis在2.6版本后原生支持Lua脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行. 将复杂的或者多步的redis操作,写为一个脚本,一次 ...

  8. 高并发解决方案(缓存、降级、限流)之限流笔记

    转载自:jinnianshilongnian 高并发系统时有三把利器用来保护系统:缓存.降级和限流.缓存的目的是提升系统访问速度和增大系统能处理的容量,可谓是抗高并发流量的银弹:而降级是当服务出问题或 ...

  9. Redis核心数据结构List应用场景-商品列表、缓存击穿、PV阅读量、抢红包、推送帖子、普通分布式锁、Redis可重入锁与红锁

    List应用场景 Redis之List 一. Redis list命令实战 二.商品列表 高并发的淘宝聚划算实现技术方案 SpringBoot+Redis实现商品列表功能 二.缓存击穿 什么是缓存击穿 ...

最新文章

  1. Hawk使用补充说明
  2. 使用Android studio完成”仿QQ的头像选择弹出的对话框“步骤及知识梳理
  3. C#学习笔记之线程 - 同步上下文
  4. python识别验证码ocr_Python 验证码识别-- tesserocr
  5. 通过Ajax解析和jQuery写了一个小小的导航条
  6. obj[]与obj._Ruby中带有示例的Array.rassoc(obj)方法
  7. 如何查看JVM内存中的对象和执行中的方法
  8. Android 学习 笔记_07. XML文件解析
  9. 登录获取token,token参数关联至所有请求的请求体内
  10. vue项目中使用阿里巴巴矢量图标库iconfont
  11. matlab中gui对话框,Matlab GUI之通用对话框
  12. 【LeetCode】75. Sort Colors(颜色排序)-C++实现的两种方法及超详细图解
  13. 解决Mybatis报错并分析原因:Invalid bound statement (not found): com.xxx.mapper.xxx
  14. RabbitMQ 中的 VirtualHost 该如何理解
  15. 去掉CAJViewer广告的方法
  16. 黑白棋(人人对战)——C语言实现方法之一
  17. C专家编程 --- 书中案例汇编与分析(持续更新中)
  18. 什么都可以丢,唯独不能丢了你
  19. 看看京东应急供应链是怎样构建的?
  20. Redirected when going from “/index“ to “/xx“via a navigation guard

热门文章

  1. 关于WiFi总是断网,联网会跳转MSN问题的解决方法
  2. ASCLL码表及字符转义
  3. 西门子S7-200PLC入门及介绍
  4. OB1203传感器的应用(一)
  5. 实战:Eclipse运行速度调优
  6. Windows 7,win7,旗舰版,家庭版,企业版等版本主要区别
  7. 计算机原理课 如何在中小学课堂中变成有趣,计算机组成原理课程习题答案秦磊华...
  8. 北京恒佳PMP管理培训中心免费在线讲座——《项目管理能力提升模型之——项目管理思维》
  9. 杰理AD14N/AD15N---UART串口使用问题
  10. 解决Ubuntu19.04英伟达(NVIDIA)显卡驱动安装问题