同设备访问php的多个接口会有先后等待问题
同设备访问php的多个接口会有先后等待问题
这个现象的核心原因通常与 PHP 的 Session 锁机制 有关,即使两个接口表面上无关联,也可能因共享 Session 导致请求排队。以下是详细分析:
关键背景:PHP 的 Session 锁机制
PHP 的 Session 默认通过文件存储(session.save_handler = files),且为了保证数据一致性,同一 Session ID 的请求会独占 Session 文件锁。具体表现为:
当第一个请求(如接口 A)启动 Session(隐式或显式)时,PHP 会锁定该 Session 文件(防止其他请求同时修改)。
在第一个请求结束或显式释放锁前,后续使用 相同 Session ID 的请求(如接口 B)会被阻塞,直到锁释放。
你的场景分析
假设你的两个接口满足以下条件:
同一设备:浏览器会自动传递相同的 Cookie(包含 PHPSESSID),因此两个请求共享同一个 Session ID。
接口 A 隐式启动了 Session:即使接口 A 的代码中没有显式调用 session_start(),PHP 也可能因配置(如 session.auto_start = 1 在 php.ini 中)自动启动 Session。
接口 B 同样需要访问 Session:即使 B 接口没有主动操作 Session,只要它因自动启动或代码中调用了 session_start(),就会尝试获取 Session 锁。
具体流程
请求 A 先到达服务器:
接口 A 启动 Session(可能隐式),PHP 锁定该 Session 文件,开始执行 sleep(20)。此时 Session 锁被 A 持有,未释放。
请求 B 随后到达:
接口 B 因使用相同 PHPSESSID,尝试启动 Session 时发现锁被 A 占用,被迫等待,直到 A 的请求结束(或显式释放锁)。
A 执行完毕:
A 的 sleep(20) 结束并输出结果后,PHP 自动释放 Session 锁(或通过 session_write_close() 提前释放)。此时 B 才能获取锁并执行,输出结果。
验证与解决方案
验证是否是 Session 锁问题
在接口 A 和 B 的代码中添加 var_dump(session_status());,若返回 PHP_SESSION_ACTIVE,说明 Session 被启动。
临时关闭 Session:在接口开头添加 session_write_close();(释放锁)或 session_abort();(不启动 Session),观察 B 是否不再等待。
解决方案
无必要时关闭 Session:
若接口不需要使用 Session,在代码开头添加 session_abort();(PHP 7.0+)或注释掉 session_start(),避免自动启动。
提前释放 Session 锁:
若接口需要使用 Session 但操作完成后无需继续持有锁,在数据读写完成后调用 session_write_close(); 提前释放锁(例如在 sleep(20) 前释放)。
修改 Session 存储方式:
将 Session 存储从文件改为 Redis/Memcached 等支持并发的存储介质(通过 session.save_handler 配置),避免文件锁问题。
总结
表面无关联的接口 A 和 B 因共享 Session ID,被 PHP 的 Session 文件锁机制强制排队。解决核心是避免不必要的 Session 启动,或提前释放 Session 锁