igbinary vs json序列化性能对比
在进行系统优化的时候,发现系统使用了大量的缓存,而在写入缓存的时候,需要先对内容进行序列化,读取缓存的时候,则需要进行内容的反序列化,从而保证可以写入和读取任何类型的缓存。早期,缓存量不大的时候,我们一直使用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_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序列化方案。