基本全局命令
Redis提供了5种数据类型,都是键值对的形式,对于键来说有一些通用的命令
KEYS命令
语法:
shell
KEYS pattern
功能:返回所有满足样式的key。支持如下统配样式:
h?llo:表示可以匹配在?位置为任意一个字符,如hallo/hbllo/hclloh*llo:表示可以匹配在*位置为任意个字符,如hllo/hello/heeelloh[ae]llo:表示可以匹配[]内的任意一个字符,如hello/halloh[^e]llo:表示可以匹配除了[]内的任意一个字符,如hallo/hblloh[a-b]llo:表示可以a到b内的任意一个字符,如hallo/hbllo
命令有效版本:1.0.0版本以后
时间复杂度:O(N)
返回值:匹配pattern的所有key
演示:
shell
127.0.0.1:6379> set hello 1
OK
127.0.0.1:6379> set hbllo 2
OK
127.0.0.1:6379> keys h?llo
1) "hbllo"
2) "hello"
127.0.0.1:6379> keys h[^a]llo
3) "hbllo"
4) "hello"
127.0.0.1:6379> keys h[^b]llo
5) "hello"
127.0.0.1:6379>
注意:
尽量不要在生产环境 使用命令keys *,这个指令会返回所有的key,如果key很多,redis执行这个命令会消耗比较多的时间,又因为redis为单线程程序,会导致其他功能被迫等待。
EXISTS命令
语法:
shell
EXISTS key [key ...]
功能:判断某个key是否存在
时间复杂度:O(1)
返回值:key存在的个数
演示:
shell
127.0.0.1:6379> exists hello
(integer) 1
127.0.0.1:6379> exists hello hbllo
(integer) 2
127.0.0.1:6379>
注意:
exists支持一次性检测多个key是否存在的目的是减少网络通信的次数。
DEL命令
语法:
shell
DEL key [key ...]
功能:
删除指定的key
命令有效版本:1.0.0以后
时间复杂度:O(1)
返回值:删除掉的key的个数
演示:
shell
127.0.0.1:6379> DEL hello
(integer) 1
127.0.0.1:6379> exists hello
(integer) 0
127.0.0.1:6379>
EXPIRE命令
语法:
shell
EXPIRE key seconds
功能:
为指定的key添加秒级的过期时间
命令有效版本:1.0.0以后
时间复杂度:O(1)
返回值:1表示设置成功。0表示设置失败
演示:
shell
127.0.0.1:6379> set example "test"
OK
127.0.0.1:6379> expire example 20
(integer) 1
127.0.0.1:6379> exists example
(integer) 1
127.0.0.1:6379> exists example
(integer) 1
127.0.0.1:6379> exists example
(integer) 0
127.0.0.1:6379>
TTL命令
语法:
shell
TTL key
功能:
获取指定key的过期时间,秒级
命令有效版本:1.0.0以后
时间复杂度:O(1)
返回值:剩余过期时间。-1表示没有关联过期时间,-2表示key不存在
演示:
shell
127.0.0.1:6379> set ttl_example "test"
OK
127.0.0.1:6379> expire ttl_example 20
(integer) 1
127.0.0.1:6379> ttl ttl_example
(integer) 13
127.0.0.1:6379>
注意:
如果你需要更高级别的时间控制,可以使用PEXPIRE和PTTL,这两个指令都支持毫秒级别的控制。
redis的定时器的核心:升序有序的过期字典 + 惰性删除 + 定时删除;
TYPE命令
语法:
shell
TYPE key
功能:
返回key对应value的数据类型
命令有效版本:1.0.0以后
时间复杂度:O(1)
演示:
shell
127.0.0.1:6379> set hello 111
OK
127.0.0.1:6379> type hello
string
127.0.0.1:6379> lpush key1 111 222
(integer) 2
127.0.0.1:6379> type key1
list
127.0.0.1:6379> sadd key2 111 222
(integer) 2
127.0.0.1:6379> type key2
set
127.0.0.1:6379>
lpush相当于列表插入,sadd相对于集合插入,此处作为了解即可。
小结
- keys:用于查看匹配规则的key
- exists:用于检查指定的key是否存在
- del:删除指定的key
- expere:给key设置过期时间
- ttl:检查指定key的过期时间
- type:查询指定key对应的value的类型
数据类型和内部编码
type命令实际返回的就是当前键的数据类型,他们分别为:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合)
如下图所示:

实际上这些只是Redis对外表示的数据结构,真实情况是Redis针对每种数据类型都有自己的底层内部编码实现,而且一种数据结构可能对应多种实现,Redis对根据合适的场景选择对应的内部编码。
| 数据类型 | 内部编码 |
|---|---|
| string | raw |
| string | int |
| string | embstr |
| hash | hashtable |
| hash | ziplist |
| list | linkedlist |
| list | ziplist |
| set | hashtable |
| set | intset |
| zset | skiplist |
| zset | ziplist |
从表格中可以看出,每种数据类型都有至少两种及以上的内部编码实现,例如list就包含了linkedlist和ziplist两种内部编码。
在什么情况下会使用对应的内部编码
核心原则:数据量小 / 简单时用「紧凑编码」节省内存,数据量大 / 复杂时用「高效编码」保证读写性能
- string
- raw : 存储字符串长度较长
- int :存储的字符串内容为纯整数且在long long内表示的范围内。
- embstr :存储的字符串长度较短
- hash
- hashtable :存储的键值对数量较大
- ziplist :存储的键值对数量较小
- list
- linkedlist :存储数量较多时
- ziplist :存储数量较少时
- set
- hashtable:存储非整数元素或者存储整数较多
- intset :存储整数元素且存储整数较少
- zset
- skiplist :存储元素较多
- ziplist :存储元素较少
注意:
-
在redis 3.2版本以后 list的内部编码变为quicklist,是
ziplist + linkedlist的结合体 -
编码切换是不可逆的:Redis 所有数据类型的内部编码,都只有 「从紧凑编码 → 高效编码」的升级 ,没有降级。
如何查看这些内部编码呢
使用 object encoding命令
shell
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> lpush mylist a b c
3
127.0.0.1:6379> object encoding key1
embstr
127.0.0.1:6379> object encoding mylist
quicklist
127.0.0.1:6379>
单线程结构
Redis使用单线程结构来实现高性能的内存数据库服务
为什么Redis使用单线程还这么快
并不是单线程就一定比多线程慢,多线程仅在 CPU 密集型任务和 IO 密集型任务中优势最大,而 Redis 的运行场景完美避开了这两个场景的短板,因此 Redis 单线程依然能做到极致的性能,核心原因有三点:
-
纯内存访问:Redis 将所有数据放在内存中,内存的响应时间为 100ns 左右,速度远快于磁盘,所有命令都是内存操作,无磁盘 IO 的耗时,这是高性能的基础;
-
非阻塞 IO:Redis 使用 epoll 作为 IO 多路复用技术的实现,再加上 Redis 自身的事件处理模型,将 epoll 中的连接、读写、关闭等操作都转化为事件统一处理,能高效监听和处理大量客户端连接,不在网络 IO 上浪费过多的时间;
-
单线程避免了线程切换和竞态的消耗:单线程可以简化数据结构和算法的实现,让程序模型更简单,同时彻底避免了多线程下线程竞争共享资源的切换开销、锁等待开销,也无需处理线程安全问题,最大化节省 CPU 资源。
总结
Redis的基本全局命令包括:KEYS、EXISTS、DEL、EXPIRE、TTL、TYPE
Redis有5种数据类型包括:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合)。这5种数据类型的底层至少有两种编码实现。
虽然Redsi使用单线程来实现高性能的内存数据库服务,但是由于纯内存访问、非阻塞IO、单线程避免了线程竞争等等优势导致Redis的速度依旧很快。