# 管理单元
Redis 的管理单元从上到下依次分为:
- database :数据库
- 一个 Redis 中默认创建了 16 个数据库,从 0 开始编号。
- key-value :键值对
- 每个数据库中可以存储很多键值对,类似于 Python 中的字典。
# database
- 命令:
select n # 切换到第 n 号数据库 move <key> n # 将当前数据库的一个 key 移动到第 n 号数据库 dbsize # 返回当前数据库的 key 总数 flushdb # 删除当前数据库的所有 key flushall # 删除所有数据库的所有 key
# key
- 命令:
keys <pattern> # 显示匹配 pattern 的所有 key ,例如 keys * exists <key>... # 判断 key 是否存在 del <key>... # 删除 key 。需要指定具体的 key 名,不能指定 pattern 。这属于同步操作,会阻塞当前终端 unlink <key>... # 删除 key 。这属于异步操作,不会阻塞当前终端 rename <key> <newkey> # 重命名 key 。如果 newkey 已存在,则覆盖它 renamenx <key> <newkey> # 重命名 key 。如果 newkey 已存在,则不执行操作 type <key> # 返回 key 的数据类型 dump <key> # 返回 key 的序列化后的 value
- 大部分命令执行之后会返回生效的 key 数,返回值为 0 则表示执行失败,返回值为 nil 则表示不存在该 key 。如下:
127.0.0.1:6379> exists key1 key2 (integer) 2 127.0.0.1:6379> get key1 "hello" 127.0.0.1:6379> del key1 (integer) 1 127.0.0.1:6379> get key1 (nil)
- keys 命令的时间复杂度为 O(n) ,如果数据库中包含上千万的 key ,则查询时可能阻塞 Redis 服务器几秒,因此要谨慎使用。
# scan
使用 scan 命令的开销比 keys 小很多,语法:
# 从游标 cursor 位置开始迭代一定数量的 key ,最多返回的数量为 count(默认为 10 ) scan <cursor> [MATCH pattern] [COUNT count] [TYPE type]
例:
127.0.0.1:6379> scan 0 MATCH key* 1) "1152" # 返回本次迭代后的游标位置 2) 1) "key:000000001311" # 返回 10 个 key 2) "key:000000000626" 3) "key:000000001973" 4) "key:000000000554" 5) "key:000000001630" 6) "key:000000000318" 7) "key:000000000761" 8) "key:000000000291" 9) "key:000000001039" 10) "key:000000001179"
- 使用本次迭代后的游标位置,作为下一次 scan 迭代的起始游标,就可以继续迭代剩下的 key 。但是多次迭代后返回的 key 可能有重复的,需要客户端自己去重。
- 如果某次迭代后返回的游标位置为 0 ,则说明已迭代完所有 key 。
- scan 每次迭代的时间复杂度为 O(1) ,不会阻塞 Redis 。不过迭代完所有 key 的时间复杂度依然为 O(n) 。
基于 scan 命令批量删除 key ,不会阻塞 Redis ,如下:
redis-cli scan 0 COUNT 1000 | xargs redis-cli del
login_redis='redis-cli -n 0' cursor=0 while [ 1 ] do echo `date`, dbsize=`$login_redis dbsize`, cursor=$cursor list=(`$login_redis scan $cursor COUNT 1000`) echo ${list[@]:1} | xargs -n 1 -d ' ' echo del | $login_redis > /dev/null cursor=${list[0]} if [ cursor == 0 ] then break fi done
- 测试发现,主从部署时,大概每秒能删除 1000 个 key 。
# 过期时间
可以给 key 设置过期时间(time to live,ttl),过期之后会被 Redis 自动删除,但不一定会立即删除。
命令:
expire <key> <seconds> # 设置 key 在几秒后过期 pexpire <key> <milliseconds> # 设置 key 在几毫秒后过期 expireat <key> <timestamp> # 设置 key 在某个时间戳(单位为秒)之后过期 pexpireat <key> <milliseconds-timestamp> # 设置 key 在某个时间戳(单位为毫秒)之后过期 ttl <key> # 返回 key 剩下的过期时间(单位为秒)。如果 key 没有设置过期时间,则返回 -1 。如果 key 不存在,则返回 -2 pttl <key> # 返回 key 剩下的过期时间(单位为毫秒) persist <key> # 取消 key 的过期时间
# 其它功能
# 事务
- 客户端可以将连续执行的多个命令声明为一个事务,如下:
multi # 声明一个事务的开始 set... get... exec # 开始执行该事务
- 在执行 exec 之前,可以用 discard 取消执行剩下的命令(但已执行的命令并不能回滚)。
- Redis 的事务不能保证原子性。
# 分区
:用于将 key 分散保存到多个 Redis 实例。
- 分区的方式
- 按 value 值的范围分区。
- 按 key 的 hash 值的范围分区。
- 优点
- 合并多个 Redis 实例,扩展容量。
- 缺点
- 如果多个 key 存储在不同 Redis 实例,则不能在一个事务中处理,不能进行 set 交集、差集等运算。
# 发布/订阅
Redis 提供了发布/订阅功能,可用作功能简单的消息队列。