redis学习(二)

redis 学习记录 关于事务,管道和其他

redis 事务机制

redis 的 事务机制和mysql的类似,都是为了解决数据库的隔离性诞生的,一组事务以MULTI语句开始, 然后写入各种操作语句,最后用EXEC结束并执行这段事务。 因为redis的事务机制是FIFO的队列,所以一个事务是按顺序逐条执行语句,然后整体返回结果。同时因为redis本身就是单线程的,所以事务机制也是线程安全的。 redis事务机制必要遗憾的是没有提供关系型数据库中的回滚机制,一旦事务发生了什么错误,只能由程序员自行解决。 事务有两种ERROR:

  1. 一种是在MULTI之后,EXEC执行之前,由于命令的语法错误或者服务器内存不够等原因,命令根本不会被放入暂存队列,Redis会拒绝执行接下来的EXEC操作,这和我们理解的原子性原理是一致的。
  2. 另外一种是在EXEC之后,当队列中的某条命令执行失败,Redis也会继续执行完其他命令,且不支持回滚,最关键的地方反而还不支持原子性!

但存在一种场景,比如某商品的购买量,在并发量高的时候不可能在等待一个事务结束后才会执行下一个事务,这个时候watch就起到了作用 ,作为一种乐观锁,在事务开始之前被加上watch的数据可以在事务中被保护:

Watch是Redis提供的事务锁,是一种乐观锁。在MULTI命令之前执行WATCH命令,当EXEC提交之后,在实际执行任何命令之前,如果发现被Watched的key值发生了改变,整个事务被丢弃,返回为空。

个人理解,使用Redis事务结合Watch命令,只是能保证在事务内被watched的key不会被重复错误修改,一定程度上能够保证原子性,但也只是针对被watched的key。

redis 的管道机制

必须意识到的一件事是redis虽然是一个很快的nosql,但如果一条一条的执行他的语句,就会遇到一个问题RTT,一条语句从客户端发出到客户端收到答复,会在哪些地方花费时间呢?

  1. 语句发出的时间
  2. 语句等待执行的时间
  3. 语句执行的时间
  4. 执行结果回到客户端的时间。

同时redis的单线程特性使得他不得不一条一条的执行,会把大量的时间浪费在1和4上。如果使用管道技术,就可以将批量的语句发送出去,然后等全部完成后再把结果全部发回客户端。

管道看上去和事务有些相似,但管道并不满足原子性和隔离性,但他批量执行的特性,还是给了我们一些启发。

python 利用管道实现事务

python 的redis库使用了管道技术来实现事务。在pipeline的注释中这样写道

    Return a new pipeline object that can queue multiple commands for later execution. transaction indicates whether all commands should be executed atomically. Apart from making a group of operations atomic, pipelines are useful forreducing the back-and-forth overhead between the client and server.

一段简单的代码如下

import redis
conn = redis.StrictRedis(host='132.232.72.122',port=6379,db=0)
print(conn.ping())
pipeline = conn.pipeline()
pipeline.ping()
pipeline.set('key233','value233')
pipeline.get('key233')
print(pipeline.execute())

pipeline.execute()会将各个语句执行的结果放在一个列表里来返回.

同时,如果在意pipeline 的性能,可以使用redis-benchamrk来测试访问速度 第一条是使用10000的管道是每秒执行的set,get 数量 第二条是不使用管道的速度 第三条是只使用100条管道的速度,可以看出不是管道越多越好。

ubuntu@VM-0-3-ubuntu:~$ redis-benchmark -n 100000 -t set,get -P 10000 -q
SET: 110619.47 requests per second
GET: 111731.84 requests per second

ubuntu@VM-0-3-ubuntu:~$ redis-benchmark -n 100000 -t set,get -q
SET: 50428.64 requests per second
GET: 50556.12 requests per second

ubuntu@VM-0-3-ubuntu:~$ redis-benchmark -n 100000 -t set,get -P 100 -q
SET: 531914.94 requests per second
GET: 591716.00 requests per second