Redis协议与异步方式(二)

news2025/5/12 14:49:22

目录

1.redis pipeline

2.redis 事务

        2.1 MULTI

        2.2 EXEC

        2.3 DISCARD

        2.4 WATCH

3.lua 脚本

 调用方式

4.ACID 特性分析

5.发布订阅

原理

命令

6.异步连接

思想

代码


1.redis pipeline

        通过一次发送多次请求命令,为了减少网络传输时间。

        注意:pipeline 不具备事务性。

2.redis 事务

        事务:用户定义一系列数据库操作,这些操作视为一个完整的逻辑处理工作单元,要么全部执行, 要么全部不执行,是不可分割的工作单元。

        当出现多条并发连接时,我们会想到事务,当出现多核时,我们会想到原子操作。

        2.1 MULTI

        开启事务,事务执行过程中,单个命令是入队列操作。

        2.2 EXEC

        提交事务,执行事务。

        2.3 DISCARD

        取消事务

        2.4 WATCH

        检测 key 的变动,若在事务执行中, key 变动则取消事务;

        在事务开启前调用乐观锁实现。

        乐观锁(redis)
“我假设你不会碰我操作的变量,冲突很少,出问题我再处理。”(用版本号实现,操作时候发现版本号不对,说明被改了,再去重试)
        悲观锁(mysql)
“我假设你一定会碰,所以我提前上锁,防止你碰。”

对比项乐观锁悲观锁
核心假设不会发生冲突一定会发生冲突
操作方式不加锁,操作前后做数据校验操作前加锁,阻塞其他操作
并发性能性能好,冲突少时效率高并发低,阻塞多时效率低
实现方式版本号(version),时间戳数据库 select...for update,行锁等
失败处理操作失败后重试先加锁,保证别人不能动
典型场景数据读多写少,如缓存数据写多读多,如账户转账,订单处理

3.lua 脚本

        redis 中加载了一个 lua 虚拟机;用来执行 redis lua 脚本;redis lua 脚本的执行是原子性的;当某 个脚本正在执行的时候,不会有其他命令或者脚本被执行;

 调用方式
redis.call("命令",key1,key2,...,arg1,arg2,...)

//call:命令失败抛出异常
//pcall:命令失败不抛异常,返回错误对象

EVAL 是 Redis 执行一段 Lua 脚本的命令,支持多 key、多参数传入,原子执行
使用 EVALSHA 来代替 EVAL 时,相当于只传递一个 hash(SHA1)值 到 Redis,而不传整段 Lua 脚本:Redis 内部维护了一张“哈希表”,这样可以根据 hash 快速定位并执行脚本,EVALSHA 时 Redis 会:

  1. 查找哈希是否存在
  2. 找到原始脚本
  3. 执行脚本(在 Lua 虚拟机中)

4.ACID 特性分析

A :原子性;事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败;redis 不支持回滚;即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直 到将事务队列中的所有命令都执行完毕为止。

C :一致性;执行事务后,数据从一个一致状态过渡到另一个一致状态(满足约束、逻辑正确)
一个是逻辑上一致性,一个是数据库一致性(完整约束)

I :隔离性;各个事务之间互相影响的程度;redis 是单线程执行,天然具备隔离性;

D :持久性;一旦事务执行成功,结果会被永久保存,即使系统崩溃也能恢复
redis只有在aof持久化策略时候,才具备持久性,实际项目中几乎不会使用aof 持久化策略;

lua 脚本满足原子性和隔离性;一致性和持久性不满足;

5.发布订阅

原理

发布者 使用 PUBLISH 向某个频道发送消息;

订阅者 使用 SUBSCRIBE、PSUBSCRIBE 订阅一个或多个频道;

一旦有新消息,所有订阅者会立即收到消息;

是即时通信模型,不做持久化,也不记录历史消息。

命令
命令说明
SUBSCRIBE订阅一个或多个频道
UNSUBSCRIBE取消订阅
PUBLISH向频道中发布消息
PSUBSCRIBE订阅一个或多个频道(支持通配符)
PUNSUBSCRIBE取消订阅
PUBSUB查看订阅状态,频道数量等信息

        发布订阅功能一般要区别命令连接重新开启一个连接;因为命令连接严格遵循请求回应模式;而 pubsub 能收到 redis 主动推送的内容;所以实际项目中如果支持 pubsub 的话,需要另开一条连接 用于处理发布订阅; 

注意:redis 停机重启,pubsub 的消息是不会持久化的,所有的消息被直接丢弃;

6.异步连接

借鉴于:小李小李快乐不已 redis异步连接

思想

hiredis 异步客户端接入自定义的 reactor 事件驱动系统的适配器,核心作用是桥接Redis的异步事件自定义事件循环机制,实现了一套hiredis的IO多路复用抽象接口。

代码

static int redisAttach(reactor_t *r, redisAsyncContext *ac)

  1. 创建一个 redis_event_t 对象(包含 event_t 和 Redis 上下文);
  2. 设置该对象的 addRead、delRead、addWrite、delWrite、cleanup 函数;
  3. 将这些函数注册进 redisAsyncContext 的 ev 成员;
static int redisAttach(reactor_t *r, redisAsyncContext *ac) {
    redisContext *c = &(ac->c);
    redis_event_t *re;
    
    /* Nothing should be attached when something is already attached */
    if (ac->ev.data != NULL)
        return REDIS_ERR;

    /* Create container for ctx and r/w events */
    re = (redis_event_t*)hi_malloc(sizeof(*re));
    if (re == NULL)
        return REDIS_ERR;

    re->ctx = ac;
    re->e.fd = c->fd;
    re->e.r = r;
    // dont use event buffer, using hiredis's buffer
    re->e.in = NULL;
    re->e.out = NULL;
    re->mask = 0;
    //这些是 hiredis 要求你实现的“注册函数”。每当 Redis 需要监听某个 FD 的读/写事件,就会调用这些函数
    ac->ev.addRead = redisAddRead;
    ac->ev.delRead = redisDelRead;
    ac->ev.addRead = redisAddWrite;
    ac->ev.delWrite = redisDelWrite;
    ac->ev.cleanup = redisCleanup;//清理函数必不可少
    ac->ev.data = re;
    return REDIS_OK;
}

 ac->ev.addRead = redisAddRead;ac->ev.addRead = redisAddWrite;

这两个去调用redisReadHandler / redisWriteHandler,去使用hiredis提供的读写处理

redisEventUpdate

这是事件变化的调度器,核心逻辑是根据 mask 来:

  1. 新增事件:调用 add_event()
  2. 删除事件:调用 del_event()
  3. 修改事件:调用 enable_event() 切换读写状态

使用逻辑

int main() {
    // 1. 创建 event loop
    reactor_t *r = reactor_create();

    // 2. 连接 Redis 异步客户端
    redisAsyncContext *ac = redisAsyncConnect("127.0.0.1", 6379);
    if (ac->err) {
        printf("Redis error: %s\n", ac->errstr);
        return -1;
    }

    // 3. 接入自己的 reactor
    if (redisAttach(r, ac) != REDIS_OK) {
        printf("Failed to attach redis context to reactor\n");
        return -1;
    }

    // 4. 设置连接成功/断开回调(可选)
    redisAsyncSetConnectCallback(ac, connectCallback);
    redisAsyncSetDisconnectCallback(ac, disconnectCallback);

    // 5. 发送异步命令
    redisAsyncCommand(ac, commandCallback, NULL, "SET foo bar");

    // 6. 启动事件循环
    reactor_run(r);

    return 0;
}

 hiredis实现了协议解析、读写事件、缓冲区操作、协议加密
我们适配文件实现了:适配事件对象以及事件操作函数

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

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

相关文章

销售管理系统使用全攻略:从基础配置到数据分析

如果你是一名刚接手公司销售管理系统的销售经理,你会深刻体会到一个好工具的重要性。如果老板突然要查看季度销售数据时,就不用手忙脚乱地翻找各种Excel表格。 今天就来分享我的经验,希望能帮助到同样需要快速上手的朋友。 系统基础配置指南 …

PowerShell 脚本中文乱码处理

问题描述 脚本带中文,执行时命令行窗口会显示出乱码 示例 Write-Host "测试成功!"解决方法 问了DeepSeek,让确认是不是 UTF8 无 BOM 格式 事实证明方向对了 但是确认信息有偏差 改成 UTF8 with BOM 使用任意支持修改编码的文本…

前端性能指标及优化策略——从加载、渲染和交互阶段分别解读详解并以Webpack+Vue项目为例进行解读

按照加载阶段、渲染阶段和交互阶段三个维度进行系统性阐述: 在现代 Web 开发中,性能不再是锦上添花,而是决定用户体验与业务成败的关键因素。为了全面监控与优化网页性能,我们可以将性能指标划分为加载阶段、渲染阶段、和交互阶段…

RDD实现单词计数

Scala(Spark Shell)方法 如果你在 spark-shell(Scala 环境)中运行: 1. 启动 Spark Shell spark-shell (确保 Spark 已安装,PATH 配置正确) 2. 执行单词统计 // 1. 读取文件&am…

Java快速上手之实验七

1.编写鼠标事件响应程序MouseEventDemo.java,当鼠标进入和离开窗口时给出相应显示,当按下、弹起时显示当前鼠标的坐标值。 2.编写鼠标事件响应程序MouseMotionEventDemo.java,当鼠标在窗口内移动时显示鼠标的坐标值。 …

可视化图解算法36: 序列化二叉树-I(二叉树序列化与反序列化)

1. 题目 描述 请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。 二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍…

Vivado FPGA 开发 | 创建工程 / 仿真 / 烧录

注:本文为 “Vivado FPGA 开发 | 创建工程 / 仿真 / 烧录” 相关文章合辑。 略作重排,未整理去重。 如有内容异常,请看原文。 Vivado 开发流程(手把手教学实例)(FPGA) 不完美先生 于 2018-04-…

Javascript:数组和函数

数组 创建数组 使用new创建 let arrnew array(数组大小); 直接赋值创建 let Arr2[];let Arr3[1,A,"HELLLO"]; 这里JS的数组里面的元素属性可以各不相同 演示代码 <script>let Arr1new Array(5);let Arr2[];let Arr3[1,A,"HELLLO"];console.…

无锁秒杀系统设计:基于Java的高效实现

引言 在电商促销活动中&#xff0c;秒杀场景是非常常见的。为了确保高并发下的数据一致性、性能以及用户体验&#xff0c;本文将介绍几种不依赖 Redis 实现的无锁秒杀方案&#xff0c;并提供简化后的 Java 代码示例和架构图。 一、基于数据库乐观锁机制 ✅ 实现思路&#xf…

NCCL N卡通信机制

转自我的博客&#xff1a;https://shar-pen.github.io/2025/05/05/torch-distributed-series/nccl_communication/ from IPython.display import Image import logging import torch import torch.distributed as distpytorch 分布式相关api torch.distributed.init_process_…

Alpha3DCS公差分析系统_国产替代的3D精度管控方案-SNK施努卡

随着智能制造发展规划的深入推进&#xff0c;工业软件国产化替代已上升为国家战略。在公差分析这一细分领域&#xff0c;长期被国外软件垄断的局面正被打破。 苏州施努卡自主研发的Alpha3DCS&#xff0c;凭借完全自主知识产权和军工级安全标准&#xff0c;成为国内实现三维公差…

ABB电机控制和保护单元与Profibus DP主站转Modbus TCP网关快速通讯案例

ABB电机控制和保护单元与Profibus DP主站转Modbus TCP网关快速通讯案例 在现代工业自动化系统中&#xff0c;设备之间的互联互通至关重要。Profibus DP和Modbus TCP是两种常见的通信协议&#xff0c;分别应用于不同的场景。为了实现这两种协议的相互转换&#xff0c;Profibus …

0基础 | L298N电机驱动模块 | 使用指南

引言 在嵌入式系统开发中&#xff0c;电机驱动是一个常见且重要的功能。L298N是一款高电压、大电流电机驱动芯片&#xff0c;广泛应用于各种电机控制场景&#xff0c;如直流电机的正反转、调速&#xff0c;以及步进电机的驱动等。本文将详细介绍如何使用51单片机来控制L298N电…

【金仓数据库征文】金仓数据库:创新驱动,引领数据库行业新未来

一、引言 在数字化转型的时代洪流中&#xff0c;数据已跃升为企业的核心资产&#xff0c;宛如企业运营与发展的 “数字命脉”。从企业日常运营的精细化管理&#xff0c;到战略决策的高瞻远瞩制定&#xff1b;从客户关系管理的深度耕耘&#xff0c;到供应链优化的全面协同&…

大模型系列(五)--- GPT3: Language Models are Few-Shot Learners

论文链接&#xff1a; Language Models are Few-Shot Learners 点评&#xff1a; GPT3把参数规模扩大到1750亿&#xff0c;且在少样本场景下性能优异。对于所有任务&#xff0c;GPT-3均未进行任何梯度更新或微调&#xff0c;仅通过纯文本交互形式接收任务描述和少量示例。然而&…

Qt QCheckBox 使用

1.开发背景 Qt QCheckBox 是勾选组件&#xff0c;具体使用方法可以参考 Qt 官方文档&#xff0c;这里只是记录使用过程中常用的方法示例和遇到的一些问题。 2.开发需求 QCheckBox 使用和踩坑 3.开发环境 Window10 Qt5.12.2 QtCreator4.8.2 4.功能简介 4.1 简单接口 QChec…

系统架构-面向服务架构(SOA)

概述 服务指的是系统对外提供的功能集 从应用的角度定义&#xff0c;可以认为SOA是一种应用框架&#xff0c;将日常业务划分为单独的业务功能和流程&#xff08;即服务&#xff09;&#xff0c;SOA使用户可以构建、部署和整合这些服务。 从软件的基本原理定义&#xff0c;SO…

AJAX原理

AJAX使用XHR 对象和服务器进行数据交互 XHR <p class"my-p"></p><script>const xhr new XMLHttpRequest()xhr.open(GET,http://hmajax.itheima.net/api/province)xhr.addEventListener(loadend,()>{// console.log(xhr.response)const data …

Paddle Serving|部署一个自己的OCR识别服务器

前言 之前使用C部署了自己的OCR识别服务器&#xff0c;Socket网络传输部分是自己写的&#xff0c;回过头来一看&#xff0c;自己犯傻了&#xff0c;PaddleOCR本来就有自己的OCR服务器项目&#xff0c;叫PaddleServing&#xff0c;这里记录一下部署过程。 1 下载依赖环境 1.1 …

Web开发—Vue工程化

文章目录 前言 Vue工程化 一、介绍 二、环境准备 1.介绍create-vue 2.NodeJS安装 3.npm介绍 三&#xff0c;Vue项目创建 四&#xff0c;项目结构 五&#xff0c;启动项目 六&#xff0c;Vue项目开发流程 七&#xff0c;API风格 前言 Vue工程化 前面我们在介绍Vue的时候&#…