高性能分布式缓存Redis-高级应用篇章

一、发布订阅

Redis提供了发布订阅功能,可以用于消息的传输 

Redis的发布订阅机制包括三个部分,publisher,subscriber和Channel

发布者和订阅者都是Redis客户端,Channel则为Redis服务器端。

发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。

指令详情

  • SUBSCRIBE / PSUBSCRIBE : 订阅,精确、或者按匹配符
  • UNSUBSCRIBE / PUNSUBSCRIBE : 退订,精确、或者按匹配符
  • PUBLISH : 发送
  • PUBSUB :查看消息列表

发布订阅的命令演示

subscribe

        订阅  subscribe channel1 channel2 ..

Redis客户端1订阅频道1和频道2

127.0.0.1:6379> subscribe ch1  ch2 
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "ch1"
3) (integer) 1
1) "subscribe"
2) "ch2"
3) (integer) 2

publish

        发布消息 publish channel message

Redis客户端2将消息发布在频道1和频道2上

127.0.0.1:6379> publish ch1 hello
(integer) 1
127.0.0.1:6379> publish ch2 world
(integer) 1

 Redis客户端1接收到频道1和频道2的消息

1) "message"
2) "ch1"
3) "hello"
1) "message"
2) "ch2"
3) "world"

unsubscribe:退订 channel

Redis客户端1退订频道1

127.0.0.1:6379> unsubscribe ch1
1) "unsubscribe"
2) "ch1"
3) (integer) 0

psubscribe

        模式匹配 psubscribe +模式

Redis客户端1订阅所有以ch开头的频道

127.0.0.1:6379> psubscribe ch*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "ch*"
3) (integer) 1

 Redis客户端2发布信息在频道5上

127.0.0.1:6379> publish ch5 helloworld
(integer) 1

 Redis客户端1收到频道5的信息

1) "pmessage"
2) "ch*"
3) "ch5"
4) "helloworld"

 punsubscribe

        退订模式

127.0.0.1:6379>  punsubscribe ch*
1) "punsubscribe"
2) "ch*"
3) (integer) 0

使用场景

在Redis哨兵模式中,哨兵通过发布与订阅的方式与Redis主服务器和Redis从服务器进行通信

Redisson是一个分布式锁框架,在Redisson分布式锁释放的时候,是使用发布与订阅的方式通知的

注:重业务的消息,推荐用消息队列

二、事务

所谓事务,是指作为单个逻辑工作单元执行的一系列操作

事务内的操作要么都成功,要么都失败

ACID特性就是刚性事务的特性

  • Atomicity(原子性):构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不执行。
  • Consistency(一致性):数据库在事务执行前后状态都必须是稳定的或者是一致的。
  • Isolation(隔离性):事务之间不会相互影响。
  • Durability(持久性):事务执行成功后必须全部写入磁盘。

那在redis中的事务如何实现的呢?

Redis 事务的本质是一组命令的集合,就是一次执行多个命令

  • Redis的事务是通过multi、exec、discard和watch这四个命令来完成的。
  • Redis的单个命令都是原子性的,所以这里需要确保事务性的对象是命令集合。
  • Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行
  • Redis不能保障失败回滚

注意!redis的事务远远弱于mysql,严格意义上,它不能叫做事务,只是一个命令打包的批处理,不能一定保障失败回滚。

工作原理

  • 调用multi指令后,redis其实是开启了一个命令队列,后续的命令被提交到队列(还没有执行)
  • 期间出现问题了(比如down机),终止操作,队列清空
  • 到exec命令后,批量提交,事务完成
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set s1 1
QUEUED
127.0.0.1:6379(TX)> get s1
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "1"

redis如何做到事务回滚?

注意!回滚要看两种情况:

  • 直接语法错误,redis完全无法执行,Redis 2.6.5之前的版本不会回滚,之后版本整个事务回滚
  • 执行期的错误,redis不会回滚,其他正确的指令会照样执行

语法错误:

#旧value是a
127.0.0.1:9010> set a a
OK
127.0.0.1:9010> get a
"a"#开启事务
127.0.0.1:9010> multi
OK
#设置成b,语法没问题,进入队列
127.0.0.1:9010> set a b
QUEUED
#语法错误!
127.0.0.1:9010> set a
(error) ERR wrong number of arguments for 'set' command
#提交事务:失败,操作被回滚
127.0.0.1:9010> exec
(error) EXECABORT Transaction discarded because of previous errors.#最终结果:a没有被修改
127.0.0.1:9010> get a
"a"

执行错误:

#旧值a
127.0.0.1:9010> get a
"a"#开启事务
127.0.0.1:9010> multi
OK
#正确的语法,没毛病!
127.0.0.1:9010> set a b
QUEUED
#语法也对,但是类型肯定是不对的,这不是一个list!
#会进入队列,执行期才会发现这个问题
127.0.0.1:9010> lpush a 1
QUEUED
#提交事务!
#发现正确的1号命令执行ok,2号错误
127.0.0.1:9010> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value#最终结果,a被修改,事务没有回滚!
127.0.0.1:9010> get a
"b"

watch监听致使回滚:

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断

关于上面的操作,如果遇到各种错误,multi可以自动帮你回滚

而watch命令提供了另一种机制,它通过监控某个key的变动,来决定是不是回滚。

#开启两个终端 T1, T2
#T1执行过程与上面一致#以下是T1的操作过程:
#初始化,a=a , b=1
127.0.0.1:9010> set a a
OK
127.0.0.1:9010> set b 1
OK
#监控a的变动
127.0.0.1:9010> watch a
OK
#开启事务,内部对b进行操作
127.0.0.1:9010> multi
OK
127.0.0.1:9010> set b 2
QUEUED# !!!这一步注意切换到T2:
#在T1的watch和exec之间执行一个 set a 123,a的值被别的终端修改了!!!#再切回T1,注意!exec得不到ok,得到了一个nil,说明队列被清空了!
127.0.0.1:9010> exec
(nil)
#来查看b的值,没有被改为2,事务回滚了!
127.0.0.1:9010> get b
"1"

三、Lua脚本

redis中的事务操作相当于一个命令的批处理执行,但是又不能真正意义上保证原子性。那么有没有什么办法来解决呢?答案就是Lua脚本

lua其实是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

redis自2.6.0起可用,通过内置的lua编译/解释器,可以使用EVAL命令对lua脚本进行求值

redis嵌入了lua脚本,其好处:

  • 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。
  • 原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。
  • 复用。客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑。

如何使用 EVAL命令

EVAL script numkeys key [key ...] arg [arg ...]

命令说明:

script:参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数
numkeys: 用于指定键名参数的个数。
key [key ...],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
arg [arg ...],附加参数,在lua脚本中通过ARGV[1], ARGV[2]获取。

如:

eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

lua脚本中调用redis命令

  • redis.call():

    • 返回值就是redis命令执行的返回值
    • 如果出错,则返回错误信息,不继续执行
  • redis.pcall():

    • 返回值就是redis命令执行的返回值
    • 如果出错,则记录错误信息,继续执行
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 n1 zhaoyun

四、慢查询日志

客户端请求的生命周期的完整生命周期,4个阶段

注意:慢查询只统计步骤3的时间,所以没有慢查询并不代表客户端没有超时问题。换句话说。redis的慢查询记录时间指的是不包括像客户端响应、发送回复等IO操作,而单单是执行一个查询命令所耗费的时间。

面试题:日常在使用redis的时候为什么要用慢查询日志?

答:

  • 慢查询日志是为了记录执行时间超过给定时长的redis命令请求
  • 让使用者更好地监视和找出在业务中一些慢redis操作,找到更好的优化方法

慢查询会监控redis执行的命令中,一些超过提前设定的阈值的命令,将他存放到慢查询日志中,供我们查看

慢查询配置相关的参数

  • slowlog-log-slower-than:选项指定执行时间超过多少微秒(默认1秒=1,000,000微秒)的命令请求会被记录到日志上。

    例:如果这个选项的值为100,那么执行时间超过100微秒的命令就会被记录到慢查询日志; 如果这个选项的值为500 , 那么执行时间超过500微秒的命令就会被记录到慢查询日志;

  • slowlog-max-len:选项指定服务器最多保存多少条慢查询日志。服务器使用先进先出的方式保存多条慢查询日志: 当服务器储存的慢查询日志数量等于slowlog-max-len选项的值时,服务器在添加一条新的慢查询日志之前,会先将最旧的一条慢查询日志删除。

    例:如果服务器slowlog-max-len的值为100,并且假设服务器已经储存了100条慢查询日志, 那么如果服务器打算添加一条新日志的话,它就必须先删除目前保存的最旧的那条日志, 然后再添加新日志。

在Redis中有两种修改配置的方法,一种是修改配置文件,另一种是使用config set命令动态修改; 

慢查询配置相关的命令

  1. config set slowlog-log-slower-than 20000
  2. config set slowlog-max-len 1024
  3. showlog get # 查看慢查询日志

慢查询日志的访问和管理相关命令

  1. 获取[n条]慢查询队列 slowlog get [n]
  2. 获取慢查询队列的当前长度 slowlog len
  3. 清空慢查询队列 slowlog reset

比如:

# 设置慢查询时长: 
config set slowlog-log-slower-than 0 # 0表示将所有命令都记录为慢查询
# 设置最多保存多少条慢查询日志: 
config set slowlog-max-len 3
# 获得慢查询日志: 
slowlog get

慢查询相关知识总结

1、slowlog-max-len:线上建议调大慢查询列表,记录慢查询时Redis会对长命令做阶段操作,并不会占用大量内存.增大慢查询列表可以减缓慢查询被剔除的可能,例如线上可设置为1000以上.2、slowlog-log-slower-than:默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值.3、慢查询只记录命令的执行时间,并不包括命令排队和网络传输时间.因此客户端执行命令的时间会大于命令的实际执行时间.因为命令执行排队机制,慢查询会导致其他命令级联阻塞,因此客户端出现请求超时时,需要检查该时间点是否有对应的慢查询,从而分析是否为慢查询导致的命令级联阻塞.4、由于慢查询日志是一个先进先出的队列,也就是说如果慢查询比较多的情况下,可能会丢失部分慢查询命令,为了防止这种情况发生,可以定期执行slowlog get命令将慢查询日志持久化到其他存储中(例如:MySQL等),然后可以通过可视化工具进行查询.

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

使用Python Flask实战构建Web应用

Python Flask是一个轻量级的Web框架,它简单易用、灵活性高,适用于构建各种规模的Web应用。本文将介绍如何使用Python Flask框架来实战构建一个简单的Web应用,并展示其基本功能和特性。 第一部分:搭建开发环境 在开始之前我们需要…

dockerfile 和 docker compose

目录 1.dockerfile和docker compose区别 主要区别 目的: 格式: 使用场景: 2.Dockerfile 2.1基本格式 2.2模块解析 2.3例子 3.docker compose 3.1安装 3.2格式 3.3执行 1.dockerfile和docker compose区别 Dockerfile 和…

如何安全的使用助听器?

安全使用助听器是非常重要的,以下是一些关键的建议和注意事项,以确保您或您的家人能够正确且安全地使用助听器: 1. 遵循专业指导 •在初次佩戴前,请务必咨询专业的听力师或医生。他们会根据您的听力状况和个人需求来调整助听器的…

VMWare安装以后虚拟机NAT模式时网卡down问题

安装完成VMware后,安装linux虚拟机,网络模式为NAT模式,用来联网,但是发现虚拟机的网卡状态一直是down的。 service network restart 会报错 解决办法如下: ctlaltdelete打开任务管理->服务->打开服务->找到…

Springcloud高校选课管理系统-计算机毕业设计源码27115

摘 要 随着信息技术的快速发展和高校信息化建设的深入推进,选课管理系统作为高校教育信息化建设的重要组成部分,其重要性和紧迫性日益凸显。传统的选课管理系统往往采用单体架构,存在系统耦合度高、可维护性差、扩展性不强等问题,…

Java项目实战II基于Spring Boot高校教师科研管理系统设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着高等教育的快速发展和科研活动的日…

Markdown快速上手(typora)

一级标题~六级标题 可以选中文本在这里直接设置,后面也有快捷键,也可以使用其语法,一个#,对应一级标题,两个#,对应二级标题,等。 我这里使用Ctrl1没生效是因为快捷键冲突,也需要注意…

更快更强 | HP15加热台新品!Max温度350度,200度只需60秒!30~150W功率可调,恒温加热和回流焊双模式!

正点原子HP15加热台更快更强!最高温度可达350度,200度只需60秒!30~150W功率可调,恒温加热和回流焊双模式! HP15是正点原子全新推出的迷你恒温加热台,设备支持30~150W功率可调,在150W功率下从室温…

【点云网络】 pointnet 和 pointnet++

这两个网络都是斯坦福大学的一个团队提出的 我先先看一下pointnet的网络架构,这个网络比较经典,是2016年提出的: PointNet 是一个专门用于点云数据处理的神经网络。它的设计目的是直接操作不规则的点云数据,而无需将点云数据转换为规则网格或…

分布式——BASE理论

简单来说: BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理论逐步演化而来的,核心思想是即便不能达到强一致性(Strong consistency),也可以根据应用特点采用适当的方…

FPGA实战篇:Moore/Mealy状态机

什么是状态机? 状态机是根据当前输入信号和自身当前所处状态来改变输出逻辑的一种逻辑系统,目前它也被抽象应用于软件设计当中,本文从硬件设计角度来解释状态机,使用Verilog语言来抽象描述并实现状态机。 状态机类型 状态分为两…

influxdb与LSM-TREE

一、什么是LSM-TREE 在一些写多读少的场景,为了加快写磁盘的速度,提出使用日志文件追加顺序写,加快写的速度,减少随机读写。但是日志文件只能遍历查询。不支持随机查询,提出使用LSM-TREE。除了利用磁盘顺序写之外&…

Mac保护电池健康,延长电池使用寿命的好方法

使用Mac的过程中,如何延长电池的使用寿命是大家非常关心的问题,而养成一个良好的充电习惯能够有效的延长电池的使用寿命 避免过度充电和过度放电能够有效的保护电池,因此长时间的充电与长时间放点都不可取,但是在日常的使用过程中…

AutosarMCAL开发——基于EB ResourceM模块

目录 一、ResourceM模块的作用以及原理1.ResourceM模块的作用2.单核系统运行原理a.上电复位b.启动代码执行c.应用程序加载d.应用程序执行 3.代码执行过程4.内存分配a.地址空间划分b.具体地址分配c.示例说明 4.多核系统运行原理a.MCU架构 二、EB配置介绍三、总结 一、ResourceM模…

【LeetCode】返回链表的中间结点、删除链表的倒数第 N 个结点

主页:HABUO🍁主页:HABUO 🌜钱塘江上潮信来,今日方知我是我🌛 1.返回链表的中间结点 题目:给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点&#xff0…

Netty篇(学习前言)

目录 一、为什么使用Netty 1. Netty编程相比NIO编程的优势 2. Netty 相比其它网络应用框架的优势 二、让我们走进Netty 1. 简介 2. 设计目标 3. 主要特点 4. Netty的作者 5. Netty 的地位 6. Netty 的优势 五、Netty版本说明 六、Netty架构设计 1. 线程模型基本介绍…

Ceph 学习指南 集群部署【 cephadm 】

文章目录 引言初识 Server SANServer SAN 和传统存储对比 Ceph 概述Ceph 的架构设计Ceph 的特点Ceph 块存储Ceph 文件系统Ceph 对象存储Ceph 介绍 Ceph 集群部署配置 aliyun 源配置时间同步配置 hosts 文件安装 docker配置免密登录ceph 集群部署ceph1 配置安装 python3安装 cep…

Linux篇(常见入门命令)

目录 一、开启终端 二、Linux命令格式 1. 什么是Linux 的命令? 三、Linux下的命令补全 四、切换用户 五、uname:查看操作系统信息 六、ls:查看目录下文件 1. 用法一 2. 用法二 3. 用法三 七、pwd:显示当前路径 八、cd&…

全面解析:网络协议及其应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 # 全面解析:网络协议及其应用 文章目录 网络协议概述定义发展历程主要优势 主要网络协议应用层协议传输层协议网络层…

02- 模块化编程-006 ADC0808数码显示对比

1、ADC0808 芯片介绍 ADC0808是一款集成的CMOS设备,包含8位模拟至数字转换器、8通道多路复用器和与微处理器兼容的控制逻辑。8位A/D转换器采用逐次逼近作为转换技术。转换器特点包括高阻抗斩波稳定比较器、256R电压分压器、模拟开关树和逐次逼近寄存器。8通道多路复…