在进行系统优化的时候,发现系统使用了大量的缓存,而在写入缓存的时候,需要先对内容进行序列化,读取缓存的时候,则需要进行内容的反序列化,从而保证可以写入和读取任何类型的缓存。早期,缓存量不大的时候,我们一直使用json进行序列化和反序列化,随着整体服务从IDC的物理机迁移到混合云平台的虚拟机,单台机器的cpu从原来的8核、16核降低到2核,cpu上就显得非常吃紧了,经常能从满日志里边看到序列化和反序列化时的日志。因此,优化序列化性能成为我们系统优化的一个重要环节。

经过对几种序列化函数的对比,最终我们选定了igbinary可以作为其中比较优秀的一个方案。要正式转型之前,当然要通过一些压测进行有效对比,才能做到有据可循。

测试代码

为了验证igbinary和json的性能,对igbinary和json做了测试对比的程序,代码如下:

$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)

[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_serialize486.4442.432igbinary_unserialize476.0722.380789
json_encode(escaped_unicode)2158.13210.791json_decode(escaped_unicode)3916.80419.5841350
json_encode(unescaped_unicode)3268.26016.341json_decode(unescaped_unicode)1732.8458.664798

结论

igbinary无论在处理性能,以及存储长度、cpu、内存占用上相对于json都具有明显的优势,可以替换原有的json序列化方案。

标签: json, igbinary, 序列化

添加新评论