Redis 内部整体的存储结构是一个大的 HashMap,通过 key -value 的方式来存储组织数据的,key冲突通过 链表去实现,每个dictEntry为一个key/value对象,value为RedisObject。
所有的key值都是string类型。
key值的命名规范:
【推荐】Redis key命名需具有可读性以及可管理性,不该使用含义不清的key以及特别长的key名;
【强制】以英文字母开头,命名中只能出现 小写字母、数字、英文点号(.) 和 英文半角冒号(:);
【强制】不要 包含 特殊字符,如下划线、空格、换行、单双引号以及其他转义字符;
【强制】命名规范:业务模块名:业务逻辑含义:其他:value类型
例如:user:basic.info:{userid}:string
Redis提供了丰富的数据类型,常见的有五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)。
String是一种安全字符串。
什么安全字符串?
使用安全字符串的函数都不会是超出字符串缓冲区。
//设置 key-value 类型的值
127.0.0.1:6379> set name sjp
OK
# 根据 key 获得对应的 value
127.0.0.1:6379> get name
"sjp"
# 判断某个 key 是否存在
127.0.0.1:6379> exists name
(integer) 1
# 返回 key 所储存的字符串值的长度
127.0.0.1:6379> strlen name
(integer) 3
# 删除某个 key 对应的值
127.0.0.1:6379> del name
(integer) 1
#批量设置 key-value类型的值
127.0.0.1:6379> mset name:1001 sjp name:1002 lisi
OK
# 批量获取多个 key 对应的 value
127.0.0.1:6379> mget name:1001 name:1002
1) "sjp"
2) "lisi"
命令例子:
SET user:1 '{"name":"sjp", "age":18}'。
采用将 key 进行分离为 user:ID:属性,采用 MSET 存储,用 MGET 获取各属性值,命令例子:
MSET user:1:name xiaolin user:1:age 18 user:2:name xiaomei user:2:age 20
# 设置 key-value 类型的值
127.0.0.1:6379> set count 1
OK
# 将 key 中储存的数字值增一
127.0.0.1:6379> incr count
(integer) 2
# 将key中存储的数字值加 10
127.0.0.1:6379> incrby count 100
(integer) 102
# 将 key 中储存的数字值减一
127.0.0.1:6379> decr count
(integer) 101
# 将key中存储的数字值键 10
127.0.0.1:6379> decrby count 10
(integer) 91
List 列表是双向链表实现,列表首尾操作(删除和增加)时间复杂度 O(1);.查找中间元素时间复杂度为O(n);
列表中数据是否压缩的依据:
1. 元素长度小于 48,不压缩;
2. 元素压缩前后长度差不超过 8,不压缩;
基础命令:
# 从队列的左侧入队一个或多个元素
LPUSH key value [value ...]
# 从队列的左侧弹出一个元素
LPOP key
# 从队列的右侧入队一个或多个元素
RPUSH key value [value ...]
# 从队列的右侧弹出一个元素
RPOP key
# 返回从队列的 start 和 end 之间的元素 0, 1 2 负索引
LRANGE key start end
# 从存于 key 的列表里移除前 count 次出现的值为 value 的
元素
# list 没有去重功能 hash set zset
LREM key count value
# 它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出
任何元素的时候阻塞连接
BRPOP key timeout # 超时时间 + 延时队列
LPUSH + LPOP
# 或者
RPUSH + RPOP
LPUSH + RPOP
# 或者
RPUSH + LPOP
消息队列在存取消息时,必须要满足三个需求,分别是消息保序、处理重复的消息 和 保证消息可靠性。
BRPOP命令也称为 阻塞式读取,客户端在 没有 读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据
2、消息队列如何处理重复的消息?
消费者要实现重复消息的判断,需要 2 个方面的要求:
List 并不会为每个消息生成 ID 号,所以我们需要自行为每个消息生成一个全局唯一ID,生成之后,我们在用 LPUSH 命令把消息插入 List 时,需要在消息中包含这个全局唯一 ID
3.消息队列如何保证消息的可靠性?
当消费者程序从 List 中读取一条消息后,List 就不会再留存这条消息了。所以,如果消费者程序在处理消息的过程出现了故障或宕机,就会导致消息没有处理完成,那么,消费者程序再次启动后,就没法再次从 List 中读取消息了。
,List 类型提供了 BRPOPLPUSH
命令,这个命令的 作用是让消费者程序从一个 List 中读取消息,同时,Redis 会把这个消息再插入到另一个 List(可以叫作备份 List)留存。
Hash 是一个键值对(key - value)集合,其中 value 的形式如: value=[{field1,value1},...{fieldN,valueN}]
。Hash 特别适合用于存储对象.
Hash 类型的底层数据结构是由压缩列表或哈希表实现的:
如果 哈希类型元素个数小于 512
个(默认值,可由 hash-max-ziplist-entries
配置),所有值小于 64
字节(默认值,可由 hash-max-ziplist-value
配置)的话,Redis 会使用压缩列表作为 Hash 类型的底层数据结构。
# 获取 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 对应的值加一个整数值
HINCRBY key field increment
# 获取 key 对应的 hash 有多少个键值对
HLEN key
# 删除 key 对应的 hash 的键值对,该键为field
HDEL key field
一般对象用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储。
购物车
Set 类型是一个 无序并唯一的键值集合,它的 存储顺序不会按照插入的先后顺序进行存储
一个集合最多可以存储 2^32-1
个元素。概念和数学中个的集合基本类似,可以交集,并集,差集等等。。
元素都为 整数且节点数量小于等于 512(set-max-intsetentries),则使用整数数组存储;
元素当中有一个不是整数或者节点数量大于 512,则使用 字典存储;
# 添加一个或多个指定的member元素到集合的 key中
SADD key member [member ...]
# 计算集合元素个数
SCARD key
# SMEMBERS key
SMEMBERS key
# 返回成员 member 是否是存储的集合 key的成员
SISMEMBER key member
# 随机返回key集合中的一个或者多个元素,不删除这些元素
SRANDMEMBER key [count]
# 从存储在key的集合中移除并返回一个或多个随机元素
SPOP key [count]
# 返回一个集合与给定集合的差集的元素
SDIFF key [key ...]
# 返回指定所有的集合的成员的交集
SINTER key [key ...]
# 返回给定的多个集合的并集中的所有成员
SUNION key [key ...]
list可以存储重复元素,set只能存储非重复元素。
list是按照元素的插入的先后顺序进行存储,而set则是无序方式存储元素
set可以保证一个用户只能点一个赞,例如,key是文章id,value是用户id
uid:1
、uid:2
、uid:3
三个用户分别对 article:1 文章点赞了。
#uid:1 uid:2 uid:3 用户对文章 article:1 点赞
127.0.0.1:6379> sadd article:1 uid:1
(integer) 1
127.0.0.1:6379> sadd article:1 uid:2
(integer) 1
127.0.0.1:6379> sadd article:1 uid:3
(integer) 1
#获取 article:1 文章所有点赞用户 :
127.0.0.1:6379> smembers article:1
1) "uid:3"
2) "uid:2"
3) "uid:1"
#获取 article:1 文章的点赞用户数量:
127.0.0.1:6379> scard article:1
(integer) 3
Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。
key 可以是用户id,value 则是好友
#插入A的好友
127.0.0.1:6379> sadd follow:A sjp king lisi
(integer) 3
#插入B的好友
127.0.0.1:6379> sadd follow:B chen lisi sjp
(integer) 3
#A不同于B的好友
127.0.0.1:6379> sdiff follow:A follow:B
1) "king"
#A与B的共同好友
127.0.0.1:6379> sinter follow:A follow:B
1) "sjp"
2) "lisi"
key为抽奖活动名,value为员工名称,把所有员工名称放入抽奖箱
#添加抽奖人员
127.0.0.1:6379> sadd lucky A B C D E
(integer) 5
#允许重复抽奖
127.0.0.1:6379> srandmember lucky 1
1) "C"
127.0.0.1:6379> srandmember lucky 2
1) "E"
2) "D"
127.0.0.1:6379> srandmember lucky 3
1) "B"
2) "C"
3) "A"
#不重复抽奖
127.0.0.1:6379> spop lucky 1
1) "A"
127.0.0.1:6379> spop lucky 2
1) "D"
2) "E"
Zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score(分值),对于有序集合
有序集合保留了集合不能有重复成员的特性(分值可以重复),但不同的是,有序集合中的元素可以排序。 zset 根据分值进行排序。
基础命令:
# 添加到键为key有序集合(sorted set)里面
ZADD key [NX|XX] [CH] [INCR] score member [score
member ...]
# 从键为key有序集合中删除 member 的键值对
ZREM key member [member ...]
# 返回有序集key中,成员member的score值
ZSCORE key member
# 为有序集key的成员member的score值加上增量increment
ZINCRBY key increment member
# 返回key的有序集元素个数
ZCARD key
# 返回有序集key中成员member的排名
ZRANK key member
# 返回存储在有序集合key中的指定范围的元素 order by id
limit 1,100
ZRANGE key start stop [WITHSCORES]
# 返回有序集key中,指定区间内的成员(逆序)
ZREVRANGE key start stop [WITHSCORES]
有序集合比较典型的使用场景就是排行榜。例如 学生成绩的排名榜、游戏积分排行榜、视频播放排名、电商系统中商品的销量排名等。