Predis和Phpredis性能测试对比

作者 Gavin 日期 2015-05-30
Predis和Phpredis性能测试对比

最近签到功能并发量有点大,php的slow log里记录的大部分日志都是关于redis的,我们线上环境是通过predis连接redis服务器的,phpredis是C预言扩展,理论上要比predis快,所以做了一下性能对比.

测试环境:

配置

  • 单连接本地、循环执行命令测试:

usePredis.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
require __DIR__.'/predis/autoload.php' ;
function getMillisecond() {
list($s1, $s2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
}
$client = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379
]);
$sTime = getMillisecond() ;
for ($i=0; $i < 100000; $i++) {
$result = $client->set('admin', 'gjx') ;
}
$eTime = getMillisecond() ;
var_dump($eTime-$sTime) ;

取三组数据:

记录 predis phpredis
1 5485 3950
2 5343 3974
3 6697 3814

取平均数:predis:5841.7毫秒 phpredis:3912.7毫秒

结果:单连接本地 单命令下 phpredis比predis快1/3

  • predis pipelining和默认模式性能对比:

翻开predis的README的时候发现predis支持pipelining模式,可以一次发送多个命令不用等待回复,最后一次读取所有的回复,管道模式能有效地节约网络延迟时间,所以理论上是要比默认一个命令一次tcp请求的模式快的.
Redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常 会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。

当客户端用pipelining发送命令时,服务器端会在内存中使用队列存储所有的回复。如果客户端发送大量的命令,最好一次发送合理数量的命令,比如一次发送10k,然后读取回复,再发送另外的10k命令。这样可以保证每一次的速度大致相同,但是额外的内存用来存储保存着回复的队列。pipelining不能使用的情形是在客户端调用写命令前先回复读取命令。

  • 本地 pipe VS default
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
require __DIR__.'/predis/autoload.php' ;
function getMillisecond() {
list($s1, $s2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
}
$client = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379
]);
$sTime = getMillisecond() ;
for ($i=0; $i < 100000; $i++) {
// $result = $client->set('admin', 'gjx') ;
$result = $client->get('admin') ;
}
$eTime = getMillisecond() ;
var_dump($eTime-$sTime) ;
$sTime = getMillisecond() ;
$responses = $client->pipeline(function ($pipe) {
for ($i = 0; $i < 100000; $i++) {
// $pipe->set('admin', 'gjx') ;
$pipe->get("admin");
}
});
$eTime = getMillisecond() ;
var_dump($eTime-$sTime) ;

取三组数据:

记录 tcp pipe
1 5366 1474
2 5587 1491
3 5804 1511

取平均数:tcp:5585.7毫秒 pipe:1492.0毫秒

pipe模式快于tcp将近75%,这仅仅是本机测试结果而已。

  • 下面看看真正网络传输情况下的对比:

这次连接 ip为:192.168.0.210 局域网内的机器,为了能尽快的出现结果,将循环数改为10000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
require __DIR__.'/predis/autoload.php' ;
function getMillisecond() {
list($s1, $s2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
}
$client = new Predis\Client([
'scheme' => 'tcp',
'host' => '192.168.0.210',
'port' => 6379
]);
$sTime = getMillisecond() ;
for ($i=0; $i < 10000; $i++) {
// $result = $client->set('admin', 'gjx') ;
$result = $client->get('admin') ;
}
$eTime = getMillisecond() ;
var_dump($eTime-$sTime) ;
$sTime = getMillisecond() ;
$responses = $client->pipeline(function ($pipe) {
for ($i = 0; $i < 10000; $i++) {
// $pipe->set('admin', 'gjx') ;
$pipe->get("admin");
}
});
$eTime = getMillisecond() ;
var_dump($eTime-$sTime) ;

取三组数据:

记录 tcp pipe
1 29071 127
2 29540 143
3 29160 124

取平均数:tcp:29257.0毫秒 pipe:131.3毫秒

这次可以看出pipeling的绝对优势了!所以将互不影响的操作能够放到pipeling里能绝对的提升性能!