01- Redis 中的 String 数据类型和应用场景
1. 介绍
String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value 其实不仅是字符串,也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M。
2. 内部实现
String 类型的底层数据结构实现主要是 int 和 SDS(简单动态字符串)。
SDS 和我们认识的 C 字符串不太一样,之所以没有使用 C 语言的字符串表示,因为 SDS 相比于 C 的原生字符串:
-
SDS 不仅可以保存文本数据,还可以保存二进制数据。因为
SDS使用len属性的值而不是空字符串来判断字符串是否结束,并且 SDS 的所有 API 都会以处理二进制的方式来处理 SDS 存放在buf[]数组里的数据。所以 SDS 不光能存放文本数据,而且能保存图片、音频、视频、压缩文件这样的二进制数据。 -
SDS 获取字符串长度的时间复杂度是 O(1)。因为 C 语言的字符串并不记录自身长度,所以获取长度的复杂度为
O(n);而 SDS 结构里使用len属性记录了字符串长度,所以复杂度为O(1)。 -
Redis 的 SDS API 是安全的,拼接字符串不会造成缓冲区溢出。因为 SDS 在拼接字符串之前会检查 SDS 空间是否满足要求,如果空间不够会自动扩容,所以不会导致缓冲区溢出的问题。
字符串对象的内部编码(encoding)有 3 种:int、raw 和 embstr。
如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void*转换成 long),并将字符串对象的编码设置为int。
如果字符串对象保存的是一个字符串,并且这个字符串的长度小于等于 32 字节(Redis 2. + 版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为embstr,embstr编码是专门用于保存短字符串的一种优化编码方式。
如果字符串对象保存的是一个字符串,并且这个字符串的长度大于 32 字节(Redis 2. + 版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为raw。
注意,embstr 编码和 raw 编码的边界在 Redis 不同版本中是不一样的:
-
Redis 2. + 是 32 字节
-
Redis 3.0 - 4.0 是 39 字节
-
Redis 5.0 是 44 字节
可以看到embstr和raw编码都会使用SDS来保存值,但不同之处在于embstr会通过一次内存分配函数来分配一块连续的内存空间来保存redisObject和SDS,而raw编码会通过调用两次内存分配函数来分别分配两块空间来保存redisObject和SDS。Redis 这样做会有很多好处:
-
embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次; -
释放
embstr编码的字符串对象同样只需要调用一次内存释放函数; -
因为
embstr编码的字符串对象的所有数据都保存在一块连续的内存里面可以更好的利用 CPU 缓存提升性能。
但是 embstr 也是有缺点的:
-
如果字符串的长度增加需要重新分配内存时,整个 redisObject 和 SDS 都需要重新分配空间,所以 embstr 编码的字符串对象实际上是只读的,Redis 没有为 embstr 编码的字符串对象编写任何相应的修改程序。当我们对 embstr 编码的字符串对象执行任何修改命令(例如 append)时,程序会先将对象的编码从 embstr 转换成 raw,然后再执行修改命令。
3. 常用指令
普通字符串的基本操作:
# 设置 key-value 类型的值
> SET name liu
OK
# 根据 key 获得对应的 value
> GET name
"liu"
#判断某个 key 是否存在
> EXISTS name
(integer) 1
# 返回 key 所储存的字符串值的长度
> STRLEN name
(integer) 3
# 删除某个 key 对应的值
> DEL name
(integer) 1
批量设置:
# 批量设置 key-value 类型的值
> MSET key1 value1 key2 value2
OK
# 批量获取多个 key 对应的 value
> MGET key1 key2
1) "value1"
2) "value2"
计数器(字符串的内容为整数的时候可以使用)
# 设置 key-value 类型的值
> SET number 0
OK
# 将 key 中储存的数字值增一
> INCR number
(integer) 1
# 将 key 中存储的数字值加 10
> INCRBY number 10
(integer) 11
# 将key 中储存的数字值减一
> DECR number
(integer) 10
# 将 key 中储存的数字值减 10
> DECRBY number 10
(integer) 0
过期(默认为永不过期)
# 设置 key 在 60 秒后过期(该方法是针对已经存在的 key 设置过期时间)
> EXPIRE name 60
(integer) 1
# 查看数据还有多久过期
> TTL name
(integer) 51
# 设置 key-value 类型的值,并设置该 key 的过期时间为 60 秒
> SET key value EX 60
OK
不存在就插入:
# 不存在就插入(not exists)
> SETNX key value
(integer) 1
4. 应用场景
4.1 缓存对象
使用 String 来缓存对象有两种方式:
-
直接缓存整个对象的 JSON,命令例子:
SET user1 '{"name":"a", "age": 18}'。 -
采用将 key 进行分离为 user:Id:属性,采用 MSET 存储,用 MGET 获取各属性值,命令例子:
MSET user:1:name a user:1:age 18 user:2:name b user:2:age 20。
4.2 常规计数
因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场景,比如计算访问次数、点赞、转发、库存数量等等。
比如计算文章的阅读量:
# 初始化文章的阅读量
> SET aritcle:readcount:1001 0
OK
# 阅读量 +1
> INCR aritcle:readcount:1001
(integer) 1
# 阅读量 +1
> INCR aritcle:readcount:1001
(integer) 2
# 阅读量 +1
> INCR aritcle:readcount:1001
(integer) 3
# 获取对应文章的阅读量
> GET aritcle:readcount:1001
"3"
4.3 分布式锁
SET 命令有个 NX 参数可以实现【key 不存在才插入】,可以用它来实现分布式锁:
-
如果 key 不存在,则显示插入成功,可以用来表示加锁成功;
-
如果 key 存在,则会显示插入失败,可以用来表示加锁失败。
一般而言,还会对分布式锁加上过期时间,分布式锁的命令如下:
SET lock_key unique_value NX PX 10000
-
lock_key 就是 key 键;
-
unique_value 是客户端生成的唯一的标识;
-
NX 代表只在 lock_key 不存在时,才对 lock_key 进行设置操作;
-
PX 10000 表示设置 lock_key 的过期时间为 10s,这是为了避免客户端发生异常而无法释放锁。
而解锁的过程就是将 lock_key 键删除,但不能乱删,要保证执行操作的客户端就是加锁的客户端。所以,解锁的时候,我们要判断锁的 unique_value 是否为加锁客户端,是的话,才将 lock_key 键删除。
可以看到,解锁是有两个操作,这时就需要 Lua 脚本来保证解锁的原子性,因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,保证了锁释放操作的原子性。
// 释放锁时,先比较 unique_value 是否相等,避免锁的误释放
if redis.call("get",KEYS[1] == ARGV[1]) thenreturn redis.call("del",KEYS[1])
elsereturn 0
end
这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。
4.4 共享 Session 信息
通常我们在开发后台管理系统时,会使用 Session 来保存用户的会话(登录)状态,这些 Session 信息会被保存在服务器端,但这只适合于单系统应用,如果是分布式系统此模式将不再适用。
例如用户一的 Session 信息被存储在服务器一,但第二次访问时用户一被分配到服务器二,这个时候服务器并没有用户一的 Sesison 信息,就会出现需要重复登录的问题,问题在于分布式系统每次会把请求随机分配到不同的服务器。
因此,我们需要借助 Redis 对这些 Session 信息进行统一的存储和管理,这样无论请求发送到哪台服务器,服务器都会去同一个 Redis 获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。
相关文章:
01- Redis 中的 String 数据类型和应用场景
1. 介绍 String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value 其实不仅是字符串,也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M。 2. 内部实现 Str…...
Android音频焦点
什么是音频焦点? 音频焦点是 API 8 中引入的一个概念。它用于传达这样一个事实:用户一次只能专注于一个音频流,例如收听音乐或播客,但不能同时关注两者。在某些情况下,多个音频流可以同时播放,但只有一个是…...
Docker安全配置
Docker安全及日志管理 文章目录 Docker安全及日志管理资源列表基础环境一、Docker安全相关介绍1.1、Docker容器与虚拟机的区别1.1.1、隔离与共享1.1.2、性能与损耗 1.2、Docker存在的安全问题1.2.1、Docker自身漏洞1.2.2、Docker源码问题 1.3、Docker架构缺陷与安全机制1.3.1、…...
文件上传之使用一个属性接收多个文件
在开发过程中,可能遇到这样的业务:文件上传时个数不定,这样我们不能枚举出所有的文件name,这种情况下我们可以使用一个name将所有的文件接收下来; html代码 <!DOCTYPE html> <html lang"en"> …...
chat4-Server端保存聊天消息到mysql
本文档描述了Server端接收到Client的消息并转发给所有客户端或私发给某个客户端 同时将聊天消息保存到mysql 服务端为当前客户端创建一个线程,此线程接收当前客户端的消息并转发给所有客户端或私发给某个客户端同时将聊天消息保存到mysql 本文档主要总结了将聊天…...
vivo鄢楠:基于OceanBase 的降本增效实践
在3 月 20 日的2024 OceanBase 数据库城市行中,vivo的 体系与流程 IT 部 DBA 组总监鄢楠就“vivo 基于 OceanBase 的降本增效实践”进行了主题演讲。本文为该演讲的精彩回顾。 vivo 在1995年于中国东莞成立,作为一家全球领先的移动互联网智能终端公司&am…...
arm cortex-m架构 SVC指令详解以及其在freertos的应用
1. 前置知识 本文基于arm cortex-m架构描述, 关于arm cortex-m的一些基础知识可以参考我另外几篇文章: arm cortex-m 架构简述arm异常处理分析c语言函数调用规范-基于arm 分析 2 SVC指令 2.1 SVC指令位域表示 bit15 - bit12:条件码&#…...
k8s笔记——kubernetes中的三种IP
kubernetes概念 Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控 Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行 Pod:kubernetes的…...
Golang | Leetcode Golang题解之第127题单词接龙
题目: 题解: func ladderLength(beginWord string, endWord string, wordList []string) int {wordId : map[string]int{}graph : [][]int{}addWord : func(word string) int {id, has : wordId[word]if !has {id len(wordId)wordId[word] idgraph a…...
微服务中feign远程调用相关的各种超时问题
1. 引言 在spring cloud微服中,feign远程调用可能是大家每天都接触到东西,但很多同学却没咋搞清楚这里边的各种超时问题,生产环境可能会蹦出各种奇怪的问题。 首先说下结论: 1)只使用feign组件,不使用ribbion组件&…...
springboot整合chatgpt,并且让其可以记录上下文
整合很简单,不过需要几个小条件 1.必须要有openai官方的key 2.国内需要有代理服务器或者国外的服务器把项目部署出去也没问题 我没有使用spring的springAI,听说很方便,日后有机会去体验体验,我今天用了两种方式整合了gpt 1.Ch…...
CTP前端:解码数字世界的魔法师
CTP前端:解码数字世界的魔法师 CTP前端,一个充满神秘与魅力的职业,他们在数字世界中挥舞着魔法棒,创造着令人惊叹的奇迹。那么,CTP前端究竟是做什么的呢?让我们从四个方面、五个方面、六个方面和七个方面&…...
rabbitmq的交换机类型以及他们的区别
RabbitMQ中有四种主要的交换机类型,它们是:Direct,Topic,Fanout,Headers。 Direct(直连交换机):接收到消息后,会将消息发送到与消息的routing key完全匹配的队列上。Dire…...
理解不同层的表示(layer representations)
在机器学习和深度学习领域,特别是在处理音频和自然语言处理(NLP)任务时,"层的表示"(layer representations)通常是指神经网络不同层在处理输入数据时生成的特征或嵌入。这些表示捕获了输入数据的…...
原生js访问http获取数据的方法
在原生JavaScript中,直接通过浏览器端的JavaScript访问HTTP接口获取数据通常涉及XMLHttpRequest对象或现代的fetch API。 1. 使用XMLHttpRequest XMLHttpRequest是一个老旧的API,但在某些情况下仍然很有用。以下是一个简单的例子: javascr…...
Windows 2000 Server:安全配置终极指南
"远古技术,仅供娱乐" 💭 前言:Windows 2000 服务器在当时的市场中占据了很大的比例,主要原因包括操作简单和易于管理,但也经常因为安全性问题受到谴责,Windows 2000 的安全性真的那么差吗&#x…...
基于 FastAI 文本迁移学习的情感分类(93%+Accuracy)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…...
集成Google Authenticator实现多因素认证(MFA)
目录 参考1、应用背景2、多因素认证3、谷歌google authenticator集成用法3.1、原理3.2、 MFA绑定3.2.1、 用户输入用户名密码登录3.2.2、检查是否已经绑定MFA(检查数据库是否保存该用户的google secret)3.2.3、谷歌身份证认证器扫描绑定3.2.4、手动测试验…...
网关(Gateway)- 自定义过滤器工厂
自定义过滤工厂类 DemoGatewayFilterFactory package com.learning.springcloud.custom;import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChai…...
HTML静态网页成品作业(HTML+CSS)—— 香奈儿香水介绍网页(1个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
