背景:业务系统需要做一些统计,但是访问量比较大,统计更新任务比较繁重。常规的方法会存在严重的性能问题。这里采用的方案是php将任务推送到redis list队列,然后通过pipeline模式批量打包任务发送给redis server执行。
这里重点说一下pipeline。
管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回。
执行流程: 打包开始->缓存->打包结束->发送->执行->返回执行结果。
优点: 1.pipeline 通过减少客户端与 redis 的通信次数来实现降低往返延时时间。 pipeline 通过打包命令,一次性执行,可以节省 连接->发送命令->返回结果 所产生的往返时间,减少网络I/O的调用次数。
2.而且 Pipeline 实现的原理是队列,而队列的原理是时先进先出,这样就保证数据的顺序性。
通俗点:pipeline就是把一组命令进行打包,然后一次性通过网络发送到Redis。同时将执行的结果批量的返回回来。
缺点: 1.pipeline 每批打包的命令不能过多,因为 pipeline 方式打包命令再发送,那么 redis 必须在处理完所有命令前先缓存起所有命令的处理结果。这样就有一个内存的消耗。
2.pipeline 是责任链模式,这个模式的缺点是,每次它对于一个输入都必须从链头开始遍历(参考Http Server处理请求就能明白),这确实存在一定的性能损耗。
最重要的注意点: pipeline 不保证原子性,如果要求原子性的,不推荐使用 pipeline。
下面是php redis扩展官方用法介绍
multi, exec, discard.
Description: Enter and exit transactional mode.
Parameters
(optional) Redis::MULTI or Redis::PIPELINE. Defaults to Redis::MULTI. A Redis::MULTI block of commands runs as a single transaction; a Redis::PIPELINE block is simply transmitted faster to the server, but without any guarantee of atomicity. discard cancels a transaction.
Return value
multi() returns the Redis instance and enters multi-mode. Once in multi-mode, all subsequent method calls return the same object until exec() is called.
Example
$ret = $redis->multi()
->set('key1', 'val1')
->get('key1')
->set('key2', 'val2')
->get('key2')
->exec();
/*
$ret == Array(0 => TRUE, 1 => 'val1', 2 => TRUE, 3 => 'val2');
*/
这里特意提到一句:
a Redis::PIPELINE block is simply transmitted faster to the server, but without any guarantee of atomicity.
意思是pipeline的目的是快速的将打包的操作传输到redis服务,但不能保证原子性。
php代码实现:
//开启pipeline模式
$pipelineObj = $redis->multi(Redis::PIPELINE);
//在$pipelineObj对象上增加打包任务操作
$pipelineObj->set('key1', 'val1')
->get('key1')
->set('key2', 'val2')
->get('key2');
//或者这样写
$pipelineObj->set('key1', 'val1');
$pipelineObj->get('key1');
$pipelineObj->set('key2', 'val2');
$pipelineObj->get('key2');
//打包完成,执行exec发送执行任务。
$pipelineObj->exec();
参考 官网pipeline介绍
















