Redis学习笔记:慢查询,Pipeline,事务,乐观锁

news2024/11/17 19:35:06

本文是自己的学习笔记。主要参考资料如下:
马士兵

  • 1、Redis的慢查询
    • 1.1、慢查询的相关参数
      • 1.1.1、设置阈值
      • 1.1.2、慢查询日志存储长度
        • 1.1.2.1、慢查询日志解析
    • 1.2、生产环境下慢查询的配置
  • 2、Pipeline
    • 2.1、简单的pipeline代码示例
    • 2.2、使用Pipeline的注意事项
  • 3、事务
    • 3.1、redis事务开启的三个阶段
    • 3.2、redis事务的特性
  • 4、Redis实现乐观锁
    • 4.1、watch关键字(乐观锁)
  • 5、LUA脚本
    • 5.1、redis中使用LUA简单示例
    • 5.2、Redis + LUA实现限流


1、Redis的慢查询

Redis是基于TCP的,所以当redis查询速度过慢时,原因可能出在下面四步中,即网络时间,命令排队,执行时间。

redis对慢查询的分析是集中在下图的第3步
请添加图片描述
慢查询是指redis查询速度过慢时,我们可以根据redis的内部工具定位原因。

redis中如果开启了慢查询,它的默认时间是10ms,即如果查询超过这个时间,相关的预警会启动。

1.1、慢查询的相关参数

1.1.1、设置阈值

我们总共有两种方式设置redis慢查询的阈值,一是在配置文件中,二是使用命令。

  • 配置文件:
slowlog-log-slower-than 10000
  • 命令
config set slowlog-log-slower-than 10000
# Don't execute below unless you want change this configuration permanently
config rewrite

1.1.2、慢查询日志存储长度

当慢查询发生时,redis会记录相关的日志到内存中,数据结构是队列,如果队列满了又有新的慢查询,那旧的慢查询记录就会被pop消失。

redis默认可以存储128条慢查询,我们也是可以通过配置文件和命令修改队列长度。

  • 配置文件:
slowlog-max-len 128
  • 命令
config set slowlog-max-len 128
# Don't execute below unless you want change this configuration permanently
config rewrite

我们可以手动清空慢查询日志队列。slowlog reset。执行后,慢查询只会记录slowlog reset这一条指令。


1.1.2.1、慢查询日志解析

下面会具体分析慢查询日志中有什么信息。为了方便测试,先将slowlog-log-slower-than设为0,让每条语句都能被慢查询日志记录。

slowlog get num,获取最新的num条慢查询记录,下面是例子。

127.0.0.1:6379> slowlog get 1
1) 1) (integer) 2
   2) (integer) 1674827308
   3) (integer) 3
   4) 1) "get"
      2) "k1"
   5) "127.0.0.1:52429"
   6) ""

下面是返回值的解析。

  1. 命令序列号,递增的,这里2意思是这是第2条执行的语句。
  2. 一串时间戳,该命令执行的时间。
  3. 命令的执行时间,单位是微秒。
  4. 命令的具体内容和返回值
  5. 客户端(请求执行命令方)的IP。
  6. 客户端的名称。



1.2、生产环境下慢查询的配置

我们需要关注的配置就两个,阈值和日志队列长度。

阈值默认值是10ms,队列长度128。

对于阈值,这个具体需要看系统对查询的要求。对于要求非常高的系统将其设为1ms或者0.1ms也是可以的。需要结合实际数据,确保阈值合适,太低查询日志会记录太多不属于慢查询的命令;太高则会导致真正的慢查询不被记录,所以需要根据测试来决定数值。

对于日志队列长度,一般来说128太小,设为1000,2000都可。日志虽然存储在内存中,但是每条日志所占用的空间不大,所以队列长度设大一点也没关系。



2、Pipeline

redis 命令执行主要是下面4步,通常情况下排队和执行命令的时间是很快的,都是微秒级。相反网络开销却比较大,很多时候都是毫秒级别。
请添加图片描述

为了优化执行速度,redis便有了pipeline。这相当于是一个批处理机制,一次网络请求带来多条指令,大量redis命令执行的情景可以节省大量时间。


2.1、简单的pipeline代码示例

下面是使用pipeline进行setget的示例。

简单来说通过Jedis#pipelined()获得Pipeline对象。如果需要获取命令的返回值就使用Pipeline#syncAndReturnAll()方法,不需要返回值就执行Pipeline#sync()即可。

//get
Jedis jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
for(String key: keys) {
	pipelined.get(key);
}
return pipelined.syncAndReturnAll();


//set
Jedis jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
for(String key: map.keySet()) {
    pipelined.set(key, map.get(key));
}
pipelined.sync();


2.2、使用Pipeline的注意事项

我自己做实验,Pipeline对10000次字符串类型的set操作耗时13ms;不使用Pipeline则耗时1023ms

虽然理论上Pipeline在一次性处理越多的命令,节约的时间就越多,但是我们也不能无限制地在一个Pipeline里塞入太多的数据,他是有瓶颈的。

因为Redis是基于TCP的,并且命令执行的主要耗时是在网络方面,所以我们需要考虑一个TCP报文能携带多少数据。如果我们一次性塞入太多指令,TCP协议会将这些指令分成多个报文分开传输,也就造成多次网络传输。

所以我们一次性执行的指令的字节数不应该超过TCP报文的最大值。

单个TCP报文是1500字节,IP头占20字节,TCP头占20字节,所以一个报文可供我们使用的空间就是1500 - 20 - 20 = 1460字节

注意pipeline一次携带命令的不要超过1460字节即可。


3、事务

3.1、redis事务开启的三个阶段

  • 开启事务:multi
  • 命令入队:开始写命令,这里写的所有命令都是放入队列的操作,不执行。命令的执行只有执行事务时才会开始顺序执行。
  • 取消事务:discard。如果取消了事务就不能执行事务,要重新开启事务。放弃了事务那事务里的命令就没有执行。
  • 执行事务:exec。只有执行事务,命令才会被顺序执行,然后会顺序返回各命令的返回值。
    在这里插入图片描述



3.2、redis事务的特性

Redis的事务不完全和其它架构的事务一致。一般来说,在其他框架中的事务中,只要有一条语句执行失败,无论什么原因导致失败,该事务中的所有语句都会回滚。

redis有一条语句发生错误的时候,redis并不会回滚事务中的其它语句,所以一般我们不会使用redis来做事务的控制。

  • 语法错误:这种就是指令的语法错误。发生这种异常的时候,事务会被直接取消。下面是例子。

在这里插入图片描述

  • 逻辑错误:指令都没问题,但是运行时发生错误。这种异常不会影响事务,事务中其他正常的指令都会被执行。比如下面的例子,我们给一个字符串执行incr操作,使其发生错误,而事务中的其他指令也能被执行。

在这里插入图片描述




4、Redis实现乐观锁

  • 悲观锁:很悲观,认为共有数据任何时候都会被修改,于是在共有数据的整个操作过程都会加上锁,哪怕这些操作过程中还包含其他操作,共有数据等会才会操作。我们熟知的sychronized就这悲观锁的代表,锁住的代码区域即使没有对共有数据操作,也不允许别人操作数据。这种锁很安全,但影响性能。
  • 乐观锁:很乐观,相信整个过程数据不会被改动,只会在操作共有数据的时候才会去检查数据有没有被改动。常见的版本号version就是乐观锁的代表。这种锁安全性低一些,但是性能很高

Redis可以通过watch关键字来实现乐观锁。

4.1、watch关键字(乐观锁)

watch关键字的语法是watch key,可以有多个key。表示对一个key进行监控(可以同时监控多个key),实际上可以理解成对这个key加上一个版本号记录。与此相反的unwatch是放弃监视,放弃监视不能指定,只能放弃所有监视。

watch要和事务一起使用。当使用watch监听一个key后,就会影响下一个开启的事务。如果在这个事务执行之前,watch的key有过写入操作(版本号变化),那么这个事务就一定提交失败。

watch影响的只有紧接着watch语句的一个事务,后面的事务不会被watch影响。

下面是示例,左边的标签页会watch k1执行事务,右边的标签页模拟一条新线程,在左标签页执行事务之前对k1写入。然后左标签的事务执行失败,事务中的k3没有存进去。

在这里插入图片描述

由上可以看出,Redis中watch关键字本身就具有乐观锁的性质,可以直接用watch实现乐观锁。


5、LUA脚本

LUA脚本是由C语言编写的,可以看成是一种语言,可以在在其他平台上执行,比如Java,Redis。

在redis中使用LUA语言有下面三点好处

  • 减少网络开销:LUA可以吧多条命令放入一个脚本中执行。
  • 原子性: redis以一个脚本为整体执行,中间不会被其他东西插入。
  • 复用性:客户端发送的LUA脚本会存储在redis中,其他客户端可以复用这一脚本完成同样的逻辑。

在这里插入图片描述


5.1、redis中使用LUA简单示例

使用eval关键字,之后是LUA的语句,之后的参数第一个数字1表示KEYS[]传一个参数,剩下的参数都是ARGV[]

请添加图片描述

前面介绍LUA的好处提到了复用性,LUA脚本可以存储在redis中重复调用。这里的实现是通过script load "LUA script"实现的。

这句话会将LUA脚本存储到redis中,返回一字符串,表示脚本的唯一id。之后通过evalsha就可以调用LUA脚本了。

请添加图片描述


5.2、Redis + LUA实现限流

请添加图片描述

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

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

相关文章

自己写的功能简单的 http server 文件下载服务器 http服务器

最近在项目中遇到过 通过ssh登录到某台机器A ,然后 又从A机器上ssh到机器B 而B机器是没有外网功能,这个时候如果想从B机器上传文件到A机器上就很不好办了 由于B机器没有外网 很多工具软件都没有 原来是是用python 起的http服务器 但是B机器没有安装py…

Black Basta 勒索软件利用 QakBot 进行分发

自 2022 年 4 月投入运营以来,Black Basta 对全球近 50 家组织发起了攻击。攻击者使用了“双重勒索”策略,如果受害者不交付赎金就会被公开数据。 勒索团伙会不断改进攻击方式,最近研究人员发现 Black Basta 与银行木马 QakBot 勾结在一起&a…

nginx+uwsgi部署django项目

1. python3.9环境安装 安装依赖 yum install zlib zlib-devel libffi-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make wget下载源码 官网地址 wget https://www.python.org/ftp/python/3.9.6/Python-3.9.6.tar.xz解压 &…

maven的下载与安装

前言 本篇文章是基于win11系统下载安装Maven的教程。 一、 Maven介绍 1. 什么是Maven? Maven是基于项目对象模型(POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管…

【FreeRTOS】详细讲解FreeRTOS中任务管理并通过示例讲述其用法

任务状态 在FreeRTOS中一个任务经创建后会有多个状态,通常可分为以下几种状态: 就绪态:新创建的任务一般处于就绪态。处于就绪态的任务表明其已经存在于就绪列表中,其已经具备所有的任务执行需要条件,只等待调度器调度…

社科院杜兰大学金融管理硕士项目——美丽的风景,在你前行的路上

一个人的强大源于内心的坚定,内心强大的人,是平和的、自信的、乐观的。在工作中也是奋发图强、积极向上的,就像选择来社科院与杜兰大学金融管理硕士充电,为职场发展注入能量,为未来发展奠定基础。近些年来,…

Centos7离线安装MySQL

使用tar.gz文件安装MySQL 1、下载MySQL离线包 下载地址:https://downloads.mysql.com/archives/community/ 根据需要下载对应版本tar.gz文件,下载完成后上传到服务器 2、解压tar.gz文件 tar -zxvf mysql-5.7.37-linux-glibc2.12-x86_64.tar.gz等待解…

【计算机网络】TCP/UDP协议

传输层协议 负责数据能够从发送端传输接收端,这篇文章主要介绍TCP和UDP协议 UDP协议 学习UDP协议需要掌握,UDP协议如何做到封装和解包的,如何做到向上交付的(分用问题) UDP协议格式 封装:添加定长报头 解包&…

用Python掌握QQ群聊天记录数据分析

当你打开QQ群时,你是否想过如何用Python提取里面的数据呢?随着社交媒体的兴起,QQ群成为了人们交流的重要平台,而提取这些数据可以帮助我们了解用户喜好和行为。那么,如何使用Python提取QQ群数据呢? 这里做了一套脚本用于提取QQ群的消息并进行一些简单的处理。 其中包括…

IB、AP、A-LEVEL,哪种最适合自己呢?

刚开始了解新加坡留学的家长和学生,一定看到这些就觉得头大吧。当下国际学校里的课程可以说五花八门,在选择之前一定要弄清楚这些名词背后的含义…… IB是什么 IB(International Baccalaureate)全称为国际预科证书课程&#xff0c…

Linux下rabbitmq的集群搭建

1 修改 3 台机器的主机名称 在三台服务器分别执行 hostnamectl set-hostname master hostnamectl set-hostname node01 hostnamectl set-hostname node022 配置各个节点的 hosts 文件 vim /etc/hosts 192.168.5.6 master 192.168.5.7 node01 192.168.5.8 node023 确保各个节…

【工具】苏格拉底式诘问法解决工作问题

目录一、什么是苏格拉底式诘问法二、苏格拉底式诘问法的细分三、在实际工作中运用苏格拉底式诘问法解决问题一、什么是苏格拉底式诘问法 苏格拉底式诘问法(Socratic Elenchus)是苏格拉底式提问的一种,也叫做"诘问法"。它是由古希腊…

OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列,持续更新中 OpenCV-PyQT项目实战(1)安装与环境配置 OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战(3)信号与槽机制 …

【Java】final的关键字和final的四种用法

final定义 final翻译成中文的意思是 “最终” , 它是java当中的一个关键字,使用final修饰的对象不允许修改或替换其原始值或定义。 假如当final修饰一个类的时候,是不能被其他类继承的。 final的四种用法 修饰类修饰方法修饰变量修饰参数 1.…

Oracle 里的优化器

对于关系型数据库而言,优化器是最核心的部分。主要是因为优化器负责解析SQL。而大家都是通过SQL来访问存储在数据库中的数据。故此,优化器的好坏直接决定该关系型数据库的强弱。 同时,想要做好SQL优化,就必须深入了解优化器。这是…

源表的基础知识

浅谈“源表”的定义、功能及应用 源表与传统电源的区别 源表速度更快; 源表电流、电压分辨率更高; 源表是四象限,可以正电压(源表提供给外部)负电流(外部灌入源表)或者负电压、正电流。 传统电…

3.组件的基本用法

目录 1 创建组件 1.1 用函数创建组件 1.2 使用类创建组件 2 项目上组件的使用方式 3 事件处理 3.1 事件绑定 3.1.1 类组件绑定事件 3.1.2 函数组件绑定事件 3.2 事件对象 4 组件状态 4.1 初始化状态 4.2 获取状态 4.3 设置状态 4.3.1 箭头函数 4.…

win10下Elasticsearch安装配置完整教程

一、在安装Elasticsearch引擎之前,必须安装ES需要的软件环境,安装Java JDK和配置JAVA_HOME环境变量 二.安装ElasticSearch服务,下载和安装es包 https://www.elastic.co/downloads/past-releases Elasticsearch 8.6.1 | Elastic 安装成功之…

数据结构 第五章 数组和广义表

还是会想你:点击收听 1 基本知识点 1、数组可以看作是下标和值的偶对的集合(具有相同类型的数据元素) 注意:数组是同类型值的集合?**错误**2、数组的存储方式:以行为主序(一行存储完成之后继续存储下一行)、以列为主序(一列存储…

【C++修行之路】C++入门之深剖变量

🍿本文主题:C语法中的变量 🎈更多内容:C较C的改进 💕我的主页:蓝色学者 文章目录前言概念什么是变量变量名变量类型为什么要有不同数据类型各自数据类型的本质结语前言 大家好久不见,今天是我…