Reids命令原理与应用2 - Redis网络层与优化,pipeline,发布订阅与事务

上篇文章:Reids命令原理与应用1 - Redis命令与原理-CSDN博客

个人代码仓库:橘子真甜 (yzc-YZC) - Gitee.com

目录

[一. Redis网络层](#一. Redis网络层)

[二. Redis pipeline](#二. Redis pipeline)

[三. Redis 发布订阅](#三. Redis 发布订阅)

[3.1 发布订阅的使用](#3.1 发布订阅的使用)

[3.2 发布订阅的缺点和使用场景](#3.2 发布订阅的缺点和使用场景)

[四. Redis事务](#四. Redis事务)

[4.1 事务与指令](#4.1 事务与指令)

[4.2 lua实现事务](#4.2 lua实现事务)

[4.3 Redis事务的acid特性](#4.3 Redis事务的acid特性)


一. Redis网络层

我们知道,redis是网络内存数据库,模型是请求-响应模型。为了高效缓存/处理请求/应答/数据安全,redis的网络层是如何处理的呢?

redis为了数据安全,对数据的操作和处理只有一个线程。同时为了高效处理不同客户端的请求,有多个辅助线程进行网络io数据。

而且redis对于请求的处理是:

对于单个连接的多个请求,处理是串行的

对于多个连接的多个请求,处理是并行的

二. Redis pipeline

pipeline是用于提高客户端发送数据的效率的,减少不必要的网络io冗余和浪费。

原理:将多个请求一起发送给redis服务器,redis返回多个响应。减少客户端发送请求的次数

目的:节约网络IO的时间,避免时间浪费。提高整体IO效率

过程图如下:

这种方式在很多网络应用使用,典型的有HTTP2对于HTTP1的升级

三. Redis 发布订阅

3.1 发布订阅的使用

发布订阅模式可以支持多播,假如我们有三个redis客户端c1,c2,c3,都和服务端s1连接。现在有一个客户端c4,c4如何发送一个信息同时告知c1,c2,c3?

这个时候就需要发布订阅:

方式是:

1 s1 s2 s3 通过subscribe 订阅频道 channel。

2 web通过 publish channel message 将message广播所有订阅channel的客户端

3 广播结束后,s1,s2,s3就能接收消息

注意:每一个发布订阅的客户端都需要一个tcp连接管理

具体命令如下:

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

3.2 发布订阅的缺点和使用场景

发布信息的一方只负责发送信息,对方有没有收到我不管。并且如果redis重启之后,我们发布的信息是不会进行持久化的。

即:不确保消息送达,不会持久化消息。

使用场景:

如果我们需要发送一个普通消息,其他用户有没有收到我不管。此时就能使用发布订阅模式

redis集群就使用了发布订阅

如果我们想要确保消息被送达并且能够持久化消息,

可以使用redis中的stream或者使用其他工具比如 kafka消息队列

四. Redis事务

4.1 事务与指令

我们知道,redis单个命令是具有原子性的,一条命令要么被执行,要么不会执行。

如果现在需要执行一个操作,这个操作包含命令 1 2 3 呢?如何保证这些命令的原子性?123要么被完成,要么不执行,不能出现中间状态。

此时就需要使用redis事务:redis单个命令是原子的,多个命令原子需要开启事务

MULTI:开启事务

EXEC:提交事务

DISCARE:关闭事务

WATCH:检查key是否变动,如果变动,回取消这个事务

事务执行过程中,单个命令是入队列操作,直到调用 EXEC 才会一起执行;

操作流程如下:

可以看到,multi本质是开启一个任务队列。

每次执行新命令后,先将命令放入队列

调用dicard后回清空这个命令队列,调用exec提交这个任务队列到客户端执行。

调用了watch,如果检查到key变动,这个事务不执行,返回nil

并且redis服务器执行multi exec提交的命令期间,不会被其他命令打断

注意:redis事务的执行是无法回滚的,如果执行事务期间由于服务器崩溃导致命令中断。一个事务中已经执行的命令不会回滚,未执行的命令之后也不会执行。

4.2 lua实现事务

直接使用multi非常麻烦,实际应用一般都使用lua脚本实现事务。redis服务端启动的时候会加载一个lua虚拟机,用于执行lua脚本。注意lua脚本执行是原子性的,这样就能实现事务

实际应哟我们不会/很少使用multi,使用lua更为方便和快捷。

lua脚本的使用有两种方式

复制代码
# 测试使用
EVAL script numkeys key [key ...] arg [arg ...] 
eval '【Lua脚本代码】' 【键的数量】 【键名1】 【附加参数1】 ...

# 线上使用
EVALSHA sha1 numkeys key [key ...] arg [arg ...] 
evashal '【Lua脚本代码的哈希值】' 【键的数量】 【键名1】 【附加参数1】 ...

测试使用:

用于将某一个key * 2

复制代码
eval 'local key = KEYS[1]; local val = redis.call("get", key);if not val then val = 1 end; redis.call("set", key, val * 2); return val * 2;' 1 score1

分行就是

复制代码
eval 'local key = KEYS[1]; 
local val = redis.call("get", key);
if not val then val = 1 end; redis.call("set", key, val * 2); 
return val * 2;' 
1 score1

注意:和multi一样,lua脚本执行出错了,已经执行的命令不会回滚,未执行的命令不再执行

不过我们线上更多的使用方式是2

线上使用:

首先使用 script load 加载lua并且返回一个哈希值(此时末尾不需要带上我们的key参数)

复制代码
script load 'local key = KEYS[1]; local val = redis.call("get", key);if not val then val = 1 end; redis.call("set", key, val * 2); return val * 2;'

分行

复制代码
script load 'local key = KEYS[1]; 
local val = redis.call("get", key);
if not val then val = 1 end; 
redis.call("set", key, val * 2); return val * 2;' # 末尾是没有score1这个参数的

然后我们就能使用这个哈希值来替代我们的lua脚本。

复制代码
evalsha 74ecc3d632197ba3a1119a65ec55200f42bbb709 1 score1

总结:

eval:

直接向redis中的lua虚拟机发送lua脚本,服务器编译执行命令完毕后向我返回响应。

script load + evalsha:

先向redis发送lua脚本,服务器编译好后不会执行命令。而是保存这个编译程序,然后向我们返回该命令对应的hash值,之后我们通过 evalsha + 哈希值向服务端发送命令。

由于此时该命令已经被编译好了,所以运行速度更快

4.3 Redis事务的acid特性

acid特性指的是:原子性,一致性,隔离性,持久性

原子性:一个事务要么完成,要么失败。redis事务虽然表面上能够保证原子性,但是redis不支持回滚。redis原子性是有问题的

一致性:需要保证数据一致和用户的逻辑一致,redis只能保证数据一致性,对于逻辑一致,一旦出现异常(由于原子性无法保证),逻辑有可能会不一致。redis一致性是有问题的

隔离性:一个事务的操作不会被其他事务打断,由于redis对数据的操作是单线程的。天然具有隔离性。

持久性:保证数据库下线后,数据能够保存在磁盘中,下次重启之后能够读取。redis支持aof持久化和rdb持久化,开启之后就能实现持久性。

相关推荐
augisTrench2 小时前
LatentFlowx是一种非令牌的、状态驱动的推理运行时,旨在通过以下方式降低计算成本并提高可控性
数据库
源代码•宸2 小时前
goframe框架签到系统项目开发(用户认证中间件、实现Refresh-token接口)
数据库·经验分享·后端·算法·中间件·跨域·refreshtoken
建群新人小猿2 小时前
陀螺匠 企业助手-经我审批
服务器·数据库·php
TDengine (老段)2 小时前
TDengine 小白入门指南
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
码农阿豪2 小时前
从 Oracle 到电科金仓:一次性能优化视角下的深度迁移体验
数据库·oracle·性能优化·金仓数据库
txzz88882 小时前
Linux系统db_load命令
数据库·翻译·db_load命令
2401_876221342 小时前
数据库系统概论(第6版)模拟题1
数据库
cike_y2 小时前
Mybatis之分页的实现&日志工厂&Log4j详解
数据库·log4j·mybatis
mixboot2 小时前
navicat配置HTTP 远程连接SQLite数据库
数据库·sqlite