笔记来自:《redis开发与维护》第二章 API的理解和使用
主要内容:全局命令、键管理、遍历键、数据库管理
全局命令
操作 | 命令 |
---|---|
查看所有键 | keys * |
键总数 | dbsize |
检查键是否存在 | exists key |
删除建 | del key [key ...] |
键过期 | expire key seconds |
键的数据结构类型 | type key |
1. 查看所有键 -- keys *
H:\Redis>redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> get hell
(nil)
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> set java jedis
OK
127.0.0.1:6379> set python redis-py
OK
127.0.0.1:6379> keys *
1) "python"
2) "java"
3) "hello"
2. 键总数 -- dbsize
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> dbsize
(integer) 4
3. 检查键是否存在 -- exists key
存在,返回1,不存,返回0
127.0.0.1:6379> exists java
(integer) 1
127.0.0.1:6379> exists no_exits_key
(integer) 0
4. 删除键 -- del key [key ...]
删除成功后,返回删除个数
127.0.0.1:6379> keys *
1) "python"
2) "mylist"
3) "java"
4) "hello"
127.0.0.1:6379> del python java
(integer) 2
127.0.0.1:6379> keys *
1) "mylist"
2) "hello"
5. 键过期 -- expire key seconds
127.0.0.1:6379> expire mylist 10
(integer) 1
127.0.0.1:6379> ttl mylist
(integer) 3
127.0.0.1:6379> ttl mylist
(integer) -2
127.0.0.1:6379> exists mylist
(integer) 0
ttl 命令返回键剩余的过期时间,有三种返回值:
- 大于等于0的整数:键剩余的过期时间
- -1: 键设置过期时间
- -2: 键不存在
6. 键的数据结构类型 -- type key
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type a
string
2. 数据结构和内部编码
redis每种数据结构都有两种以上自己底层的内部编码实现
查询内部编码命令:object encoding
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> rpush mylist a b c d e f g
(integer) 7
127.0.0.1:6379> object encoding mylist
"quicklist"
优点:
1. 改进内部编码,对外部的数据结构命令没影响
2. 多种内部编码实现可以在不同场景下各自发挥
3.单线程架构;
redis 使用单线程架构
和I/O多路复用模型
来实现高性能的内存数据库服务。
引出 单线程模型
开启3个redis-cli客户端同时执行命令,每个客户端都会执行3个步骤:发送命令、执行命令、返回结果三个过程
所有命令到服务端会进入一个队列,然后被执行
为什么单线程还能这么快
存内存访问,redis将所有数据存放内存中
非阻塞I/O,
避免切换和竞争产生的消耗
键管理
一、单个键管理
1. 键重命名 -- rename key newkey
127.0.0.1:6379> get a
"1"
127.0.0.1:6379> rename a keya
OK
127.0.0.1:6379> get keya
"1"
127.0.0.1:6379> get a
(nil)
情况1: 如果b存在,则b键的值也会被覆盖
127.0.0.1:6379> rename keya b
OK
127.0.0.1:6379> get b
"1"
127.0.0.1:6379> get keya
(nil)
情况2: 重命名不存键 b ,键返回错误
127.0.0.1:6379> get b
(nil)
127.0.0.1:6379> get keya
"1"
127.0.0.1:6379> renamenx b keya
(error) ERR no such key
注意:
重命名键期间会执行del命令删除旧的键,如果键对应的值比较大,会存在阻塞的可能性
-
rename和renamenx 的key 和 value 一样,redis 3.2 和之前的版本返回结果不同
redis3.2版本返回ok,之前的会报错 127.0.0.1:6379> rename keya keya OK 127.0.0.1:6379> get keya "1"
2.随机返回一个键 -- randomkey
127.0.0.1:6379> dbsize
(integer) 36
127.0.0.1:6379> randomkey
"user:1_2:tags"
127.0.0.1:6379> randomkey
"mylist"
3.键过期 -- expire key seconds/expireat key timestamp
ttl 返回 -1 键没有设置过期时间
返回-2 键不存
127.0.0.1:6379> expire d 10
(integer) 1
127.0.0.1:6379> ttl d
(integer) 7
127.0.0.1:6379> ttl d
(integer) 3
127.0.0.1:6379> ttl d
(integer) 0
127.0.0.1:6379> ttl d
(integer) -2
127.0.0.1:6379> get d
(nil)
expireat key timestamp 键在秒级时间错过期
2019-02-13 23:43:30 时间戳 1550072610
127.0.0.1:6379> expireat c 1550072610
(integer) 1
127.0.0.1:6379> ttl c
(integer) 23
127.0.0.1:6379> ttl c
(integer) 21
127.0.0.1:6379> ttl c
(integer) -2
127.0.0.1:6379> get c
(nil)
注意:
- expire key不存在,返回0
127.0.0.1:6379> expire no_exist_key 10
(integer) 0
127.0.0.1:6379> get no_exist_key
(nil)
- 过期时间负值,键立即被删除
127.0.0.1:6379> expire keya -5
(integer) 1
127.0.0.1:6379> get keya
(nil)
- persist 命名可以将过期时间清除
127.0.0.1:6379> expire keya 30
(integer) 1
127.0.0.1:6379> ttl keya
(integer) 25
127.0.0.1:6379> persist keya
(integer) 1
127.0.0.1:6379> ttl keya
(integer) -1
- set 命令会将设置的过期时间清除掉
127.0.0.1:6379> set hi world
OK
127.0.0.1:6379> expire hi 30
(integer) 1
127.0.0.1:6379> ttl hi
(integer) 24
127.0.0.1:6379> set hi 10
OK
127.0.0.1:6379
- redis 不支持二级数据结构的过期时间设置,比如哈希、列表内元素的过期设置
- setex命令 为set + expire 组合,具有原子性,同时减少一次网络时间
4. 迁移键 -- move\dump + restore\migrate
三个命令比较
命令 | 作用域 | 原子性 | 支持多个建 |
---|---|---|---|
move | redis示例内部 | 是 | 否 |
dump + restore | redis示例之间 | 否 | 否 |
migrate (推荐) | redis示例之间 | 是 | 是 |
(1)nove key db
指定的键从源数据库迁移到目标数据库中,但多数据库功能不建议在生产环境中使用,所以这个命令知道就可以
(2)dump + restore
dump key
restore key ttl value
实现redis实例之间迁移功能,分2步骤:
- 在源redis上dump命令,将键值序列化,格式:RDB格式
- 在目标redis上,restore命令将上面序列化的值进行复原,其中ttl参数代表过期时间,ttl=0表示没有过期时间
示例:
- redis-6380 新添key6380 , redis-6379 并不存该key
127.0.0.1:6380> set key6380 hi6380
OK
127.0.0.1:6379> get key6380
(nil)
- redis-6380 执行dump命令,将key6380的值进行序列化
127.0.0.1:6380> dump key6380
"\x00\x06hi6380\a\x00\x88%\xa4k\xa2\xc7\x97n"
- redis-6379执行restore命令,将key6380的值进行反序列化,保存到内存中
127.0.0.1:6379> restore key6380 0 "\x00\x06hi6380\a\x00\x88%\xa4k\xa2\xc7\x97n"
OK
127.0.0.1:6379> get key6380
"hi6380"
注意:
- 整个过程不是原子性的,是通过客户端分步完成的
- 开启两个客户端,所以dump的结果不是在源redis和目标redis之间进行传输
(3)migrate
migrate host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]
参数说明:
host : 目标redis IP地址
port :目标redis 端口
key|"" :迁移的键,“”代表 多个迁移键
destination-db :目标redis的数据库索引,默认是0
timeout :超时时间
[COPY] :添加的话,不会删除源redis键
[REPLACE]:如果目标redis存在迁移键,则会迁移覆盖数据
[KEYS key]:迁移多个键
用于redis实例之间进行数据迁移,
dump、restore、del 三个命令组合,简化操作流程
3点不太相同:
- 整个过程是
原子
执行,只需在源redis
上migrate命令 - migrate命令的数据直接在
源redis
和目标redis
上完成 - 目标redis完成restore后会发送ok给源redis,
源redis
接受后会根据migrate对应的选项
来决定是否在源redis删对应的键
示例:
- 情况 源redis有 键key6379 ,目标redis没有
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 0 2000 copy replace
OK
- 源redis和目标redis都有键key6379, 如果migrate 没加replace参数,则会报错
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 0 1000
(error) ERR Target instance replied with error: BUSYKEY Target key name already exists.
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 0 1000 replace
OK
- 源redis没有迁移键key6381,则返回nokey
127.0.0.1:6379> migrate 127.0.0.1 6380 key6381 0 1000
NOKEY
遍历键
1. 全量遍历键 -- keys pattern
pattern 通配符:
- “*”:任意字符
- ?:一个字符
- [] : 部分字符,[1,3] 代表匹配1,3
- \x : 用来做转义
示例:
- 查找user开头的键
127.0.0.1:6379> keys user*
1) "user:2:tags"
2) "user:ranking:1"
3) "user:ranking:2"
4) "user:1:follow"
...
- 查找含tag的键
127.0.0.1:6379> keys *tags*
1) "user:2:tags"
2) "user:3:tags"
3) "user:1_2:tags"
4) "user:1:tags"
如果redis包含大量的键,keys命令可能会造成redis阻塞,所以一般不要在生产环境中使用keys命令,以下三种情况使用:
- 在一个
不对外提供服务的
redis从节点上执行 - 如果确认键值总数较少,可以执行该命令
- 使用scan渐进式遍历所有键,有效阻止阻塞
2.渐进式遍历 -- scan cursor [MATCH pattern] [COUNT count]
scan命令 采取渐进式遍历方式解决keys的阻塞问题
时间复杂度为O(1),reids存储键值对实际是用hashtable数据结构
scan的使用方式如下:
scan cursor [MATCH pattern] [COUNT count]
参数:
- cursor 必填参数 ,一个游标,第一次遍历时从0开始,每次遍历完返回当前游标值直到游标值为0, 表示遍历结束
- [MATCH pattern] 可选参数,作用:做模式匹配,跟keys相似
- [COUNT count] 可选参数,表示每次遍历的键个数,默认值为0
示例:
- 遍历但是redis6379所有键
127.0.0.1:6379> scan 6
1) "41"
2) 1) "user:2:follow"
2) "article:2"
3) "user:1_2:union"
4) "user:3:tags"
5) "hashkey"
6) "user:ranking:1_union_2"
7) "listkey"
8) "user:ranking:1_inter_2"
9) "user:ranking:1"
10) "setkey"
11) "user:ranking:2"
127.0.0.1:6379> scan 41
1) "27"
2) 1) "myset"
2) "user:ranking"
3) "article:3"
4) "tag1:users"
5) "hashkey1"
6) "user:1_2:tags"
7) "lishkey"
8) "list:test3"
9) "testkey"
10) "user:1"
127.0.0.1:6379> scan 27
1) "0"
2) 1) "user:1:tags"
2) "article:1"
3) "user:ranking:20190210"
如果scan过程中如有有键变化(增加、删除、修改),那么遍历可能会出问题:新的键没遍历到,遍历出了重复的键等情况
数据库管理
1.切换数据库 -- select index
redis只是用数字
作为多个数据库的实现,redis默认中是16
个数据库
databases 16
0-15号数据库之间是没有任何联系,甚至可以存在相同的键
127.0.0.1:6379> get hello
"word"
127.0.0.1:6379> select 15 # 15号切换数据库
OK
127.0.0.1:6379[15]> get hello
(nil)
如果使用多个数据库功能,可以一台机器上部署多个redis实例,然后用端口来划分,因为现在服务器是多个cpu的,保证了业务不受到影响,合理使用cpu资源
2.清楚数据库--flushdb/flushall
两者区别:flushdb只清除当前数据,flushall会清除所有数据库
127.0.0.1:6379[15]> set hello world15
OK
127.0.0.1:6379[15]> keys hello
1) "hello"
127.0.0.1:6379[15]> flushdb
OK
127.0.0.1:6379[15]> keys
(error) ERR wrong number of arguments for 'keys' command
# 切到0号数据库,还是有数据
127.0.0.1:6379[15]> select 0
OK
127.0.0.1:6379> get hello
"word"
flushall 清除所有数据库
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty list or set)
flushdb/flushall会将所有数据清除,一旦误操作后果不堪设想
如果数据库键值数量比较多,存在阻塞redis可能性,一定要小谨慎使用
--END--
创作不易,觉得不错的话,欢迎关注、点赞或掌赏!