Redis-全局命令及键管理

笔记来自:《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

注意:

  1. 重命名键期间会执行del命令删除旧的键,如果键对应的值比较大,会存在阻塞的可能性

  2. 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)

注意:

  1. 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)
  1. 过期时间负值,键立即被删除
127.0.0.1:6379> expire keya -5
(integer) 1
127.0.0.1:6379> get keya
(nil)
  1. 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
  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
  1. redis 不支持二级数据结构的过期时间设置,比如哈希、列表内元素的过期设置
  2. 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步骤:

  1. 在源redis上dump命令,将键值序列化,格式:RDB格式
  2. 在目标redis上,restore命令将上面序列化的值进行复原,其中ttl参数代表过期时间,ttl=0表示没有过期时间

示例:

  1. redis-6380 新添key6380 , redis-6379 并不存该key
127.0.0.1:6380> set key6380 hi6380
OK

127.0.0.1:6379> get key6380
(nil)
  1. redis-6380 执行dump命令,将key6380的值进行序列化
127.0.0.1:6380> dump key6380
"\x00\x06hi6380\a\x00\x88%\xa4k\xa2\xc7\x97n"
  1. 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"

注意:

  1. 整个过程不是原子性的,是通过客户端分步完成的
  2. 开启两个客户端,所以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点不太相同:

  1. 整个过程是原子执行,只需在源redis上migrate命令
  2. migrate命令的数据直接在源redis目标redis上完成
  3. 目标redis完成restore后会发送ok给源redis, 源redis接受后会根据migrate对应的选项决定是否在源redis删对应的键

示例:

  1. 情况 源redis有 键key6379 ,目标redis没有
127.0.0.1:6379> migrate 127.0.0.1 6380 key6379 0 2000 copy replace
OK
  1. 源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
  1. 源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 : 用来做转义

示例:

  1. 查找user开头的键
127.0.0.1:6379> keys user*
 1) "user:2:tags"
 2) "user:ranking:1"
 3) "user:ranking:2"
 4) "user:1:follow"
...
  1. 查找含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命令,以下三种情况使用:

  1. 在一个 不对外提供服务的redis从节点上执行
  2. 如果确认键值总数较少,可以执行该命令
  3. 使用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

示例:

  1. 遍历但是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--
创作不易,觉得不错的话,欢迎关注、点赞或掌赏!

你可能感兴趣的:(Redis-全局命令及键管理)