Redis是什么
- 远程字典服务
- 分布式场景重的一个单独的节点。
- 请求回应的模式:发起请求,处理之后得到回应的结果。
- 字典的形式存储&索引数据。
- 内存数据库
- 数据在内存中,不可以出现需要的内存不在内存中而在磁盘中
- 速度快,内存100ns,磁盘一次IO10ms
- kv数据库
- 关系型数据库:b+树索引
- kv数据库:通过key索引数据
- 数据结构数据库
- string:字节串(不是以\0作为分隔符,是用长度描述的)
- list:链表
- hash:
- zset:有序集合(member确定唯一,score确定有序)
- set:集合
- stream:消息队列,通常用kafka
- hyperloglog:基于统计的数据,概率型数据结构
- 。。。
认识Redis
- key:都是字节串,用户定义的名字。
- value:使用什么命令决定。
安装编译
git clone https://github.com/redis/redis.git -b 6.2 cd redis make -j32 sudo make install
启动
mkdir redis-server cd redis-server redis-server redis.conf redis-cli >auth [password]
Redis命令
set teacher king # ok keys * #1) "teacher" get teacher # "king" lpush teachers mark darren king # (integer) 3 lrange teachers 0 -1 hset teacher:10001 name mark hset teacher:10001 age 30 hset teacher:10001 sex 1 hgetall teacher:10001 sadd teacher:set mark king darren smembers teacher:set zadd teacher:rank 98 mark 99 darren 100 king zrange teacher:rank 0 -1 withscores zadd teacher:rank 101 mark
Redis存储结构
- key通过哈希,生成一个64位的整数。Redis维护一个恰好大于n的2的n次幂的数组。对key取余,得到数组的索引值。kv对存储在索引下面,有多个的时候用链表链接。
- list是一个双向循环链表
- list,hash和zset可能会使用压缩列表,数据少的时候使用(7.0之后是listpack不记录最后偏移,时间复杂度差不多)
- zset:跳表
- set:整形数组,如果元素使整数,那就是整数有序数组
- string:动态字节串
object encoding teacher # 查看value的类型 incr teacher incr counter # 没有自动创建为0然后+1 incrby counter 100 decr counter 1 setnx counter 10000 setbit bitstr 1 1 setbit bitstr 2 1 getbit bitstr 3 bitcount bitstr 0 -1
Redis存储转换
String
字符数组,这不是字符串的意思,是字节串。也就是说,redis的string是可以有’\0’符号的。该字符串是动态字符串raw,字符串长度小于1M时,加倍扩容;超过1M每次只扩容1M;字符串的最大长度为512M;
由于String是二进制安全字符串,所以他可以存储图片,二进制协议等二进制数据。
基础命令
# 设置key的val值 set key val # 获取key的val值 get key # 执行原子加1操作 incr key # 执行原子加一个整数的操作 incrby key increment # 执行原子减1操作 decr key # 执行原子操作减一个整数 drcrby key increment # 如果key不存在就等于set,如果存在就什么都不做 setnx key value # 删除key val键值对 del key # 设置动态字符串,节省内存 setbit key offset value # 获取offset处的bit值 getbit key offset # 统计字符串设置为1的数量 bitcount key [start end]
存储结构
字符串长度小于20且能转化为整数,则用int存储;
字符串长度小于等于44,使用embstr;
字符串长度大于44,使用raw;
实际使用
对象存储
set role:1001 '{["name"]:"lennlouis",["sex"]:"male",["age"]:21}' set role:1002 '{["name"]:"selena",["sex"]:"female",["age"]:20}' get role:1001
- 用在属性字段极少改变的时候
- redis客户端(redisinsight)使用:来构建树状目录;
- 存储json格式的value,方便业务解析;
累加器
# 统计阅读数 累加1 incr reads # 累加100 incrby reads 100
分布式锁
# 尝试将lock的值设置为1 setnx lock 1 # 尝试将lock的值设置为一个唯一的标识符uuid setnx lock uuid #设置过期时间为30s,每个客户端只有一把有效期为30s的锁 set lock uuid nx ex 30 # 释放锁 del lock if (get(lock) == uuid) del(lock);
位运算
setbit sign:10001:202106 1 1 # 计算 2021年6月份 的签到情况 bitcount sign:10001:202106 # 获取 2021年6月份 第二天的签到情况 1 已签到 0 没有签到 getbit sign:10001:202106 2
List
双向链表的实现,列表首尾操作(删除和增加)时间复杂度为o(1);查找中间元素时间复杂度为o(n);
列表中数据是否压缩的依据
- 元素长度小于48,不压缩;
- 元素压缩前后长度差不超过8,不压缩;
基础命令
# 从队列左侧入队一个或者多个元素 lpush key value [value ...] # 从队列左侧弹出一个元素 lpop key # 从队列右侧入队一个或多个元素 rpush key value [value ...] # 从队列右侧弹出一个元素 rpop key # 返回差从队列的start和end之间的元素 lrange key start end # 从存于key的列表里移除前count次出现的值为value的元素 # list没有去重功能 lrem key count value # 他是rpop的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞链接 brpop key timeout # 超时时间 + 延时队列
应用
队列(先进先出FIFO)
lpush+rpop # 或者 rpush+lpop
阻塞队列
lpush+brpop rpush+blpop
异步消息队列
一般不用,会选择kafka这种消息队列。
获取固定窗口记录
hash
散列表,在很多高级语言中包含这种数据结构;C++`unordered_map`通过key快速索引value;
基础命令
# 获取key对应hash中的field hget key field # 设置key对应hash中的field hset key field value # 设置多个hash键值对 hmset key field1 value1 field2 value2 ... fieldn valuen # 获取多个field值 hmget key field1 field2 ... fieldn # 给key对应hash中的field对应的值加1 hincrby key field increment # 获取key对应的hash中有几个键值 hlen key # 删除key对应的hash键值对 hdel key field
存储结构
节点数量大于512(hash-max-ziplist-entries)或者所有字符串长度大于64(hash-max-ziplist-value),则使用dict实现;如果节点数量小于等于512且有一个字符串小于64,则使用ziplist。
应用
存储对象
hmset hash:10001 name jiejie age 18 sex male # 与string比较 set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:18}' # 如果现在要更新数据将年龄改为19岁 # hash hset hash:10001 age 19 # string set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:19}'
购物车
set
集合:用来存储唯一性字段,不要求有序;
存储不需要有序,操作需要有序。(在取出数据后使用排序算法排序)
基础命令
sadd key member [member ...] scard key smembers key sismember key member srandmember key [count] spop key [count] sdiff key [key ...] sinter key [key ...] sunion key [key ...] • 1 • 2 • 3 • 4 • 5 • 6 • 7 • 8 • 9
存储结构
元素都为整数且节点数量小于等于512,则使用整数数组存储;
元素中有一个不是整数或者节点数量大于512,则使用字典存储;
应用
抽奖
# 添加抽奖用户 sadd Award:1 10001 10002 10003 10004 10005 10006 sadd Award:1 10009 # 查看所有抽奖用户 smembers Award:1 # 抽取用户 srandmember Award:1 10
共同关注
sadd follow:A xiaomin lihua liuwei zhuzhu sadd follow:B xiaomin lihua liuwei sinter follow:A follow:B
推荐好友
sadd follow:A xiaomin lihua liuwei zhuzhu sadd follow:B xiaomin lihua liuwei # B可能认识的人 sdiff sinter follow:A follow:B
zset
有序集合:用来实现排行榜,是一个唯一有序的集合。
基础命令
zadd key [NX|XX] [CH] [INCR] score member [score member ...] zrem key member [member ...] zscore key member zincrby key increment member zcard key zrank key member zrange key start stop [WITHSCORES] zrevrange key start stop [WITHSCORES]
存储结构
节点数量大于128或者有一个字符串长度大于64,则使用跳表;
节点数量小于等于128且所有字符串长度小于等于64,则使用`ziplist`;
数据少的时候,节省空间;O(n)
数据多的时候,访问性能;O(1) 或者 O(log2n)
应用
百度热榜
# 点击新闻 增加一个热度 zincrby hot:20240711 1 10001 zincrby hot:20240711 1 10002 zincrby hot:20240711 1 10003 zincrby hot:20240711 1 10004 zincrby hot:20240711 1 10005 zincrby hot:20240711 1 10006 zincrby hot:20240711 1 10007 zincrby hot:20240711 1 10008 zincrby hot:20240711 1 10009 zincrby hot:20240711 1 10010 zincrby hot:20240711 1 10011 zincrby hot:20240711 1 10012 zincrby hot:20240711 1 10013 zincrby hot:20240711 1 10014 zincrby hot:20240711 1 10015 # 获取排行榜 zrevrange hot:20240711 0 14 withscores