redis 的事务、锁、流水线
Redis与 mysql事务的对比
- 开启 mysql:start transaction redis:multi
- 语句:mysql:普通sql redis:普通命令
- 成功:mysql:commit redis:exec
- 失败: mysql:rollback redis:discard
在mutil后面的语句中, 语句出错可能有2种情况
- 1: 语法就有问题,
这种,exec时,报错, 所有语句得不到执行,这时事务保持原子性
- 2: 语法本身没错,但适用对象有问题. 比如 zadd 操作list对象
Exec之后,会执行正确的语句,并跳过有不适当的语句.这时事务没有保持原子性
redis 锁
- 命令:watch key
- Redis的事务中,启用的是乐观锁,只负责监测key没有被改动.如果有改动,则事务执行失败。此时事务有原子性。
- 可以监视多个key,只要有一个改动,则事务都会执行失败
- unwatch 作用: 取消所有watch监听
redis流水线
- Redis客户端与Redis之间使用TCP协议进行连接,一个客户端可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client,因此当执行多条命令的时候都需要等待上一条命令执行完毕才能执行,如:get ‘0’,get ‘1’,get ‘2’
- 在大多数情况下,执行命令时的绝大部分时间都消耗在了发送命令和接收命令的过程中,因此减少客户与服务器之间的通信次数可以有效地提高程序的执行效率
- 而管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间,pipeline方式执行效率要比其他方式高10倍左右的速度;
- 在执行pipeline()时传入True作为参数,或者不传入任何参数,那么客户端将使用MULTI和EXEC包裹起用户要执行的所有命令。如果传入False为参数,那么客户端同样会像执行事务那样收集用户要执行的所有命令,只是不再使用MULTI和EXEC包裹这些命令。如果用户需要向Redis发送多个命令,并且对于这些命令来说,一个命令的执行结果并不会影响另一个命令的输入,而且这些命令也不需要以事务的方式来执行的话,那么我们可以通过向pipeline()方法传入False来进一步提升Redis的整体性能
- Pipeline虽然好用,但是每次Pipeline组装的命令个数不能没有节制,否则一次组装Pipeline数据量过大,一方面会增加客户端的等待时机,另一方面会造成一定的网络阻塞,可以将一次包含大量命令的Pipeline拆分成多次较小的Pipeline来完成.
性能测试
<?php
set_time_limit(0);
ini_set('memory_limit','1024M');
$redis = new Redis();
G('1');
$redis->connect('127.0.0.1');
//不具备原子性 ,管道
$redis->pipeline();
for ($i=0;$i<100000;$i++)
{
$redis->set("test_{$i}",pow($i,2));
$redis->get("test_{$i}");
}
$redis->exec();
$redis->close();
G('1','e');
G('2');
$redis->connect('127.0.0.1');
//事物具备原子性
$redis->multi();
for ($i=0;$i<100000;$i++)
{
$redis->set("test_{$i}",pow($i,2));
$redis->get("test_{$i}");
}
$redis->exec();
$redis->close();
G('2','e');
//普通
G('3');
$redis->connect('127.0.0.1');
//事物具备原子性
for ($i=0;$i<100000;$i++)
{
$redis->set("test_{$i}",pow($i,2));
$redis->get("test_{$i}");
}
$redis->close();
G('3','e');
function G($star,$end = '')
{
static $info = array();
if (!empty($end))
{
$info[$end] = microtime(true);
$sconds = $info[$end] - $info[$star];
echo $sconds,"ms<br/>";
} else {
$info[$star] = microtime(true);
}
}
//测试输出的结果:
0.043839931488037ms
0.4456958770752ms
0.45916604995728ms