Karp 的技术博客

近期遇到三个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]
Shell

问题如上 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源码, 我们能看是网络的问题.

源码地址 :
Xnip2024-02-20_14-13-25.png

问题在于客户端连接的丢失. 上面三个抛错实际带给生产的问题就是服务停滞, 死掉了. 新数据进不来.偶尔才能进来一些请求.
我们开始认为是处理能力不足导致的. 降低频率增加机器都没有好转. 后来发现服务中访问的一个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进程抛出, 这个抛错 源码地址

Xnip2024-02-20_14-19-27.png

上述代码是一个发送数据的函数,使用阻塞方式进行发送。下面使用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 进行加密通信时会调用相应的发送函数。

能看出来的确是发送请求非正常原因失败, 说了句废话. 因为我上面两个抛错已经发生服务基本废废. 所以没什么好说的.

php swoole

版权属于:karp
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
更新于: 2024年10月18日 07:17
7

目录

来自 《[踩坑] Swoole 抛错 记录》