最近公司许多团队进行升级php7,目前支持php7读取mc的扩展只有memcached。

但是公司许多项目都会共用一个mc集群来存取用户session数据,存的时候是登陆时用memcache扩展以array的形式写进去,读的时候自然是用memcache扩展以array的形式读出来。 但是现在只能使用memcached进行读取。但是据我所知两者读取array形式的数据是互不兼容的,因此想探究一下究竟是为什么。

验证memcache扩展和memcached扩展读写数组数据是否不相兼容

测试脚本:

<?phpecho"==========teststring============\n";$mc=newmemcache;$mc->addServer('10.199.189.129',10002);$key='testString';$mc->set($key,'testsuccess');var_dump($mc->get($key));$mc2=newmemcached;$mc2->addServer('10.199.189.129',11511);var_dump($mc2->get($key));echo"==========testarray============\n";$key2='testArray';$mc->set($key2,[1,2,3]);var_dump($mc->get($key2));var_dump($mc2->get($key2));

执行结果:

~php/apps/dat/test.php==========teststring============string(12)"testsuccess"string(12)"testsuccess"==========testarray============array(3){[0]=>int(1)[1]=>int(2)[2]=>int(3)}int(0)

从结果来看,印证了我们之前的说法。

猜测原因

由于string没有问题,出问题是在array格式里面。所以怀疑是array存进mc时的序列化方法不同。于是乎进行进一步的测试:

编写测试脚本

<?phpecho"==========testarray============\n";$mc=newmemcache;$mc->addServer('10.199.189.129',11511);$mc2=newmemcached;$mc2->addServer('10.199.189.129',11511);$key2='testArray1';$key3='testArray2';$mc->set($key2,[1,2,3]);$mc2->set($key3,[1,2,3]);var_dump($mc->get($key2));var_dump($mc2->get($key3));

执行结果:

~php/apps/dat/test.php==========testarray============array(3){[0]=>int(1)[1]=>int(2)[2]=>int(3)}array(3){[0]=>int(1)[1]=>int(2)[2]=>int(3)}

接下来直接连接mc进行查看

~telnet10.199.189.12911511Trying10.199.189.129...Connectedtomsession.vip.vip.co.Escapecharacteris'^]'.gettestArray1VALUEtestArray1130a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}ENDgettestArray2VALUEtestArray2430a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}END

从结果来看,我们可以发现,memcache和memcached写到mc里面的结果是一样的,也就是说我们的猜测是错误的。两个值的序列化处理一模一样,区别在于值的flag不同。 memcache存储array数据的时候,falg为1,而memcached为4. 我们知道,mc中值的flag是提供给使用者自定义,方便再读取的时候做不同的处理。但是为什么两者的flag定义会不相同呢。 抱着这个疑问,试着通过阅读两个扩展的源码查找原因。

阅读源码memcache

php_memcache.h:

#defineMMC_SERIALIZED1#defineMMC_COMPRESSED2memcached

php_memcached.c

#defineMEMC_VAL_IS_STRING0#defineMEMC_VAL_IS_LONG1#defineMEMC_VAL_IS_DOUBLE2#defineMEMC_VAL_IS_BOOL3#defineMEMC_VAL_IS_SERIALIZED4#defineMEMC_VAL_IS_IGBINARY5#defineMEMC_VAL_IS_JSON6#defineMEMC_VAL_IS_MSGPACK7

经阅读源码,发现memcache将array的数组格式的flag定义为1,而memcached为了将php存进mc中的值进行详细的类型区分,将数据类型定义了string,long,double等等的数据类型。

也就是说,当你使用memcache的时候,运行

$mc=newmemcache;$mc->addServer('10.199.189.129',11511);$mc->set('123',1);var_dump($mc->get('123'));

执行结果是:

string(1)"1"

你明明存了一个值为数字1的key,但是读取的时候却为字符串。 而当你使用memcached的时候,运行

$mc=newmemcached;$mc->addServer('10.199.189.129',11511);$mc->set('123',1);var_dump($mc->get('123'));

执行结果是:

int(1)结论

memcache扩展和memcached扩展读写数组数据不相兼容的原因是,memcached为了详细地区分数据类型,定义了各种数据类型的标示,而导致其中数组的标识与memcache定义的数组标识不一致导致。 经过这次探究,也让我认识到许多memcached比memcache更优秀的地方,相信随着php7的普及,memcache会加速地被历史所淘汰。

作者:Akay

本文地址:http://www.akayzhang.com/article/6

转载请注明出处