Redis进阶
慢查询分析
慢查询日志:系统在命令执行前后计算每条命令的执行时间,当超过预设阀值时记录命令相关信息。
配置参数
slowlog-log-slower-than 预设阀值,单位微秒,默认10000 即10ms,为0则记录所有命令,<0不记录
slowlog-max-len 慢查询列表的最大长度,超过则先入先出
修改配置:
修改配置文件
config set
动态修改config set slowlog-log-slower-than 20000
config set slowlog-max-len 1000
config rewrite 持久化到本地配置文件
慢查询日志存放在list中,但redis没有暴露key,通过一组命令来查询和管理
获取慢查询日志
slowlog get [n]
返回日志包含4个属性:id, timestamp, duration, command, params
h获取慢查询日志列表当前长度
slowlog len
重置
slowlog reset
实践
- slowlog-log-slower-than建议10ms,高OPS(operation per second )建议1ms
- slowlog-max-len 线上如1000
- 可以定义slow get持久化到其他存储中(CacheCloud)
Redis Shell
redis-cli
-r
: repeat, 重复执行多次redis-cli -r 3 ping
-i
: interval, 执行间隔,单位秒,毫秒可以用0.01,须与-r一起使用redis-cli -r 5 -i 1 ping
-x
: 从标准输入stdin读取数据作为redis-cli的最后一个参数echo “word” | redis-cli -x set hello
-c
: cluster, 连接redis cluster结点使用,防止moved和ask异常-a
: auth, 如果配置了密码可以使用该选项--scan
和--pattern
: 扫描指定模式的key,相当于使用scan命令--slave
: 把当前客户端模拟为当前redis结点的从节点,可以获取当前redis结点的更新操作--rdb
: 请求redis生成并发送RDB文件存于本地,可用于持久化备份--pipe
: 用于将命令封装为redis通信协议定义的数据格式,批量发送给redis执行--bigkeys
: 使用scan命令对redis的key进行采样,找到内存占用比较大的value,可能是系统瓶颈--eval
: 执行指定Lua脚本--latency
: 用于检测网络延迟--latency
: 测试客户端到目标redis的网络延迟 redis-cli -h {host} –latency--latency-history
: 每15s输出一次,可以-i控制间隔 redis-cli -h {host} –latency-history--latency-dist
: 使用统计图表的形式从控制台输出延迟统计信息
--stat
: 实时获取redis重要统计信息--raw
和--no-raw
: 返回格式化后的结果还是返回原始结果
redis-server
--test-memory
选项,用来检测当前操作系统能否稳定地分配指定容量的内存给redis
避免因内存问题造成redis崩溃。
redis-server –test-memory 1024 检测OS能否提供1G的内存给redis
检测时间较长,输出passed this test说明检测完毕
redis-benchmark
-c
: clients , 客户端并发数量,默认50-n<requests>
: 客户端请求总量,默认100000-q
: 仅显示redis-benchmark的requests per second信息-r
: random, 插入更多的随机key,会在key、counter键上加一个12位的后缀 -r10000代表只对value后四位做随机处理-P
: 每个请求pipeline的数据量,默认为1-k<boolean>
: keepalive,客户端是否使用keepalive,1为使用,0为不使用,默认为1-t
: 对指定命令进行基准测试 redis-benchmark -t get,set -q-csv
: 将结果按csv格式输出
Pipeline
客户端执行一条命令有如下过程:
graph LR
a(发送命令) --> b(命令排队)
b --> c(命令执行)
c --> d(返回结果)
合起来成为Round Trip Time,即RTT,往返时间
pipeline指将一组redis命令进行组装,通过一次RTT传输给redis,结果按顺序返回
对比原生批量命令
- 原生批量命令是原子的,Pipeline是非原子的
- 原生批量命令是一个命令对应多个key,Pipeline支持多个命令
- 原生批量命令时服务端支持实现,Pipeline需要服务端和客户端共同实现
可以将包含大量命令的Pipeine拆分为多次较小的Pipeline来完成
事务与Lua
事务与Lua用来保证多条命令组合的原子性
事务
事务表示一组动作,要么全部执行,要么全部不执行
multi
cmd1
cmd2
...
exec
multi
代表事务开始
exec
代表事务结束
discard
停止事务的执行
错误处理:
- 命令错误:事务无法执行
- 运行时错误:redis不支持回滚,需要自己修复
watch
命令:类似乐观锁,确保事务中的key没被其他客户端修改过,才执行事务,否则不执行
Lua简述
数据类型
booleans, numbers, strings, tables
local val = "world"
local myarray = {"redis", "jedis", true, 88.0} 数组下标从1开始
--comment
循环
local int sum = 0
for i = 1, 100
do
sum = sum + i
end
print(sum)
while i <= 100
do
...
end
去数组长度#array
遍历数组
for index, value in ipairs(myarray)
do
...
end
条件判断
if xxx
then
...
else
...
end
使用table
local user = {age=28, name="tome"}
for key,value in pairs(user)
do
print(key .. value)
end
函数
function funcName()
...
end
Redis与Lua
Redis执行Lua
eval
eval 脚本内容 key个数 key列表 参数列表
eval ‘return “hello ” .. KEYS[1] .. ARGV[1] ’ 1 redis word
返回 “hello redisworld”
如果Lua脚本较长,可以使用redis-cli –eval file执行文件
evalsha
首先将Lua脚本加载到redis服务端,得到脚本的SHA1校验和
该命令使用SHA1作为参数执行对应Lua脚本,避免每次发送
加载脚本:
redis-cli script load “$(cat lua_get.lua)”
执行脚本:
evalsha 脚本SHA1 key个数 key列表 参数列表
Lua的Redis API
使用redis.call
函数访问redis,如果执行失败,直接返回错误
redis.call("set", "hello", "world")
redis.call("get", "hello")
redis.pcall
则忽略错误继续执行脚本
redis.log
将Lua脚本的日志输出到redis日志文件,注意控制日志级别
redis 3.2提供了Lua Script Debugger来调试复杂的Lua脚本
Redis管理Lua脚本
- script load script
- script exists sha1
- script flush 清除内存加载的所有Lua脚本
- script kill 杀掉正在执行的Lua脚本,如果Lua正在执行写操作,则kill不生效,只能等或者shutdown save
Bitmaps
Bitmaps实际就是字符串,提供了一组api可以对字符串的bit进行操作
命令
设置
setbit key offset value 设置第offset个bit的值
第一次初始化Bitmaps时,如果偏移量非常大,可能造成redis阻塞
获取
gitbit key offset
获取指定范围值为1的个数
bitcount [start] [end] start end代表字节数
Bitmaps间运算
bitop op destkey key [key …] 运算结果保存在destkey中
op可以是and, or, not, xor,分别为 交集,并集,非,异或
计算Bitmaps中第一个值为targetBit的offset
bitpos key targetBit [start] [end]
HyperLogLog
HyperLogLog实际类型为字符串类型,是一种基数算法,可以利用极小的内存完成独立总数的统计。
命令
添加
pfadd key element [element … ] 向HyperLogLog添加元素,成功返回1
计算独立总数
pfcount key [key … ]
存在一定的误差率,redis官方数据位0.81%的失误率
合并
pfmerge destkey sourcekey [sourcekey … ]
求多个HyperLogLog的并集赋值给destkey
选型:
- 只为计算独立总数,不需要获取单条数据
- 可以容忍一定误差率
发布订阅
消息发布者和订阅者不直接通信,发布者客户端向指定channel发布消息,订阅该channel的每个客户端可以收到该消息。
redis提供了发布、订阅、取消订阅、按模式订阅和取消等命令
】
命令
发布消息
publish channel message 返回订阅的客户端数
订阅消息
subscribe channel [channel … ] 订阅一个或多个频道
客户端执行订阅命令后,进入订阅状态,只能接收subscribe, psubscribe, unsubscribe, punsubscribe
新开启的订阅客户端无法收到频道之前的消息,redis不会做持久化
取消订阅
unsubscribe [channel [channel … ] ]
按模式订阅和取消订阅
psubscribe pattern [pattern … ]
punsubscribe [pattern [pattern … ] ]
glob风格
查询订阅
查看活跃频道
pubsub channels [pattern] 至少有一个订阅者
查看频道订阅数
pubsub numsub [channel … ]
查看模式订阅数
pubsub numpat
使用场景
聊天室、公告牌、服务之间利用消息解耦
GEO
redis 3.2提供了GEO(地理信息定位),存储地理位置信息来实现附近位置、摇一摇等功能
GEO由Matt Stancliff借鉴NoSQL数据库Ardb(中国)实现。
命令
增加
geoadd key longitude latitude member [longitude latitude member … ]
对应地理位置的经度、纬度、成员
返回添加成功数,已存在返回0
更新同样使用geoadd
获取
geopos key member [member … ]
例如:geopos cities:locations beijing
获取两个地理位置的距离
geodist key member1 member2 [unit]
unit表示结果单位:
- m:meters,米
- km:kilometers,千米
- mi:miles,英里
- ft:feet,尺
获取指定位置范围内的地理信息位置集合
georadius key longtitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
- radius m|km|ft|mi用于指定半径
- withcoord 结果包含经纬度
- withdist 结果包含离中心节点位置的距离
- withhash 结果包含geohash
- COUNT count 指定返回结果数量
- asc|desc 结果按离中心节点距离做升序或降序
- store key 将返回结果的地理位置信息保存到指定key
- storedist key 将返回结果离中心节点的距离保存到指定key
获取geohash
geohash key member [member …]
将二维经纬度转换为一维字符串
- GEO的数据类型为zset,redis将所有地理位置的geohash存放在zset中
- 字符串越长,表示的位置更精确,geohash长度为9时,精度在2米左右
- 字符串越相似,距离越近,redis用字符串前缀匹配算法实现相关命令
- geohash编码和经纬度是可以相互转换的
删除
zrem key member