Redis 初解
Redis
命令
flushdb 清除当前库数据
flushall 删除全部库数据
dbsize 查看当前数据库的数据量
exists 判断 key 是否存在
del 删除键
setnx 只有不存在时,才会进行创建
expire 设置过期时间
mset 批量设置
mget 批量获取
append 追加
incr 原子递增
type key : 查看类型
object encoding key :查看key 编码
例:set lock 1 EX 10 NX – 设置 lock 值为1,10S之后过期,不存在的时候才会创建
K,V 的最大容量为 512M
数据类型
String(Binary - safe - string) 二进制安全
- 整形
- 浮点型
- 字符串
存储
List
Set
Sorted Set
Hash
Bit arrays
HyperLogLogs
Streams
数据结构
- String
- dictEntiry 用来存放 K,V
- key 指向一个 SDS
- value 指向一个 redisObject -> 指向一个 SDS
String 有三种编码
int , 存储8个字节类型的长整型
embstr , embstr格式的 SDS (Simple Dynamic String)小于44字节,只读
raw , SDS ,存储大于44个字节的字符串
SDS
len 判断长度
空间预分配,惰性空间释放
整形就是 int
embstr 从整形变为字符类型,会转变为 raw,超过44个字符
编码不会还原
- Hash
hkeys :获取全部key
hvals:获取全部值
底层数据结构:
ziplist:双向链表,存储上下一个链表的长度,通过长度计算下一个链表在哪,节省内存空间
zlentry -> prevrawlensize 上一个链表节点长度
-> prevrawlen 存储prevrawlensize 会占用多大长度
-> lensize 当前链表的长度需要多大空间存储
-> len 当前
占用内存字节数、列表末尾偏移量、节点数、标记末端
redis 配置文件中 , hash-max-ziplist-entries 512 , 小于 512 字节会用
hash-max-ziplist-value 64 , 任意value都小于64字节
超过则会转换为 ht
hashtable
dict -> dictht -> dictEntry
- list
有序,
lpush queue a
lpop queue -> 左边弹出
rpush queue a b -> 插入两个
rpop queue -> 右边弹出
lindex queue 0 -> 基于下标获取
lrange queue 0 -1 -> 范围获取
-
结构 (quicklist)
quickList 内部有一个 quicklistNode
双向链表
quickList -> head,tail,count,len
quicklistNode -> pre,tail,zl(ziplist)
-
场景
- 用户时间线
- 消息队列(左进右出或反)
-
Set
无序集合
sadd myset a b c d e -> 添加
smembers myset -> 查看 key 所有
scard myset -> 统计key 集合个数
srandmember key -> 随机获取一个元素,不会删除
spop myset -> 弹出一个元素
srem myset d e f -> 删除
sismember myset a -> 是否是
sdiff set1 set2 -> 差集
sinter set1 set2 -> 交集
sunion set1 set2 -> 并集
-
抽奖可以,点赞 -》文章id :1001 , key : like:1001 ,sadd like:1001 userId1 userId2 userId3
-
intset
- 存储整形
- 元素不大于 512 个
-
hashtable
- 用 key 存储,value 为空
- 不是整形
- 大于512个
-
Zset 有序集合
sort -> 进行排序,如果值相同,会根据 key ascii 在进行一次排序
数据结构
-
ziplist
- 元素个数小于128个
- 所有的 member 的值的大小小于 64个字节
-
skiplist + dict
- 大于128
- 大于64字节
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
增加指针 level,由高级往低级查
-
-
geospatial
存储经纬度信息,计算记录,范围内
-
hyperloglogs
存放不重复数据(奇数统计) , 统计UV,使用内存少,存放数据大
pfadd
pfcount
-
Streams
可以实现一个持久化的消息队列,发布订阅
发布订阅
publish channel message -> 推送消息
subscribe channel -> 订阅频道
unsubscribe channel -> 取消订阅频道
事务
会进入一个队列,按顺序进行执行
进入队列后,不会受到别的干扰
多个命令组合成原子性操作,保证都成功,或者都失败
multi -> 开启一个事务
decrby -> 减
incrby -> 增
exec -> 执行事务
discard -> 取消事务
watch -> 乐观锁(CAS),watch 监测一个 key , 如果事务中途,key 被修改,那么这个事务会取消
- 执行 exec 之前异常:整个事务都被取消
- 执行 exec 之后异常:异常的不会执行,正常的继续执行
也就是说 ,事务无非完全保证原子性,出现异常的时候,不会进行回滚
Lua 脚本
轻量级脚本语言
一次发送多个命令,减少网络开销
保证绝对的原子性,会当作一个整体会执行,不会被其他操作打断
lua file 实现脚本文件的复用
redis > eval lua-script key-num [key1 key2 key3] [value1 value2 value3 …]
eval :代表执行 lua 命令
lua-script:代表 lua 脚本内容
key-num:表示参数中有多少个 key,注意 Redis 中的 key 是从1开始的,如果没有 key 参数,那么写0
[key1,key2,key3] :是key作为参数传递给 Lua 语言,也可以不填,但是需要和 key-num 参数对应
[value1,value2,value3]:这些参数传递给 Lua 语言,他们是可以不填的
实例:eval “return ‘Hello World’” 0 : 返回一个 ‘Hello World’
Lua 执行 Redis 命令
redis.call(command key,key [param1,param2. …])
command 是命令,包括 set,get ,del 等
key 是被操作的键
param1,param2 代表给 key 的参数
实例:eval “return redis.call(‘set’,KEYS[1],ARGV[1])” 0 gupao 666
运行文件
redis-cli --eval file name key-num key value
脚本限流 :X秒只能访问 Y次
key = IP
expire X
incr = Y的时候,return 0
local num = redis.call(‘incr’,KEYS[1])
if tonumber(num) ==1 then
redis.call(‘expire’,KEYS[1],ARGV[1])
return 1
elseif tonumber(num) > tonumber(ARGV[2]) then
return 0
else
return 1
end
调用 redis-cli --eval filename 192.168.11.12, 6 10
自乘8
local num = redis.call(‘get’,KEYS[1])
if num == false then
num = 0
else
num = tonumber(num)
end
num = num * tonumber(ARGV[1])
redis.call(‘set’,KEYS[1],num)
return num
redis.conf 配置了 lua-time-limit 5000 :设置了 lua 脚本的超时时间,超过这个时间还没有执行完毕,会接收命令,但不执行
script kill 终止命令
如果有一部分命令是执行成功的话,script kill 是无法杀掉的,只能shutdown 服务端
shutdown nosave
生成脚本命令摘要
script load “return ‘hello world’” -> 会生成一个摘要串
evalsha 摘要串 keynum