Redis入门指南学习笔记(3):Redis高级特性

一.前言

上一篇博客对Redis常用的数据结构进行了详细介绍。Redis除了丰富的数据类型支持,还包含许多高级特性,例如事务、内存驻留策略、排序、消息队列等,本文将对这些进行逐一介绍。

二.事务

Redis同样包含事务(transaction)的概念,事务是一组命令的集合,事务中的命令要不全部都执行,要不都不执行。

下面展示的便是Redis事务用法。

> MULTI # 事务的开始, 告知Redis下面的命令属于同一个事务, 先不要执行, 而是暂存起来。
"OK"> DEL cpp
"QUEUED" # 表示命令已经放入等待执行的事务队列中> DEL program
"QUEUED"> EXEC # 告知Redis将事务队列中的命令按顺序执行
1) "1"
2) "1"

Redis事务还可以保证一个事务内的命令依次执行而不被其他命令插入。

2.1 错误处理

事务中的命令可能会出错,错误原因主要包含语法错误运行错误两种,针对两种错误类型,Redis采用了不同的应对策略。

语法错误

语法错误主要指命令不存在或者命令参数不对。下面便展示了一个语法错误的例子,事务中总共添加了两条命令,其中第二条语法出错,执行EXEC后可以看到Redis会直接返回错误,事务中语法正确的命令也不会执行

> MULTI
"OK"> SET money 11
"QUEUED"> GET money 11
"ERR wrong number of arguments for 'get' command"> EXEC
"EXECABORT Transaction discarded because of previous errors."

运行错误

运行错误指在符合语法但执行过程中出现的错误,该类错误是由程序员造成的。对于该种类型,事务里的错误命令不会导致其他命令无法执行

下面展示的是一个运行错误的例子,事务的第二天命令错误的对非整数形式的字符串类型应用了自增命令INCR,在执行EXEC后可以看到,第一条命令成功执行,第二条命令返回错误信息。

> MULTI
"OK"> GET JAPAN
"QUEUED"> INCR JAPAN
"QUEUED"> EXEC
1) "Tokyo"
2) "ReplyError: ERR value is not an integer or out of range"

Redis没有提供回滚(rollback)功能,开发者需要为自己写的命令负责。

2.2 WATCH命令

WATCH命令可以用来监控一个或多个键,一旦其中有一个键被修改或删除,之后的事务就不会执行,监控一直持续到EXEC命令。

执行EXEC命令后会取消对所有键的监控,若不想执行事务中的命令,也可以使用UNWATCH命令来取消监控

下面例子中,WATCH命令监控键count之后对其进行了自增操作,之后又进入了一个事务,从结果可以看出,事务并没有执行。

> SET count 1
"OK"> WATCH count
"OK"> INCR count
(integer) 2> MULTI
"OK"> INCR count
"QUEUED"> EXEC
(nil)> GET count
"2"

三.过期时间

Redis可以使用EXPIRE命令设置一个键的过期时间,到期后Redis会自动删除它,该命令具体的形式为:

# seconds表示键过期的时间,单位是秒
EXPIRE key seconds

使用示例如下,这里设置了一个折扣discount的过期时间为10秒,其中TTL命令是用来查看一个键还有多久被删除的,-2表示键已经不存在,对永久存在的键应用TTL命令返回的是-1

> SET discount 8.5
"OK"> EXPIRE discount 10
(integer) 1> TTL discount
(integer) -2> EXISTS discount
(integer) 0

若想清除键的过期时间设置,可以使用PERSIST命令,若清除成功返回1,否则返回0。

> SET discount 8
"OK"> EXPIRE discount 20
(integer) 1> TTL discount
(integer) 17> PERSIST discount
(integer) 1> TTL discount
(integer) -1

使用SETGETSET命令为键赋值同样也会清除键的过期时间。

> GET discount
"8"> EXPIRE discount 20
(integer) 1> TTL discount
(integer) 17> SET discount 7
"OK"> TTL discount
(integer) -1

四.排序

在Redis中倘若需要数据有序有多种方法,下面将对其进行逐一介绍。

4.1 有序集合

Redis提供了有序集合类型ZSET,其用法形式如下:

# score和member一一对应, score是排序的依据
ZADD key score member [score member ...]  

使用示例为:

> ZADD rank 90 xm 88 xh 95 xz 86 xl
(integer) 4> ZRANGE rank 0 -1
1) "xl"
2) "xh"
3) "xm"
4) "xz"

可以看到默认为升序排序。

4.2 SORT命令

SORT命令可以对列表类型、集合类型和有序集合类型键进行排序。

SORT命令的时间复杂度为 O ( n + m log ( m ) ) O(n + m \text{log}(m)) O(n+mlog(m)),其中n表示待排序的列表/集合中的元素个数,m表示要返回元素的个数。

SORT的使用示例如下:

> LPUSH scores 87 77 90 68 100
(integer) 5> SORT scores
1) "68"
2) "77"
3) "87"
4) "90"
5) "100"> SORT scores DESC
1) "100"
2) "90"
3) "87"
4) "77"
5) "68"

SORT命令还可以通过ALPHA参数实现按字典序排列非数字元素。

> LPUSH namelist tom james shelly sala andy
(integer) 5> LRANGE namelist 0 -1
1) "andy"
2) "sala"
3) "shelly"
4) "james"
5) "tom"> SORT namelist ALPHA
1) "andy"
2) "james"
3) "sala"
4) "shelly"
5) "tom"

SORT与SQL一样也支持使用LIMIT offset count来指定跳过前offset个元素并获取之后的count个元素。

> SORT scores DESC LIMIT 0 3
1) "100"
2) "90"
3) "87"

使用STORE描述符可以将排序的结果存储的指定的键上

> SORT scores DESC STORE sorted_scores
(integer) 5> LRANGE sorted_scores 0 -1
1) "100"
2) "90"
3) "87"
4) "77"
5) "68"

SORT还可以通过BY参数来指定排序的模式,其语法形式为BY 参考键,参考键可以是字符串类型键或哈希类型键的某个字段(键名->字段名)。

> LPUSH students student:1 student:2 student:3 student:4
(integer) 4> HMSET student:1 age 18 name Tom
"OK"> HMSET student:2 age 17 name Shelly
"OK"> HMSET student:3 age 20 name Andy
"OK"> HMSET student:4 age 18 name Jack
"OK"# 按年龄排序
> SORT students BY *->age
1) "student:2"
2) "student:1"
3) "student:4"
4) "student:3"# 按名字排序
> SORT students BY *->name ALPHA
1) "student:3"
2) "student:4"
3) "student:2"
4) "student:1"

SROT还包含GET参数,该参数不影响排序,它的作用是使SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值。

# 根据年龄排序,并返回学生名字
> SORT students BY *->age GET *->name
1) "Shelly"
2) "Tom"
3) "Jack"
4) "Andy"

五.消息通知

通知可以借助任务队列实现,任务队列就是传递任务的队列,与任务队列交互的实体有生产者(将需要处理的任务放入任务队列)和消费者(不从任务队列中读取任务消息并执行)。

使用任务队列有如下好处:

  • 松耦合:生产者和消费者无须知道彼此的实现细节,只需要约定好任务的描述格式。
  • 易于扩展:可以有多个消费者,且可以分布在不同的服务器上,从而减轻单台服务器的负载。

5.1 基于列表的队列

可以列表可以实现队列,即让生产者在一边使用LPUSH命令将任务加入到列表中,然后让消费者在另一边使用RPOP不断从里列表中取出任务执行。但采用RPOP有一点不完美之处,当任务队列中没有任务时,需要不断调用RPOP去检查,而使用BRPOP命令则不会有这个问题,当列表中没有元素时,BRPOP命令会不断阻塞,直到有新元素加入

BRPOP命令接受两个参数,第一个是键名,第二个是超时时间,单位为秒,当到达设定的超时时间还没有新元素时,则返回nil。该命令会返回两个值,分别是键名和元素值

> LPUSH message m1 m2 m3
(integer) 3> BRPOP message 1
1) "message"
2) "m1"

BRPOP可以同时接收多个键,其语法形式为BRPOP key [key ...] timeout,若所有键都没有元素则阻塞,否则会按顺序弹出第一个非空列表中的元素。

> LPUSH message1 m1 m2 m3
(integer) 3> LPUSH message2 m4
(integer) 1> BRPOP message1 message2 1
1) "message1"
2) "m1"> BRPOP message1 message2 1
1) "message1"
2) "m2"> BRPOP message1 message2 1
1) "message1"
2) "m3"> BRPOP message1 message2 1
1) "message2"
2) "m4"> BRPOP message1 message2 1
(nil)

5.2 发布订阅模式

Redis还提供了一组命令可以实现发布订阅模式,该模式中包含两种角色,发布者和订阅者,订阅者可以订阅一个或多个频道(channel),发布者可以想指定频道发送消息,只有订阅该频道的订阅者才能收到相关的消息。

发布者发布消息的命令为PUBLISH channel message,其返回值为接收到这条消息的订阅者的数量。订阅频道的命令为SUBSCRIBE channel [channel ...],从语法可以看出可以订阅多个频道。

# 客户端1
# 订阅频道, 等待和接收消息
> SUBSCRIBE mchannel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mchannel"
3) (integer) 1
1) "message"
2) "mchannel"
3) "hello world"# 客户端2
# 往频道发布消息
> PUBLISH mchannel "hello world"
(integer) 1

从上面可以看到,客户端可以收到3种类型的回复,每种类型的回复都包含3个值,第一个是消息的类型,第二、三个视消息类型而不同。

消息类型包括:

  • subscribe:表示订阅成功的反馈信息。第二个值为订阅的频道名,第三个值为当前客户端订阅的频道数量。
  • message:表示接收到的消息,第二个值为产生消息的频道名,第三个值为消息的内容。
  • unscribe:表示成功取消订阅某个频道,第二个为要取消的频道名,第三个是当前客户端订阅的频道数量。

通过UNSUBSCRIBE channel [channel ...]可以取消订阅的频道。

5.3 强大的流

Redis 5.0引入了全新的流类型,流类型除了能高效存储日志结构的数据,还可以作为消息中间件。作为消息中间件时,其与上述介绍的列表、发布/订阅模式的对比如下表所示:

列表-发布订阅模式对比

由上图可见,流同时具备列表和发布/订阅模式的所有优点

流的基本用法

流类型具备日志的特征,一是仅在末尾追加,二是每一条记录都包含了多个结构化的信息

流在插入新条目时会为其自动生成一个在流中唯一的ID,这个ID可以用来进行查询操作。

往流中增加条目的命令为:

XADD key [MAXLEN [=|~] threshold] *|ID field value [field value ...]

其中:

  • [MAXLEN [=|~] threshold]用来指定流最多保持指定数量的条目,~表示近似裁剪,即非精确地保持thresold条,而是可以稍微多一点,这样可以提升性能。
  • *|ID用来指定条目的ID,其中*的含义是让Redis按规则自动生成,也可以由用户主动指定ID。
  • field value [field value ...]表示若干字段及其对应的字段值。

添加条目的示例如下:

> XADD logs MAXLEN ~ 20 * IP 172.146.5.3 status 200
"1699929848274-0"> XADD logs MAXLEN ~ 20 * IP 172.146.5.6 status 304
"1699930100371-0"

由上示例可知ID的格式为<millisecondsTime>-<sequenceNumber>,其中前半部分为Redis服务器的时间戳,后半部分为序列号。

流的查询可以使用如下命令,其中startend表示条目的ID,查询时ID中的序列号部分可以省略,通过这种方式,可以查询指定范围内的条目列表。COUNT可以用来限制返回结果的条数。

XRANGE key start end [COUNT count]

此外,xRANGE还支持两个特殊的ID,即-+,分别表示最小ID和最大ID,通过这两个特殊ID可以获取流中所有的条目

> XRANGE logs - +
1) 1) "1699929848274-0"2) 1) "IP"2) "172.146.5.3"3) "status"4) "200"
2) 1) "1699930100371-0"2) 1) "IP"2) "172.146.5.6"3) "status"4) "304"

流对消息中间件的支持

流提供了高效查询消息历史的命令,并可以自定义从哪个ID开始读。具体通过XREAD命令实现。

XREAD命令可以从流中读取数据,其语法形式为:

XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]

其中count表示读取的条目数,BLOCK表示阻塞多久,单位是毫秒,STREAMS参数后是要读取键名,以及从哪个ID开始读。

命令示例为:

> XREAD COUNT 1 STREAMS logs 1699929848274-0
1) 1) "logs"2) 1) 1) "1699930100371-0"2) 1) "IP"2) "172.146.5.6"3) "status"4) "304"

由上可知,XREAD返回数据是一个列表,最外层列表中每个元素对应XREAD命令请求的键名,接下来每个结果中包含条目ID和条目中所有的键值对。

5.4 流与消费组

消费组中包含若干消费者,消费组在对外接收消息时可以视为一个整体,当消费组接收一条消息时,会将该消息分发给组内的其中一个消费者,即同一条消息不会发给组内的多个消费者。例如下图中包含5个消费者,其中有2个消费者处于同一个消费组中,故它们各自只收到了一条消息,而其他的消费者能收到所有的消息。

消费者与消费者组

创建消费者组的命令为:

XGROUP [CREATE key groupname] ID|$ [MKSTREAM]

其中MKSTREAM参数用来说明若指定的流不存在,则会创建一个流,若不指明该参数的话,流不存在会返回一个错误。符号$用来说明当前消费组的ID,其表示最后一个条目,也可以指定具体的ID。

消费组的创建示例为:

> XGROUP CREATE mystream mygroup $ MKSTREAM
OK

消费者组消费消息的命令为XREADGROUP,该命令与XREAD的定义类似,具体语法为:

XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]

往流mystream中添加消息,两个属于同一个消费组mygroup的消费者消费流中消息的示例为:

# 往消费组添加消息
> XADD mystream * message A
"1700632675587-0"
> XADD mystream * message B
"1700632678571-0"# 客户端
> XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >
1) 1) "mystream"2) 1) 1) "1700632675587-0"2) 1) "message"2) "A"# 客户端2
> XREADGROUP GROUP mygroup consumer2 COUNT 1 STREAMS mystream >
1) 1) "mystream"2) 1) 1) "1700632678571-0"2) 1) "message"2) "B"

上述命令中末尾的>表示还没有分发的消息ID,消费组读取要提供ID是为了进行消息确认。消费者组内消费者读取每个条目并正确处理后,都必须通过XACK命令告诉消费者组处理成功,否则该条目会被加入该消费者的等待队列,直接到接收到XACK命令,或用XCLAIM命令将这条消息转移给组内的其他消费者重新处理。

XACK命令语法形式为:

XACK key group ID [ID ...]

其中key表示流,group表示消费者组,ID表示消费消息的ID。

消费者2确认处理成功的示例如下:

> XACK mystream mygroup 1700632678571-0
(integer) 1

消费者组内维护了每个消费者的等待队列,可以通过XPENDING命令查看:

XPENDING key group

使用示例为:

> XACK mystream mygroup 1700632678571-0
(integer) 1
> XPENDING mystream mygroup
1) (integer) 1
2) "1700632675587-0"
3) "1700632675587-0"
4) 1) 1) "consumer1"2) "1"

上述返回结果中第一行表示,mygroup消费者组内所有消费者的等待队列中包含的条目数,接下来两行表示条目的最大和最小ID,紧接着是有等待条目的消费者名称和相应队列的条目数量。

六.结语

参考资料:

  • 《Redis入门指南》 李子骅编著

以上便是文本的全部内容,若有任何错误敬请批评指正,要是觉得不错可以点赞或关注一下,后续会持续更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/206612.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【刷题笔记】H指数||数组||二分查找的变体

H指数 最新编辑于2023.11.29 之前的代码写得有点抽象&#xff0c;实在抱歉&#xff0c;好像我自己都不理解当时自己怎么写的&#xff0c;现在重新更新了代码&#xff0c;保证好理解。 1 题目描述 https://leetcode.cn/problems/h-index/ 给你一个整数数组 citations &#xf…

Python基础学习之包与模块详解

文章目录 前言什么是 Python 的包与模块包的身份证如何创建包创建包的小练习 包的导入 - import模块的导入 - from…import导入子包及子包函数的调用导入主包及主包的函数调用导入的包与子包模块之间过长如何优化 强大的第三方包什么是第三方包如何安装第三方包 总结关于Python…

【人工智能Ⅰ】实验3:蚁群算法

实验3 蚁群算法的应用 一、实验内容 TSP 问题的蚁群算法实现。 二、实验目的 1. 熟悉和掌握蚁群算法的基本概念和思想&#xff1b; 2. 理解和掌握蚁群算法的参数选取&#xff0c;解决实际应用问题。 三、实验原理 1&#xff0e;算法来源 蚁群算法的基本原理来源于自然界…

网络基础_1

目录 网络基础 协议 协议分层 OSI七层模型 网络传输的基本流程 数据包的封装和分用 IP地址和MAC地址 网络基础 网络就是不同的计算机之间可以进行通信&#xff0c;前面我们学了同一台计算机之间通信&#xff0c;其中有进程间通信&#xff0c;前面学过的有管道&#xff…

在Linux上安装KVM虚拟机

一、搭建KVM环境 KVM&#xff08;Kernel-based Virtual Machine&#xff09;是一个基于内核的系统虚拟化模块&#xff0c;从Linux内核版本2.6.20开始&#xff0c;各大Linux发行版就已经将其集成于发行版中。KVM与Xen等虚拟化相比&#xff0c;需要硬件支持的完全虚拟化。KVM由内…

百度人工智能培训第二天笔记

参加了百度人工智能初步培训&#xff0c;主要是了解一下现在人工智能的基本情况&#xff0c;以便后续看可以参与一些啥&#xff1f; 下面就继续前一天的内容记录。 一、先做电动自行车的电梯里检测 先进行图片资料的上传与标注&#xff0c;这个昨天的最好也说了一下。 训练完后…

手摸手Element-ui组件化开发

前端环境准备 编码工具: VSCode 依赖管理:NPM 项目构建: Vuecli NPM的全称是Node Package Manager&#xff0c;是一个NodeJS包管理和分发工具&#xff0c;已经成为了非官方的发布Node模块&#xff08;包&#xff09;的标准。2020年3月17日&#xff0c;Github宣布收购npm&am…

WebGL/threeJS面试题扫描与总结

什么是 WebGL&#xff1f;什么是 Three.js&#xff1f;请解释three.js中的WebGL和Canvas的区别&#xff1f; WebGL(全写Web Graphics Library)是一种3D绘图协议&#xff0c;这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起&#xff0c;通过增加OpenGL ES 2.0的一个…

龙芯loongarch64服务器编译安装pyarrow

1、简介 pyarrow是一个高效的Python库,用于在Python应用程序和Apache Arrow之间进行交互。Arrow是一种跨语言的内存格式,可以快速高效地转移大型数据集合。它提供了一种通用的数据格式,将数据在内存中表示为表格,并支持诸如序列化和分布式读取等功能。 龙芯的Python仓库安…

【教程】 一文部署配置并入门 Redis

综述 什么是Redis Redis官网——Redis.io Redis, 作为一个高性能的键值对数据库&#xff0c;主要应用于以下场景&#xff1a; 缓存系统&#xff1a;由于其高速读写能力&#xff0c;Redis 非常适合用作缓存系统&#xff0c;减少数据库负载。 会话存储&#xff08;Session St…

构建未来:云计算 生成式 AI 诞生科技新局面

目录 引言生成式 AI&#xff1a;开发者新伙伴云计算与生成式 AI 的无缝融合亚马逊云与生成式 AI 结合的展望/总结我用亚马逊云科技生成式 AI 产品打造了什么&#xff0c;解决了什么问题未来科技发展趋势&#xff1a;开发者的机遇与挑战结合实践看未来结语开源项目 引言 2023年…

基于SpringBoot母婴商城

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本母婴商城系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

04.里氏替换原则(Liskov Substitution Principle)

暴论&#xff1a;一般的&#xff0c;如果一个富二代不想着证明自己&#xff0c;那么他一辈子都会衣食无忧。 一言 里氏替换原则想告诉我们在继承过程中会遇到什么问题&#xff0c;以及继承有哪些注意事项。 概述 这是流传较广的一个段子&#xff1a; “一个坐拥万贯家财的富二…

DBS note6:Hashing(哈希存储)

目录 一、一般策略 二、算法简述 三、哈希缺点&#xff08;Drawbacks of Hashing&#xff09; 四、举例 五、外部哈希的分析 一、一般策略 由于我们无法一次性将所有数据放入内存中&#xff0c;我们需要构建多个不同的哈希表并将它们连接在一起。然而&#xff0c;这个想法…

第20 章 多线程

20.1线程简介. 20.2创建线程 2.1继承Thread类 Thread 类是java.lang包中的一个类&#xff0c;从这个类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立Thread 实例。Thread类中常用的两个构造方法如下: public Thread():创建一个新的线程对象。 public Threa…

如何提高3D建模技能?

无论是制作影视动画还是视频游戏&#xff0c;提高3D建模技能对于你的工作都至关重要的。那么如何能创建出精美的3D模型呢&#xff1f;本文给大家一些3D建模技能方面的建议。 3D建模通过专门的软件完成&#xff0c;涉及制作三维对象。这项技能在视频游戏开发、建筑、动画和产品…

18、串口通信

串口介绍 串口是一种应用十分广泛的通讯接口&#xff0c;串口成本低、容易使用、通信线路简单&#xff0c;可实现两个设备的互相通信。 单片机的串口可以使单片机与单片机&#xff0c;单片机与电脑、单片机与各式各样的模块互相通信&#xff0c;极大的扩展了单片机的应用范围&…

大模型能否生成搜索引擎的未来?

文&#xff5c;郝 鑫 编&#xff5c;刘雨琦 ChatGPT火爆之前&#xff0c;水面下&#xff0c;也有中国公司也在朝着智能助手的方向努力。夸克便是其中之一。在GPT风靡科技圈后&#xff0c;国内就开始陆续冒出一些大模型厂商。对当时夸克而言&#xff0c;做大模型毋庸置疑&am…

Python list列表添加元素的3种方法及删除元素的3种方法

Python list列表添加元素的3种方法 Python list 列表增加元素可调用列表的 append() 方法&#xff0c;该方法会把传入的参数追加到列表的最后面。 append() 方法既可接收单个值&#xff0c;也可接收元组、列表等&#xff0c;但该方法只是把元组、列表当成单个元素&#xff0c;这…

“逆风飞翔·事实孤儿同行计划”成长陪伴主题区域陪伴培训会

为推进各机构更好地开展事实孤儿成长陪伴工作&#xff0c;促进事实孤儿成长陪伴实施成效&#xff0c;搭建各机构间事实孤儿成长陪伴方式方法交流平台。11月26日&#xff0c;在中国乡村发展基金会、中国民生银行的支持下&#xff0c;由湖南省大爱无疆青少年公益发展中心主办&…