[Redis Slowlog]是排查性能问题关键监控指标。它是记录Redis queries运行时间超时特定阀值的系统。
这类慢查询命令被保存到Redis服务器的一个定长队列,最多保存slowlog-max-len(默认128)个慢查询命令。
当慢查询命令达到128个时,新产生的慢查询被加入前,会从队列中删除最旧的慢查询命令。
创建并修改Lua环境
Redis中带有不确定性的命令:
1 2 3 4 5 6 7 |
SINTER SUNION SDIFF SMEMEBERS HKEYS HVALS KEYS |
注意:
环境协作组件
环境组件:
执行Lua脚本的伪客户端
使用redis.call或者redis.pcall执行Redis命令:
lua_s字典
保存Lua脚本的SHA1【校验和】checksum,值是对应的脚本。Redis会把EVAL命令执行过的脚本,或者 LOAD加载的脚本都保存在字典中。
字典的作用:实现 EXISTS命令;实现脚本的复制
EVAL命令的实现
通过函数保存传入的脚本好处:
准备执行脚本:
使用EVALSHA “xxx校验和”0 就可执行EVAL “return ‘hello world!’” 0
脚本管理命令实现
1 2 3 4 |
FLUSH 用于清除服务器中lua有关的脚本,释放lua_s字典,关闭现有的lua环境,并重新创建 EXISTS 输入SHA1校验和,判断是否存在 LOAD 与EVAL相同,创建对应的lua函数,存放到字典中 KILL 使用钩子定期检查脚本运行时间,如果没有执行过,可以使用 KILL杀掉;如果执行过,只能使用SHUTDOWN nosave停止服务器 |
https://my.oschina.net/wangxu3655/blog/3125737?from=singlemessage
这个文章介绍了,当lua脚本出现动态变量时的处理方式
-- 当前时间
local now_time = redis.call('TIME');
-- 设置OPERATE_TIME值为当前秒数
redis.call('SET','OPERATE_TIME',now_time[1]);
Write commands not allowed after non deterministic commands.
Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.
翻译过来就是说, 写命令不被允许出现在‘非确定性命令’的后面, 请在脚本开始时调用redis.replicate_commands()来切换到命令复制模式.
修改后的lua脚本:
-- 开启单命令复制模式
redis.replicate_commands();
-- 当前时间
local now_time = redis.call('TIME');
-- 设置OPERATE_TIME值为当前秒数
redis.call('SET','OPERATE_TIME',now_time[1]);
再执行就不会报错, 然后我们到AOF文件下去查看一下, 我们发现追加的不是脚本内容, 而是MULTI...EXEC命令:
$1
0
*1
$5
MULTI
*3
$3
SET
$12
OPERATE_TIME
$10
1572855544
*1
$4
EXEC
回到脚本上来, 我们的脚本包含了TIME命令来获取系统时间, 这个命令在不同时间去执行返回的值肯定不一样, 如果在主从复制和AOF追加时, 直接复制整个脚本的内容, 那么肯定会造成执行时数据的不一致性.
所以, 在执行Lua时Redis默认不允许动态的不确定性的变量存在. 如果存在, 则需要开启命令复制模式, 即只复制Lua脚本里包含的写命令, 所有的写命令会被包装在MULTI ... EXEC里.
Redis官方, 把默认的复制整个脚本内容的模式定义为whole scripts replication, 把只复制脚本里写命令的模式定义为 script effects replication.
在命令复制模式下, 还可以选择是否对某个命令进行目标复制, 即是否需要复制到‘从服务器’和‘AOF文件’ , 如下:
redis.set_repl(redis.REPL_ALL) -- Replicate to AOF and slaves.
redis.set_repl(redis.REPL_AOF) -- Replicate only to AOF.
redis.set_repl(redis.REPL_SLAVE) -- Replicate only to slaves.
redis.set_repl(redis.REPL_NONE) -- Don't replicate at all.
下面这个slowlog的时间讲解很到位
https://my.oschina.net/u/3023401/blog/2231347
如MySQL/MongoDB等常见数据库,慢查询的query_time都会包含命令所有耗时,包含锁等待这类时间; 而Redis的慢查询query_time只记录自己“被cpu服务的时间”,不包含排队等待、IO等待(如AOF SYNC)这类时间。
理解这点非常重要
参考:
The Redis Slow Log is a system to log queries that exceeded a
specified execution time. The execution time does not include I/O
operations like talking with the client, sending the reply and so forth,
but just the time needed to actually execute the command (this is the only
stage of command execution where the thread is blocked and can not serve
other requests in the meantime).
Redis Server是单线程的处理(bgsave或aof重写时会Fork子进程处理),同一时间只能处理一个命令,并且是同步完成的。
所以RD和DBA在设计keyspace和访问模式时,应尽量避免使用耗时较大的命令。
在理想状态下,Redis单实例能处理8~10w的QPS, 如果大量的redis命令大量耗时大于1ms, 其实QPS只能达到1000基于几百。
Redis出现耗时大的命令,导致其他所有请求被阻塞等待,redis处理能力急剧退化,易导致整个服务链雪崩。