前言
距离过年那会闲在家更新的 MySQL 系列已经过去一段时间了,这段时间一直在忙其他的,所以博客的更新也就搁置了,但是一直在想着要更新啥内容比较好,刚好朋友给了我一本 Redis 的书籍,我就打算看完结合官方的文档总结一下,分享给大家,如果有什么不对的地方请指正。
Redis 系列,我想以“起承转合”的形式来更新,不过不一定是四篇噢,因为篇幅有限,太长怕你们没有耐心看完,可能《起》篇就分为几篇博文来叙述了,我也会对其进行规整,方便大家看完能更好的吸收,毕竟写文章的我能得到各位观看我的文章,是我的荣幸,我必须得对大家负责的嘛~
话归正题,Redis 应该很多人都有用过(没用过应该看这篇也能看得懂,但是一些基本理论就得自己上网百度啦)。至于 Redis 是什么,有什么好处,怎么用,那就继续往下看吧~本文会侧重于让大家对Redis 基本数据类型的操作命令,底层存储结构以及其应用场景得到一定的认知。
附上基础篇的脑图(上传平台有压缩,有兴趣可以到我的公众号【6曦轩】领取原图)
今天这一篇章给大家介绍一下 Redis 的基本数据类型(高阶的暂不介绍)。
篇幅有点长,我分了几篇来写,这篇是继前面两章节之后的,主要介绍 Zset 以及 Bitmap。
正文
Redis 基本数据类型
List 列表
存储类型
存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
操作命令
元素增减:
lpush queue a
lpush queue b c
rpush queue d e
lpop queue
rpop queue
blpop queue
brpop queue
复制
取值
lindex queue 0
lrange queue 0 -1
复制
存储(实现)原理
在早期的版本中,数据量较小时用 ziplist 存储,达到临界值时转换为 linkedlist 进行存储,分别对应 OBJENCODINGZIPLIST 和 OBJENCODINGLINKEDLIST 。
3.2 版本之后,统一用 quicklist 来存储。quicklist 存储了一个双向链表,每个节点都是一个 ziplist。
127.0.0.1:6379> object encoding queue
"quicklist"
复制
quicklist
quicklist(快速列表)是 ziplist 和 linkedlist 的结合体。quicklist.h,head 和 tail 指向双向列表的表头和表尾
typedef struct quicklist {
quicklistNode *head; /* 指向双向列表的表头 */
quicklistNode *tail; /* 指向双向列表的表尾 */
unsigned long count; /* 所有的 ziplist 中一共存了多少个元素 */
unsigned long len; /* 双向链表的长度,node 的数量 */
int fill : 16; /* fill factor for individual nodes */
unsigned int compress : 16; /* 压缩深度,0:不压缩;*/
} quicklist;
复制
redis.conf 相关参数:参数 |含义 -|- list-max-ziplist-size(fill)| 正数表示单个 ziplist 最多所包含的 entry 个数。
负数代表单个 ziplist 的大小,默认 8k。
-1:4KB;-2:8KB;-3:16KB;-4:32KB;-5:64KB list-compress-depth(compress)| 压缩深度,默认是 0。
1:首尾的 ziplist 不压缩;
2:首尾第一第二个 ziplist 不压缩,以此类推
quicklistNode 中的*zl 指向一个 ziplist,一个 ziplist 可以存放多个元素。
typedef struct quicklistNode {
struct quicklistNode *prev; /* 前一个节点 */
struct quicklistNode *next; /* 后一个节点 */
unsigned char *zl; /* 指向实际的 ziplist */
unsigned int sz; /* 当前 ziplist 占用多少字节 */
unsigned int count : 16; /* 当前 ziplist 中存储了多少个元素,占 16bit(下同),最大 65536 个 */
unsigned int encoding : 2; /* 是否采用了 LZF 压缩算法压缩节点,1:RAW 2:LZF */
unsigned int container : 2; /* 2:ziplist,未来可能支持其他结构存储 */
unsigned int recompress : 1; /* 当前 ziplist 是不是已经被解压出来作临时使用 */
unsigned int attempted_compress : 1; /* 测试用 */
unsigned int extra : 10; /* 预留给未来使用 */
} quicklistNode;
复制
ziplist 的结构前面已经说过了,不再重复。
应用场景
用户消息时间线 timeline
因为 List 是有序的,可以用来做用户时间线
消息队列 List 提供了两个阻塞的弹出操作:BLPOP/BRPOP,可以设置超时时间。BLPOP:BLPOP key1 timeout 移出并获取列表的第一个元素, 如果列表没有元素的话会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOP:BRPOP key1 timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
队列:先进先出:rpush blpop,左头右尾,右边进入队列,左边出队列。栈:先进后出:rpush brpop
Set 集合
存储类型
String 类型的无序集合,最大存储数量 2^32-1(40 亿左右)。
操作命令
添加一个或者多个元素
sadd myset a b c d e f g
复制
获取所有元素
smembers myset
复制
统计元素个数
scard myset
复制
随机获取一个元素
srandmember key
复制
随机弹出一个元素
spop myset
复制
移除一个或者多个元素
srem myset d e f
复制
查看元素是否存在
sismember myset a
复制
存储(实现)原理
Redis 用 intset 或 hashtable 存储 set。如果元素都是整数类型,就用 inset 存储。如果不是整数类型,就用 hashtable(数组+链表的存来储结构)。
问题:KV 怎么存储 set 的元素?
key 就是元素的值,value 为 null。
如果元素个数超过 512 个,也会用 hashtable 存储。
配置文件 redis.conf
set-max-intset-entries 512
127.0.0.1:6379> sadd iset 1 2 3 4 5 6
(integer) 6
127.0.0.1:6379> object encoding iset
"intset"
127.0.0.1:6379> sadd myset a b c d e f
(integer) 6
127.0.0.1:6379> object encoding myset
"hashtable"
复制
应用场景
抽奖 随机获取元素
- 点赞、签到、打卡

这条微博的 ID 是 t1001,用户 ID 是 u3001。
用 like:t1001 来维护 t1001 这条微博的所有点赞用户。
点赞了这条微博:```sadd like:t1001 u3001```
取消点赞:```srem like:t1001 u3001```
是否点赞:```sismember like:t1001 u3001```
点赞的所有用户:```smembers like:t1001```
点赞数:```scard like:t1001```
比关系型数据库简单许多。
- 商品标签
用 tags:i5001 来维护商品所有的标签。

复制
sadd tags:i5001 画面清晰细腻```
```sadd tags:i5001 流畅至极```
- 商品筛选
获取差集
复制
sdiff set1 set2``` 获取交集(intersection )
获取并集
复制
sunion set1 set2``` iPhone11 上市了。
```sadd brand:ios iPhone11```
复制
sadd screensize:6.0-6.24 iPhone11```
筛选商品,苹果的,iOS 的,屏幕在 6.0-6.24 之间的,屏幕材质是 LCD 屏幕
复制
sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd```
用户关注、推荐模型 留下悬念(留言中留下你的思考):1)相互关注?2)我关注的人也关注了他?3)可能认识的人?
By the way
有问题?可以给我留言或私聊 有收获?那就顺手点个赞呗~
当然,也可以到我的公众号下「6曦轩」,
回复“学习”,即可领取一份 【Java工程师进阶架构师的视频教程】~
回复“面试”,可以获得: 【本人呕心沥血整理的 Java 面试题】
回复“MySQL脑图”,可以获得 【MySQL 知识点梳理高清脑图】
还有【阿里云】【腾讯云】的购买优惠噢~具体请联系我
曦轩我是科班出身的程序员,php,Android以及硬件方面都做过,不过最后还是选择专注于做 Java,所以有啥问题可以到公众号提问讨论(技术情感倾诉都可以哈哈哈),看到的话会尽快回复,希望可以跟大家共同学习进步,关于服务端架构,Java 核心知识解析,职业生涯,面试总结等文章会不定期坚持推送输出,欢迎大家关注~~~