用jstack发现的一例hbase region server线程死锁

本文详细阐述了在升级Hadoop集群过程中遇到的HBase偶尔无法读写的问题,通过jstack工具发现并分析了由logRoller和HLog.syncer线程引起的死锁现象。文章深入探讨了HBase的WAL机制及其在数据持久化过程中的作用,揭示了死锁的根本原因,并指出是由于集群升级后磁盘I/O增加,以及大型任务执行导致的HLog.syncer异常引发了此问题。最终,文章指出已知的社区修复方案,以及通过优化集群配置来减少磁盘I/O压力作为预防措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在升级hadoop集群的过程中,hbase偶尔出现无法读写的情况,看region server进程并没有挂掉,于是用jstack看下是什么情况:

Found one Java-level deadlock:
=============================
'IPC Server handler 127 on 60020':
  waiting to lock monitor 0x00007fa185def330 (object0x000000057becf198, a java.lang.Object),
  which is held by 'IPC Server handler 21 on 60020'
'IPC Server handler 21 on 60020':
  waiting to lock monitor 0x00007fa1984780b0 (object0x000000057b96e178, a java.lang.Object),
  which is held by 'regionserver60020.logRoller'
'regionserver60020.logRoller':
  waiting to lock monitor 0x00007fa185def330 (object0x000000057becf198, a java.lang.Object),
  which is held by 'IPC Server handler 21 on 60020'
 
Java stack information for the threads listed above:
===================================================
'IPC Server handler 127 on 60020':
        at org.apache.hadoop.hbase.regionserver.wal.HLog.syncer(HLog.java:1305)
        - waiting to lock <0x000000057becf198> (a java.lang.Object)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.sync(HLog.java:1460)
        at org.apache.hadoop.hbase.regionserver.HRegion.doMiniBatchMutation(HRegion.java:2231)
        at org.apache.hadoop.hbase.regionserver.HRegion.batchMutate(HRegion.java:1968)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.multi(HRegionServer.java:3428)
        at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.hadoop.hbase.ipc.WritableRpcEngine$Server.call(WritableRpcEngine.java:364)
        at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1389)
'IPC Server handler 21 on 60020':
 at org.apache.hadoop.hbase.regionserver.wal.HLog.syncer(HLog.java:1314)
        - waiting to lock <0x000000057b96e178> (a java.lang.Object)
        - locked <0x000000057becf198> (a java.lang.Object)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.sync(HLog.java:1460)
        at org.apache.hadoop.hbase.regionserver.HRegion.doMiniBatchMutation(HRegion.java:2231)
        at org.apache.hadoop.hbase.regionserver.HRegion.batchMutate(HRegion.java:1968)
        at org.apache.hadoop.hbase.regionserver.HRegionServer.multi(HRegionServer.java:3428)
        at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.hadoop.hbase.ipc.WritableRpcEngine$Server.call(WritableRpcEngine.java:364)
        at org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:1389)
'regionserver60020.logRoller':
        at org.apache.hadoop.hbase.regionserver.wal.HLog.syncer(HLog.java:1305)
        - waiting to lock <0x000000057becf198> (a java.lang.Object)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.syncer(HLog.java:1283)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.sync(HLog.java:1456)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.cleanupCurrentWriter(HLog.java:876)
        at org.apache.hadoop.hbase.regionserver.wal.HLog.rollWriter(HLog.java:657)
        - locked <0x000000057b96e178> (a java.lang.Object)
        at org.apache.hadoop.hbase.regionserver.LogRoller.run(LogRoller.java:94)
        at java.lang.Thread.run(Thread.java:662)
 
Found 1 deadlock.

显然,这是logRoller和HLog.syncer两个线程发生了死锁。

Hbase中,采用WAL(Write Ahead Log)的方式来保证数据不丢失。一个Region Server对应一个HLog,任何数据都是先写HLog,然后才真正的写MemStore。HLog文件有个轮转的过程,当达到默认大小(一般是block size * 0.95)就会写一个新的HLog文件,logRoller线程就是做这个事情的。而buffer中的数据每隔一秒钟会写一次HLog文件,这个是HLog.syncer线程负责的。logRoller和HLog.syncer进程不能同时进行,不然会导致数据问题,于是就需要通过锁来进行互斥了。

查看了下代码,是在HLog.syncer往HDFS写文件发生IO Exception时会触发死锁。一番google后发现是我们集群使用的hbase 0.94.1版本的一个bug,目前在社区已经修复了:https://issues.apache.org/jira/browse/HBASE-7728

其实频繁触发Hbase的这个bug主要还是因为这次hadoop集群升级引起的。由于hadoop集群升级后导致集群的diskIO变高,加上有些大的任务在测试,HLog.syncer发生IO Exception的几率就更高了,所以RS假死就更频繁了。

<think>好的,我现在需要回答用户的问题:“如何使用jstack诊断Java线程死锁”。用户之前已经询问过Java多线程程序卡住的原因,现在想具体了解如何用jstack工具来检测死锁。首先,我需要回忆之前提供的关于死锁的部分,其中提到使用jstack生成线程转储来查看锁的情况。用户现在希望详细步骤,所以需要分步骤说明操作流程。接下来,参考用户提供的引用内容。引用[1]中提到jstack可以生成线程转储,并且使用-l参数显示死锁信息。引用[2]同样说明jstack用于查找死锁和分析线程堆栈。需要结合这些信息,给出具体的命令和示例。 用户可能不太清楚如何获取jpid,所以需要提到使用jps命令来查找Java进程ID。然后,执行jstack命令,并解释如何分析输出结果中的死锁信息。例如,在输出中搜索“deadlock”或者“Foundone Java-level deadlock”,并展示示例代码块。 还要注意用户提到的系统级指令,比如数学表达式用$...$,但这个问题可能不太涉及数学公式,所以可能不需要。但需要确保中文回答,结构清晰,分步骤说明,并添加引用标识。另外,用户可能需要诊断死锁的具体例子,比如两个线程互相持有锁的情况,所以在步骤中应该包括如何在线程转储中识别这种情况。可能还需要提到如何检查线程状态,如BLOCKED,以及锁的持有者和等待者。 最后,生成相关问题,比如如何预防死锁、其他诊断工具等,确保相关问题与主题相关,并引导用户进一步学习。</think>### 使用 jstack 诊断 Java 线程死锁的方法 #### 1. 获取 Java 进程 ID (PID) ```bash jps -l ``` 输出示例: ```text 12345 com.example.MainApplication 67890 sun.tools.jps.Jps ``` 记录目标程序的 PID(如 `12345`)[^1]。 #### 2. 生成线程转储文件 ```bash jstack -l 12345 > thread_dump.txt ``` `-l` 参数会显示锁的持有和等待信息[^2]。 #### 3. 分析死锁特征 在 `thread_dump.txt` 中搜索以下关键词: - **`deadlock`**:系统检测到的死锁标识 - **`BLOCKED`**:线程阻塞状态 - **`waiting to lock <0x0000000712345678>`**:等待锁的线程 - **`holding lock <0x0000000712345678>`**:持有锁的线程 #### 4. 识别死锁示例 ```text Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007f88d8001234 (object 0x0000000712345678) which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00007f88d8005678 (object 0x0000000712345abc) which is held by "Thread-1" ``` 此示例显示两个线程互相持有对方需要的锁[^2]。 #### 5. 关键数据解析 - **锁标识符**:`0x0000000712345678` 表示内存中的锁对象地址 - **线程状态**:`BLOCKED` 表示线程因锁竞争被阻塞 - **堆栈跟踪**:显示线程在哪个代码行等待锁(需结合源代码) #### 6. 诊断流程图 $$ \begin{cases} \text{运行程序} \rightarrow \text{发现卡顿} \\ \downarrow \\ \text{jps获取PID} \rightarrow \text{jstack生成转储} \\ \downarrow \\ \text{分析死锁特征} \rightarrow \text{定位冲突锁} \\ \downarrow \\ \text{修改同步逻辑} \rightarrow \text{验证修复} \end{cases} $$ #### 7. 高级技巧 - **连续抓取**:间隔 5 秒抓取 3 次转储,观察锁状态变化 ```bash for i in {1..3}; do jstack -l 12345 > dump_$i.txt; sleep 5; done ``` - **结合代码**:通过 `synchronized` 关键字或 `ReentrantLock` 的调用位置验证锁竞争点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值