Redis数据类型应用场景

作者: ML李嘉图

目录

  • [一些小问题]
  • [String]
  • [Hash]
  • [List]
  • [Set]
  • [ZSet]
  • [BitMaps]
  • [Hyperloglog]
  • [Geo]
  • [Streams]
  • [应用场景小结]

一些小问题

Redis一共有几种数据类型? (注意是数据类型不是数据结构)

一共是八种,String、Hash、Set、List、Zset、Hyperloglog、Geo、Streams。

为什么要把数据放在内存中?

内存的速度更快,10W QPS

减少计算的时间,减轻数据库压力

如果是用内存的数据结构作为缓存,为什么不用HashMap或者Memcached?

更丰富的数据类型

支持多种编程语言

功能丰富:持久化机制、内存淘汰策略、事务、发布订阅、pipeline、LUA

支持集群、分布式

Memcached和redis的区别是什么?

Memcached只能存储KV、没有持久化机制、不支持主从复制、是多线程的。

Redis Key的最大长度限制是512M,值的限制不同,有的是用长度限制的,有的是用个数限制的。

关于其他有趣的 Reids 的内容可以移步这儿:https://www.cnblogs.com/zwtblog/tag/Redis/

String

get和set命令就是String的操作命令,Redis的字符串被叫做二进制安全的字符串(Binary-safe strings)。 String可以存储三种类型,INT(整数)、float(单精度浮点数)、string(字符串)

操作命令

 存值(如果对同一个key set多次会直接覆盖旧值)
set jack 2673
 取值
get jack
 查看所有键
keys *
 获取键总数(生产环境数据量大,慎用)
dbsize
 查看键是否存在
exists jack
 删除键
del jack tonny
 重命名键
rename jack tonny
 查看类型
type jack 
 获取指定范围的字符
getrange jack 0 1
 获取值长度
strlen jack
 字符串追加内容
append jack good
 设置多个值(批量操作,原子性)
mset jack 2673 tonny 2674
 获取多个值
mget jack tonny
 设置值,如果key存在,则不成功
setnx jack shuaige
 基于此实现分布式锁
set key value [expiration EX seconds|PX milliseconds][NX|XX]
 (整数)值递增(值不存在会得到1)
incr jack
incrby jack 100
 (整数)值递减
decr jack
decrby jack 100
 浮点数增量
set mf 2.6
incrbyfloat mf 7.3

应用场景 1、缓存 String类型,这是最常用的,可以缓存一些热点数据,比如首页新闻,可以显著提升热点数据的访问速度,同时减轻DB压力。 2、分布式数据共享 String 类型,因为Redis是分布式的独立服务,可以在多个应用之间共享。

例如:分布式Session

<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
</dependency>

3、分布式锁

详情见博客:https://www.cnblogs.com/zwtblog/p/15185894.html 4、全局ID INT类型,INCRBY,利用原子性

incrby userid 1000(分表分库的场景,一次性拿一段) 

5、计数器 INT类型,INCR方法

例如:文章的阅读量,微博点赞数,允许一定的延迟,先写入Redis再定时同步到数据库 6、限流 INT类型,INCR方法

以访问者的IP和其他信息作为key,访问一次增加一次计数,超过次数则返回false。

Hash

这样也便于集中管理,划分的粒度不同,可以按照实际场景,key 的过期时间,灵活度考虑选取哪一种存储方式。 Hash用来存储多个无序的键值对,最大存储数量2^32-1(40亿左右)。 优点:

  1. 把所有相关的值聚集到一个Key中,节省内存空间

  2. 只使用一个Key,减少Key冲突

  3. 当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU的消耗 缺点:

  4. Field不能单独设置过期时间

  5. 需要考虑数据量分布的问题(field非常多的时候,无法分布到多个节点) 操作命令

    设置、批量设置值
    hset h1 f 6
    hset h1 e 5
    hmset h1 a 1 b 2 c 3 d 4
    取值
    hget h1 a
    批量取值
    hmget h1 a b c d
    获取所有field
    hkeys h1
    获取所有field的值
    hvals h1
    返回哈希表中,所有的字段和值
    hgetall h1
    删除field
    hdel h1 a
    获取哈希表中字段的数量
    hlen h1
    
    

    应用场景 String可以做的事情,Hash都可以做。

    再补充一个场景,购物车

List

存储有序的字符串(从左到右),元素可以重复,最大存储数量2^32-1(40亿左右)。 操作命令

 左推
lpush queue a
lpush queue b c
 右推
rpush queue d e
 左边移除并返回列表的第一个元素
lpop queue
 右边移除并返回列表的第一个元素
rpop queue
 通过索引获取列表中的元素
lindex queue 0
 返回列表中指定区间内的元素
lrange queue 0 -1

应用场景 1、列表

例如用户的消息列表、网站的公告列表、活动列表、博客的文章列表、评论列表等,通过 LRANGE 取出一页,按顺序显示。 2、队列/栈 List还可以当做分布式环境的 队列 / 栈 使用。

队列:先进先出,rpush 和 blpop

栈:先进后出,rpush 和 brpop

这里介绍两个阻塞的弹出操作:blpop/brpop,可以设置超时时间(单位:秒)

blpop:blpop key1 timeout,

移出并获取列表的第一个元素, 

如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
brpop:brpop key1 timeout,

移出并获取列表的最后一个元素,

如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

Set

Set 存储 String 类型的无序集合,最大存储数量 2^32-1(40亿左右)。 操作命令

 添加一个或多个元素
sadd myset a b c d e f g
 获取所有元素
smembers myset
 统计元素个数
scard myset
 随机获取一个元素
srandmember myset
 随机弹出一个元素
spop myset
 移除一个或者多个元素
srem myset d e f
 查看元素是否存在
sismember myset a
 获取差集
sdiff set1 set2
 获取交集
sinter set1 set2
 获取并集
sunion set1 set2

应用场景 1、抽奖

随机获取元素:spop myset 2、点赞、签到、打卡

们以微博举例子,假设这条微博的ID是t1001,用户ID是u6001,


用  dianzan:t1001  来维护  t1001  这条微博的所有点赞用户。


点赞了这条微博:sadd dianzan:t1001 u6001

取消点赞:srem dianzan:t1001 u6001

是否点赞:sismember dianzan:t1001 u6001

点赞的所有用户:smembers dianzan:t1001

点赞数:scard dianzan:t1001


比关系型数据库简单了许多。

3、商品标签

用 tags : i8001 来维护商品所有的标签。

sadd tags:i8001 画面清晰细腻
sadd tags:i8001 真彩清晰显示屏
sadd tags:i8001 流畅至极

4、商品筛选

华为P50上线了,支持民族品牌,加到各个标签中去。

sadd brand:huawei p50
sadd os:android p50
sadd screensize:6.0-6.24 p50

买的时候筛选,牌子是华为,操作系统是安卓,屏幕大小在6.0-6.24之间的,取交集:

sinter brand:huawei os:android screensize:6.0-6.24

ZSet

sorted set 存储有序的元素。每个元素都有个 score,按照 score 从小到大排序。 score 相同时,按照 key 的ASCII码排序。 操作命令

 添加元素
zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python
 获取全部元素
zrange myset 0 -1 withscores
zrevrange myzset 0 -1 withscores
 根据分数区间获取元素
zrangebyscore myzset 20 30
 移除元素(也可以根据score rank删除)
zrem myzset php cpp
 统计元素个数
zcard myzset
 分值增加
zincrby myzset 5 python
 根据分值minmax统计个数
zcount myzset 20 60
 获取python排名
zrank myzset python
 获取元素分数
zscore myzset python

应用场景 1、排行榜

今天是2021年5月23号,建一个 key 为 hotSearch:20210523 的 zset。

这条新闻的id是n1234,每点击一下:zincrby hotSearch:20210523 1 n1234

获取热搜排行榜前十条:zrevrange hotSearch:20210523 0 10 withscores

BitMaps

BitMaps是在字符串类型上定义的位操作,一个字节由8个二进制位组成。 操作命令

 设置字符串key为k1,value为mic
set k1 mic
 取k1的第七位,结果是0
getbit k1 6
 取k1的第八位为0,此时的ASCII码是108,对应字母是l
setbit k1 7 0
 所以取出来值为lic
get k1
 统计二进制中1的个数,一共是12个
bitcount k1
 获取第一个1或者0的位置
bitpos k1 1
bitpos k1 1

BITOP AND destkey key [key ...],对一个或多个key求逻辑并,并将结果保存到 destkey。
BITOP OR destkey key [key ...],对一个或多个key求逻辑或,并将结果保存到 destkey。
BITOP XOR destkey key [key ...],对一个或多个key求逻辑异或,并将结果保存到 destkey。
BITOP NOT destkey key,对给定key求逻辑非,并将结果保存到 destkey。

应用场景 1、连续在线用户

setbit firstday 0 1 //设置第一天uid是0的用户登录
setbit firstday 1 0 //设置第一天uid是1的用户未登录
setbit firstday 2 1 //设置第一天uid是2的用户登录
...
setbit secondday 0 0 //设置第二天uid是0的用户未登录
setbit secondday 1 1 //设置第二天uid是1的用户登录
setbit secondday 2 1 //设置第二天uid是2的用户登录
... //以此类推

那么在算连续七天在线用户就是:
BITOP AND 7_both_online_users firstday secondday thirdday fourthday fifthday sixthday seventhday

2、应用访问统计 3、在线用户统计

Hyperloglog

Hyperloglog 提供了一种不太精确的基数统计方法,用来统计一个集合中不重复的元素个数,

在 Redis 中实现的 Hyperloglog,只需要12k内存就能统计2^64个数据。

    public static void main(String[] args) {
        Jedis jedis = new Jedis("39.103.144.86", 6379);
        float size = 100000;
        for (int i = 0; i < size; i++) {
            jedis.pfadd("hll", "hll-" + i);
        }
        long total = jedis.pfcount("hll");
        System.out.println(String.format("统计个数: %s", total));
        System.out.println(String.format("正确率: %s", (total / size)));
        System.out.println(String.format("误差率: %s", 1 - (total / size)));
        jedis.close();
    }

操作命令

PFADD key element [element ...]

添加指定元素到 HyperLogLog 中。
PFCOUNT key [key ...]

返回给定 HyperLogLog 的基数估算值。
PFMERGE destkey sourcekey [sourcekey ...]

将多个 HyperLogLog 合并为一个 HyperLogLog

应用场景 1、统计网站的UV,或者应用的日活、月活,存在一定的误差。

Geo

操作命令

 存经纬度
geoadd location 121.445 31.213 shanghai
 取经纬度
geopos location shanghai

应用场景 1、增加地址位置信息、获取地址位置信息 2、计算两个位置的距离 3、获取指定范围内的地理位置集合

    public static void main(String[] args) {
        Jedis jedis = new Jedis("39.103.144.86", 6379);
        Map<String, GeoCoordinate> geoMap = new HashMap<>();
        GeoCoordinate coordinate = new GeoCoordinate(121.445, 31.213);
        geoMap.put("shanghai", coordinate);
        jedis.geoadd("positions", geoMap);
        System.out.println(jedis.geopos("positions", "shanghai"));
        jedis.close();
    }

Streams

Redis Stream 是 Redis 5.0 版本新增加的数据结构。 Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。 Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

每个 Stream 都有唯一的名称,它就是 Redis 的 key,在们首次使用 xadd 指令追加消息时自动创建。

上图解析:

  • Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
  • last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
  • pending_ids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。 操作命令

消息队列相关命令: 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 - 打印流信息

应用场景

应用场景小结

缓存======提升热点数据的访问速度

共享数据======数据的存储和共享的问题

全局ID======分布式全局ID的生成方案(分库分表)

分布式锁======进程间共享数据的原子操作保证

在线用户统计和计数

队列、栈======跨进程的队列/栈

消息队列======异步解耦的消息机制

服务注册与发现======RPC通信机制的服务协调中心(Dubbo支持Redis)

购物车

新浪用户消息时间线

抽奖逻辑(礼物、转发)

点赞、签到、打卡

商品标签

用户(商品)关注(推荐)模型

电商产品筛选

排行榜

原文创作:ML李嘉图

原文链接:https://www.cnblogs.com/zwtblog/p/15186262.html

文章列表

更多推荐

更多
  • Pharo敏捷人工智能-第一部分:神经网络
    Apache CN

  • Pharo敏捷人工智能-第二部分:遗传算法
    Apache CN

  • Pharo敏捷人工智能-# 第三部分:神经进化 第三部分:神经进化
    Apache CN

  • Azure数据工程指南-二十四、数据治理的权限 创建 azure 预览帐户,探索 azure 预览,探索词汇表,浏览资产,以编程方式使用预览,摘要,管理凭证和访问,创建扫描, 许多组织需要建立数据治理流程、标准和方法,并且已经能够使用内部 SQL Server 工具(如 Master
    Apache CN

  • Azure数据工程指南-二十二、Synapse 分析工作区 创建 Synapse 分析工作区,使用 Spark 探索样本数据,用 SQL 查询数据,用 SQL 创建外部表,摘要, 微软 Azure 数据平台的众多新增功能已经围绕许多类似的产品及其在现代 Azure 数据平台中的用途产生了兴奋和困
    Apache CN

  • Azure数据工程指南-二十三、数据块中的机器学习 创建 MLflow 实验,安装 MLflow 库,创建笔记本,选择性测井,自动记录,摘要, 寻求利用机器学习(ML)和人工智能能力的组织和开发人员花费大量时间构建 ML 模型,并寻求一种方法来简化他们的机器学习开发生命周期,以跟踪实验,
    Apache CN

  • Azure数据工程指南-二十一、将 Apache Spark 的 GraphFrame API 用于图形分析 安装 JAR 库,加载新数据表,将数据加载到数据块笔记本中,用顶点和边构建一个图,查询图表,寻找有图案的图案,用 PageRank 发现重要性,探索入度和出度度量,摘要,进行广度优先搜索,查找连接的组件, 图形技术使用户能够以图形的形式
    Apache CN

  • Azure数据工程指南-20 二十、部署 SQL 数据库先决条件,创建 Visual Studio SQL 数据库项目,安装 Visual Studio GitHub 扩展,导入 AdventureWorks 数据库,连接到 GitHub Repo 源代码控制,将
    Apache CN

  • Azure数据工程指南-十九、部署数据工厂更改 先决条件,创建 DevOps 持续集成构建管道,创建 DevOps 持续部署发布渠道,验证部署的数据工厂资源,摘要,Azure PowerShell 任务停止触发器,ARM 模板部署任务,Azure PowerShell 任务启动触发器
    Apache CN

  • Azure数据工程指南-十八、用于 Cosmos DB 的 Azure Synapse 链接 创建一个 Azure Cosmos DB 帐户,启用 Azure Synapse 链接,创建一个 Cosmos DB 容器和数据库,将数据导入 Azure Cosmos DB,在 Azure Synapse Analytics 中创建
    Apache CN

  • 近期文章

    更多
    文章目录

      推荐作者

      更多