最近在项目中发现了一个奇葩的 BUG ,当用户调用后台时,后台向消息队列中发布一条消息,这条消息会被监听器(消费者)监听到,有趣的事情就在这里,此时由于只发送了一条消息,照理说监听器应该只会触发一次,但是却总是订阅2次(有的客户服务器启动甚至会初始化好几次,不知具体原因),然后就不会再订阅了,当时向消息队列发布信息我是使用的 RedisTemplate 里面的 convertAndSend(channel,message) 方法(看了一遍发现并没有看出什么代码上的问题),于是我去看了一下源码并走了一下断点,发现程序在发布消息的时候确确实实只发布了一次,但是监听器却订阅了2次。

当时为了测试,特意写了一个跟下面所有代码片段差不多的内容

消息发布者

// Controller 的某个方法内容 用于向 "channel" 发布信息
// 此处使用的 RedisTemplate 对象
// 消息发布者
@RequestMapping("publishMsg")
public void publishMsg(){// 向 "channel" 发布一个信息 "这是我发送的一个消息"redisTemplate.convertAndSend("channel","这是我发送的一个消息");
}

消息订阅者 ( xxxConsumer )

// xxxListener 类,主要用于订阅向 "channel" 发布的信息
// 消息订阅者
public void handleMessage(Message message,byte[] pattern){// 输出 channelSystem.out.print("channel : " + stringRedisSerializer.deserialize(message.getChannel()));// 输出发布的信息System.out.print("message : " + stringRedisSerializer.deserialize(message.getBody()));
}

spring.xml Redis 的队列大概配置

<!-- 将订阅者的类注册到 spring 中 -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
<!-- 将订阅者的类注册到 spring 中,这个 bean 是消息订阅者 -->
<bean id="xxxConsumer" class="com.xxx.xxx.xxxConsumer"></bean>
<redis:listener-container><redis:listener ref="xxxConsumer" serializer="stringRedisSerializer" method="handleMessage" topic="channel" />
</redis:listener-container>

此时我联想到以下几点可能会引起的问题。
1、代码逻辑或者配置文件内容写的还是有问题,需要再 review 一遍 ?
2、spring-data-redis 版本问题导致的重复订阅多次 ?
3、redis 版本过于古老 ?
4、程序从前几个月的某次更新之后就出现了扫描了两次项目的问题,会不会跟这个有关系 ?

经过排查与尝试之后,最终问题定位在了第 4 点上,随后我便想到每次初始化资源的时候队列都会起一个线程(xxxConsumer)来监听(订阅) 某个 channel 发布的信息,如果程序连续初始化了两次项目,会不会有两个消费者线程,同时运作并监听一个 channel 发布的信息呢 ?
于是我尝试了一下,在程序第一次初始化成功之后立马在我的 redis 客户端中手动向 “channel” 发布了一个信息,这时候发现该信息的订阅者数量是 1,然后我定位到了问题所在,随后我突然想到了很久之前为了只用 ip 地址加端口访问到项目,特意在 server.xml 中的 Host 元素里多加了一个 Context 标签,用于忽略项目名访问项目,之后我在为了能去掉项目名的同时,也不被实例化两次的想法下,进行了一些修改,下面放出代码
修改前

<Host appBase="wtpwebapps" autoDeploy="true" name="localhost" unpackWARs="true"><Context debug="0" docBase="" path="ProjectName" reloadable="false"></Context><Context debug="0" docBase="ProjectName" path="/ProjectName" reloadable="false" source="..." ></Context><!-- 忽略掉其它的默认配置内容 -->
</Host>

修改后
注意:如果是在 IDE 中启动 tomcat 可能路径会有变化,甚至还会造成项目启动失败的问题,报错内容主要就是路径对应的项目找不到,改成正确的路径就好了,server.xml docBase 路径配置示例 : ../wtpwebapps/ProjectName

<Host appBase="" autoDeploy="true" name="localhost" unpackWARs="true"><Context debug="0" docBase="webapps/ProjectName" path="/" reloadable="false" source="..." ></Context><!-- 忽略掉其它的默认配置内容 -->
</Host>

经过这次事件之后也算是有了一点小收获(调的时候真的是一头雾水……)
了解了一点 Tomcat 加载的机制,也巩固了一遍 redis 队列配置方法,而且不知道算不算是找到了一个比较靠谱一点的去掉项目名的配置方案 ╰(°▽°)╯
[手动骄傲]

PS:这是我第一次写调试笔记,主要是为了记录工作中遇到的一些尴尬事儿(居然花了我几个小时的时间,才调完),防止下次重蹈覆辙 XD,可能比较啰嗦QAQ,还望谅解

调试笔记 — Redis 消息队列发布信息被消费者重复订阅多次牵扯到的 Tomcat 配置问题 [#00001]相关推荐

  1. Redis消息队列发布微博

    一些基于用户创造内容的应用中(SNS,微博),很容易出现一秒钟上万个用户同时发布消息的情况.这个时候,很容易出现MySQL的"too many connections"的情况,增大 ...

  2. Java实现redis消息队列发布/订阅模式

    最近在一个老项目中需要用消息队列,本来想着用卡夫卡,但是试了几个版本之后发现jdk和卡夫卡版本一直对不上,最后选择用redis来实现消息队列的发布/订阅模式.感谢这位大佬的博客给了我很多的帮助,htt ...

  3. PHP下使用Redis消息队列发布微博(复制)

    phpRedisAdmin :github地址  图形化管理界面 git clone https://github.com/ErikDubbelboer/phpRedisAdmin.git cd ph ...

  4. 微博群发私信 php,PHP下使用Redis消息队列发布微博

    phpRedisAdmin :github地址  图形化管理界面 git clone https://github.com/ErikDubbelboer/phpRedisAdmin.git cd ph ...

  5. php mysql redis mq_PHP基于Redis消息队列实现发布微博的方法

    本文实例讲述了PHP基于Redis消息队列实现发布微博的方法.分享给大家供大家参考,具体如下: phpRedisAdmin :github地址  图形化管理界面 git clone [url]http ...

  6. Redis应用实践-使用消息队列发布微博

    使用消息队列发布微博 有时候我们的应用中(如:微博)会出现这样的情况,一秒钟有很多用户同时发布消息.这个时候数据库Mysql可能会出现"too many connections". ...

  7. 微博群发私信 php,用PHP基于Redis消息队列实现发布微博的方法

    用PHP基于Redis消息队列实现发布微博的方法 PHP基于Redis消息队列实现发布微博的方法,结合实例形式分析了php+redis数据库的安装.连接.读取.插入等相关操作技巧,需要的朋友可以参考下 ...

  8. 使用jedis实现Redis消息队列(MQ)的发布(publish)和消息监听(subscribe)

    前言: 本文基于jedis 2.9.0.jar.commons-pool2-2.4.2.jar以及json-20160810.jar 其中jedis连接池需要依赖commons-pool2包,json ...

  9. 【Redis消息队列实现异步秒杀】--Redis学习笔记08

    前言 秒杀业务的优化思路: 先利用Redis完成库存余量.一人一单判断,完成抢单业务 再将下单业务放入队列中(阻塞队列,消息队列),利用独立线程异步下单 基于阻塞队列的异步秒杀存在哪些问题? 内存限制 ...

最新文章

  1. 无人驾驶 | 为什么双目自动驾驶系统难以普及?
  2. Python中list复制引发的问题
  3. ui vue 创建项目教程 并关闭语法_使用vue ui命令创建vue项目步骤
  4. 牛客网_PAT乙级1016_部分A+B (15)
  5. 2014 网选 上海赛区 hdu 5047 Sawtooth
  6. 图像处理技术(二)滤波去噪
  7. PHP添加php-java-brideg模块(ubuntu环境)
  8. Mybatis 入门之resultMap与resultType讲解实例
  9. 正态分布解释“剩女”现象——只因爱才子
  10. 清理offset_关于 kafka 日志清理策略的问题
  11. spring mysql 连接池配置_SpringBoot数据库连接池常用配置
  12. 信息学奥赛一本通(1093:计算多项式的值)
  13. CMU计算机学院院长Andrew Moore离职,下一任院长人选未定
  14. C#winform可视化(当主窗体不能拖动时)
  15. Leetcode 647.回文子串
  16. selenium模拟登录QQ空间
  17. Intel 80286工作模式
  18. 转载:十款主流科研绘图软件
  19. mac屏幕分辨率调整:SwitchResX
  20. caffe函数入口caffe.cpp详解

热门文章

  1. android米思奇打地鼠源代码,打地鼠 - 源码下载|游戏|源代码 - 源码中国
  2. 【机器学习-贷款用户逾期情况分析2】3.stacking模型融合
  3. 2022年中国互联网招聘行业发展现状及行业优化策略分析[图]
  4. 如何有效提高技能?推荐《刻意练习》
  5. 制作一款STC32G封装为TSSOP20的测试电路板
  6. 线程与并行编程【总结】
  7. 高新技术企业,如何从研发项目中挖掘专利申请?
  8. 增广矩阵的秩判断解的个数_系数矩阵与增广矩阵的秩如何判断
  9. 台湾地震引起的网络危机,即时通讯用什么?
  10. qt emit是什么意思_2020年9月25日 无赞赏QT吗哪 :藐视神的话语也必被藐视