Bash读取postgres输出fd3时阻塞死锁的问题排查及解决方案
问题解答
1. 管道缓冲区大小调整方法
你之前调整的net.unix.max_dgram_qlen是Unix域数据报套接字的队列参数,和你用到的进程替换生成的管道无关,所以不生效。Linux系统下管道缓冲区的调整方法如下:
- 先调整系统级管道最大缓冲区限制:
临时生效执行:
永久生效将sysctl -w fs.pipe-max-size=10485760 # 单位为字节,这里设置为10Mfs.pipe-max-size=10485760写入/etc/sysctl.conf,执行sysctl -p加载配置。 - 针对你脚本中打开的fd3单独调整缓冲区大小:
在exec 3< <(...)语句执行后,新增以下代码调整缓冲区到1M:
也可以用C写轻量工具调用fcntl接口实现相同效果,适合没有python环境的场景。python3 -c "import fcntl; fcntl.fcntl(3, fcntl.F_SETPIPE_SZ, 1048576)"
2. 方案优化建议
调整缓冲区大小只能降低死锁概率,只要存在暂停读取管道的逻辑,缓冲区总有被打满的可能,你自己提供的执行SQL前清空缓冲区的方案稳定性更高,可优化以下细节:
- 移除重复行判断逻辑:原有逻辑中如果出现连续两行相同的合法日志,会被误判为缓冲区已空,导致还有积压数据未读取。优化后的清空逻辑如下:
调整超时时间为0.5秒、连续2次超时判空的逻辑,兼顾清空效率和准确性。echo "Empty postgres output buffer before executing sql command" # 连续2次读取超时则认为缓冲区已空 local timeout_count=0 while [ $timeout_count -lt 2 ] do read -u 3 -t 0.5 line if [ $? -ne 0 ] then ((timeout_count++)) continue fi timeout_count=0 echo "Postgres: $line" done echo "Buffer is empty"
内容的提问来源于stack exchange,提问作者Torge
相关产品推荐
相关产品推荐

