Redis慢查询与事务

慢查询

我们知道,redis执行命令有4个步骤:

  1. 发送命令
  2. 命令排队
  3. 执行命令
  4. 返回结果

慢查询只统计步骤3的时间
对于慢查询功能,需要明确两件事:

  • 预设阀值怎么设置?
  • 慢查询记录存放在哪?

Redis提供了slowlog-log-slower-than和slowlog-max-len配置来解决这两个
问题。从字面意思就可以看出,slowlog-log-slower-than就是那个预设阀值,它的单位是微秒(1秒=1000毫秒=1000000微秒),默认值是10000,假如执行了一条“很慢”的命令(例如keys*),如果它的执行时间超过了10000微秒,那么它将被记录在慢查询日志中。

从字面意思看,slowlog-max-len只是说明了慢查询日志最多存储多少条,并没有说明存放在哪里?实际上Redis使用了一个列表来存储慢查询日志,slowlog-max-len就是列表的最大长度。一个新的命令满足慢查询条件时被插入到这个列表中,当慢查询日志列表已处于其最大长度时,最早插入的一个命令将从列表中移出,例如slowlog-max-len设置为5,当有第6条慢查询插入的话,那么队头的第一条数据就出列,第6条慢查询就会入列。

虽然慢查询日志是存放在Redis内存列表中的,但是Redis并没有暴露这个列表的键,而是通过一组命令来实现对慢查询日志的访问和管理。

事务

事务表示一组动作,要么全部执行,要么全部不执行。例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。
Redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的

例如下面操作实现了上述用户关注问题

1
2
3
4
5
6
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd user:a:follow user:b
QUEUED
127.0.0.1:6379> sadd user:b:fans user:a
QUEUED

Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

Redis事务没有隔离级别的概念:

批量操作在发送EXEC命令前被放入到队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务内的更新,事务外查询不能看到.

Redis不保证原子性:

Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚,事务中任意命令执行失败,其余的命令仍会被执行.

事务的三个阶段

  • 开始事务
  • 命令入队
  • 执行事务

Redis事务相关命令:
watch key1 key2…:监视一个或多个key,被监视的key被其他命令改动,则事务被打断

Redis使用WATCH命令来决定事务是继续执行还是回滚,那就需要在MULTI之前使用WATCH来监控某些键值对,然后使用MULTI命令来开启事务,执行对数据结构操作的各种命令,此时这些命令入队列。

当使用EXEC执行事务时,首先会比对WATCH所监控的键值对,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。当然无论是否回滚,Redis都会取消执行事务前的WATCH命令。
Snipaste_20210301_214109.png

若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行

1659331201904162051377401887538258.png

若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。

Snipaste_20210301_214401.png

使用watch检测balance,在开启事务后(标注1处),在新窗口执行标注2中的操作,更改balance的值,模拟其他客户端在事务执行期间更改watch监控的数据,然后再执行标注1后命令,执行EXEC后,事务未成功执行。
Snipaste_20210301_214605.png


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!