redis笔记一
如果图片显示有问题,欢迎访问我的语雀链接:https://www.yuque.com/u28057058/kfwbwy/hakzvxg0i36a69oc?singleDoc#
redis基本命令
- 连接redis客户端
- 如果报错(error) NOAUTH Authentication required.需要权限验证
- 使用命令AUTH [password] ,password为你设置的redis密码
- 沟通状态,查看命令
- 连接到客户端之后,输入ping,redis返回pong。表示redis能够正常运行。
-
- 切换库命令:select db
- redis默认有16个库,下标0-15。刚进去的时候默认在0库。
- dbsize 查看当前库所有拥有的key数量
- type name : name为key的名字。查看key所存的value的类型
- keys * : * 为匹配任意字符,这个命令的意思是返回当前库所有的key
- ttl :查看key所剩的生命周期。声明周期以秒为单位。
- 返回-1 说明当前key 永不过期
- 返回-2 说明当前key已经过期
Redis对象
Redis Object
redis是键值对存储(key-value),key和value在redis里面都被抽象为对象。
在 Redis 中,键(Key)只能是一个字符串对象,用于唯一标识一个数据项。Redis 中的键是以字节数组的形式存储的,可以是任意长度的字符串(字符串的长度影响底层的编码方式,后面会讲到),但是建议使用较短的字符串作为键,以减少内存占用和提高性能。
值(Value)是 Redis 中存储的数据对象,可以是String、List、Set、Hash、ZSet等多种数据类型。Redis 中的值可以是任意长度的二进制数据,因此可以存储各种类型的数据,包括文本、图片、音频、视频等。
需要注意的是,Redis 中的键和值都是以字节数组的形式存储的,因此在使用时需要进行序列化和反序列化操作。Redis 提供了多种序列化和反序列化方式,包括 JSON、MessagePack、Protobuf 等,可以根据实际需求选择合适的方式。
redis的Object源码结构
- type 字段表示对象的类型,包括字符串、列表、哈希表、集合、有序集合等多种类型。
- encoding 字段表示对象的底层编码方式,使用object encoding [key] 可以看到对应的编码方式
- lru 字段表示对象的最近访问时间,用于实现 Redis 的 LRU 策略。
- refcount 字段表示对象的引用计数,用于实现 Redis 的内存回收机制。
- ptr :内容指针,指向对象的值,可以是字符串、列表、哈希表、集合、有序集合等多种类型的值。
redis实际操作的主要有6个Redis对象,他们底层依赖一些数据结构,包括字符串、跳表、哈希表、压缩
列表、双端链表等,不同对象可能有依赖相同数据结构。接下来我们会一一讲到。
Redis-String
String是什么?
String也就是字符串,他是redis中最常见的的基本数据对象,他最大可存储512MB的数据。但是我们也可以定制他的大小,我们可以通过redis配置项proto-max-bulk-len 来修改它的大小。但是我们一般不会去修改它。
使用场景
一般可以用来存字节数据、文本数据、序列化后的对象数据等。
也就是说只要是字符串,都可以往里存。再具体点的例子:
- 缓存场景,Value存Json字符串等信息
- 计数场景,因为Redis处理命令是单线程,所以执行命令的过程是原子的。因此String数据类型适
合计数场景,比如计算访问次数、点赞、转发、库存数量等等。
常见操作
1. SET
语法:SET key value
功能:设置一个key的值为特定的value,成功则返回OK。
String对象的创建或者更新都是该命令。
Set命令很重要,这里多讲几个扩展参数:
- EX second:设置键的过期时间为多少秒。
- PX millisecond:设置键的过期时间为多少毫秒。
- NX:SET key value NX 命令用于向 Redis 中设置一个键值对,当且仅当该键不存在时才会设置成功。如果键已经存在,则该命令不会执行任何操作。拓展:(可以使用 SET key value NX EX seconds 命令来实现分布式锁。具体来说,可以将 key 参数设置为锁的名称,将 value 参数设置为一个唯一的标识符,将 NX 参数设置为保证原子性,将 EX 参数设置为锁的过期时间。)
- XX:只在键已经存在时,才对键进行设置操作
2. SETNX
SETNX是Redis中的一个常见命令,用于设置键的值,当且仅当键不存在时。下面是SETNX的常见操作:
- 如果键不存在,执行SETNX key value,设置键key的值为value。
- 如果键已经存在,SETNX不会对键进行任何操作,保持键原有的值不变。
- SETNX返回一个整数值,表示操作的结果:如果键被成功设置,返回1;如果键已经存在,返回0。
设置成功:
设置失败:
3. DEL
DEL命令用于删除Redis中的一个或多个键。它的语法如下:
DEL key [key ...]
其中,key是要删除的键的名称。可以一次指定多个键进行删除。
删除单个键:
删除多个键:
- 在第一个示例中,DEL mykey命令将删除键mykey,并返回整数1表示成功删除了一个键。
- 在第二个示例中,DEL key1 key2 key3命令将删除键key1、key2和key3,并返回整数3表示成功删除了三个键。
- 请注意,删除键操作是永久性的,一旦执行DEL命令,键及其对应的值将被立即删除,无法恢复。
4. GET
语法:GET key
功能:查询某个key,存在就返回对应的value,如果不存在返回nil。
5. MGET
语法:MGET key [key....]
功能:一次查询多个key,如果某个key不存在,对应位置返回nil。
底层操作
String底层有三种编码方式,INT,EMBSTR,RAW
- INT编码:可以long表示的整数就以这种编码存储;(非整数类型,比如float类型数据首先会转成字符串,然后判断该字符串的大小是否小于等于阈值字节或者大于阈值字节。小于使用EMBSTR编码,大于使用RAW编码)
- EMBSTR编码:如果字符串小于等于阈值字节,使用EMBSTR编码;
- RAW编码:字符串大于阈值字节,则用RAW编码。
这个阈值字节在源码里是用常量OBJ_ENCODING EMBSTR SIZE LIMIT:来表示,redis3.2版本之前是
39字节,redis3.2版之后是44字节。
EMBSTR和RAW都是由redisObject和SDS两个结构组成,它们的差异在于,EMBSTR下redisObject和
SDS是连续的内存,RAW编码下redisobject和SDS的内存是分开的。
EMBSTR优点是redisObjecti和SDS两个结构可以一次性分配空间,
缺点在于如果重新分配空间,整体都需要再分配,所以EMBSTR设计为只读,任何写操作之后EMBSTR都会变成RAW,理念是发生过修改的字符串通常会认为是易变的。(也因为阈值字节大小的限制,更容易遇到重新分配大小的情况。因为底层实现是连续的内存空间,所以重新分配内存的代价是比较大的,所以综合考虑使用只读模式)
EMBSTR内存结构:
RAW内存结构:
随着我们的操作,编码可能会转换:
- INT->RAW:当存的内容不再是整数,或者大小超过了Iong的时候,
- EMBSTR->RAW:任何写操作之后EMBSTR都会变成RAW,原因前面有解释。
我们注意到,字符串编码EMBSTR和RAW都包含一个结构叫SDS,它是Simple Dynamic String的缩
写,即简单动态字符串,这是Redis内部作为基石的字符串封装,十分重要,下面我们详细介绍下
SDS.
SDS
SDS(Simple Dynamic String)是Redis中用于字符串存储的动态字符串实现。SDS是一种自定义的字符串类型,用于替代C语言中的传统字符串表示。
Redis中SDS分为sdshdr8、sdshdr16、sdshdr32、sdshdr64,它们的字段属性都是一样,区
别在于应对不同大小的字符串,我们以sdshdr8为例:
其中有两个关键字段,
- len字段表示SDS中存储的字符串的字节长度,即字符串占用的内存大小。这个字段的值等于实际存储在buf数组中的字节数。(请注意len不是表示存储字符串的长度,而是实际字符串占用的大小),
- alloc字段表示为字符串分配的实际内存大小,它通常会比字符串的长度(len字段)大,其中包含了一定的预留空间。这个预留空间可以用于未来字符串长度的扩展,以减少频繁的内存重分配操作,提高性能。
- 这两个字段的差值(alloc-len)就是预留空间的大小。
- flags则是标记是哪个分类,比如sdshdr8的分类 #define SDS_TYPE_8 1。
- buf[]为一个字节数组,存储字符串数据。
在redis中字符串的追加和长度计算很常见,所以这两个操作不应该成为性能的瓶颈,所以redis封装了sds字符串结构
- 在redis中怎么进行字符串的追加。使用append命令
- 让我们来根据sds的结构来理解一下redis中字符串的追加操作的步骤
sds的结构
1.增加长度字段len,快速返回长度;
2.增加预留空间(alloc-len),为后续追加数据留余地;
3.不再以'\0'作为判断标准,二进制安全。(传统C语言的字符串会以空字符'\0'作为截断标志,如果我们在字符串中不小心存入一个空字符'\0',那么他就会被C语言当成字符串的结尾从而被截断。这就是二进制不安全。
那么因为在sds中,不在以'\0'作为字符串的结尾标志,而是以len的大小从buf数组里读出len位。所以他是二进制安全。也正是他的这个二进制安全性,使得SDS可以存储任意二进制数据,包括文本字符串和非文本数据
包括文本字符串、图像数据、序列化对象等)
科普一下什么是空字符:
空字符(null character),在C语言中通常表示为\0,是一个特殊的控制字符。它的ASCII码为0,也被称为NUL字符。
空字符并不代表空格或空白位置,而是用于表示字符串的结束标志。在C语言中,字符串是由一系列字符组成的,以空字符作为结尾。空字符告诉程序字符串的结束位置。
空字符在字符串中起到了重要的作用,它标志着字符串的结束,帮助C语言函数正确识别字符串的边界。
在C语言中,字符串通常使用字符数组来表示,以空字符结尾。例如,"Hello"这个字符串实际上是由5个字符组成的,最后以空字符结尾。其存储形式为{'H', 'e', 'l', 'l', 'o', '\0'}。
需要注意的是,空字符是一个不可打印字符,它在字符串中不会显示出来,但它是字符串结束的标志。
这里可能会想,SDS可以预留空间,那么预留空间有多大呢,规则如下:
- len小于1M的情况下,alloc=2倍len,即预留len大小的空间;
- len大于1M的情况下,alloc是1M+len,即预留1M大小的空间.
- 简单来说,预留空间为min(len,1M)



