PHP 8.2中哪些内置函数会意外创建Unix Socket对?
PHP CLI进程Unix Socket泄漏排查
我们在Kubernetes上运行的多个PHP Pod中,有两个出现了Unix Socket泄漏问题。PHP CLI进程持续打开Unix Socket却不关闭,最终在无关代码处触发PHP崩溃,报错:
PHP Warning: stream_select(): You MUST recompile PHP with a larger value of FD_SETSIZE.
其他Pod也会打开少量Unix Socket,但数量极少,不构成问题。
令人困惑的是,我们并未主动使用Unix Socket,所有进程间通信均通过TCP/IP完成。这些泄漏的Socket具备以下特征:
- 处于
ESTABLISHED状态 ss -x显示这些Socket未发送或接收任何数据- 文件系统中无对应文件
netstat显示它们的RefCount均为3ss -xp显示每个Socket的两端均由同一个PHP进程持有
代码中未调用stream_socket_pair或socket_create_pair函数,推测这些Socket是调用其他PHP内置函数时的副作用产生的。CURL是主要怀疑对象,但其他Pod也大量使用CURL却无此问题,且暂时未发现这两个Pod的特殊操作。
疑问:哪些PHP内置函数(含默认捆绑扩展中的函数)会意外创建Unix Socket对?
补充:ss -xp输出
# ss -xp Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process u_str ESTAB 0 0 * 481304571 * 481304572 users:(("php",pid=7,fd=494)) u_str ESTAB 0 0 * 480934363 * 480934362 users:(("php",pid=7,fd=289)) u_str ESTAB 0 0 * 480899260 * 480899259 users:(("php",pid=7,fd=255)) u_str ESTAB 0 0 * 480853228 * 480853229 users:(("php",pid=7,fd=207)) u_str ESTAB 0 0 * 478659551 * 478659550 users:(("php",pid=7,fd=82)) u_str ESTAB 0 0 * 481263776 * 481263775 users:(("php",pid=7,fd=484)) u_str ESTAB 0 0 * 481014545 * 481014546 users:(("php",pid=7,fd=339)) u_str ESTAB 0 0 * 480847844 * 480847845 users:(("php",pid=7,fd=221)) u_str ESTAB 0 0 * 479446282 * 479446283 users:(("php",pid=7,fd=185)) u_str ESTAB 0 0 * 479430966 * 479430965 users:(("php",pid=7,fd=162)) u_str ESTAB 0 0 * 481391710 * 481391711 users:(("php",pid=7,fd=515)) u_str ESTAB 0 0 * 481013994 * 481013995 users:(("php",pid=7,fd=352)) u_str ESTAB 0 0 * 480884372 * 480884373 users:(("php",pid=7,fd=233)) .... many, many more lines ...
可能的PHP内置函数及分析
以下是可能在内部创建Unix Socket对的PHP内置函数/扩展,结合你的场景逐一分析:
1. CURL扩展相关操作
虽然其他Pod也使用CURL,但特定场景下仍可能触发内部Socket创建:
- 若CURL启用
CURLOPT_PROXY且存在配置错误(比如误设为Unix Socket类型代理),或PHP/CURL版本存在bug,可能意外创建Unix Socket对 - 第三方库、配置文件或环境变量可能间接设置
CURLOPT_UNIX_SOCKET_PATH参数,导致Socket创建 - 长运行CLI进程中,部分PHP版本的CURL扩展在连接池管理、超时回调逻辑中存在Socket未正确回收的bug
2. 进程控制(pcntl)扩展
如果代码使用pcntl_fork()等函数,PHP内部可能通过Unix Socket对实现父子进程间通信(如信号同步、状态传递)。若子进程退出时未正确关闭Socket,会导致父进程残留Socket描述符。
3. 外部命令执行函数
proc_open():未显式指定管道类型时,PHP可能默认创建Unix Socket对作为进程间通信管道,若未调用proc_close()关闭资源,会造成泄漏exec()/shell_exec():部分PHP版本处理标准IO重定向时,内部可能创建临时Unix Socket对,回收逻辑bug会导致泄漏
4. 流处理函数
popen():内部可能创建Unix Socket对作为管道,未通过pclose()关闭会引发泄漏stream_select()本身不创建Socket,但未关闭的泄漏Socket会加剧文件描述符耗尽问题
5. 其他默认扩展
posix扩展:部分进程间通信相关函数可能回退使用Unix Socketsysvmsg/sysvsem等IPC扩展:部分实现会以Unix Socket作为 fallback 机制
额外排查建议
- 对比异常Pod与正常Pod的PHP版本、扩展版本(重点CURL、pcntl),定位版本差异引发的bug
- 启用
zend.detect_leaks配置,结合valgrind跟踪文件描述符变化,定位具体触发函数 - 检查异常Pod的环境变量、php.ini等配置文件,确认是否存在与正常Pod不同的Socket/代理相关配置
内容的提问来源于stack exchange,提问作者Vilx-
相关产品推荐
相关产品推荐

