近期遇到三个swoole
的抛错日志, 很头疼 有的有解释 有的并没有, 但总体也算是解决了问题.
[2023-11-21 19:44:02<.978122> #9118.2] WARNING del (ERRNO 800): failed to delete events[430], it has already been removed
[2023-11-21 22:17:28<.225417> *19693.61] WARNING Worker_discard_data (ERRNO 1007): [2] ignore data[1272 bytes] received from session#15689
[2023-11-18 09:15:07 *22844.90] WARNING send_blocking(:206): send 40 bytes failed, Error: Resource temporarily unavailable[11]
问题如上 3种抛错, 数据都是swoole
抛错日志, 需要注意的是 :
在Swoole
日志信息中,进程 ID 前会加一些标号,表示日志产生的线程 / 进程类型。
#
Master 进程$
Manager 进程*
Worker 进程^
Task 进程
依次介绍错误日志以及解决方案:
[2023-11-21 19:44:02<.978122> #9118.2] WARNING del (ERRNO 800): failed to delete events[430], it has already been removed
直接翻译下: 警告:删除失败(错误号800):无法删除事件[588],它已经被移除。
首先这个错误使用#
Master 进程 抛出 删除事件失败. 通过抛错读取swoole源码, 我们能看是网络的问题.
源码地址 :
问题在于客户端连接的丢失. 上面三个抛错实际带给生产的问题就是服务停滞, 死掉了. 新数据进不来.偶尔才能进来一些请求.
我们开始认为是处理能力不足导致的. 降低频率增加机器都没有好转. 后来发现服务中访问的一个tcp
服务请求丢包后.没有回执导致进程一直在recv
, 因为客户端是使用的 swoole
同步阻塞TCP
客户端 超时时间设置的 -1
;
[2023-11-21 22:17:28<.225417> *19693.61] WARNING Worker_discard_data (ERRNO 1007): [2] ignore data[1272 bytes] received from session#15689
这个抛错就比较好理解了. 他总是和 ERRNO 800 一起出现. 能看到日志* Worker 进程抛出的错误 .
直接翻译下 : 警告:Worker_discard_data(错误号1007):[2] 忽略从会话#15689接收到的数据[1272字节]。
细节内容可以看之前的文章 , 简单来说就是 服务端找不到客户端的连接了, 客户端没了就拒绝执行请求了. 设置一下 discard_timeout_request 参数, 没有客户端后仍执行请求就好了, 这个参数设置需要参考场景, 我是内部服务不存在外部垃圾请求.
[2023-11-18 09:15:07 *22844.90] WARNING send_blocking(:206): send 40 bytes failed, Error: Resource temporarily unavailable[11]
直接翻译下 : 警告:send_blocking(:206):
发送40
字节失败,错误:资源暂时不可用。
这个错误抛错 是 *
Worker进程抛出, 这个抛错 源码地址
上述代码是一个发送数据的函数,使用阻塞方式进行发送。下面使用ChatGPT对代码进行逐行解释:
上述代码是一个发送数据的函数,使用阻塞方式进行发送。下面使用ChatGPT对代码进行逐行解释:
ssize_t Socket::send_blocking(const void *__data, size_t __len) {
ssize_t n = 0;
ssize_t written = 0;
// 循环发送数据,直到全部数据发送完成
while (written < (ssize_t) __len) {
#ifdef SW_USE_OPENSSL
if (ssl) {
// 使用 OpenSSL 发送数据
n = ssl_send((char *) __data + written, __len - written);
} else
#endif
{
// 使用系统的 send 函数发送数据
n = ::send(fd, (char *) __data + written, __len - written, 0);
}
// 发送数据时发生错误
if (n < 0) {
// 如果错误码为 EINTR,表示发送过程被中断,可以继续尝试发送数据
if (errno == EINTR) {
continue;
}
// 如果错误类型为 SW_WAIT,并且在发送超时时间内等待写事件发生,则继续尝试发送数据
else if (catch_write_error(errno) == SW_WAIT &&
wait_event((int) (send_timeout_ * 1000), SW_EVENT_WRITE) == SW_OK) {
continue;
}
// 其他情况下发送数据失败,记录日志并返回错误码
else {
swoole_sys_warning("send %lu bytes failed", __len);
return SW_ERR;
}
}
// 更新已发送字节数
written += n;
}
// 返回已发送的总字节数
return written;
}
该函数使用一个循环来保证在发送过程中能够完整地发送全部数据,处理了一些错误情况,并通过返回值来表示发送的结果。其中,在使用 OpenSSL 进行加密通信时会调用相应的发送函数。
能看出来的确是发送请求非正常原因失败, 说了句废话. 因为我上面两个抛错已经发生服务基本废废. 所以没什么好说的.