igbinary vs json序列化性能对比 作者: 灯小笼 时间: 2017-12-01 分类: 架构 在进行系统优化的时候,发现系统使用了大量的缓存,而在写入缓存的时候,需要先对内容进行序列化,读取缓存的时候,则需要进行内容的反序列化,从而保证可以写入和读取任何类型的缓存。早期,缓存量不大的时候,我们一直使用json进行序列化和反序列化,随着整体服务从IDC的物理机迁移到混合云平台的虚拟机,单台机器的cpu从原来的8核、16核降低到2核,cpu上就显得非常吃紧了,经常能从满日志里边看到序列化和反序列化时的日志。因此,优化序列化性能成为我们系统优化的一个重要环节。 经过对几种序列化函数的对比,最终我们选定了igbinary可以作为其中比较优秀的一个方案。要正式转型之前,当然要通过一些压测进行有效对比,才能做到有据可循。 ## 测试代码 为了验证igbinary和json的性能,对igbinary和json做了测试对比的程序,代码如下: ```php $arr = [ 'foo' => [ 'bar' => [ 'item' => [ 'msg' => ' 1、 如果手机号为空,则用存在的手机号替换空的数据2、 如果手机号不同,则以当前索票手机号为3、 更新信息手机归属地需要同时更新' ] ] ], 'user' => [ 'content' => '配置代理实际上通过php -S的方式运行了一个简单的单进程php服务,需要将其部署到nginx代理服务器上。目前部署位置为192.168.2.2的/home/jhthird/shell/newproxy/目录。', 'content1' => 'B对应的配置文件有两个,一个是jiehun.conf,另一个是jiehun.conf.tmp。jiehun.conf是用于生产环境的配置,而jiehun.conf.tmp用于测试配置是否成功。两者的差别只在于最后一行,jiehun.conf包含了jiehun目录所有vhost.conf文件,而jiehun.conf.tmp包含了所有vhost.conf.tmp文件。', ] ]; define('TEST_NUM', 200000); $testType = $argv[1] ?? 1; if ($testType == 1) { // json_encode 中文编码 $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { json_encode($arr); } printf('json_encode(escaped_unicode):%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } if ($testType == 2) { $jsonDest = json_encode($arr); printf('json_encode(escaped_unicode) length:%d'.PHP_EOL, strlen($jsonDest)); $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { json_decode($jsonDest, true); } printf('json_decode(escaped_unicode):%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } if ($testType == 3) { // json_encode 中文不编码 $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { json_encode($arr, JSON_UNESCAPED_UNICODE); } printf('json_encode(unescaped_unicode):%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } if ($testType == 4) { $jsonDest = json_encode($arr, JSON_UNESCAPED_UNICODE); printf('json_encode(unescaped_unicode) length:%d'.PHP_EOL, strlen($jsonDest)); $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { json_decode($jsonDest, true); } printf('json_decode(unescaped_unicode):%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } // igbinary if ($testType == 5) { $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { igbinary_serialize($arr); } printf('igbinary_serialize:%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } if ($testType == 6) { $igDest = igbinary_serialize($arr); printf('igbinary_unserialize length:%d'.PHP_EOL, strlen($igDest)); $start = microtime(true); for($i = 0; $i < TEST_NUM; $i++) { igbinary_unserialize($igDest); } printf('igbinary_unserialize:%.3f ms'.PHP_EOL, (microtime(true) - $start) * 1000); } ``` ## 测试详细数据 测试环境:1核4G CentOS release 6.9 (Final) ```bash [root@test1 ~]# php test.php 1 json_encode(escaped_unicode):2158.132 ms [root@test1 ~]# php test.php 2 json_encode(escaped_unicode) length:1350 json_decode(escaped_unicode):3916.804 ms length:789 [root@test1 ~]# php test.php 3 json_encode(unescaped_unicode):3268.260 ms [root@test1 ~]# php test.php 4 json_encode(unescaped_unicode) length:798 json_decode(unescaped_unicode):1732.845 ms [root@test1 ~]# php test.php 5 igbinary_serialize:486.444 ms [root@test1 ~]# php test.php 6 igbinary_unserialize length:789 igbinary_unserialize:476.072 ms ``` ### 最终结果 汇总一下结果到表格,如下: | 序列化方法 | 20w次测试结果(ms) | 平均单次测试时间(μs) | 反序列化方法 | 20w次测试结果(ms) | 平均单次测试时间(μs) | 数组序列化后长度 | |----------|--------------|---------------|------------|-------------|----------------|----------| | igbinary_serialize | 486.444 | 2.432 | igbinary_unserialize | 476.072 | 2.380 | 789 | | json_encode(escaped_unicode) | 2158.132 | 10.791 | json_decode(escaped_unicode) | 3916.804 | 19.584 | 1350 | | json_encode(unescaped_unicode) | 3268.260 | 16.341 | json_decode(unescaped_unicode) | 1732.845 | 8.664 | 798 | ## 结论 igbinary无论在处理性能,以及存储长度、cpu、内存占用上相对于json都具有明显的优势,可以替换原有的json序列化方案。 标签: json, igbinary, 序列化