Redis 协议与异步方式

redis pipeline 模式

  • redis pipeline 是一个客户端提供的机制,与 redis 无关。
  • pipeline 不具备事务性。
  • 目的:节约网络传输时间。
  • 通过一次发送多条请求命令,从而减少网络传输时间。
    在这里插入图片描述
  • 时间窗口限流
    • 系统限定某个用户某个行为在指定的时间范围内(动态)只能发生 N 次
# 指定用户 user_id 的某个行为 action 在特定时间内 period 只允许发生该行为的最大次数 max_count
# 维护一次时间窗口,将窗口外的记录全部清理掉,只保留窗口内的记录
local function is_action_allowed(red, userid, action, period, max_count)
    local key = tab_concat({"hist", userid, action}, ":")
    local now = zv.time()
    red:init_pipeline()
    -- 记录行为
    red:zadd(key, now, now)
    -- 移除时间窗口之前的行为记录,剩下的都是时间窗口内的记录
    red:zremrangebyscore(key, 0, now - period * 100)
    -- 获取时间窗口内的行为数量
    red:zcard(key)
    -- 设置过期时间,避免冷用户持续占用内存 时间窗口的长度 + 1秒
    red:expire(key, period + 1)
    local res = red:commit_pipeline()
    return res[3] <= max_count
end

redis 发布订阅模式

  • 为了支持消息的多播机制,redis 引入了发布订阅模块。
  • 作用:
    • 没有建立连接的服务器之间进行交互。
    • 第三方系统和与 redis 建立连接的服务器之间进行交互。
  • 缺点:不确定消息到达。kafka 分布式消息队列、redis stream 模式可以确保消息到达。
    • 发布订阅的生产者传递过来一个消息,redis 会直接找到相应的消费者并传递过去。假如没有消费者,消息直接丢弃。假如开始有 2 个消费者,一个消费者突然挂掉了,另一个消费者依然能接收到消息。但是,如果刚挂掉的消费者重新连上后,在断开连接期间的消息对于该消费者来说彻底丢失了。
    • redis 停机重启,pubsub 的消息是不会持久化的,所有的消息都被直接丢弃。
  • 使用场景
    • 业务可以接受消息丢失。
    • redis cluster 集群之间通信。
  • 服务器需要和 redis 建立多少连接
    • 5 种基本数据结构的处理,只需要一条连接,可以使用连接池。
    • 如果有阻塞连接的需求,另外建立一条连接。
    • 如果需要发布订阅模式,另外建立一条连接。

在这里插入图片描述

# 订阅频道
subscribe 频道
# 订阅模式频道
psubscribe 频道
# 取消订阅频道
unsubscribe 频道
# 取消订阅模式频道
punsubscribe 频道
# 发布具体频道或模式频道的内容
publish 频道 内容
# 客户端收到具体频道内容
message 具体频道 内容
# 客户端收到模式频道内容
pmessage 模式频道 具体频道 内容

subscribe news.A news.B news.C
psubscribe news.*
publish new.B 'zcoder is good'

redis 事务

  • 前提:有并发连接。
  • 事务是用户定义的一系列的数据库操作,要么全部执行,要么全部不执行,是不可分割的单元。
  • redis 事务原理:当使用 MULTI 开启事务时,redis 会创建一个队列,后续的所有命令都会入队,直到使用 EXEC 提交事务。提交事务时会将队列中的所有命令出队执行。因为 redis 处理命令是单线程的,所以在处理队列中的命令时会阻塞其它连接的命令,直到队列中的命令全部处理完。使用 DISCARD 可以清空队列。使用 WATCH 可以观察 key,如果 key 对应的 value 变动,说明其它连接修改了 value,事务的逻辑一致性被破坏,那么调用 EXEC 就会清空该事务的队列,返回 nil。
# 开启事务
MUITI
# 提交事务 
EXEC
# 取消事务
DISCARD

# 检测 key 对应的 value 的变动,若在事务执行中,value 变动则取消事务并返回 nil。
# 在事务开启前调用,乐观锁实现(cas) 
WATCH
  • 应用
    • 加倍操作
      WATCH score
      val = GET score
      MULTI
      SET score val * 2
      EXEC
      

lua 脚本

  • redis 中加载了一个 lua 虚拟机,用来执行 lua 脚本。
  • redis lua 脚本的执行是原子性的,当某个脚本正在执行的时候,不会有其他命令或者脚本被执行。
  • lua 脚本中的命令会直接修改数据状态。
  • 先将 lua 脚本提交到 redis 中,redis 会通过 lua 虚拟机解析 lua 脚本,并返回一个 hash 值,这个 hash 值可以代替这个 lua 脚本(通过这个 hash 值去索引对应的 lua 脚本)。
    • 优点:使用较短的字符串代替复杂的 lua 脚本。意味着在网络传输的过程中可以减少发送数据的流量。其次,效率会更高,因为使用的是已经编译好的 lua 脚本。
      在这里插入图片描述
# 测试使用
EVAL script numkeys key [key ...] arg [arg ...]

# 线上使用
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
  • 应用
    • 项目启动时,建立 redis 连接并验证,通过 script load 加载项目中使用的 lua 脚本,script load 会返回对应 lua 脚本的 hash 值。
    • 项目中若需要热更新,通过 redis-cli 执行 script flush 然后可以使用订阅发布功能通知所有服务器重新加载 lua 脚本。
    • 若项目中 lua 脚本发生阻塞,可通过 script kill 暂停当前阻塞脚本的执行。
# 从文件中读取 lua脚本内容
cat test.lua | redis-cli script load --pipe
# 加载 lua脚本字符串 生成 sha1
> script load 'local val = KEYS[1]; return val'
"b8059ba43af6ffe8bed3db65bac35d452f8115d8"
# 检查脚本缓存中,是否有该 sha1 散列值的lua脚本
> script exists "b8059ba43af6ffe8bed3db65bac35d452f8115d8"
1) (integer) 1
# 清除所有脚本缓存
> script flush
OK
# 如果当前脚本运行时间过长(死循环),可以通过 script kill杀死当前运行的脚本
> script kill
(error) NOTBUSY No scripts in execution right now.

ACID 特性

  • 原子性(A)
    • 事务是一个不可分割的单位,事务中的操作要么全部成功,要么全部失败。
    • redis 不支持回滚,即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。
  • 一致性(C)
    • 事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测。这里的一致性是指预期的一致性而不是异常后的一致性,所以 redis 也不满足。
      • 这个争议很大:redis 能确保事务执行前后的数据的完整约束,但是并不满足业务功能上的一致性,比如转账功能,一个扣钱一个加钱,可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功,系统凭空多了钱。
  • 隔离性(I)
    • 各个事务之间互相影响的程度,redis 是单线程执行,天然具备隔离性。
  • 持久性(D)
    • redis 只有在 aof 持久化策略的时候,并且需要在 redis.conf 中 appendfsync=always 才具备持久性,实际项目中几乎不会使用 aof 持久化策略。
  • lua 脚本满足原子性和隔离性,不满足一致性和持久性

redis 异步连接

  • 同步连接方案采用阻塞 io 实现。通常用多个线程实现线程池解决效率问题。
    • 优点:代码书写是同步的,业务逻辑没有割裂。
    • 缺点:阻塞当前线程,直至 redis 返回结果。
  • 异步连接方案采用非阻塞 io 实现。
    • 优点:没有阻塞当前线程,就算 redis 没有返回,依然可以往 redis 发送命令。
    • 缺点:代码书写是异步的(回调函数),业务逻辑割裂。
  • 基于 reactor 实现异步连接:
    1. 与 redis 建立连接
    a. 创建 socket, 设置 fd 为非阻塞 io
    b. 调用 connect(fd, &addr, &len)
    c. 将 fd 注册到 epoll, 注册写事件
    d. 如果连接建立成功, fd 的写事件会进行响应, 然后注销写事件
    
    1. 向 redis 发送数据(使用 redis 协议加密,然后通过 tcp 发送过去)
    a. int n = write(fd, buf, sz)
       如果 n < sz && n != -1 或者 n == -1 && errno = EWOULDBLOCK 
       说明 fd 对应的发送缓冲区已经满了
    b. 注册写事件, 如果写事件触发, 继续 write(fd, buf, sz),
       如果发送完毕, 注销写事件
    c. 注册读事件
    
    1. 读取 redis 的返回(通过 tcp 接收数据并分割数据包,然后使用 redis 协议解密)
    a. 读事件触发, int n = read(fd, buf, sz)
    b. 根据 redis 协议分割数据包
    c. 使用 redis 协议解密
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot项目中如何结合Mybatis进行数据库查询

在Spring Boot项目中使用Mybatis进行数据库操作是一种常见的实现方式。下面我将展示如何在Spring Boot项目中整合Mybatis。这个示例将包括几个主要部分&#xff1a;项目依赖配置、配置文件、实体类、Mapper接口及其XML配置文件、服务类、以及一个简单的控制器。 1. 项目依赖配…

一键安装|卸载 mysql 8.2.0 shell脚本

场景&#xff1a;为了在无网、外网 mysql 安装方便&#xff0c;这里分享一个自己编写得 shell脚本 这里以当前最新版 mysql 8.2.0&#xff1b;centos-7 二进制包下载&#xff1a; 下载地址 mysql_install.sh #!/bin/bash # 解压安装包 tar -xf mysql-8.2.0-linux-glibc2.17-x8…

opencv中两个LSD直线检测算法的区别与应用

opencv中两个LSD直线检测算法的区别与应用 同样是Line Segment Detector(lsd)算法&#xff0c;opencv中提供了两种实现&#xff0c;并且位于不同的模块。下面分别介绍它们的使用方法&#xff1a; 1. LineSegmentDetector 由于源码许可证问题 OpenCV 3.4.6-3.4.15、4.1.0-4.5.…

IDEA类和方法注释模板设置

一、概述 IDEA自带的注释模板不是太好用&#xff0c;我本人到网上搜集了很多资料系统的整理了一下制作了一份比较完整的模板来分享给大家&#xff0c;我不是专业玩博客的&#xff0c;写这篇文章只是为了让大家省事。 这里设置的注释模板采用Eclipse的格式&#xff0c;下面先贴…

【深度优先搜索】【图论】【推荐】332. 重新安排行程

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 深度优先搜索 图论 LeetCode332. 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&a…

C++:常量表达式

C11开始constexpr作为一种声明&#xff0c;为编译器提供了在编译期间确认结果的优化建议&#xff0c;满足部分编译期特性的需求 constexpr和const区别 int b10; const int ab; //运行成功 constexpr int cb; //编译器报错&#xff0c;b的值在编译期间不能确定 const int size1…

研发日记,MatlabSimulink开箱报告(九)——Simulink Test模块

文章目录 前言 Simulink Test模块 静态测试 动态测试 逻辑测试 前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;四&#xff09;——S-Fuction模块》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;五&#xff09;——S-F…

vue a-table 实现指定字段相同数据合并行

vue a-table 实现相同数据合并行 实现效果代码实现cloums数据格式数据源格式合并代码 实现效果 代码实现 cloums数据格式 const getColumns function () {return [{title: "分类",dataIndex: "checked",width: "150px",customRender: (text, …

有哪些视频媒体?邀请视频媒体报道活动的好处

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 视频媒体在当今的媒体生态中占据了重要的地位。以下是一些主要的视频媒体类型&#xff1a; 电视台&#xff1a;如中央电视台、各省级卫视台、地方电视台等&#xff0c;他们拥有专业的视…

mac命令行下计算文件SHA-256散列值

源起 从国内的第三方网站下载了Android sutiod的zip包下载地址&#xff0c;为了安全起见还是得跟Android官网上的对应的zip包的SHA值做下对比。以前是经常使用md5命令的&#xff0c;所以理论在命令行下应该是有对应的命令行工具可以计算SHA值的。后来搜索到可以用 shasum命令来…

yolov8训练目标检测模型

1.环境安装 conda安装&#xff08;miniconda&#xff09;&#xff0c;配置环境变量 创建环境 conda create -n yolo python3.8安装ultralytics conda activate yolopip install ultralytics2.数据集标注 使用labelimg标注工具对图片进行标注&#xff1a;将标注产生的xml转为t…

表格图片太大怎么批量压缩?快速处理图片大小的方法

在工作或者学习中制作表格的时候&#xff0c;经常需要插入一些图片来修饰内容&#xff0c;当遇到图片太大无法导入的情况就比较麻烦&#xff0c;尤其是多张图片处理的时候&#xff0c;那么表格图片太大怎么批量压缩呢&#xff1f;接下来小编就分享给大家一个快速图片压缩的方法…

HTTP详解(HTTP的特点,状态码,工作原理,GET和POST的区别,如何解决无状态通信)!!!

文章目录 一、HTTP协议简介二、HTTP的主要特点三、HTTP之URL四、Request和Respons五、HTTP的状态码六、HTTP工作原理七、GET和POST请求的区别八、解决HTTP无状态通信——Cookie和Session 一、HTTP协议简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&…

92. 递归实现指数型枚举 刷题笔记

思路 dfs 考虑选或者不选每个位置 用0表示未考虑 1表示选 2表示不选 用u表示搜索状态 u>n时 已经搜到底层了 需要输出当前方案 遍历 如果选了则输出 #include<iostream> using namespace std; int n; const int N16; int st[N]; void dfs(int u){ //u来记…

JVM运行时数据区——程序计数器

1、程序计数器介绍 JVM中的程序计数器英文全称是Program Counter Register&#xff0c;其中Register的命名源于CPU的寄存器&#xff0c;寄存器用于存储指令相关的现场信息&#xff0c;CPU只有把数据装载到寄存器才能够运行。 程序计数器中的寄存器并非是广义上所指的物理寄存…

音频提取使用什么方法?视频提取音频

在数字技术与多媒体日益普及的今天&#xff0c;音频提取已成为一个常见且重要的任务。无论是为了制作视频、编辑音乐&#xff0c;还是进行语音识别和分析&#xff0c;我们都需要从原始材料中提取音频。那么&#xff0c;音频提取通常使用什么方法呢&#xff1f; 1. 使用专业的音…

vue-router4 (六) 路由嵌套

应用场景&#xff1a; ①比如京东页面的首页、购物车、我的按钮&#xff0c;可以点击切换到对应的页面&#xff1b; ② 比如 Ant Design左侧这些按钮点击就会切到对应的页面&#xff0c;此时可以把左侧按钮放在父路由中&#xff0c;右侧的子路由 1.路由配置&#xff0c;子路由…

NLP-词向量、Word2vec

Word2vec Skip-gram算法的核心部分 我们做什么来计算一个词在中心词的上下文中出现的概率&#xff1f; 似然函数 词已知&#xff0c;它的上下文单词的概率 相乘。 然后所有中心词的这个相乘数 再全部相乘&#xff0c;希望得到最大。 目标函数&#xff08;代价函数&#xff0…

web学习笔记(二十二)DOM开始

目录 1.DOM简介 2.DOM树 3.DOM节点 4.查找DOM节点方法汇总 5.查找子结点的属性 5.1父子关系 5.2兄弟关系 6.几个特殊元素的查找 1.DOM简介 DOM&#xff08;Document Object Model&#xff09; 也叫页面文档对象模型&#xff0c;是W3C组织推荐的处理可扩展标记语言(HTML…

年度目标制定:数据驱动的深度策略,打造你的成功蓝图!

导语&#xff1a;在快节奏的生活中&#xff0c;制定年度目标不仅仅是为了完成任务&#xff0c;更是为了在一年中明确方向、聚焦重点、持续进步。而数据分析&#xff0c;则是我们制定年度目标时不可或缺的利器。通过深入挖掘数据&#xff0c;我们可以更准确地理解自己的需求、优…