共计 1320 个字符,预计需要花费 4 分钟才能阅读完成。
景象
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 依然没有敞开,能够根本必定现场环境应该曾经复现。
问题剖析
一次残缺的数据库申请包含三个阶段:
1、建设连贯
2、数据传输
3、断开连接 connect timeout: 如果与服务器 (这里指数据库) 申请建设连贯的工夫超过 ConnectionTimeOut,就会抛 ConnectionTimeOutException,即服务器连贯超时,没有在规定的工夫内建设连贯。
socket timeout: 如果与服务器连贯胜利,就开始数据传输了。如果服务器解决数据用时过长,超过了 SocketTimeOut,就会抛出 SocketTimeOutExceptin,即服务器响应超时,服务器没有在规定的工夫内返回给客户端数据。
在未设置超时工夫场景下,nifi 通过 jdbc 获取数据库数据,实质是操作系统在调用 Socket.read(),如果网络问题被阻塞住,那么操作系统会很少在调用 Socket,java 培训因为底层没有数据交互,那么其无奈晓得对端是否宕机,所以会始终期待。
难道零碎没有默认的 socketTimeout?
有的,上述场景下内核会在一个 socket 两个小时都没有数据交互状况下 (可设置) 启动 keepalive 定时器来探测对端的 socket。
也就是说呈现假死会在 7875 秒后复原,大略两个多小时吧。
这就是 nifi 端线程假死的起因;
论断
JDBC 的 socket 未设置超时,呈现了死连贯。
JDBC 驱动是用 Socket 形式与数据库连贯的,应用程序和数据库之间的连贯超时并不是由数据库解决的。
当数据库忽然宕掉或产生网络谬误(设施故障等)时,JDBC 驱动的 Socket 超时的值是必须的。因为 TCP/IP 的构造,Socket 没有方法检测到网络谬误,因而利用不能检测到与数据库到连贯断开了。如果没有设置 Socket 超时,应用程序会始终期待数据库返回后果。(这个连贯也被叫做“死连贯”)为了防止死连贯,Socket 必须要设置超时工夫。Socket 超时能够通过 JDBC 驱动程序配置。通过设置 Socket 超时,能够防止出现网络谬误时始终期待的状况并缩短故障工夫。
在 timeout 为 0 的时候,走默认的零碎调用不设置超时工夫的逻辑。在 timeout>0 时,将 socket 设置为非阻塞,而后用 select 零碎调用去模仿超时, 而没有走 linux 自身的超时逻辑。
解决措施
设置 socket 和 Connection 的超时工夫。
避免因为网络问题呈现死连贯,给数据库的拜访 url 加 socket timeout 和 Connection timeout。