1. XFS文件系统死锁问题深度解析
最近在排查一个PostgreSQL数据库性能问题时,遇到了XFS文件系统挂起(hung)的棘手情况。多个postgres进程都处于D状态(不可中断睡眠),系统几乎无法响应。通过分析内核堆栈,发现问题出在XFS文件系统的inode管理机制上,两个进程因为锁的相互等待形成了典型的ABBA死锁。下面我将详细剖析这个问题的来龙去脉,以及最终的解决方案。
注意:本文涉及Linux内核和XFS文件系统的底层机制,需要一定的操作系统和文件系统基础知识。但我会尽量用通俗的语言解释关键概念。
1.1 问题现象与初步诊断
系统表现出以下症状:
- 多个postgres进程处于D状态(不可中断睡眠)
- 系统响应缓慢,几乎无法执行新命令
- iostat显示磁盘I/O极低,但系统负载很高
- 通过
cat /proc/<pid>/stack获取的进程堆栈显示,多个进程卡在xfs_iget和xfs_fs_destroy_inode路径上
通过分析最早进入D状态的进程(pid=202276)的堆栈,发现它卡在xfs_fs_destroy_inode路径上,具体是在尝试获取AGF(Allocation Group Free space)缓冲区锁时被阻塞。AGF是XFS用来管理空闲块的重要数据结构。
1.2 关键堆栈分析
1.2.1 进程1:销毁文件路径
这是最早进入D状态的进程堆栈(简化版):
code复制#9 xfs_read_agf / xfs_alloc_read_agf [xfs] ← 尝试获取AGF buf
#14 xfs_inodegc_* / xfs_ifree_cluster [xfs]
#15 xfs_inactive_ifree [xfs]
#16 xfs_destroy_inode [xfs]
#17 xfs_fs_destroy_inode [xfs] ← 释放inode主路径
这个进程正在执行文件删除操作,需要释放inode和相关的磁盘空间。在这个过程中,它需要:
- 获取inode cluster buffer的锁
- 获取AGF的锁来更新空闲块信息
1.2.2 进程2:创建文件路径
另一个关键进程(pid=1894063)的堆栈:
code复制#2 xf
