Redis各种数据类型讲解

  1. 字符串使用与内部实现

  1. 使用

  1. 添加键值对

语法:set key value 示例:set k1 val1

  1. 获取键值对

语法:get key 示例:get k1 ---->val1

  1. 给元素追加值

语法:append key value 示例:append k1 append

  1. 查询字符串的长度

语法:strlen key 实例:strlen k1

  1. 内部实现

针对不同长度的字符串申请相应的存储类型,从而有效的节约了内存使用。

通过object encoding key 命令可以看到SDS 对象包含了三种不同的数据类型:int、embstr 和 raw:int 类型很好理解,整数类型对应的就是 int 类型,而字符串则对应是 embstr 类型,当字符串长度大于 44 字节时,会变为 raw 类型存储。

如果 SDS 的存储值大于 64 字节时,Redis 的内存分配器会认为此对象为大字符串,并使用 raw 类型来存储,当数据小于 64 字节时(字符串类型),会使用 embstr 类型存储。

因为 Redis 在存储对象时,会创建此对象的关联信息,redisObject 对象头和 SDS 自身属性信息,这些信息都会占用一定的存储空间,因此长度判断标准就从 64 字节变成了 44 字节。

上图说明了在存储大数据量的k-v值的时候,选择string类型存储会浪费非常多的空间。所以我们可以选择list(压缩列表)、hash结构(超限之前也是压缩列表)

  1. 字典使用与内部实现(hash)

字典类型 (Hash) 又被成为散列类型或者是哈希表类型,它是将一个键值 (key) 和一个特殊的“哈希表”关联起来,这个“哈希表”表包含两列数据:字段和值。

字典类型本质上是由数组和链表结构组成的。Hash 类型设置了用压缩列表保存数据时的两个阈值,一旦超过了阈值,Hash 类型就会用哈希表来保存数据了。

hash-max-ziplist-entries:表示用压缩列表保存时哈希集合中的最大元素个数。

hash-max-ziplist-value:表示用压缩列表保存时哈希集合中单个元素的最大长度。

  1. 使用

  1. 插入单个元素

语法:hset key field value 示例:hset myhash key1 value1

  1. 当某键不存在时,插入数据

语法:hsetnx key field value 示例:hsetnx myhash k4 v4

如果尝试插入已存在的键,不会改变原来的值

  1. 查询单个元素

语法:hget key field 示例:hget myhash key1

  1. 删除key 中的一个或多个元素

语法:hdel myhash field [field ...] 示例:hdel myhash key1 key2

不能使用类似于hdel myhash 的命令删除整个 Hash 值的。

  1. 某个整数值累加计算

语法:hincrby key field increment 示例:hincrby myhash k3 2

  1. 插入一个或多个元素

语法:hmset key field value [field value ...] 示例:hmset myhash k1 val1 k2 val2

  1. 内部实现

字典类型的存储流程是先将键值进行 Hash 计算,得到存储键值对应的数组索引,再根据数组索引进行数据存储,但在小概率事件下可能会出完全不相同的键值进行 Hash 计算之后,得到相同的 Hash 值,这种情况我们称之为哈希冲突。

哈希冲突一般通过链表的形式解决,相同的哈希值会对应一个链表结构,每次有哈希冲突时,就把新的元素插入到链表的尾部。

查询流程:

通过算法(Hash,计算和取余等) 操作获得数组的索引值,根据索引值找到对应的元素;

判断元素和查找的键值是否相等,相等则成功返回数据,否则需要查看next 指针是否还有对应其他元素,如果没有,则返回 null,如果有的话,重复此步骤。

渐进式 rehash操作:

进行渐进式 rehash 时,会同时保留两个 hash 结构,新键值对加入时会直接插入到新的 hash 结构中,并会把旧 hash 结构中的元素一点一点的移动到新的 hash 结构中,当移除完最后一个元素时,清空旧 hash 结构,主要的执行流程如下:

1、扩容或者缩容时把字典中的字段 rehashidx 标识为 0;

2、在执行定时任务或者执行客户端的 hset、hdel 等操作指令时,判断是否需要触发 rehash 操作(通过 rehashidx 标识判断),如果需要触发 rehash 操作,也就是调用 dictRehash 函数,dictRehash 函数会把 ht[0] 中的元素依次添加到新的 Hash 表 ht[1] 中;

3、rehash 操作完成之后,清空 Hash 表 ht[0],然后对调 ht[1] 和 ht[0] 的值,把新的数据表 ht[1] 更改为 ht[0],然后把字典中的 rehashidx 标识为 -1,表示不需要执行 rehash 操作。

  1. 列表使用与内部实现(list)

  1. 使用

  1. 给列表添加一个或多个元素

语法:lpush key value [value …] 示例:lpush list 1 2 3

  1. 给列表尾部添加一个或多个元素

语法:rpush key value [value …] 示例:rpush list2 1 2 3

  1. 返回列表指定区间内的元素

语法:lrange key start stop 示例:lrange list 0 -1

其中-1 代表列表中的最后一个元素。

  1. 获取并删除列表的第一个元素

语法:lpop key 示例:lpop list

  1. 内部实现

debug encoding key列表类型的底层数据类型是 quicklist。

quicklist (快速列表) 是 Redis 3.2 引入的数据类型,早期的列表类型使用的是ziplist (压缩列表) 和双向链表组成的,Redis 3.2 改为用 quicklist 来存储列表元素。

quicklist 是一个双向链表,链表中的每个节点实际上是一个 ziplist

ziplist 作为 quicklist 的实际存储结构,它本质是一个字节数组

添加流程:

quicklistPushHead 函数的执行流程,先判断 quicklist 的 head 节点是否可以插入数据,如果可以插入则使用 ziplist 的接口进行插入,否则就新建 quicklistNode 节点进行插入。

函数的入参是待插入的 quicklist,还有需要插入的值 value 以及他的大小 sz。

函数的返回值为 int,0 表示没有新建 head,1 表示新建了 head。

quickli 内部默认定义的单个 ziplist 的大小为 8k 字节. 超过这个大小,就会重新分配一个 ziplist 了。这个长度可以由参数list-max-ziplist-size来控制。

1、如果头节点(或尾节点)上ziplist大小没有超过限制(即_quicklistNodeAllowInsert返回1),那么新数据被直接插入到ziplist中(调用ziplistPush)。

  1. 如果头节点(或尾节点)上ziplist太大了,那么新创建一个quicklistNode节点(对应地也会新创建一个ziplist),然后把这个新创建的节点插入到quicklist双向链表中。

删除流程:

quicklist 在区间删除时,会先找到 start 所在的 quicklistNode,计算删除的元素是否小于要删除的 count,如果不满足删除的个数,则会移动至下一个 quicklistNode 继续删除,依次循环直到删除完成为止。

  1. 集合使用与内部实现(set)

集合类型 (Set) 是一个无序并唯一的键值集合。

  1. 使用

  1. 添加一个或多个元素

语法:sadd key member [member ...] 示例:sadd myset v1 v2 v3

  1. 查询集合所有元素

语法:smembers key 示例:smembers myset

  1. 查询集合的成员数量

语法:scard key 示例:scard myset

  1. 查询集合中是否包含某个元素

语法:sismember key member 示例:sismember myset v1

  1. 从一个集合中移动一个元素到另一个集合

语法:smove source destination member 示例:smove myset myset2 v3

  1. 移除集合中一个或多个元素

语法:srem key member [member ...] 示例:srem myset v5

注意:使用srem 指令,不存在的元素将会被忽略。

  1. 移除并返回集合中的一个随机元素

语法:spop key [count] 示例:spop myset 1

  1. 随机返回集合中指定数量的元素列表

语法:srandmember key [count] 示例:srandmember myset 2

  1. 返回一个集合或多个集合的交集

语法:sinter key [key ...] 示例:sinter myset myset2

  1. 把集合的交集复制到新的集合中

语法:sinterstore destination key [key ...] 示例:sinterstore myset3 myset myset2

  1. 内部实现

集合类型是由intset (整数集合) 或 hashtable (普通哈希表) 组成的。

  1. 当元素为非整数时,集合会使用hashtable 进行存储。当集合类型以 hashtable 存储时,哈希表的 key 为要插入的元素值,而哈希表的 value 则为 Null。

  1. 当集合中所有的值都为整数时,Redis 会使用 intset 结构来存储。

  1. 集合类型使用hashtable 而非 intset 存储:

  1. 当元素的个数超过一定数量时,默认是512 个,该值可通过命令 set-max-intset-entries xxx 来配置。

  1. 当元素为非整数时,集合将会使用hashtable 来存储

  1. 有序集合使用与内部实现(zset)

有序集合是由 ziplist (压缩列表) 或 skiplist (跳跃表) 组成的。

  1. 使用

  1. 添加一个或多个元素

语法:zadd key [NX|XX] [CH] [INCR] score member [score member ...] 示例:zadd zset1 3 golang 4 sql 1 redis 有序集合的添加是 zadd 键值 分值1 元素值1 分值2 元素值2 的形式

  1. 查询所有元素列表

语法:zrange key start stop [WITHSCORES] 示例:zrange zset 0 -1

  1. 删除一个或多个元素(根据元素值)

语法:zrem key member [member ...] 示例:zrem zset1 redis sql

删除命令中如果包含了不存在的元素,并不会影响命令的正常执行,不存在的元素将会被忽略。

  1. 查询某元素的score 值

语法:zscore key member 示例:zscore zset1 redis

  1. 查询score 区间内元素

语法:zrangebyscore key min max [WITHSCORES] [LIMIT offset count] 示例:zrangebyscore zset1 3 10

  1. 查询某元素排名

语法:zrank key member 示例:zrank zset java

排名是从0 开始的,排名可以理解为元素排序后的下标值。

  1. 查询有序集合的总个数

语法:zcard key 示例:zcard zset1

  1. 查询score 区间内的元素个数

语法:zcount key min max 示例:zcount zset1 0 10

  1. 累加元素的score 值

语法:zincrby key increment member 示例:zincrby zset1 2 redis

  1. 查询某元素倒序排名

语法:zrevrank key member 示例:zrevrank zset1 python

  1. 根据排名删除元素

语法:zremrangebyrank key start stop 示例:zremrangebyrank zset1 0 2

  1. 内部实现

  1. 当数据比较少时,有序集合使用的是 ziplist 存储的

  1. Ziplist变成跳跃表

  1. 有序集合保存的元素个数要小于 128 个;

  1. 有序集合保存的所有元素成员的长度都必须小于 64 字节。

注意:可以通过配置文件中的zset-max-ziplist-entries(默认 128)和 zset-max-ziplist-value(默认 64)来设置有序集合使用 ziplist 存储的临界值。

跳跃表结构:

  1. Bitmap(二值状态统计)

比如我们记录客户每天签到情况(0:未签到,1:已签到),以为bitmap是以0开头的,如果我们记录1号的状态就是 0-1,2号为1-1,当我们进行统计的时候可以通过bitcount命令统计所有1的数量。

但是当我们统计1亿用户10天的连续签到情况呢?

这种我们就可以根据bitmap提供的三种“与”“或”“异或”方式去做统计,上面的问题我们可以通过按位与来操作,先将每天的签到情况转化成一个新的bitmap。

获取到一个新的bitmap,在通过bitcount命令进行统计就能获得连续签到的数量了。

  1. HyperLogLog

待拓展

  1. GEO(经纬度存储)

Geo通过编码格式将经纬度转化成一个长编码(二分区间,区间编码),例如120,30:经度120,将(-180,180]分为(-180,0)和(0,180),120在(0,180)区间,第一位取1,再将(0,180)分为(0,90]和[90,180),120在[90,180)区间,第二位取1,以此类推获得一个编码。长度根据设置的分区的次数,次数越多越精准。纬度(90,90)如上。获得的经度编码11001,纬度编码为01010,然后穿插拼接经纬度编码得到1011000101,经度第一位+纬度第一位+经度第二位+纬度第二位以此类推即可获得一个长编码。

例子:(116.37,39.86)

这样就将位置分成多个小方块,但是有一些特殊情况会导致两个小方块之间距离比较远,如图:

所以需要判断周边四个方块或者八个方块的位置。

  1. RedisTimeSeries 时间序列数据

用 TS.CREATE 命令创建时间序列数据集合;

用 TS.ADD 命令插入数据;

用 TS.GET 命令读取最新数据;

用 TS.MGET 命令按标签过滤查询数据集合;

用 TS.RANGE 支持聚合计算的范围查询。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Node-RED 中操作 Redis 数据需要使用 Redis 官方提供的 Node.js 客户端库,即 `redis` 库。可以通过在命令行中输入以下命令来安装该库: ``` npm install redis ``` 安装完成后,在 Node-RED 工具栏中点击右上角的菜单按钮,选择“Manage palette”打开“Palette Manager”窗口,搜索并安装“node-red-contrib-redis”节点模块。 安装完成后,可以在 Node-RED 编辑器的左侧节点栏中找到“redis”节点,该节点提供了一系列 Redis 操作的功能,包括连接 Redis 服务器、读取数据、写入数据、删除数据等。 以下是一个简单的示例,演示如何在 Node-RED 中操作 Redis 数据: 1. 首先需要连接 Redis 服务器,可以使用`redis`节点中的`redis-server`配置节点。将该节点拖放到工作区中,并配置连接信息,包括服务器地址、端口号和密码(如果有的话)。 2. 接下来,我们可以使用`redis`节点中的`redis in`节点来读取 Redis 数据。将该节点拖放到工作区中,并配置读取信息,包括键名和数据类型。 3. 然后,我们可以使用`function`节点来对读取到的数据进行处理。将该节点拖放到工作区中,并编写 JavaScript 代码,对读取到的 Redis 数据进行处理。 4. 最后,我们可以使用`redis`节点中的`redis out`节点来写入 Redis 数据。将该节点拖放到工作区中,并配置写入信息,包括键名、数据类型和数据值。 示例流程图如下: ![node-red-redis-example-flow](https://cdn.jsdelivr.net/gh/TheaJie/blog-images/images/2022/03/node-red-redis-example-flow.png) 其中,`redis-server`节点配置如下: ![node-red-redis-server-config](https://cdn.jsdelivr.net/gh/TheaJie/blog-images/images/2022/03/node-red-redis-server-config.png) `redis in`节点配置如下: ![node-red-redis-in-config](https://cdn.jsdelivr.net/gh/TheaJie/blog-images/images/2022/03/node-red-redis-in-config.png) `function`节点代码如下: ```javascript msg.payload = "Hello " + msg.payload; return msg; ``` `redis out`节点配置如下: ![node-red-redis-out-config](https://cdn.jsdelivr.net/gh/TheaJie/blog-images/images/2022/03/node-red-redis-out-config.png) 执行该示例后,可以在 Redis 中查看到写入的数据,如下所示: ![node-red-redis-data](https://cdn.jsdelivr.net/gh/TheaJie/blog-images/images/2022/03/node-red-redis-data.png) 以上就是在 Node-RED 中操作 Redis 数据的简单示例,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值