PHP 8.1中连接Memcached失败?确认libmemcached版本及扩展配置正确吗?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1032个文字,预计阅读时间需要5分钟。
这是一个关于PHP与memcached库兼容性的问题描述,以下是其简写版:
验证方式很简单:php --ri memcached 输出里若出现 libmemcached version => 0.0.0 或直接空白,说明扩展根本没绑定到真正的库;若显示版本号但低于 1.0.18,建议升级。
- Linux 下用
ldd $(php-config --extension-dir)/memcached.so | grep memcached看是否能找到libmemcached.so动态链接 - Windows 下需确认
libmemcached.dll和libhashkit.dll已放在C:\Windows或系统%PATH%路径中(缺任一都会加载失败) - 编译安装时必须显式指定
--with-libmemcached-dir=/usr/local(假设你把 libmemcached 装在了 /usr/local)
addServer() 不报错但 set() 总是返回 true、get() 却拿不到值
这是典型的“协议接收成功但服务端未写入”现象,根源常在序列化配置和过期时间语义上。Memcached 扩展默认使用 Memcached::SERIALIZER_PHP,而 PHP 8.1 默认禁用了 unserialize() 的对象反序列化(unserialize_callback_func 未设),导致 get() 解包失败后静默返回 false。
最稳妥的做法是关闭序列化:$mc->setOptions([Memcached::OPT_SERIALIZER => Memcached::SERIALIZER_NONE]);
立即学习“PHP免费学习笔记(深入)”;
-
set($key, $value, $expiration)中的$expiration是相对秒数(≤30 天),不是时间戳;传 0 表示永不过期,但某些旧版 libmemcached 会误判为立即过期 - 别依赖
set()返回值判断写入成功——它只表示请求发出去了;要用$mc->getResultCode() === Memcached::RES_SUCCESS校验 - 如果 value 是数组或对象,又必须用序列化,请确保 PHP 配置中
unserialize_callback_func已正确定义,且类定义已提前加载
PHP 8.1 连接本地 127.0.0.1:11211 超时,但 telnet 能通
说明服务端正常,问题出在客户端连接策略上。PHP 8.1 的 memcached 扩展默认启用 TCP_NODELAY,且对 connect timeout 更严格;若未显式设置超时选项,可能卡在 DNS 解析或内核重传上。
必须在 new Memcached() 后、addServer() 前调用:$mc->setOptions([Memcached::OPT_CONNECT_TIMEOUT => 1000, Memcached::OPT_RETRY_TIMEOUT => 1]);
-
OPT_CONNECT_TIMEOUT单位是毫秒(不是秒),设成 1000 比设 1 更安全 -
OPT_RETRY_TIMEOUT控制重试间隔,设为 1 表示失败后立刻重试一次,避免长等待 - 绝对不要碰
OPT_SEND_TIMEOUT和OPT_RECV_TIMEOUT——PHP 8+ 已废弃,设了反而触发警告甚至 fatal error - 检查
addServer()的第三个参数$weight是否为 0:权重为 0 会导致该节点被跳过,看似连了实则没路由过去
为什么 isPristine() 返回 true 却 getVersion() 报错
isPristine() 只表示对象刚 new 出来、还没调用过任何网络操作;它不保证服务器可达。getVersion() 是第一个真正发请求的方法,此时才触发实际连接。如果这时报错,说明 addServer() 后没有做连接探测,或者服务端响应异常(如返回空包、协议不匹配)。
可靠探测方式是组合使用:if ($mc->isPristine() || !$mc->getVersion()) { $mc->addServer('127.0.0.1', 11211); }
- 这个判断不能放每次请求里——开销大,适合放在连接池初始化或上一次操作失败后的恢复逻辑中
- 注意
getVersion()返回的是 array,不是 string;若返回空数组或false,大概率是连接失败或服务端拒绝响应 - Windows 下尤其要注意:PHP 8.1 的 memcached 扩展对 IPv6 地址解析有 bug,强制用
127.0.0.1而非localhost,否则可能卡住
本文共计1032个文字,预计阅读时间需要5分钟。
这是一个关于PHP与memcached库兼容性的问题描述,以下是其简写版:
验证方式很简单:php --ri memcached 输出里若出现 libmemcached version => 0.0.0 或直接空白,说明扩展根本没绑定到真正的库;若显示版本号但低于 1.0.18,建议升级。
- Linux 下用
ldd $(php-config --extension-dir)/memcached.so | grep memcached看是否能找到libmemcached.so动态链接 - Windows 下需确认
libmemcached.dll和libhashkit.dll已放在C:\Windows或系统%PATH%路径中(缺任一都会加载失败) - 编译安装时必须显式指定
--with-libmemcached-dir=/usr/local(假设你把 libmemcached 装在了 /usr/local)
addServer() 不报错但 set() 总是返回 true、get() 却拿不到值
这是典型的“协议接收成功但服务端未写入”现象,根源常在序列化配置和过期时间语义上。Memcached 扩展默认使用 Memcached::SERIALIZER_PHP,而 PHP 8.1 默认禁用了 unserialize() 的对象反序列化(unserialize_callback_func 未设),导致 get() 解包失败后静默返回 false。
最稳妥的做法是关闭序列化:$mc->setOptions([Memcached::OPT_SERIALIZER => Memcached::SERIALIZER_NONE]);
立即学习“PHP免费学习笔记(深入)”;
-
set($key, $value, $expiration)中的$expiration是相对秒数(≤30 天),不是时间戳;传 0 表示永不过期,但某些旧版 libmemcached 会误判为立即过期 - 别依赖
set()返回值判断写入成功——它只表示请求发出去了;要用$mc->getResultCode() === Memcached::RES_SUCCESS校验 - 如果 value 是数组或对象,又必须用序列化,请确保 PHP 配置中
unserialize_callback_func已正确定义,且类定义已提前加载
PHP 8.1 连接本地 127.0.0.1:11211 超时,但 telnet 能通
说明服务端正常,问题出在客户端连接策略上。PHP 8.1 的 memcached 扩展默认启用 TCP_NODELAY,且对 connect timeout 更严格;若未显式设置超时选项,可能卡在 DNS 解析或内核重传上。
必须在 new Memcached() 后、addServer() 前调用:$mc->setOptions([Memcached::OPT_CONNECT_TIMEOUT => 1000, Memcached::OPT_RETRY_TIMEOUT => 1]);
-
OPT_CONNECT_TIMEOUT单位是毫秒(不是秒),设成 1000 比设 1 更安全 -
OPT_RETRY_TIMEOUT控制重试间隔,设为 1 表示失败后立刻重试一次,避免长等待 - 绝对不要碰
OPT_SEND_TIMEOUT和OPT_RECV_TIMEOUT——PHP 8+ 已废弃,设了反而触发警告甚至 fatal error - 检查
addServer()的第三个参数$weight是否为 0:权重为 0 会导致该节点被跳过,看似连了实则没路由过去
为什么 isPristine() 返回 true 却 getVersion() 报错
isPristine() 只表示对象刚 new 出来、还没调用过任何网络操作;它不保证服务器可达。getVersion() 是第一个真正发请求的方法,此时才触发实际连接。如果这时报错,说明 addServer() 后没有做连接探测,或者服务端响应异常(如返回空包、协议不匹配)。
可靠探测方式是组合使用:if ($mc->isPristine() || !$mc->getVersion()) { $mc->addServer('127.0.0.1', 11211); }
- 这个判断不能放每次请求里——开销大,适合放在连接池初始化或上一次操作失败后的恢复逻辑中
- 注意
getVersion()返回的是 array,不是 string;若返回空数组或false,大概率是连接失败或服务端拒绝响应 - Windows 下尤其要注意:PHP 8.1 的 memcached 扩展对 IPv6 地址解析有 bug,强制用
127.0.0.1而非localhost,否则可能卡住

