1.基本数据类型

通用存储结构

1.redisDb

redis数据库数据类型 在服务启动的时候会根据configured来初始化数据库的数量 默认是16个

  1. typedef struct redisDb {
  2. dict *dict; /* The keyspace for this DB key 空间*/ /*hash存储key value*/
  3. dict *expires; /* Timeout of keys with a timeout set 超时key的集合 再惰性删除和定时删除的时候使用 */
  4. dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) 堵塞读的key*/
  5. dict *ready_keys; /* Blocked keys that received a PUSH 收到的堵塞key*/
  6. dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
  7. int id; /* Database ID 数据库id */
  8. long long avg_ttl; /* Average TTL, just for stats */
  9. unsigned long expires_cursor; /* Cursor of the active expire cycle. */
  10. list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
  11. } redisDb;

可以看到dict指向一个dict对象 字典对象

2.dict

  1. typedef struct dict {
  2. dictType *type;
  3. void *privdata;
  4. dictht ht[2];
  5. long rehashidx; /* rehashing not in progress if rehashidx == -1 */
  6. unsigned long iterators; /* number of iterators currently running */
  7. } dict;

3.dictht 真正的hash表实现

如注释所示dict维护了两个哈希字典来做扩容

  1. /* This is our hash table structure. Every dictionary has two of this as we
  2. * implement incremental rehashing, for the old to the new table. */
  3. typedef struct dictht {
  4. dictEntry **table;
  5. unsigned long size;
  6. unsigned long sizemask;
  7. unsigned long used;
  8. } dictht;

4.dictEntry

  1. typedef struct dictEntry {
  2. void *key; //key 的指针
  3. union {
  4. void *val; //值
  5. uint64_t u64;
  6. int64_t s64;
  7. double d;
  8. } v;
  9. struct dictEntry *next;//下一个
  10. } dictEntry;

5. redisobject

redisobject居然也不是真正的存储数据结构而是多封了一层再指向真正的存储结构.

  1. 第一,可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发开发出优秀的内部编码,无需改动外部数据结构和命令。
  2. 第二,多种内部编码实现可以在不同场景下发挥各自的优势。例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,

为了节省宝贵的性能 redis优先选择内存占用小的数据结构来存储数据。这样多封一层就能解耦

  1. typedef struct redisObject {
  2. unsigned type:4; // type类型
  3. unsigned encoding:4; // encoding类型
  4. unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
  5. * LFU data (least significant 8 bits frequency
  6. * and most significant 16 bits access time). */
  7. int refcount;
  8. void *ptr;
  9. } robj;

QQBrowser_r5kxdyAWx4.png
redisDb (简单认为是一个哈希表) 根据key获取 dictEntry —->redisObject —->具体encoding的数据实现


2.常用数据结构

1.Redis数据类型和结构及其运用 - 图2


1.string

1.常用命令

  1. //set 命令
  2. set name loafer
  3. //返回长度
  4. strlen name
  5. /** 添加至key的末尾 数据类型立刻转换成 raw*/
  6. append name bigdick
  7. /* 如果不存在则插入 返回影响条数 可以用来做分布式锁 */
  8. setnx name 123
  9. /*批量插入*/
  10. mset [key1] [value1] [key2] [value2]
  11. /*批量获取*/
  12. mget [key1][key2]
  13. // 步长++
  14. incr [key]
  15. // 步长++
  16. incrby [key] [步长]
  17. // --
  18. decr [key]
  19. // --步长
  20. decrby [key] [步长]
  21. //浮点数 ++
  22. incrbybyfloat [key] [步长]

2.数据结构

image.png

  • int 8字节长整型 2^63-1
  • embstr embstring的sds 小于44字节
  • raw sds 大于44 1.Redis数据类型和结构及其运用 - 图4可以在redis源码中验证 可以看到该方法在 44位以下 createEmbeddedStringObject 之上返回createRawStringObject(ptr,len);
    1. /* Create a string object with EMBSTR encoding if it is smaller than
    2. * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
    3. * used.
    4. *
    5. * The current limit of 44 is chosen so that the biggest string object
    6. * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
    7. #define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
    8. robj *createStringObject(const char *ptr, size_t len) {
    9. if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
    10. return createEmbeddedStringObject(ptr,len);
    11. else
    12. return createRawStringObject(ptr,len);
    13. }

需要注意的是 int ->embstr ->raw 是不可逆的 不会随着数据量变小而变回int

2.SDS simple dynamic string

简单动态字符串

  1. 常数复杂度获得字符串长度。
  2. 杜绝缓冲区溢出。
  3. 减少修改字符串长度时所需的内存重分配次数。
  4. 二进制安全。
  5. 兼容部分C字符串函数

    1. struct sdshdr {
    2. // buf 中已占用空间的长度
    3. int len;
    4. // buf 中剩余可用空间的长度
    5. int free;
    6. // 数据空间
    7. char buf[];
    8. };

3.常用场景

1.缓存 缓存json

2.分布式会话

3.分布式锁 setnx ex (需要设置获取锁的超时时间,不然会出现死锁)

4.分布式全局id

5.分布式计算器

6.限流计数器

7.位操作

…….

2.Hash 哈希

哈希表就是用一个 key 管理大量的子key -value (field -value)键值对 需要注意的 field 不能分片存储 1.Redis数据类型和结构及其运用 - 图5

1.常用命令

  1. hset [key] [field] [value] //设置
  2. hmset [key] [f1] [v1] [f2] [v2] // 批量设值
  3. hget h1 a
  4. hmget [key] [v1] [v2]
  5. hkeys [name] //显示全部的key值
  6. hcals [name] //显示全部的value值
  7. hgetall [name] //显示全部的key value值
  8. hdel [name] [f] //删除对应属性
  9. hlen [name] //哈希表有几个键值对
  10. del [name] 删除

2.数据结构

1.Redis数据类型和结构及其运用 - 图6

1.ziplist

  • zlbytes: ziplist的长度(单位: 字节),是一个32位无符号整数
  • zltail: ziplist最后一个节点的偏移量,反向遍历ziplist或者pop尾部节点的时候有用。
  • zllen: ziplist的节点(entry)个数
  • entry: 节点
  • zlend: 值为0xFF,用于标记ziplist的结尾

普通数组的遍历是根据数组里存储的数据类型 找到下一个元素的,例如int类型的数组访问下一个元素时每次只需要移动一个sizeof(int)就行(实际上开发者只需让指针p+1就行,在这里引入sizeof(int)只是为了说明区别)。
上文说了,ziplist的每个节点的长度是可以不一样的,而我们面对不同长度的节点又不可能直接sizeof(entry),那么它是怎么访问下一个节点呢?
ziplist将一些必要的偏移量信息记录在了每一个节点里,使之能跳到上一个节点或下一个节点。
1.Redis数据类型和结构及其运用 - 图7

每个节点由三部分组成:prevlength、encoding、data

  • prevlengh: 记录上一个节点的长度,为了方便反向遍历ziplist
  • encoding: 当前节点的编码规则,下文会详细说
  • data: 当前节点的值,可以是数字或字符串

为了节省内存,根据上一个节点的长度prevlength 可以将ziplist节点分为两类:

1.Redis数据类型和结构及其运用 - 图8

  • entry的前8位小于254,则这8位就表示上一个节点的长度
  • entry的前8位等于254,则意味着上一个节点的长度无法用8位表示,后面32位才是真实的prevlength。用254 不用255(11111111)作为分界是因为255是zlend的值,它用于判断ziplist是否到达尾部。

根据当前节点存储的数据类型及长度,可以将ziplist节点分为9类
其中整数节点分为6类:
1.Redis数据类型和结构及其运用 - 图9

2.HashMap

image.png

持有一个空的哈希表的目的就是为了 rehash扩容时用 可以在源码中看见hash碰撞的因子是5

static unsigned int dict_force_resize_ratio = 5;

3.常用场景

sting能做的hash基本也能做

特殊场景购物车

image.png

3. list (队列 ,栈)

1.常用命令

image.png

2,数据结构 quicklist 双向链表+ ziplist

image.png

3,应用场景

1.消息队列

2.文章链表

3.评论链表

4 xxx列表….

因为有 blpop brpop 堵塞读方法就可以用来实现简单的消息队列.

4. set

1.常用命令

  1. sadd [key] [v1] [v2] [v3]....
  2. //显示set内的值
  3. smembers [name]
  4. // set的长度
  5. scard [name]
  6. // 随机返回不删除
  7. srandmember [name]
  8. //随机弹出
  9. spop [name]
  10. //删除元素
  11. srem [v1] [v2]
  12. //是否在集合中
  13. sismember [name] [v1]

2. 数据结构

1.Redis数据类型和结构及其运用 - 图14根据配置文件 intset —>hashtable

intset的实现非常简单

就是一个数组
intsetSearch 方法就是二分法查找

  1. typedef struct intset {
  2. uint32_t encoding;
  3. uint32_t length;
  4. int8_t contents[];
  5. } intset;
  1. static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
  2. int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
  3. int64_t cur = -1;
  4. if (intrev32ifbe(is->length) == 0) {
  5. if (pos) *pos = 0;
  6. return 0;
  7. } else {
  8. if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) {
  9. //大于集合中最大的数
  10. if (pos) *pos = intrev32ifbe(is->length);
  11. return 0;
  12. } else if (value < _intsetGet(is,0)) {
  13. //小于集合中最小的数
  14. if (pos) *pos = 0;
  15. return 0;
  16. }
  17. }
  18. //采用二分查找算法进行搜索
  19. while(max >= min) {
  20. mid = ((unsigned int)min + (unsigned int)max) >> 1;
  21. cur = _intsetGet(is,mid);
  22. if (value > cur) {
  23. min = mid+1;
  24. } else if (value < cur) {
  25. max = mid-1;
  26. } else {
  27. break;
  28. }
  29. }
  30. if (value == cur) {
  31. //找到相同的元素
  32. if (pos) *pos = mid;
  33. return 1;
  34. } else {
  35. //未找到
  36. if (pos) *pos = min;
  37. return 0;
  38. }
  39. }

2. 常用场景(超好用)

  • SINTER key [key …] //交集运算
  • SINTERSTORE destination key [key ..] //将交集结果存入新集合destination中
  • SUNION key [key ..] //并集运算
  • SUNIONSTORE destination key [key …] //将并集结果存入新集合destination中
  • SDIFF key [key …] //差集运算
  • SDIFFSTORE destination key [key …] //将差集结果存入新集合destination中

1.Redis数据类型和结构及其运用 - 图15

  1. 1. 127.0.0.1:6379> sadd shediao guojing huangrong huazheng yangkang
  2. 2. (integer) 4
  3. 3. 127.0.0.1:6379> sadd shendiao guojing huangrong yangguo xiaolongnv
  4. 4. (integer) 4
  5. 5. 127.0.0.1:6379> sinter shediao shendiao
  6. 6. 1) "huangrong"
  7. 7. 2) "guojing"
  8. 8. 127.0.0.1:6379> sinterstore sheshendiao shediao shendiao
  9. 9. (integer) 2
  10. 10. 127.0.0.1:6379> smembers sheshendiao
  11. 11. 1) "huangrong"
  12. 12. 2) "guojing"
  13. 13. 127.0.0.1:6379> sunion shediao shendiao
  14. 14. 1) "yangguo"
  15. 15. 2) "xiaolongnv"
  16. 16. 3) "yangkang"
  17. 17. 4) "huangrong"
  18. 18. 5) "guojing"
  19. 19. 6) "huazheng"
  20. 20. 127.0.0.1:6379> sunionstore shenshediao shediao shendiao
  21. 21. (integer) 6
  22. 22. 127.0.0.1:6379> smembers shenshediao
  23. 23. 1) "yangguo"
  24. 24. 2) "xiaolongnv"
  25. 25. 3) "yangkang"
  26. 26. 4) "huangrong"
  27. 27. 5) "guojing"
  28. 28. 6) "huazheng"
  29. 29. 127.0.0.1:6379> sdiff shediao shendiao
  30. 30. 1) "huazheng"
  31. 31. 2) "yangkang"
  32. 32. 127.0.0.1:6379> sdiffstore diaoshenshe shediao shendiao
  33. 33. (integer) 2
  34. 34. 127.0.0.1:6379> smembers diaoshenshe
  35. 35. 1) "huazheng"
  36. 36. 2) "yangkang"

1.点赞

1.Redis数据类型和结构及其运用 - 图16

  1. 点赞:sadd like_msg_10010 friend_1
  2. 取消点赞: srem like_msg_10010 friend_1
  3. 获取点赞用户列表:smembers like_msg_10010
  4. 获取点赞数量:scard like_msg_10010

    2.共同关注

说这个关注模型首先得说明几个前提
xiaolinziSet(我关注的人): uzi 微博会员小秘书 lol无双小智 微博会员 55开 SDR 电竞练习生 不拉的P特
UZISet(UZI关注的人): lol无双小智 55开 微博会员小秘书 微博会员 xiaohu
xiaozhiSet(小智关注的人): UZI 小莫

  • 我和UZI共同关注:sinter xiaolinziSet UZISet —————》》uzi 微博会员小秘书 lol无双小智 微博会员

    【取交集】

  • 我关注的人也关注UZI:sismember xiaozhiSet UZI

  • 我可能认识的人:sdiff UZISet xiaolinziSet —————-》》 xiaohu

【我同时关注的人 他们关注的人取交集】

3.打标签

image.png

5. zset有序set

image.png

1.常用命令

  1. //插入数据并赋值
  2. zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python
  3. //根据分值排序 降序
  4. zrange myzset 0 -1 withscores
  5. //根据分值排序 显示0-2条
  6. zrange myzset 0 2 withscores
  7. //倒排序
  8. zrangebyscore myzset 20 30
  9. //长度
  10. zcard myzset
  11. //remove by key
  12. zrem myzset php cpp
  13. //分值减5
  14. zincrby myzset 5 python
  15. //统计 20-60分的数据
  16. zcount myzset 20 60
  17. //第几名
  18. zrank myzset python
  19. //key的分数
  20. zscore myzset python

2. 数据结构

1.Redis数据类型和结构及其运用 - 图19如果长度小于128且所以长度小于64 ziplist 否则使用skiplist+dict 跳表加字典

1.跳表

image.png

  1. /* ZSETs use a specialized version of Skiplists */
  2. typedef struct zskiplistNode {
  3. sds ele;
  4. double score; // zset分数
  5. struct zskiplistNode *backward;
  6. struct zskiplistLevel {
  7. struct zskiplistNode *forward; //后退指针
  8. unsigned long span; //跨度
  9. } level[]; //层
  10. } zskiplistNode;
  11. //跳表
  12. typedef struct zskiplist {
  13. struct zskiplistNode *header, *tail; // 指向跳表头尾
  14. unsigned long length; //长度
  15. int level; //最大层数
  16. } zskiplist;
  17. // zset实现
  18. typedef struct zset {
  19. dict *dict;
  20. zskiplist *zsl;
  21. } zset;

3.常用场景

1.微博热搜排行榜

1.Redis数据类型和结构及其运用 - 图21

  1. 每点击一次新闻,增加一次浏览量: zincrby hotSearch_20200426 1 接种疫苗7大建议
  2. 展示当日热搜前十: zrevrange hotSearch_20200426 0 9 withscores
  3. 七日搜索榜单计算: zunionstore hotSearch_20200420-20200426 7 hotSearch_20200420 hotSearch_20200421 hotSearch_20200422 hotSearch_20200423 hotSearch_20200424 hotSearch_20200425 hotSearch_20200426
  4. 展示七日排行版前十:zrevrange hotSearch_20200420-20200426 0 9 withscores

3.其他数据类型

BitMap(状态判断 用户签到 统计活跃 用户在线)

就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。

setbit命令介绍

指令 SETBIT key offset value
设置或者清空key的value(字符串)在offset处的bit值(只能只0或者1)。

空间占用、以及第一次分配空间需要的时间

在一台2010MacBook Pro上,offset为230-1(分配128MB)需要~80ms,offset为226-1(分配8MB)需要8ms。<来自官方文档>
大概的空间占用计算公式是:($offset/8/1024/1024)MB

使用场景一:用户签到

很多网站都提供了签到功能(这里不考虑数据落地事宜),并且需要展示最近一个月的签到情况,如果使用bitmap我们怎么做?一言不合亮代码!
根据日期 offset =hash % 365 ; key = 年份#用户id

使用场景二:统计活跃用户

使用时间作为cacheKey,然后用户ID为offset,如果当日活跃过就设置为1
那么我该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃),有请下一个redis的命令
命令 BITOP operation destkey key [key …]
说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
说明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数

20190216 活跃用户 【1,2】
20190217 活跃用户 【1】
统计20190216~20190217 总活跃用户数: 1

统计20190216~20190217 在线活跃用户数: 2

使用场景三:用户在线状态

前段时间开发一个项目,对方给我提供了一个查询当前用户是否在线的接口。不了解对方是怎么做的,自己考虑了一下,
使用bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户ID为offset,如果在线就设置为1,
不在线就设置为0,和上面的场景一样,5000W用户只需要6MB的空间。

geospatial 地理空间(附近的xx 打车距离计算)

朋友的定位,附近的人,打车距离的计算
Redis的Geo,3.2版本推出,可以推算地理位置的信息,两地之间的距离
城市经纬度查询:http://www.jsons.cn/lngcode/

geoadd

  1. # geoadd 先经度后维度(官方文档疑似写错了)
  2. 127.0.0.1:6379[1]> geoadd china:city 39.9 116.4 beijing
  3. (error) ERR invalid longitude,latitude pair 39.900000,116.400000
  4. 经纬度反了会报错
  5. # 两极无法直接添加!南北极,而且我们一般会下载城市数据通过java程序一次性导入
  6. 127.0.0.1:6379[1]> geoadd china:city 116.4 39.9 beijing
  7. # 批量 geoadd china:city 116.4 39.9 beijing 121.4 31.2 shanghai 114.1 22.5 shenzhen 113.3 23.1 guangzhou 114.2 22.3 xianggang 113.5 22.2 aomen 121.9 29.5 xiangshan
  8. (integer) 1
  9. 127.0.0.1:6379[1]> geoadd china:city 121.4 31.2 shanghai
  10. (integer) 1
  11. 127.0.0.1:6379[1]> geoadd china:city 114.1 22.5 shenzhen
  12. (integer) 1
  13. 127.0.0.1:6379[1]> geoadd china:city 113.3 23.1 guangzhou
  14. (integer) 1
  15. 127.0.0.1:6379[1]> geoadd china:city 114.2 22.3 xianggang
  16. (integer) 1
  17. 127.0.0.1:6379[1]> geoadd china:city 113.5 22.2 aomen
  18. (integer) 1
  19. 127.0.0.1:6379[1]> geoadd china:city 121.9 29.5 xiangshan
  20. (integer) 1

geopost

  1. # 获取地理位置
  2. 127.0.0.1:6379[1]> GEOPOS china:city beijing shanghai shenzhen xianggang
  3. 1) 1) "116.39999896287918091"
  4. 2) "39.90000009167092543"
  5. 2) 1) "121.40000134706497192"
  6. 2) "31.20000061483705878"
  7. 3) 1) "114.09999936819076538"
  8. 2) "22.50000113800319212"
  9. 4) 1) "114.19999748468399048"
  10. 2) "22.29999896492555678"

geodist

两人之间的直线距离

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。
  1. 127.0.0.1:6379[1]> GEODIST china:city beijing xianggang
  2. "1968579.6084"
  3. 127.0.0.1:6379[1]> GEODIST china:city beijing xianggang m
  4. "1968579.6084"
  5. 127.0.0.1:6379[1]> GEODIST china:city beijing xianggang km
  6. "1968.5796"
  7. 127.0.0.1:6379[1]> GEODIST china:city beijing xianggang ft
  8. "6458594.5159"
  9. 127.0.0.1:6379[1]> GEODIST china:city beijing xianggang mi
  10. "1223.2217"

georadius

以给定的经纬度为中心,找出某一半径内所有的元素 实现附近的人: 1、获取所有附近的人的地址(GPS)

  1. # 范围查找 经度110 纬度 30为圆心 半径100km内所有的城市
  2. 127.0.0.1:6379[1]> GEORADIUS china:city 110 30 100 km
  3. (empty list or set)
  4. # 范围查找 经度110 纬度 30为圆心 半径1000km内所有的城市
  5. 127.0.0.1:6379[1]> GEORADIUS china:city 110 30 1000 km
  6. 1) "aomen"
  7. 2) "xianggang"
  8. 3) "shenzhen"
  9. 4) "guangzhou"
  10. # 范围查找 经度110 纬度 30为圆心 半径100km内所有的城市 带上经纬度和城市距离该点的直线距离
  11. 127.0.0.1:6379[1]> GEORADIUS china:city 110 30 1000 km withcoord withdist
  12. 1) 1) "aomen"
  13. 2) "935.1758"
  14. 3) 1) "113.49999994039535522"
  15. 2) "22.19999914574732003"
  16. 2) 1) "xianggang"
  17. 2) "953.3433"
  18. 3) 1) "114.19999748468399048"
  19. 2) "22.29999896492555678"
  20. 3) 1) "shenzhen"
  21. 2) "928.8366"
  22. 3) 1) "114.09999936819076538"
  23. 2) "22.50000113800319212"
  24. 4) 1) "guangzhou"
  25. 2) "834.6077"
  26. 3) 1) "113.29999834299087524"
  27. 2) "23.10000005307264104"
  28. # count 控制个数
  29. 127.0.0.1:6379[1]> GEORADIUS china:city 110 30 1000 km withcoord withdist count 2
  30. 1) 1) "guangzhou"
  31. 2) "834.6077"
  32. 3) 1) "113.29999834299087524"
  33. 2) "23.10000005307264104"
  34. 2) 1) "shenzhen"
  35. 2) "928.8366"
  36. 3) 1) "114.09999936819076538"
  37. 2) "22.50000113800319212"
  38. # GEORADIUSBYMEMBER 根据给定的元素确定中心点,再进行查找
  39. 127.0.0.1:6379[1]> GEORADIUSBYMEMBER china:city shanghai 1000 km withdist
  40. 1) 1) "xiangshan"
  41. 2) "195.0791"
  42. 2) 1) "shanghai"
  43. 2) "0.0000"
  44. 127.0.0.1:6379[1]> GEORADIUSBYMEMBER china:city shanghai 2000 km withdist
  45. 1) 1) "aomen"
  46. 2) "1271.1657"
  47. 2) 1) "xianggang"
  48. 2) "1220.4023"
  49. 3) 1) "shenzhen"
  50. 2) "1207.9869"
  51. 4) 1) "guangzhou"
  52. 2) "1205.0747"
  53. 5) 1) "xiangshan"
  54. 2) "195.0791"
  55. 6) 1) "shanghai"
  56. 2) "0.0000"
  57. 7) 1) "beijing"
  58. 2) "1067.7424"
  59. # GEOHASH 将二维的经纬度转换为一维的字符串,经过hash之后的结果
  60. #
  61. # 如果两个字符串越像,则代表越接近!
  62. #
  63. 127.0.0.1:6379[1]> GEOHASH china:city beijing shanghai
  64. 1) "wx4fbxxfke0"
  65. 2) "wtw36xbc1j0"

HyperLogLog(基数统计)

Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

stream

1.Redis数据类型和结构及其运用 - 图22

消息队列相关命令:

  • XADD - 添加消息到末尾
  • XTRIM - 对流进行修剪,限制长度
  • XDEL - 删除消息
  • XLEN - 获取流包含的元素数量,即消息长度
  • XRANGE - 获取消息列表,会自动过滤已经删除的消息
  • XREVRANGE - 反向获取消息列表,ID 从大到小
  • XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

  • XGROUP CREATE - 创建消费者组
  • XREADGROUP GROUP - 读取消费者组中的消息
  • XACK - 将消息标记为”已处理”
  • XGROUP SETID - 为消费者组设置新的最后递送消息ID
  • XGROUP DELCONSUMER - 删除消费者
  • XGROUP DESTROY - 删除消费者组
  • XPENDING - 显示待处理消息的相关信息
  • XCLAIM - 转移消息的归属权
  • XINFO - 查看流和消费者组的相关信息;
  • XINFO GROUPS - 打印消费者组的信息;
  • XINFO STREAM - 打印流信息

    3.总结

    redis会优先选用内存占用少的数据结构在数据量扩大的时候再转换为时间复杂度少的数据结构。
    ziplist就是典型的时间换空间的结构 所以 zset hashtable在数据较少的时候都采用ziplist
    redisobject 不仅仅是解耦这一层 也做了 lru和fru等缓存删除策略