Redis服务器是一个事件驱动程序。处理以下两类事件:
+ 文件事件:Redis服务器通过套接字与客户端进行连接,文件事件就是服务器对套接字操作的抽象。
+ 时间事件:服务器对定时操作的抽象。
+ #### 1.文件事件
Redis 基于Reactor模式开发了自己的网络事件处理器即文件事件处理器
文件事件处理器使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事务处理器。
当被监听的套接字准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
- 文件事件处理器 由四个部分组成:套接字、I/O多路复用程序、文件事件分派器以及事件处理器 I/O多路复用程序总是会将所有产生事件的套接字放到一个队列里面,然后通过这个队列以有序、同步、每次一个套接字的方式向文件事件分派器传送套接字。当上一个套接字产生的事件被处理完毕之后,I/O多路复用程序才会继续向文件事件分派器传送下一个套接字。
![图片]()
- I/O多路复用程序 I/O多路复用程序的功能是通过包装常见的select、epoll、evport和kqueue这些I/O多路复用函数库来实现的。
#### 2.时间事件
* 分类
+ 定时事件:指定时间执行一次。
+ 周期性事件:每隔一段时间执行一次。目前Redis只使用周期性事件,而没有使用定时事件。 一个事件时间主要由三个属性组成:
1)id:服务器为时间事件创建的全局唯一ID
2) when:毫秒精度的UNIX时间戳,记录了时间事件的到达时间
3) timeProc:时间事件处理器,一个函数
- * 实现 服务器将所有时间事件都放在一个无序链表中,每当时间事件执行器运行时,遍历整个链表,查找所有已到达的时间事件,并调用相应的事件处理器。(该链表为无序链表,不按when属性的大小排序)
Redis事务
Redis通过 MULTI 、 EXEC 、 WATCH 等命令来实现事务功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。
1.事务的实现
下面给了一个事务的简单例子:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set "name" "wangjia06"
QUEUED
127.0.0.1:6379> get "name"
QUEUED
127.0.0.1:6379> set "company" "dianping"
QUEUED
127.0.0.1:6379> get "company"
QUEUED
127.0.0.1:6379> set age 28
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec
1) OK
2) "wangjia06"
3) OK
4) "dianping"
5) OK
6) "28"
退出一个事务可以用 MULTI 命令, 此时再执行事务会报错:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> get "company"
QUEUED
127.0.0.1:6379> get "age"
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
一个事务包括三个步骤:
- 事务开始:事务以 MULTI 开始,返回OK命令。
- 命令入队:每个事务命令成功进入队列后,返回 QUEUED 。
- 事务执行: EXEC 执行事务。
Redis事务内会遇到两种错误:
- 队列入队不成功:语法错误,错误的命令名字或者一些重要的条件如OOM条件。这种客户端会进行校验,如果入队成功则返回QUEUED ,否则返回错误。如果一个命令入队失败,大多数客户端会终止该事务。
127.0.0.1:6379> get name
"wangjia08"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name "wangjia09"
QUEUED
127.0.0.1:6379> get
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379>
- 命令执行时报错:如对一个String值进行列表操作。所有其他的命令会被正常执行即使在事务执行中一些命令失败。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set sex man
QUEUED
127.0.0.1:6379> lpop sex
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get sex
"man"
127.0.0.1:6379>
Redis不支持事务回滚功能,原因大概有两点:
watch 命令给redis事务提供了一个 CAS 功能。它是一个乐观锁,检查被监视的健是否至少有一个已经被修改过了,如果是的话拒绝执行,并返回nil代表执行失败。
如下面例子,在一个客户端开启事务前对键“name”进行监视,若在这个事务执行前,另一个客户端修改了键“name”的值,之后事务执行后就会报nil。
127.0.0.1:6379> watch "name"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 10
QUEUED
127.0.0.1:6379> get "name"
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> set "name" "wangjia08"
OK
watch 命令监视多个键:
127.0.0.1:6379> watch "name" "age"
OK
127.0.0.1:6379> multi