使用Dalli调用GET无法读取旧版Memcached实例记录的问题排查
问题原因解析
Meta协议请求失败
Memcached 1.4.4不支持Meta协议——Meta协议是在Memcached 1.4.23版本才引入实验性支持的,你的旧版服务器完全无法识别Dalli发送的mg(Meta Get)命令,直接返回ERROR,触发Dalli的Dalli::DalliError。从日志也能看到,客户端协商Meta协议失败后回退到ASCII协议,但发送的mg命令依然不被支持。
二进制协议反序列化失败
二进制协议本身能和Memcached 1.4.4兼容,但数据序列化格式不匹配:
- 你用Perl模块写入的数据,是Perl
Storable模块的序列化格式,和Ruby的Marshal格式完全不同。 - Dalli默认用Ruby
Marshal反序列化值,遇到Perl序列化的二进制数据时,就会因格式不兼容抛出Dalli::UnmarshalError(日志里的版本号提示是误判,本质是格式完全不同)。
修复方案
替换Meta协议为ASCII协议
改用Memcached 1.4.4支持的ASCII协议,修改Dalli初始化代码:
dc = Dalli::Client.new("<address>:11211", socket_timeout: 2.0, protocol: :ascii, namespace: 'ws') dc.get('item_679')
注意:ASCII协议下Dalli依然会自动用Marshal反序列化,所以读取Perl写入的数据时,还要配合下面的步骤。
处理跨语言序列化兼容问题
- 获取原始二进制数据:添加
raw: true选项,让Dalli跳过自动反序列化,返回原始数据:raw_data = dc.get('item_679', raw: true) - 解析Perl Storable格式:安装
ruby-storablegem(gem install ruby-storable),用它解析原始数据:require 'storable' parsed_data = Storable.load(raw_data)
额外建议
- Memcached 1.4.4是2011年的老旧版本,存在安全漏洞和性能瓶颈,建议尽快升级到1.6.x及以上版本。
- 如果需要Ruby和Perl共享Memcached数据,建议统一使用JSON这种跨语言的序列化格式,避免语言特定序列化带来的兼容问题。
内容的提问来源于stack exchange,提问作者ThorTL67
相关产品推荐
相关产品推荐

