zoukankan      html  css  js  c++  java
  • golang RWMutex RLock重入导致死锁

    现象

    一个组件实现了raft分布式协议,在分布式部署环境中来进行选主,在某客户现场突然发生文件句柄泄露,在打印某些错误日志后,几个小时内没有日志打印,然后某个协程突然报无可用的文件句柄。

    分析

    经过代码和日志分析,组件正常每分钟会打印所有部署节点的日志信息,没有打印日志说明定时器处理逻辑for...select里面某个函数逻辑卡住了,然后发生文件句柄泄露,经过梳理是在响应心跳的逻辑没有回,导致一直创建协程。心跳响应逻辑和定时器处理逻辑中有用到同一个锁,初步判断为这个锁发生死锁。

    在本地环境复现了后,通过debug/pprof分析,确实有四处在等待该锁,两处等待写锁,两处等待读锁,但是代码看起来都很正常;pprof分析也没有提示死锁。然后通过搜索引擎搜索关键词“RWMutex 死锁”,找到一篇文件说RWMutex RLock重入可能导致死锁,如果网络异常,有分布式节点疑似下线时,代码中确实有一处会有该锁的RLock同一协程两次重入调用。

    RLock重入死锁复现

     1 func TestDeadLock(t *testing.T) {
     2     var l sync.RWMutex
     3     var wg sync.WaitGroup
     4     wg.Add(2)
     5 
     6     c := make(chan int)
     7     go func() {
     8         defer wg.Done()
     9 
    10         l.RLock()
    11         defer l.RUnlock()
    12         t.Log("acquire RLock first")
    13 
    14         c <- 1
    15         runtime.Gosched()
    16 
    17         t.Log("wait readLock")
    18         l.RLock()
    19         defer l.RUnlock()
    20         t.Log("acquire RLock second")
    21     }()
    22 
    23     go func() {
    24         defer wg.Done()
    25 
    26         <-c
    27 
    28         t.Log("wait writeLock")
    29         l.Lock()
    30         defer l.Unlock()
    31         t.Log("acquire Lock")
    32     }()
    33 
    34     wg.Wait()
    35     t.Log("test finish")
    36 }

    通过以上测试代码,很容易复现该死锁现象,而在java中可重入读写锁读锁重入不会导致死锁,所以刚开始看到RLock重入时也没有想到该问题。

    源码分析

    参考文档

    golang RWMutex RLock重入导致死锁

  • 相关阅读:
    JDBC 复习4 批量执行SQL
    JDBC 复习3 存取Oracle大数据 clob blob
    Oracle复习
    Linux命令(1)grep
    JDBC 复习2 存取mysql 大数据
    JDBC 复习1 DBUtil
    php 环境搭建问题
    Windows 批处理 bat 开启 WiFi 菜单选项 设置ID PWD
    Bat 批处理启动和停止Oracle 服务
    docker 学习1 WSL docker ,Windows docker
  • 原文地址:https://www.cnblogs.com/luoming1224/p/14636543.html
Copyright © 2011-2022 走看看