【中间件开发】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 1000

get 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
hgetall

hset key field value
# 设置多个键值对
hmset key field1 value1 field2 value2 field3 value3 ... fieldn valuen

hmget key field1 field2 ...

hincrby key field increment
# 获取有多少个键值对
hlen key

hdel key field

image.png

应用

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

1.1.4 set

无序集合

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

# 添加一个或多个
sadd key member ...
# 计算集合元素个数
scard key

smembers 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] then
	redis.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 ==>100

set 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 buffer
    re->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

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

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

相关文章

运输层4——TCP格式(重点!)

目录 一、TCP报文段格式 二、最大报文长度 MSS 一、TCP报文段格式 长度&#xff1a;前20个字节固定 后4n个字节&#xff08;报文段格式不固定&#xff09; 1、源端和目的端&#xff1a;各2个字节 作用&#xff1a;指明TCP链接的发送 2、序号 4字节 作用&#xff1…

「Mac玩转仓颉内测版46」小学奥数篇9 - 基础概率计算

本篇将通过 Python 和 Cangjie 双语实现基础概率的计算&#xff0c;帮助学生学习如何解决简单的概率问题&#xff0c;并培养逻辑推理和编程思维。 关键词 小学奥数Python Cangjie概率计算 一、题目描述 假设有一个袋子中有 5 个红球和 3 个蓝球&#xff0c;每次从袋子中随机…

从变更到通知:使用Python和MongoDB Change Streams实现即时事件监听

MongoDB提供了一种强大的功能&#xff0c;称为Change Streams&#xff0c;它允许应用程序监听数据库中的变更事件&#xff0c;并在数据发生变化时立即做出响应。这在mysql数据库是不具备没有这个功能的。又如&#xff1a;我们在支付环节想一直监听支付回调的状态&#xff0c;就…

决策树:ID3、C4.5和CART特征选择方式

1 前言 该文章主要目的是记录ID3、C4.5和CART特征选择方式&#xff0c;这里只对决策树进行简单介绍。 决策树&#xff08;Decision Tree&#xff09;算法是一种有监督学习算法&#xff0c;它利用分类的思想&#xff0c;根据数据的特征构建数学模型&#xff0c;从而达到数据的筛…

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别 一、背景 财务数据是指企业经营活动和财务结果的数据记录&#xff0c;反映了企业的财务状况 与经营成果。对行业、企业的财务数据进行分析&#xff0c;就是要评价其过去的经营业绩、 衡量现在的财务状况、预测…

UE5.5 Geometry库平面切割原理分析

平面切割--FMeshPlaneCut 平面定义: 面上一个点 法线 算法流程如下 求几何体所有顶点和面的有向距离(Signs) Sign计算&#xff1a; float Sign (VertexPos - PlaneOrigin).Dot(PlaneNormal); 遍历所有几何体所有交叉边, 进行SplitEdge 对于位于切割面两侧的交叉边(Sign…

【计算机学习笔记】GB2312、GBK、Unicode等字符编码的理解

之前编写win32程序时没怎么关注过宽字符到底是个啥东西&#xff0c;最近在编写网络框架又遇到字符相关的问题&#xff0c;所以写一篇文章记录一下&#xff08;有些部分属于个人理解&#xff0c;如果有错误欢迎指出&#xff09; 目录 几个常见的编码方式Unicode和UTF-8、UTF-16、…

CSS 快速上手

目录 一. CSS概念 二. CSS语法 1. 基本语法规范 2. CSS的三种引入方式 (1) 行内样式 (2) 内部样式表 (3) 外部样式表 3. CSS选择器 (1) 标签选择器 (2) 类选择器 (3) id选择器 (4) 通配符选择器 (5) 复合选择器 <1> 空格 <2> 没有空格 <3> &q…

【时间之外】IT人求职和创业应知【60】-卡脖子

目录 新闻一&#xff1a;达成合作&#xff0c;将在中国推出生成式人工智能服务 新闻二&#xff1a;机器人新赛道 新闻三&#xff1a;简化用户信息获取流程&#xff0c;提升小程序体验 去年人口出生下降&#xff0c;3年以后&#xff0c;幼儿园要关闭很多&#xff0c;6年以后小…

centos9升级OpenSSH

需求 Centos9系统升级OpenSSH和OpenSSL OpenSSH升级为openssh-9.8p1 OpenSSL默认为OpenSSL-3.2.2&#xff08;根据需求进行升级&#xff09; 将源码包编译为rpm包 查看OpenSSH和OpenSSL版本 ssh -V下载源码包并上传到服务器 openssh最新版本下载地址 wget https://cdn.openb…

node.js中实现GETPOST请求

创建基本的服务器 const express require(express); const indexRouter require(./router); // 引入路由 const app express(); const port 3000; // 挂载路由 app.use(/api, indexRouter); app.listen(port, () > {console.log(Server is running on http://localhost…

shell 条件测试

一、命令执行结果判定 && &#xff1a; 在命令执行后如果没有任何报错时会执行符号后面的动作 || &#xff1a; 在命令执行后有报错执行符号后的动作 [rootlong ~]# a10 [rootlong ~]# echo $a 10 [rootlong ~]# [ $a -gt "5" ] && echo yes || e…

JS中的原型链与继承

原型链的类比 JS中原型链&#xff0c;本质上就是对象之间的关系&#xff0c;通过protoype和[[Prototype]]属性建立起来的连接。这种链条是动态的&#xff0c;可以随时变更。 这个就跟C/C中通过指针建立的关系很相似&#xff0c;比如&#xff0c;通过指针建立一个链表&#xf…

【Linux网络编程】第七弹---构建类似XShell功能的TCP服务器:从TcpServer类到主程序的完整实现

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、TcpServer.hpp 1.1、TcpServer类基本结构 1.2、 Execute() 2、Command.hpp 2.1、Command类基本结构 …

C语言控制语句与案例

控制语句与案例 1. 选择结构 1.1 if 语句 if 语句用于根据条件执行不同的代码块。最基本的语法形式如下&#xff1a; // 单分支 if (条件) {// 条件为真时执行的代码 }// 双分支 if (条件) {// 条件为真时执行的代码 } else {// 条件为假时执行的代码 }// 多分支 if (条件1…

【分子材料发现】——GAP:催化过程中吸附构型的多模态语言和图学习(数据集处理详解)(二)

Multimodal Language and Graph Learning of Adsorption Configuration in Catalysis https://arxiv.org/abs/2401.07408Paper Data: https://doi.org/10.6084/m9.figshare.27208356.v2 1 Dataset CatBERTa训练的文本字符串输入来源于Open Catalyst 2020 &#xff08;OC20…

SpringBoot自动配置底层核心源码

SpringBoot底层核心源码 一、工程创建二、进一步改造三、自动配置 探究SpringBoot的自动配置原理&#xff0c;我们可以自己写一个启动类的注解。 一、工程创建 首先创建一个工程&#xff0c;工程目录如下&#xff1a; 自定义一个启动函数&#xff1a; package org.springboo…

【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之后端环境搭建

【Springboot3vue3】从零到一搭建Springboot3vue3前后端分离项目&#xff0c;整合knef4j和mybaits实现基础用户信息管理 后端环境搭建1.1 环境准备1.2 数据库表准备1.3 SpringBoot3项目创建1.4 MySql环境整合&#xff0c;使用druid连接池1.5 整合mybatis-plus1.5.1 引入mybatie…

【书生大模型实战营】Linux 基础知识-L0G1000

前言&#xff1a;书生大模型实战营是上海人工智能实验室开展的大模型系列实践活动&#xff0c;提供免费算力平台&#xff0c;学员通过闯关式任务&#xff0c;可获得免费算力和存储&#xff0c;助力项目实践。本期是第4期&#xff0c;时间从十一月份开始&#xff0c;持续到十二月…

JS进阶DAY3|事件(二)事件流

目录 一、事件流说明 1.1 事件流概念 1.2 事件捕获阶段 1.3 事件冒泡阶段 二、事件传播的两个阶段说明 2.1 事件捕获 2.2 事件冒泡 3.3 示例代码 三、阻止冒泡 四、事件解绑 4.1 removeEventListener方法 4.2 使用 DOM0 级事件属性 4.3 使用一次性事件监听器 一、…