Redis数据类型应用场景(redis的数据类型,以及每种数据类型的使用场景)
mhr18 2024-10-30 02:38 15 浏览 0 评论
Redis数据类型应用场景
在Redis中常用类型为五个String、List、Hash、Set、Sorted Set,扩展类型为三个GEO、BitMaps、HyperLogLog,那我们对这些类型的特性是否了解呢,什么业务场景下选择什么样的数据类型呢,下面借助多种常见业务场景聊聊数据类型的选择。
聚合计算
聚合计算就是指多个集合间的聚合结果如
- 交集:统计多个集合间的相同元素。
- 并集:统计多个集合间的所有元素,相同元素只显示一个。
- 差集:两个集合对比,统计一个集合对于另外一个集合独有的元素。
有聚合计算功能为Set、Sorted Set两个,但需要注意的是Sorted Set集合没有差集计算功能。
Set聚合运算命令如下
127.0.0.1:6379> SADD test1 1 2 3 4 5 6 7
(integer) 7
127.0.0.1:6379> SADD test2 3 5 2 9 10
(integer) 5
## 并集计算 如果想将结果存入单独的集合中可以使用SUNIONSTORE
## SUNION时间复杂度O(N) SUNIONSTORE时间复杂度O(N)
127.0.0.1:6379> SUNION test1 test2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "9"
9) "10"
## 差集计算 如果想将结果存入单独的集合中可以使用SDIFFSTORE
## SDIFF时间复杂度O(N) SDIFFSTORE时间复杂度O(N)
127.0.0.1:6379> SDIFF test1 test2
1) "1"
2) "4"
3) "6"
4) "7"
## 交集计算 如果想将结果存入单独的集合中可以使用SINTERSTORE
## SINTER 时间复杂度O(N*M) N 为给定集合当中基数最小的集合, M 为给定集合的个数
## SINTERSTORE 时间复杂度O(N*M)
127.0.0.1:6379> SINTER test1 test2
1) "2"
2) "3"
3) "5"
Sorted Set聚合命令如下
127.0.0.1:6379> ZADD test1 100 a 99 b 89 c 97 d 101 e
(integer) 5
127.0.0.1:6379> zadd test2 110 a 100 b 90 k 99 f
(integer) 4
######################################计算合集##########################
## numkeys指参与计算key的数量,AGGREGATE统计方式默认是SUM WEIGHTS指给每个集合元素的score乘上weight(乘法因子)
## ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
## 时间复杂度O(N)+O(Mlog(M)), N为给定有序集基数的总和, M为结果集的基数。
127.0.0.1:6379> ZUNIONSTORE test3 5 test1 test2 weights 1 1
(integer) 7
127.0.0.1:6379> ZRANGE test3 0 -1 withscores
1) "c"
2) "89"
3) "k"
4) "90"
5) "d"
6) "97"
7) "f"
8) "99"
9) "e"
10) "101"
11) "b"
12) "199"
13) "a"
14) "210"
######################################计算并集##########################
## ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
## 时间复杂度O(N*K)+O(Mlog(M)), N为给定key中基数最小的有序集, K为给定有序集的数量, M为结果集的基数。
127.0.0.1:6379> ZINTERSTORE test3 2 test1 test2 weights 1 1 aggregate max
(integer) 2
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> ZRANGE test3 0 -1
1) "b"
2) "a"
127.0.0.1:6379> ZRANGE test3 0 -1 withscores
1) "b"
2) "100"
3) "a"
4) "110"
不论是Set还是Sorted Set在聚合运算时的时间复杂度都是较高的,对于大数据的运算就会阻塞主线程。
如果Redis采用的是主从模式建议采用从库计算,但从库计算一定需要注意的是从库不允许写只允许读所以对于SUNIONSTORE、SDIFFSTORE、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE这类需要写入目标集合的命令显然是不可行的,需要根据业务进行取舍。
如果采用的是Cluster集群模式,去执行聚合统计那么可能发生错误,因为聚合包含的key可能不在同一个实例中导致报错,演示如下。
在Cluster集群中存在主节点7002、7003、7004详细信息如下所示。
### 在集群7004中新增set集合key为test
127.0.0.1:7004> SADD test 1 2 3 4 5 6 7 8 0 10 5 15 12 13
(integer) 13
### 在集群7003中新增set集合key为test1
127.0.0.1:7003> SADD test1 11 4515 12 13
(integer) 4
### 在集群7003中执行聚合命令,报错!!!!!!!
127.0.0.1:7003> SUNION test1 test
(error) CROSSSLOT Keys in request don't hash to the same slot
所以建议把这些统计数据与在线业务数据拆分开,实例单独部署,防止在做统计操作时影响到在线业务。
排序统计
对于排序有很多业务场景如小说热榜、排行榜等,在Redis中具排序功能的是Sorted Set和List,需要注意的是List没有排序命令而是根据写入顺序排序,而Sorted Set则可以通过权重进行排序。
List命令演示如下,如果元素是按顺序入队那么统计没有问题,但如果是中间插入数据需要人为判断过于复杂,在排序统计中不建议使用。
127.0.0.1:6379> lpush test 1 2 3 4 5 6 7
(integer) 7
127.0.0.1:6379> LRANGE test 0 -1
1) "7"
2) "6"
3) "5"
4) "4"
5) "3"
6) "2"
7) "1"
127.0.0.1:6379> rpush test 0
(integer) 8
127.0.0.1:6379> LRANGE test 0 -1
1) "7"
2) "6"
3) "5"
4) "4"
5) "3"
6) "2"
7) "1"
8) "0"
127.0.0.1:6379> lpush test -1
(integer) 9
127.0.0.1:6379>
127.0.0.1:6379> LRANGE test 0 -1
1) "-1"
2) "7"
3) "6"
4) "5"
5) "4"
6) "3"
7) "2"
8) "1"
9) "0"
Sorted Set命令演示如下,Sorted Set无论以怎样的方式插入集合都会根据权重进行排序,非常适用于各种排序统计逻辑。
127.0.0.1:6379> ZADD test 100 a 80 b 99 c 109 d 40 f 77 h
(integer) 6
127.0.0.1:6379> ZRANGEBYSCORE test -inf +inf withscores
1) "f"
2) "40"
3) "h"
4) "77"
5) "b"
6) "80"
7) "c"
8) "99"
9) "a"
10) "100"
11) "d"
12) "109"
127.0.0.1:6379> ZADD test 78 q
(integer) 1
127.0.0.1:6379>
### ZRANGE和ZRANGEBYSCORE的不同点在于ZRANGE是根据下标范围查询列表
### ZRANGEBYSCORE根据scores范围查询列表
127.0.0.1:6379> ZRANGE test 0 -1
1) "f"
2) "h"
3) "q"
4) "b"
5) "c"
6) "a"
7) "d"
127.0.0.1:6379> ZRANGE test 0 -1 withscores
1) "f"
2) "40"
3) "h"
4) "77"
5) "q"
6) "78"
7) "b"
8) "80"
9) "c"
10) "99"
11) "a"
12) "100"
13) "d"
14) "109"
二值状态统计
二值指的是值只有两种状态,最典型的例子就是签到统计,统计是否签到只需要两种状态是和否,只要涉及到两种状态的都可以采用如下的形式。
二值统计可以使用Bitmap来做统计,Bitmap其底层就是String,String类型会被保存为一个字符数组buf[],而Bitmap就是利用这一特性将数组的每一个bit位利用起来,用来表示一个元素的二值状态,所以可以将Bitmap理解为是一个字符数组构成的。
如需要统计用户id为10001的4月打卡情况可以如下模拟
### 因为Bitmap的offset从0开始,所以在统计的时候从0开始计算
127.0.0.1:6379> SETBIT sign:user:10001:202204 0 1
(integer) 0
127.0.0.1:6379> SETBIT sign:user:10001:202204 1 1
(integer) 0
127.0.0.1:6379> SETBIT sign:user:1000:2022041 2 1
(integer) 0
127.0.0.1:6379> SETBIT sign:user:10001:202204 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign:user:10001:202204 5 1
(integer) 0
### 统计bit位为1的个数,统计已签到次数
127.0.0.1:6379> BITCOUNT sign:user:10001:202204
(integer) 5
如果需要统计4月有多少个用户连续签到,这个可以利用Bitmap的按位运算的特性计算,将key按照时间划分进行统计,采用BITOP做按位运算
BITOP operation destkey key [key ...]
operation 支持四种参数
BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN ,对一个或多个 key 求逻辑并(同为1才为1、只要有0就为0),并将结果保存到 destkey 。
BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN,对一个或多个 key 求逻辑或(同为0才为0、只要有1就为1),并将结果保存到 destkey 。
BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN,对一个或多个 key 求逻辑异或(相异为1、相同为0),并将结果保存到 destkey 。
BITOP NOT destkey srckey,对给定 key 求逻辑非,并将结果保存到 destkey 。
### 采用日期作为key,每个bit位就是一个用户,这样计算占用内存小同时效率高
127.0.0.1:6379> SETBIT 20220401 0 1
(integer) 0
127.0.0.1:6379> SETBIT 20220401 1 1
(integer) 0
127.0.0.1:6379> SETBIT 20220401 2 1
(integer) 0
127.0.0.1:6379> SETBIT 20220401 3 1
(integer) 0
127.0.0.1:6379> SETBIT 20220401 4 0
(integer) 0
127.0.0.1:6379> SETBIT 20220402 0 0
(integer) 1
127.0.0.1:6379> SETBIT 20220402 1 1
(integer) 0
127.0.0.1:6379> SETBIT 20220402 2 1
(integer) 0
127.0.0.1:6379> SETBIT 20220402 3 0
(integer) 0
127.0.0.1:6379> SETBIT 20220402 4 1
### 按位运算,每天都签到那么对应每天的日期key上相同bit为应都为1
127.0.0.1:6379> BITOP and test 20220402 20220401
(integer) 1
127.0.0.1:6379> BITCOUNT test 0 -1
(integer) 2
127.0.0.1:6379>
基数统计
首先需要了解的是什么为基数,基数就是不会重复的数字,对于基数统计就是统计元素中不会重复的元素,常见于网站的PV(网页点击量一个用户一天内点击多次也只算一次)、UV(独立访客数,一个用户一天内进入多次也只计算一次)统计,这个统计其实方案有很多,如Set、HyperLogLog,甚至可以使用Hash。
Set方案
Set集合本来就是可以去重的,所以在计算时只要将用户id设置到集合中即可
### 用户1001 20220401 访问page1页面
127.0.0.1:6379> SADD web:page1:20220401 1001
(integer) 1
### 用户1002 20220401 访问page1页面
127.0.0.1:6379> SADD web:page1:20220401 1002
(integer) 1
### 用户1001 20220401 访问page1页面
127.0.0.1:6379> SADD web:page1:20220401 1001
(integer) 0
### 统计pv数
127.0.0.1:6379> SCARD web:page1:20220401
(integer) 2
127.0.0.1:6379>
127.0.0.1:6379> SMEMBERS web:page1:20220401
1) "1001"
2) "1002"
### 用户1001 20220401 进入系统
127.0.0.1:6379> SADD web:user:20220401 1001
(integer) 1
### 用户1002 20220401 进入系统
127.0.0.1:6379> SADD web:user:20220401 1002
(integer) 1
### 用户1001 20220401 进入系统
127.0.0.1:6379> SADD web:user:20220401 1001
(integer) 0
### 统计uv数
127.0.0.1:6379> SCARD web:user:20220401
(integer) 2
Hash方案
Hash方案和Set方案类型,Hash方案是利用了Hash中的属性不能重复的特性来处理。
### 用户1001 20220401 访问page1页面
127.0.0.1:6379> HSET web:page1:20220401 1001 1
(integer) 1
### 用户1002 20220401 访问page1页面
127.0.0.1:6379> HSET web:page1:20220401 1002 1
(integer) 1
### 用户1001 20220401 访问page1页面
127.0.0.1:6379> HSET web:page1:20220401 1001 1
(integer) 0
### 统计pv数
127.0.0.1:6379> HLEN web:page1:20220401
(integer) 2
### uv类似
HyperLogLog方案
无论是hash方案还是set方案如果用户数据量逐渐增加,集合的内存消耗也将大幅度提升会出现bigkey的情况,再来看看HyperLogLog,redis官网这样描述:
A HyperLogLog is a probabilistic data structure used in order to count unique things (technically this is referred to estimating the cardinality of a set). Usually counting unique items requires using an amount of memory proportional to the number of items you want to count, because you need to remember the elements you have already seen in the past in order to avoid counting them multiple times. However there is a set of algorithms that trade memory for precision: you end with an estimated measure with a standard error, in the case of the Redis implementation, which is less than 1%. The magic of this algorithm is that you no longer need to use an amount of memory proportional to the number of items counted, and instead can use a constant amount of memory! 12k bytes in the worst case, or a lot less if your HyperLogLog (We’ll just call them HLL from now) has seen very few elements.
译:
HyperLogLog是一种概率数据结构,用于计算唯一的东西(从技术上讲,这指的是估计集合的基数)。通常计算唯一的条目需要使用与要计算的条目数量成比例的内存,因为您需要记住过去已经看到的元素,以避免多次计算它们。然而有一套算法可以用精度换内存,在Redis实现的情况下,你会得到一个标准误差的估计值,误差小于1%。这个算法的神奇之处在于,您不再需要使用与所计数的项目数量成比例的内存,而是可以使用恒定的内存数量!最坏情况下是12k字节,HyperLogLog(从现在开始我们就称它们为HLL)只看到的元素则会少很多。
HyperLogLog代码演示如下
127.0.0.1:6379> info memory
# Memory 初始内存容量
used_memory:927936
# Memory 第一次添加内存容量
127.0.0.1:6379> PFADD web:pv:20220424 1001 1002 1003 1004 1005 1006 1007
(integer) 1
127.0.0.1:6379> info memory
used_memory:928080
# Memory 第二次添加内存容量
127.0.0.1:6379> PFADD web:pv:20220424 10101 10102 10103 10104 10105 10106 10017
(integer) 1
127.0.0.1:6379> info memory
used_memory:928128
# Memory 第二次添加内存容量
127.0.0.1:6379> PFADD web:pv:20220424 1041201 1042102 1012403 1012404 1012405 1012406 1002317
(integer) 1
127.0.0.1:6379> info memory
used_memory:928224
# Memory 第二次添加内存容量
127.0.0.1:6379> PFADD web:pv:20220424 10415201 10425102 10152403 10512404 10125405 10124506 10052317
(integer) 1
127.0.0.1:6379> info memory
used_memory:928224
################后续持续加入基数,内存容量保持928224不变基数查询正常#############
### 基数查询
127.0.0.1:6379> PFCOUNT web:pv:20220424
(integer) 49
HyperLogLog就是概率性的结构,采取精度换空间的形式,内存消耗是固定的不会随着基数的增加内存增大,所以在业务要求数据精度不高的情况下如统计网站pv、uv这类业务完全可以使用HyperLogLog解决,但如果业务要求精度过高则还是采用Set或者Hash数据类型较为稳妥。
总结
Redis效率高的一个重要原因就是支持丰富的数据结构,正确的选择数据结构对于业务是非常重要的,将数据类型和常见业务对比总体如下。
相关推荐
- Docker安装详细步骤及相关环境安装配置
-
最近自己在虚拟机上搭建一个docker,将项目运行在虚拟机中。需要提前准备的工具,FinallShell(远程链接工具),VM(虚拟机-配置网络)、CentOS7(Linux操作系统-在虚拟机上安装)...
- Linux下安装常用软件都有哪些?做了一个汇总列表,你看还缺啥?
-
1.安装列表MySQL5.7.11Java1.8ApacheMaven3.6+tomcat8.5gitRedisNginxpythondocker2.安装mysql1.拷贝mysql安装文件到...
- Nginx安装和使用指南详细讲解(nginx1.20安装)
-
Nginx安装和使用指南安装1.检查并安装所需的依赖软件1).gcc:nginx编译依赖gcc环境安装命令:yuminstallgcc-c++2).pcre:(PerlCompatibleRe...
- docker之安装部署Harbor(docker安装hacs)
-
在现代软件开发和部署环境中,Harbor作为一个企业级的容器镜像仓库,提供了高效、安全的镜像管理解决方案。通过Docker部署Harbor,可以轻松构建私有镜像仓库,满足企业对镜像存储、管理和安全性...
- 成功安装 Magento2.4.3最新版教程「技术干货」
-
外贸独立站设计公司xingbell.com经过多次的反复实验,最新版的magento2.4.3在oneinstack的环境下的详细安装教程如下:一.vps系统:LinuxCentOS7.7.19...
- 【Linux】——从0到1的学习,让你熟练掌握,带你玩转Linu
-
学习Linux并掌握Java环境配置及SpringBoot项目部署是一个系统化的过程,以下是从零开始的详细指南,帮助你逐步掌握这些技能。一、Linux基础入门1.安装Linux系统选择发行版:推荐...
- cent6.5安装gitlab-ce最新版本-11.8.2并配置邮件服务
-
cent6.5安装gitlab-ce最新版本-11.8.2并配置邮件服务(yum选择的,时间不同,版本不同)如果对运维课程感兴趣,可以在b站上搜索我的账号:运维实战课程,可以关注我,学习更多免费的运...
- 时隔三月,参加2020秋招散招,终拿字节跳动后端开发意向书.
-
3个月前头条正式批笔试4道编程题只AC了2道,然后被刷了做了200多道还是太菜了,本来对字节不抱太大希望,毕竟后台竞争太大,而且字节招客户端开发比较多。后来看到有散招免笔试,抱着试一试的心态投了,然而...
- Redisson:Java程序员手中的“魔法锁”
-
Redisson:Java程序员手中的“魔法锁”在这个万物互联的时代,分布式系统已经成为主流。然而,随着系统的扩展,共享资源的争夺成为了一个棘手的问题。就比如你想在淘宝“秒杀”一款商品,却发现抢的人太...
- 【线上故障复盘】RPC 线程池被打满,1024个线程居然不够用?
-
1.故障背景昨天晚上,我刚到家里打开公司群,就看见群里有人讨论:线上环境出现大量RPC请求报错,异常原因:被线程池拒绝。虽然异常量很大,但是异常服务非核心服务,属于系统旁路,服务于数据核对任务,即使...
- 小红书取消大小周,有人不高兴了!
-
小红书宣布五一节假日之后,取消大小周,恢复为正常的双休,乍一看工作时长变少,按道理来说大家应该都会很开心,毕竟上班时间缩短了,但是还是有一些小红书的朋友高兴不起来,心情很复杂。因为没有了大小周,以前...
- 延迟任务的多种实现方案(延迟机制)
-
场景订单超时自动取消:延迟任务典型的使用场景是订单超时自动取消。功能精确的时间控制:延时任务的时间控制要尽量准确。可靠性:延时任务的处理要是可靠的,确保所有任务最终都能被执行。这通常要求延时任务的方案...
- 百度java面试真题(java面试题下载)
-
1、SpingBoot也有定时任务?是什么注解?在SpringBoot中使用定时任务主要有两种不同的方式,一个就是使用Spring中的@Scheduled注解,另一个则是使用第三方框架Q...
- 回归基础:访问 Kubernetes Pod(concurrent.futures访问数据库)
-
Kubernetes是一头巨大的野兽。在它开始有用之前,您需要了解许多概念。在这里,学习几种访问集群外pod的方法。Kubernetes是一头巨大的野兽。在它开始有用之前,您需要了解许多不同的...
- Spring 缓存神器 @Cacheable:3 分钟学会优化高频数据访问
-
在互联网应用中,高频数据查询(如商品详情、用户信息)往往成为性能瓶颈。每次请求都触发数据库查询,不仅增加服务器压力,还会导致响应延迟。Spring框架提供的@Cacheable注解,就像给方法加了一...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Docker安装详细步骤及相关环境安装配置
- Linux下安装常用软件都有哪些?做了一个汇总列表,你看还缺啥?
- Nginx安装和使用指南详细讲解(nginx1.20安装)
- docker之安装部署Harbor(docker安装hacs)
- 成功安装 Magento2.4.3最新版教程「技术干货」
- 【Linux】——从0到1的学习,让你熟练掌握,带你玩转Linu
- cent6.5安装gitlab-ce最新版本-11.8.2并配置邮件服务
- 时隔三月,参加2020秋招散招,终拿字节跳动后端开发意向书.
- Redisson:Java程序员手中的“魔法锁”
- 【线上故障复盘】RPC 线程池被打满,1024个线程居然不够用?
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)