现象
ExcuteSql不工作不调度,stop也停止不了,active的任务个数也不降低。
场景复现
1. 模仿现场构造数据
2. Tc命令模拟现场网络环境模拟丢包30%
tc qdisc del dev enp4s0f0 root netem loss 30%
问题排查
netstat -pan | grep $NIFI_PID

可以看到和数据库开启了5个tcp连接,也可以看到有五个socket处于连接状态
直接看线程
jstack -l $NIFI_PID | grep 'java.net.SocketInputStream.socketRead0(Native Method)' -C 10

观察了一段时间,socket仍然没有关闭,可以基本肯定现场环境应该已经复现。
问题分析

也就是说出现假死会在7875秒后恢复,大概两个多小时吧。
这就是nifi端线程假死的原因;
结论
JDBC的socket未设置超时,出现了死连接。
JDBC 驱动是用 Socket 方式与数据库连接的,应用程序和数据库之间的连接超时并不是由数据库处理的。
当数据库突然宕掉或发生网络错误(设备故障等)时,JDBC 驱动的 Socket 超时的值是必须的。由于 TCP/IP 的结构,Socket 没有办法检测到网络错误,因此应用不能检测到与数据库到连接断开了。如果没有设置 Socket 超时,应用程序会一直等待数据库返回结果。(这个连接也被叫做“死连接”) 为了避免死连接,Socket 必须要设置超时时间。Socket 超时可以通过 JDBC 驱动程序配置。通过设置 Socket 超时,可以防止出现网络错误时一直等待的情况并缩短故障时间。
设置socketTimeout好处如下图:

在timeout为0的时候,走默认的系统调用不设置超时时间的逻辑。在timeout>0时,将socket设置为非阻塞,然后用select系统调用去模拟超时,而没有走linux本身的超时逻辑。
解决措施
设置socket和Connection的超时时间。
JDBC Driver | Timeout单位 | Url格式(+) |
sqlserver | s | connectTimeout=300&socketTimeout=300 |
Pgsql/gpsql | s | loginTimeout=300&socketTimeout=300 |
mysql | ms | loginTimeout=300000&socketTimeout=300000 |
oracle | ms | 不支持url配置 |
防止因为网络问题出现死连接,给数据库的访问url加socket timeout和Connection timeout。




