一次 HashSet 所引起的并发问题(下)

简介: 首先了解下这个应用大概是做什么的。 简单来说就是从 MQ 中取出数据然后丢到后面的业务线程池中做具体的业务处理。 而报警的队列正好就是这个线程池的队列。

已经很明显了。这里在遍历链表,同时由于形成了环形链表导致这个 e.next 永远不为空,所以这个循环也不会退出了。


到这里其实已经找到问题了,但还有一个疑问是为什么线程池里的任务队列会越堆越多。我第一直觉是任务执行太慢导致的。


仔细查看了代码发现只有一个地方可能会慢:也就是有一个数据库的查询


把这个 SQL 拿到生产环境执行发现确实不快,查看索引发现都有命中。


但我一看表中的数据发现已经快有 7000W 的数据了。同时经过运维得知 MySQL 那台服务器的 IO 压力也比较大。


所以这个原因也比较明显了:


由于每消费一条数据都要去查询一次数据库,MySQL 本身压力就比较大,加上数据量也很高所以导致这个 IO 响应较慢,导致整个任务处理的就比较慢了。


但还有一个原因也不能忽视;由于所有的业务线程在某个时间点都进入了死循环,根本没有执行完任务的机会,而后面的数据还在源源不断的进入,所以这个队列只会越堆越多!


这其实是一个老应用了,可能会有人问为什么之前没出现问题。


这是因为之前数据量都比较少,即使是并发写入也没有出现并发扩容形成环形链表的情况。这段时间业务量的暴增正好把这个隐藏的雷给揪出来了。所以还是得信墨菲他老人家的话。


总结


至此整个排查结束,而我们后续的调整措施大概如下:


  • HashSet 不是线程安全的,换为 ConcurrentHashMap同时把 value 写死一样可以达到 set 的效果。


  • 根据我们后面的监控,初始化 ConcurrentHashMap 的大小尽量大一些,避免频繁的扩容。


  • MySQL 中很多数据都已经不用了,进行冷热处理。尽量降低单表数据量。同时后期考虑分表。


  • 查数据那里调整为查缓存,提高查询效率。


  • 线程池的名称一定得取的有意义,不然是自己给自己增加难度。


  • 根据监控将线程池的队列大小调整为一个具体值,并且要有拒绝策略。


  • 升级到 JDK1.8


  • 再一个是报警邮件酌情考虑为电话通知😂。


HashMap 的死循环问题在网上层出不穷,没想到还真被我遇到了。现在要满足这个条件还是挺少见的,比如 1.8 以下的 JDK 这一条可能大多数人就碰不到,正好又证实了一次墨菲定律。


同时我会将文章更到这里,方便大家阅读和查询。


相关文章
|
11月前
|
计算机视觉
Opencv学习笔记(十二):图片腐蚀和膨胀操作
这篇文章介绍了图像腐蚀和膨胀的原理、作用以及使用OpenCV实现这些操作的代码示例,并深入解析了开运算和闭运算的概念及其在图像形态学处理中的应用。
617 1
Opencv学习笔记(十二):图片腐蚀和膨胀操作
|
9月前
|
存储 关系型数据库 数据库
【赵渝强老师】PostgreSQL的控制文件
本文介绍了PostgreSQL数据库的物理存储结构,重点解析了控制文件,包括其重要性及如何通过`pg_controldata`命令查看控制文件内容。控制文件记录了数据库运行的关键信息,如数据库状态、WAL位置等。
238 14
|
机器学习/深度学习 并行计算 Linux
Stabble Diffusion 本地部署教程详解
Stabble Diffusion 本地部署教程详解
1182 1
|
11月前
|
存储 缓存 数据处理
简述计算机X86架构
【10月更文挑战第3天】本文介绍了计算机的基本工作原理,重点阐述了CPU(中央处理器)及其组成部分:运算单元、数据单元和控制单元的功能。文中解释了CPU通过总线与内存等设备通信的过程,并详细描述了指令执行的步骤,包括指令获取、数据处理和结果存储。此外,还介绍了地址总线和数据总线的作用,以及段寄存器在内存管理中的应用。最后,提供了一些基本的CPU指令示例。文中配有多幅插图帮助理解。
|
9月前
|
Web App开发 JavaScript 前端开发
Node.js开发
Node.js开发
185 13
|
SQL 运维 分布式计算
一文看懂如何做好 SQL 质量监控
一文看懂如何做好 SQL 质量监控
113314 51
|
12月前
|
Linux Go C语言
用 Cython 包装静态库和动态库
用 Cython 包装静态库和动态库
185 0
|
NoSQL 应用服务中间件 Redis
分布式锁【 基于synchronized锁解决超卖问题、分布式锁解决方案、悲观锁实现的分布式锁】(二)-全面详解(学习总结---从入门到深化)
分布式锁【 基于synchronized锁解决超卖问题、分布式锁解决方案、悲观锁实现的分布式锁】(二)-全面详解(学习总结---从入门到深化)
193 1
|
存储 SQL NoSQL
数据库是存储和管理数据的核心组件
【5月更文挑战第14天】数据库是存储和管理数据的核心组件
196 1
|
数据采集 前端开发 关系型数据库
修剪字符串:深入了解MySQL中的TRIM()函数
在数据库操作中,去除字符串首尾的空格或特定字符是常见的需求,这时可以使用MySQL中的TRIM()函数。本文将深入探讨TRIM()函数的用法、示例以及在数据库操作中的应用。
1408 0