【中间件开发】Redis基础命令详解及概念介绍

文章目录

  • 前言
  • 一、Redis相关命令详解及原理
    • 1.1 string、set、zset、list、hash
      • 1.1.1 string
      • 1.1.2 list
      • 1.1.3 hash
      • 1.1.4 set
      • 1.1.5 zset
    • 1.2 分布式锁的实现
    • 1.3 lua脚本解决ACID原子性
    • 1.4 Redis事务的ACID性质分析
  • 二、Redis协议与异步方式
    • 2.1 Redis协议解析
      • 2.1.1 redis pipeline
      • 2.1.2 Redis协议图
    • 2.2 特殊协议操作-订阅发布
    • 2.3 异步redis协议
      • 2.3.1 hiredis + libevent
  • 总结


前言

本文介绍了Redis相关命令以及Redis当中的一些概念(协议)。


一、Redis相关命令详解及原理

内存是稀缺资源,所以:

  1. 当数据量少时,存储效率高为主
  2. 当数据量多时,运行速度快为主

1.1 string、set、zset、list、hash

  1. string 是一个安全的二进制字符串(兼容’\0’作为分隔符,安全指按长度);
  2. 双端队列 (链表) list :有序(插入有序);
  3. 散列表 hash:对顺序不关注,field 是唯一的;
  4. 无序集合 set:对顺序不关注,里面的值都是唯一的;
  5. 有序集合 zset :对顺序是关注的,里面的值是唯一的;根据 member 来确定唯一;根据 score 来 确定有序;

1.1.1 string

set key_test 1000get key_test# 原子减一
decr key_test
decrby key_test decrement(一个数字)# 原子加一
incr key_test
incrby key_test increment# set Not exist,当key_test存在时,什么也不做,否则等同于set
setnx key_test value
del key_test----------
# 
setbit key_test offset value
# 第offset位设置为value
getbit key_test offset
# 统计字符串被设置为1的bit数
bitcount key_test
----------

image.png

image.png
image.png

应用

  1. 对象存储:set,get
  2. 累加器:incr
  3. 分布式锁:setnx
  4. 位运算:setbit,getbit,bitcount

1.1.2 list

双向链表,首尾操作时间复杂度O(1);中间元素操作O(n)

  1. list.size < 48 不压缩
  2. 元素压缩前后长度差不超过8,不压缩

为什么压缩?如何压缩的?

# 从队列左侧入队
lpush key value ...
lpop key# 从队列右侧入队
rpush key value ...
rpop key # 尾索引
lrange key start end# 从存于 key 的列表里移除前 count 次出现的值为 value 的元素
lrem key count value# rpop的阻塞版本
brpop key timeout

image.png

应用

  1. 栈:lpush + lpop
  2. 队列:lpush + rpop
  3. 阻塞队列:lpush + brpop
  4. 异步消息队列
    1. 操作和队列一样,但是在不同系统间;生产者和消费者;
  5. 获取固定窗口记录
    1. ltrim key 0 4 保留最近5条记录

1.1.3 hash

散列表;C++ unordered_map

(节点数量 > 512 || 所有字符串长度 > 64) 采用dict
(节点数量 <= 512 || 所有字符串长度 < 64) 采用ziplist

hget key field
hgetallhset key field value
# 设置多个键值对
hmset key field1 value1 field2 value2 field3 value3 ... fieldn valuenhmget key field1 field2 ...hincrby key field increment
# 获取有多少个键值对
hlen keyhdel key field

image.png

应用

  1. 存储对象
  2. 购物车:商品列表用list,其中属性用hash

1.1.4 set

无序集合

(元素都为整数 && 节点数量 <= 512) 采用整数数组存储
(元素不全为整数 || 节点数量 > 512) 采用字典存储

# 添加一个或多个
sadd key member ...
# 计算集合元素个数
scard keysmembers key
# 返回成员member是否为key的成员
sismember key member
# 随机返回key集合中的一个或多个元素
srandmember key [count]
# 移除一个随机元素
spop key [count]
# 返回差集
sdiff key [key...]
# 返回交集
sinter key [key...]
# 返回并集
sunion key [key...]

image.png

应用

  1. 抽奖:srandmember
  2. 共同关注:sdiff ; sinter; sunion

1.1.5 zset

有序集合;实现排行榜;有序唯一


zadd key 
# 从key中删除member的键值对
zrem key member [member...]
# 返回有序集key中member的score值
zscore key member
# 成员member的score值加上增量
zincrby key increment member
# 返回个数
zcard key
# 返回排名
zrank key member
# 返回指定范围的元素
zrange key start stop
# 返回指定范围的元素(逆序)
zrevrange key start stop

image.png

应用

  1. 百度热榜
  2. 延时队列
  3. 分布式定时器
  4. 时间窗口限流

1.2 分布式锁的实现

释放锁操作:事务操作

锁:谁持有,谁释放

get dislock
-- 释放锁
local uuid = redis.call("get", KEYS[1])
if uuid == KEYS[2] thenredis.call("del", KEYS[1])
end

1.3 lua脚本解决ACID原子性

# 开启事务
multi# 提交事务
exec# 取消事务
discard# 检测key的变动
watch实际中是使用lua脚本
  • redis 中加载了一个 lua 虚拟机;用来执行 redis lua 脚本;
  • redis lua 脚本的执行是原子性的;
  • 当某个脚本正在执行的时候,不会有其他命令或者脚本被执行;
  • lua 脚本当中的命令会直接修改数据状态;
  • lua 脚本 mysql 存储区别:MySQL存储过程不具备事务性,所以也不具备原子性;

注意:如果项目中使用了 lua 脚本,不需要使用上面的事务命令
image.png

1.4 Redis事务的ACID性质分析

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

  • C 一致性;事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测;这里 的一致性是指预期的一致性而不是异常后的一致性;所以 redis 也不满足;这个争议很大:redis 能 确保事务执行前后的数据的完整约束;但是并不满足业务功能上的一致性;比如转账功能,一个扣 钱一个加钱;可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功;系统凭空多了 钱;

set zhang 1000
lpush zhang 1 3 4 #error
get mark
  • I 隔离性;各个事务之间互相影响的程度;redis 是单线程执行,天然具备隔离性;

  • D 持久性;redis 只有在 aof 持久化策略的时候,并且需要在 appendfsync=always 才具备持久性;实际项目中几乎不会使用 redis.conf 中 aof 持久化策略;

  • 面试时候回答:lua 脚本满足原子性和隔离性;一致性和持久性不满足;

get zhang ==>100set zhang 200

如果这两个命令没有作为一个整体,那么可以会有另一条连接set。这将导致数据不一致。

什么时候探讨事务?多条并发连接
什么时候探讨原子操作?多核

二、Redis协议与异步方式

2.1 Redis协议解析

2.1.1 redis pipeline

redis pipeline 是一个客户端提供的机制,而不是服务端提供的;

注意:pipeline 不具备事务性;

目的:节约网络传输时间;

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

image.png

2.1.2 Redis协议图

image.png

上图描述了如何界定数据包:

  1. 长度 + 二进制流
  2. 二进制流 + 特殊分割符

2.2 特殊协议操作-订阅发布

为了支持消息的多播机制,redis引入了发布订阅:发送者发送消息,订阅者接收消息。

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

应用

  1. 发布订阅可以收到redis主动推送的内容
  2. 项目中支持发布订阅,需要另开一条连接

缺点

  1. 生产者传递来一条消息,redis找到相应的消费者并传递过去,如果没有消费者,消息丢弃;
  2. 如果有两个消费者,此时其中一个消费者挂掉了,重连上来将不会接收到该消息;
  3. redis停机重启,发布订阅的消息不会持久化。

2.3 异步redis协议

同步连接方案采用阻塞IO来实现
优点:代码书写是同步的,业务逻辑不割裂
缺点:阻塞当前线程,直到返回结果,通常需要多个线程来实现线程池来解决效率问题。

异步连接方案采用非阻塞IO来实现
优点:不阻塞当前线程,redis没有返回,可以继续向redis发送命令
缺点:代码书写是异步的,业务逻辑割裂,可以通过协程解决(skynet,openresty)

2.3.1 hiredis + libevent

我们需要做的事情:
适配

  1. 事件对象
  2. 事件操作函数

hiredis需要做:

  1. 协议解析
  2. 读写事件
  3. 缓冲区操作
  4. 协议加密等

适配事件对象和函数。

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 bufferre->e.in = NULL;re->e.out = NULL;re->mask = 0;ac->ev.addRead = redisAddRead;ac->ev.delRead = redisDelRead;ac->ev.addWrite = redisAddWrite;ac->ev.delWrite = redisDelWrite;ac->ev.cleanup = redisCleanup;ac->ev.data = re;return REDIS_OK;
}

总结

本文介绍了Redis的基本命令以及Redis协议中的部分内容。Redis是内存型数据库,围绕着内存的特性,Redis结合了lua脚本,分布式锁(最快的),异步连接等一系列特性。

参考链接:
https://github.com/0voice

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

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

相关文章

【WRF理论第十三期】详细介绍 Registry 的作用、结构和内容

目录 1. Introduction&#xff1a;介绍 Registry 的作用和功能。2. Registry Contents&#xff1a;详细描述 Registry 的结构和内容&#xff0c;包括各个部分的条目类型。2.1. DIMSPEC ENTRIES&#xff08;维度规格条目&#xff09;2.2. STATE ENTRIES&#xff08;状态变量条目…

计算机键盘简史 | 键盘按键功能和指法

注&#xff1a;本篇为 “计算机键盘简史 | 键盘按键功能和指法” 相关文章合辑。 英文部分机翻未校。 The Evolution of Keyboards: From Typewriters to Tech Marvels 键盘的演变&#xff1a;从打字机到技术奇迹 Introduction 介绍 The keyboard has journeyed from a humb…

Java版-图论-拓扑排序与有向无环图

拓扑排序 拓扑排序说明 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列…

LeetCode 0935.骑士拨号器:动态规划(DP)

【LetMeFly】935.骑士拨号器&#xff1a;动态规划(DP) 力扣题目链接&#xff1a;https://leetcode.cn/problems/knight-dialer/ 象棋骑士有一个独特的移动方式&#xff0c;它可以垂直移动两个方格&#xff0c;水平移动一个方格&#xff0c;或者水平移动两个方格&#xff0c;垂…

String【Redis对象篇】

&#x1f3c6; 作者简介&#xff1a;席万里 ⚡ 个人网站&#xff1a;https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜&#xff0c;同时略懂Vue与React前端技术&#xff0c;也了解一点微信小程序开发。 &#x1f37b; 对计算机充满兴趣&#xff0c;愿意并且希望学习更多的技…

生成SSH秘钥文件

git生成文件命令 # 配置用户名和邮箱 git config --global user.name "你的GitHub用户名" git config --global user.email "你的GitHub邮箱"# 生成ssh-key ssh-keygen -t rsa -C “你的GitHub邮箱" # 验证 ssh -T gitgithub .com 第一步&#xff1a;…

mac删除程序坞(Dock)中“无法打开的程序“

参考&#xff1a; Mac删除软件之后图标还在怎么办&#xff1f;https://blog.csdn.net/weixin_46500474/article/details/124284161Mac程序坞中软件删除出现残留“&#xff1f;”图标无法删除解决方法&#xff1a; https://blog.csdn.net/shenwenhao1990/article/details/12865…

前端学习笔记-Vue篇-03

3、使用Vue脚手架 Home | Vue CLI 3.1 具体步骤 第一步(仅第一次执行):全局安装vue/cli npm install -g vue/clie第二步:切换到你要创建项目的目录&#xff0c;然后使用命令创建项目 vue create xxxx第三步:启动项目npm run serve 3.2 脚手架项目的结构 ----…

Ubuntu上使用system()函数运行不需要输入密码

使用system()运行一些终端命令的时候&#xff0c;需要sudo权限&#xff0c;也就是必须输入密码&#xff0c;那么在程序自启动的时候就无法成功启动。如果设置Ubuntu下所有操作都不需要密码&#xff0c;安全性太低&#xff0c;所以我们可以将需要用到的终端指令给予无需输入密码…

学习记录:js算法(一百一十九):网络延迟时间

文章目录 网络延迟时间思路一 网络延迟时间 有 n 个网络节点&#xff0c;标记为 1 到 n。 给你一个列表 times&#xff0c;表示信号经过 有向 边的传递时间。 times[i] (ui, vi, wi)&#xff0c;其中 ui 是源节点&#xff0c;vi 是目标节点&#xff0c; wi 是一个信号从源节点…

嵌入式硬件-- 元器件焊接

1.锡膏的使用 锡膏要保存在冰箱里。 焊接排线端子&#xff1b;138度的低温锡&#xff08;锡膏&#xff09;&#xff0c; 第一次使用&#xff0c;直接拿东西挑一点涂在引脚上&#xff0c;不知道多少合适&#xff0c;加热台加热到260左右&#xff0c;放在上面观察锡融化&#…

Cocos Creator 开发微信小游戏分包

作为以后端选手,吭哧吭哧的好不容易用cocos开发了一款小游戏, 上传的时候发现包太大了,主包超过4M; 我不是选小游戏分包了吗? 怎么还超? 分包的方案: 功能裁剪资源压缩主包迁移WASM分离 1. 功能裁剪 项目设置中引擎管理器中 功能裁剪里面有很多个引擎,我们剔除掉没用的引…

华为eNSP实验:VRRP基本配置

VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;是一种网络冗余协议&#xff0c;旨在提高网络的可靠性和容错能力。VRRP通过把几台路由设备联合组成一台虚拟的路由设备&#xff0c;将虚拟路由设备的IP地址作为用户的默认网关实现与外部网络通信。 实验拓扑&a…

axi can ip相关笔记

1&#xff0c;can_clk最大24m&#xff0c;最后用的24m 2&#xff0c;axi总线不超过100m&#xff0c;且大于can_clk&#xff0c;最后用的100m 结构如下&#xff1a; 3&#xff0c;axi can ip需要专门的license&#xff0c;否则会导致不能生成bitstream 4&#xff0c;编…

单臂路由配置

知识点 单臂路由指在路由器上的一个接口配置子接口&#xff08;逻辑接口&#xff09;来实现不同vlan间通信 路由器上的每个物理接口都可以配置多个子接口&#xff08;逻辑接口&#xff09; 公司的财务部、技术部和业务部有多台计算机&#xff0c;它们使用一台二层交换机进行互…

STM32F103单片机使用STM32CubeMX创建IAR串口工程

打开stm32cubeMX&#xff0c;选择新建工程 输入单片机型号&#xff0c;在下面选中具体型号&#xff0c;然后点右上角 开始工程 第一步设置 调试接口&#xff0c;否则生成的工程就会下载不到单片机中&#xff0c;使用stlink或者jlink的话&#xff0c;在debug选项中直接选择ser…

【笔记】分布式任务调度平台XXL-JOB

这篇笔记主要记录以下内容&#xff1a; &#xff08;1&#xff09;第一次启动xxl-job的过程 &#xff08;2&#xff09;模块、文件、数据库&#xff08;表和字段&#xff09;的作用 &#xff08;3&#xff09;极少的源码解读&#xff08;XxlJobConfig&#xff09; 有点像实…

hbuilder 安卓app手机调试中基座如何设置

app端使用基座 手机在线预览功能 1.点击运行 2.点击运行到手机或者模拟器 3.制作自定义调试基座 4.先生成证书【可以看我上一篇文档写的有】&#xff0c;点击打包 5.打包出android自定义调试基座【android_debug.apk】,【就跟app打包一样需要等个几分钟】 6.点击运行到手…

uniapp中父组件传参到子组件页面渲染不生效问题处理实战记录

上篇文件介绍了,父组件数据更新正常但是页面渲染不生效的问题,详情可以看下:uniapp中父组件数组更新后与页面渲染数组不一致实战记录 本文在此基础上由于新增需求衍生出新的问题.本文只记录一下解决思路. 下面说下新增需求方便理解场景: 商品信息设置中添加抽奖概率设置…

零基础学安全--Burp Suite验证码识别以及爆破

目录 学习连接 本次文章直接以例子来讲解 正式开始 插件安装 抓取验证码脚本下载 识别验证码脚本下载 将插件导入到BP中 开始识别 目标寻找 验证码连接获取 运行.pyt文件 BP抓取加载验证码的数据包&#xff0c;就是如下数据包观察以下和那个验证码连接​编辑 将包发…