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 协议解密
    

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

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

相关文章

基于Java SSM框架实现众筹平台网站系统项目【项目源码】计算机毕业设计

基于java的SSM框架实现众筹平台网站系统演示 SSM框架 当今流行的“SSM组合框架”是Spring SpringMVC MyBatis的缩写&#xff0c;受到很多的追捧&#xff0c;“组合SSM框架”是强强联手、各司其职、协调互补的团队精神。web项目的框架&#xff0c;通常更简单的数据源。Spring…

【C++】string 类 ( 上)

标准库中的string类 注意&#xff1a; 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同&#xff0c;再添加了一些专门用来操作string的常规操作。 比特就业课 3. string在底层实际是&#xff1a;basic_string模板类的别名&#xff0c;typedef basi…

Java集合-Map接口

在Java中&#xff0c;Map接口表示键值对的集合&#xff0c;其中每个键都是唯一的&#xff0c;并且每个键映射到一个值。Map接口是集合框架中的一部分&#xff0c;位于java.util包中。它定义了一系列操作来管理键值对&#xff0c;例如添加键值对、删除键值对、获取键对应的值等。…

leetcode 热题 100_盛最多水的容器

题解一&#xff1a; 双指针遍历&#xff1a;容量计算公式为min(左高度&#xff0c;右高度)*底部距离&#xff0c;我们可以令底部距离逐步递减&#xff08;左右两边的指针向中部移动&#xff09;。此时对于min(左高度&#xff0c;右高度)&#xff0c;假设较高的线向中部移动&…

SpringBoot+Redis 解决海量重复提交问题,yyds!

在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求&#xff0c;我们来解释一下幂等的概念&#xff1a;任意多次执行所产生的影响均与一次执行的影响相同。按照这个含义&#xff0c;最终的含义就是 对数据库的影响只能是一次性的&#xff0c;不能重复处理。如何保证其…

中国电子学会2019年12月份青少年软件编程Scratch图形化等级考试试卷四级真题。

第 1 题 【 单选题 】 1.以下模块&#xff0c;可以“说”出“我喜欢Apple”的是&#xff1f; A&#xff1a; B&#xff1a; C&#xff1a; D&#xff1a; 2.某学校为教师外出提供车辆服务&#xff0c;当外出人数小于5人时&#xff0c;派轿车&#xff1b;当外出人数为5至7人的话…

C++ 前缀和

目录 例1 例2 例3 例4 例5 例6 例7 例8 例1 DP34 【模板】前缀和 分析&#xff1a;dp和arr的大小并不是固定的&#xff0c;就是有没有偏移量&#xff0c;这里的n是从1开始&#xff0c;不如直接放到下标1处&#xff0c;在最后的减法时&#xff0c;如果用第一个参考代码会…

C语言中的字符魔法:大小写转换的艺术

引言 在C语言的世界里&#xff0c;字符处理是一项基础且重要的任务。字符作为编程中最基本的元素之一&#xff0c;承担着信息展示、数据交互等多重角色。特别是在处理文本信息时&#xff0c;字符的转换和识别显得尤为重要。大小写字母的转换就是其中一个常见的需求&#xff0c…

P4913 【深基16.例3】二叉树深度题解

题目 有一个n(n≤) 个结点的二叉树。给出每个结点的两个子结点编号&#xff08;均不超过n&#xff09;&#xff0c;建立一棵二叉树&#xff08;根节点的编号为1&#xff09;&#xff0c;如果是叶子结点&#xff0c;则输入0 0。 建好这棵二叉树之后&#xff0c;请求出它的深度…

【解决】虚幻导入FBX模型不是一个整体

问题&#xff1a; 现在有一个汽车的fbx模型&#xff0c;导入虚幻引擎&#xff0c;导入后变成了很多汽车零件模型。 解决&#xff1a; 把“合并网格体”勾选上&#xff0c;解决问题。

三层靶机靶场之环境搭建

下载&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;f4as 简介 2019某CTF线下赛真题内网结合WEB攻防题库&#xff0c;涉 及WEB攻击&#xff0c;内网代理路由等技术&#xff0c;每台服务器存在一个 Flag&#xff0c;获取每一 个Flag对应一个积分&…

PDF 解析问题调研

说点真实的感受 &#xff1a;网上看啥组件都好&#xff0c;实际测&#xff0c;啥组件都不行。效果好的不开源收费&#xff0c;开源的效果不好。测试下来&#xff0c;发现把组件融合起来&#xff0c;还是能不花钱解决问题的&#xff0c;都是麻烦折腾一些。 这里分享了目前网上能…