# 管理单元

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 。这属于异步操作,不会阻塞当前终端
    scan      cursor [MATCH pattern] [COUNT count] [TYPE type]  # 从游标 cursor 位置开始迭代一定数量的 key ,最多返回的数量为 count(默认为 10 )
    
    rename    <key> <newkey>  # 重命名 key(如果 newkey 已存在,则覆盖它)
    renamenx  <key> <newkey>  # 重命名 key(如果 newkey 已存在,则不执行操作)
    
    type      <key>           # 返回 key 的数据类型
    dump      <key>           # 返回 key 的序列化后的 value
    
  • keys 的时间复杂度为 O(n) ,如果在上千万的 key 中进行查询,容易阻塞 Redis 几秒,因此要谨慎使用。
  • 大部分命令执行之后会返回生效的 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)
    
  • 关于 scan 命令:
    • 例:
      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
      
      • 实测发现,主从部署时,删 key 的速度为每秒 1000 个左右,即使每次删 1w 个 key 也是这么慢。

# 过期时间

  • 可以给 key 设置过期时间(time to live),过期之后会被 Redis 自动删除(不一定会立即删除)。

    • 如果 key 的 ttl 为-1 ,则表示不会过期。
  • 命令:

    expire    <key> <seconds>         # 设置 key 在几秒后过期
    pexpire   <key> <milliseconds>    # 设置 key 在几毫秒后过期
    
    expireat  <key> <timestamp>                 # 设置 key 在某个时间戳(单位为秒)之后过期
    pexpireat <key> <milliseconds-timestamp>    # 设置 key 在某个时间戳(单位为毫秒)之后过期
    
    ttl       <key>                   # 返回 key 剩下的过期时间(单位为秒)
    pttl      <key>                   # 返回 key 剩下的过期时间(单位为毫秒)
    
    persist   <key>                   # 取消 key 的过期时间