Redis事件与事务

一、Redis特点

  • 特性:速度快、基于键值对的数据结构服务器、功能丰富、简单稳定、客户端语言多、持久化、主从复制、支持高可用和分布式
  • 单线程架构:redis使用单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。一条命令从客户端到服务端不会立刻被执行,所有命令都会进入一个队列中,然后逐个被执行。(执行顺序不确定的)。

单线程如何满足线上运行速度? 

  • 纯内存访问:所有数据放在内存中,响应时长大约100纳秒。 
  • 非阻塞I/O,使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将poll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
  • 单线程避免了线程切换和竞态产生的消耗。

二、事件

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时间戳,记录了时间事件的到达时间

    扫描二维码关注公众号,回复: 2572327 查看本文章

    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不支持事务回滚功能,原因大概有两点:

  • 一个redis命令执行失败,一般是语法错误或者应该在开发阶段被检测出来,而不是在生产环境。
  • redis追求简单、速度快,所以不提供事务回滚功能.

2.WATCH命令的实现

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
OK
127.0.0.1:6379> get "name"
QUEUED
127.0.0.1:6379> get "age"
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379>
127.0.0.1:6379> set "age" 11
OK

3.事务的ACID性质

  • 原子性:redis事务多个操作当做一个整体来执行,要么执行事务中的所有操作,要么一个也不执行。
  • 一致性:“一致”指的是数据符合数据库本身的定义和要求,没有包含非法的或无效的错误数据
    • 入队错误:服务器拒绝执行该事务。
    • 执行错误:出错的命令会被服务器识别出来,并进行相应的错误处理,不会对数据库做任何修改,也不会对数据一致性造成影响。
    • 服务器停机: RDB  AOF 还原数据库状态
  • 隔离性:单线程执行事务,且服务器保证事务期间不会对事务进行中断
  • 持久性:当一个事务执行完毕时,执行这个事务所得的结果已经被保存到永久性存储介质(比如硬盘)里面了。Redis事务的持久性由Redis所使用的持久化模式决定(无持久化模式、 RDB  AOF )。Redis工作在无持久化模式下时,事务无持久性。在 AOF 模式下 appenfsync  no 时,事务也无持久性

猜你喜欢

转载自blog.csdn.net/i10630226/article/details/79058513