目前nginx内部处理网络事件是基于epoll机制:先收集目前处于ready状态的网络事件列表,然后逐个处理。处理完再收集处理ready状态的网络事件,再逐个处理。依次循环。
如果某个网络事件处理比较慢,遇到瓶颈,则后续所有的网络事件都受到影响被延迟处理。这就会导致网络对端迟迟得不到响应,提前断开连接。导致网络访问日志很多5xx错误。
设计思路:
1、在nginx收集网络事件串行处理前,预写入每个worker进程号和时间戳;
2、正常情况下,如果不存在阻塞网络事件,所有的网络事件很快就处理完了,进程号和时间戳得到了刷新;
3、如果存在阻塞网络事件,在x秒之后还未更新时间戳,此时外部扫描时间超时,并打印当前的进程堆栈信息和堆栈变量信息到文件中,保留第一现场资料。
现有方式:
优化后的方式:
具体实现方式:
1.在initwork阶段预写每个worker进程号和时间戳:timer_bottleneck_check.lua,写入到哈希字典中,key为不加密的进程号,value为十位的时间戳,精确到秒;
2.外部扫描程序:获取当前所有worker进程号,判断当前时间-上次时间戳是否大于配置的超时时间,如果大于,则通过执行bstack.sh得到当前进程的堆栈信息,并输出到bstack_pid.log中;
3.bstack.sh 类似于pstack,输入进程的堆栈信息和局部变量信息。