一、数据结构与内部编码¶
1.1 全局命令¶
Redis有5种数据类型,它们是键值对中的值,对于键来说有一些通用的命令。我们可以通过 dis.cn/commands.html 查看redis的命令。
查看当前库所有key,时间复杂度是O(n)
keys *
键总数,时间复杂度是O(1)
dbsize
检查键是否存在,如果键存在则返回1,不存在则返回0
exists key
127.0.0.1:6379> exists java
(integer) 1
127.0.0.1:6379> exists not_exist_key
(integer) 0
删除键
del key [key ...]
unlink key #非阻塞,可用版本>= 4.0.0
键过期
expire key seconds
ttl key #查看key还有多少秒过期,-1表示没设置过期时间,-2表示不存在
键的数据结构类型
type key
其他命令
select 1 #切换数据库
flushdb #清空当前库
flushall #清空全部库
rename key newkey #键重命名
randomkey #随机返回一个键
1.2 内部编码¶
type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、hash(哈希)、list (列表)、set(集合)、zset(有序集 合),但这些只是Redis对外的数据结构。
查看内部编码
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> object encoding mylist
"ziplist"
这样设计的优势:
-
改进内部编码,对外的数据结构和命令没有影响
-
多种内部编码实现可以在不同场景下发挥各自的优势

1.3 内存模型¶


1、dictEntry,每个键值对都对应一个dictEntry,里面存储了指向Key和Value的指针,next指向下一个dictEntry,与本Key-Value无关。
2、Key:左上角可见,Key(“hello”)并不是直接以字符串存储,而是存储在SDS结构中,但是这个SDS是一个指定长度的,没有空闲空间的sds。
3、redisObject:Value(“world”)既不是直接以字符串存储,也不是像Key一样直接存储在SDS中,而是存储在redisObject中。实际上,不论Value是5种类型的哪一种,都是通过RedisObject来存储的。
redisObject数据结构:
typedef struct redisObject{
//用于表示存储的对象类型
unsigned type:4;
//数据结构的编码
unsigned encoding:4;
//LRU策略
unsigned lru:LRU_BITS;
//引用次数
int refcount;
//指针,指向具体的数据类型
void *ptr;
}
二、常用五大数据类型¶
string,hash,list,set,zset
2.1 String¶
-
String类型是Redis最基本的数据类型
-
value可以是字符串、数字、二进制
-
值最大不能超过512MB
常用命令-单个键值
设置的单个键值
set key value [ex seconds] [px milliseconds] [nx|xx]
-
ex seconds:为键设置秒级过期时间。
-
px milliseconds:为键设置毫秒级过期时间。
-
nx:键必须不存在,才可以设置成功,用于添加。
-
xx:与nx相反,键必须存在,才可以设置成功,用于更新
setex 和 setnx
setex key seconds value
setnx key value
127.0.0.1:6379> setnx hello redis # 因为键redis已存在,所以setnx失败,返回结果为0
(integer) 0
获取值
get key
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> get aaa
(nil)
计数
incr key
-
值不是整数,返回错误。
-
值是整数,返回自增后的结果。
-
键不存在,按照值为0自增,返回结果为1
除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、 decrby(自减指定数字)、 incrbyfloat(自增浮点数)
-
decr key
-
incrby key increment
-
decrby key decrement
-
incrbyfloat key increment
示例
127.0.0.1:6379> get counter
"2"
127.0.0.1:6379> incr counter
(integer) 3
127.0.0.1:6379> get counter
"3"
127.0.0.1:6379> incrby counter 100
(integer) 103
127.0.0.1:6379> get counter
"103"
127.0.0.1:6379> decr counter
(integer) 102
其他命令
(1)追加值
append <key> <value> #将给定的<value>追加到原值的末尾
127.0.0.1:6379> get key
"redis"
127.0.0.1:6379> append key world
(integer) 10
127.0.0.1:6379> get key
"redisworld"
(2)字符串长度
strlen <key> #获得值的长度
(3)设置并返回原值
getset key value
(4)设置指定位置的字符
setrange key offeset value
#下面操作将值由pest变为了best:
127.0.0.1:6379> set redis pest
OK
127.0.0.1:6379> setrange redis 0 b
(integer) 4
127.0.0.1:6379> get redis
"best"
(5)获取部分字符串
getrange key start end
127.0.0.1:6379> getrange redis 0 1
"be"
字符串类型命令的时间复杂度,如下图所示:/ 结合自身业务需求和数据大小选择适合的命令 /

Redis 原子性操作
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
1、在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只能发生于指令之间。
2、在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。Redis单命令的原子性主要得益于Redis的单线程。即使6.0以后变成了多线程,由于只有主线程执行命令,所以命令的原子性还是可以保证的。
多个键值
批量设置值
mset key value [key value ...]
msetnx key value [key value ...]
127.0.0.1:6379> mset a 1 b 2 c 3 d 4
OK
批量获取值
mget key [key ...]
数据结构
String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。具有以下特点:
1、长度可变:SDS内部使用一个len属性记录当前字符串的长度,因此可以动态地扩展和缩小字符串的大小,从而满足各种需求。
2、二进制安全:SDS中的内容不以任何形式被视为C字符串,因此可以存储任何类型的数据,包括二进制数据、图片、音频等等。
3、空间预分配:在SDS中,每个字符串都会预分配一定的额外空间,避免了多次扩容和内存重新分配的开销,提高了存储和读取数据的效率。
4、缓冲区复用:在SDS中,当一个字符串被修改后,原来的缓冲区不会被立即释放,而是被保留在SDS中,以便以后可以被复用。
5、O(1)复杂度的长度计算:SDS通过使用len属性来存储字符串长度,使得计算字符串长度的复杂度为O(1)。
字符串类型的内部编码有3种:
-
int:8个字节的长整型。
-
embstr:小于等于44个字节的字符串(一次空间申请,空间紧凑)
-
raw:大于44个字节的字符串。
示例
127.0.0.1:6379> set key22 "one string greater than 44 byte............."
OK
127.0.0.1:6379> strlen key22
(integer) 44
127.0.0.1:6379> object encoding key22
"embstr"
127.0.0.1:6379> set key33 "one string greater than 45 byte.............."
OK
127.0.0.1:6379> strlen key33
(integer) 45
127.0.0.1:6379> object encoding key33
"raw"
数据结构如下:
len:已用空间
alloc:sds申请的buf总空间
flags:标志符,是sds8/sds16/sds32/sds64/sds128等
buf[]:存储字符串的字节数组
所以key的最大长度为sds128,计算完以后最大长度为512M。

应用场景
- 缓存

-
计数器
-
共享session
-
限速
2.2 hash¶
1、简介
Redis hash 是一个键值对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
字符串与哈希对比

2、常用命令
设置值
hset key field value
hmset key field value [field value ...] #批量设置field-value
查询
hget key field #获取field的值
hmget key field [field ...] #批量获取field-value
hkeys key #获取所有field
hvals key #获取所有value
hgetall key #获取所有的field-value
hlen key #计算field个数
hexists key field #判断field是否存在
hstrlen key field #计算value的字符串长度
删除field
hdel key field [field ...]
#计数
hincrby key field
hincrbyfloat key field
3、数据结构
Hash类型对应的数据结构是两种:
-
ziplist(压缩列表)
-
hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用 hashtable。
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding hashkey
"ziplist"
127.0.0.1:6379> hstrlen hashkey f5
(integer) 75
127.0.0.1:6379> object encoding hashkey
"hashtable"

4、应用场景
缓存对象,一个key里有多个字段,比如缓存用户登录信息,如果使用hash 存储,会比直接使用json 存储节省很多空间