­

Redis开发与运维学习笔记—(4)

  • 2020 年 3 月 31 日
  • 筆記
redis中针对单个键有很多命令,之前我们已经接触到了type、del、object、exists、expire等等,再来看其他命令。开始之前,来看一个小插曲:

———————开始—————-

set hello world的时候,竟然提示read-only。使用info replication的方法查看当前复制状态,发现role变成了slave,所以使用slaveof no one来修改下属性。

[root@VM_48_10_centos ~]# redis-cli -h 127.0.0.1 -p 6379  127.0.0.1:6379> set hello world  (error) READONLY You can't write against a read only slave.  127.0.0.1:6379> info replication  # Replication  role:slave  master_host:xxx.xx.5.121  master_port:20556  master_link_status:down  master_last_io_seconds_ago:-1  master_sync_in_progress:0  slave_repl_offset:1  master_link_down_since_seconds:1585363887  slave_priority:100  slave_read_only:1  connected_slaves:0  master_repl_offset:0  repl_backlog_active:0  repl_backlog_size:1048576  repl_backlog_first_byte_offset:0  repl_backlog_histlen:0  127.0.0.1:6379> slaveof no one  OK  127.0.0.1:6379> set hello world  OK

———————小插曲结束—————-

正式开始看其他键操作

1

键重命名

rename key newkey

举例如下:

127.0.0.1:6379> get hello  "world"  127.0.0.1:6379> rename hello hi  OK  127.0.0.1:6379> get hello  (nil)  127.0.0.1:6379> get hi  "world"  127.0.0.1:6379> set hello world2  OK  127.0.0.1:6379> get hello  "world2"  127.0.0.1:6379> rename hi hello  OK  127.0.0.1:6379> get hello  "world"  127.0.0.1:6379> get hi  (nil)  

收件创建hello–>world键值对,然后将hello重命名为hi,发现hello键的value为空,而hi键的value为world,再重新设置hello,再次重命名,发现hello键被覆盖。

通过这个例子,我们发现,使用rename操作是有可能覆盖已经存在的键值的,这在线上可能不安全,因此,redis提供了renamenx命令,表示仅在rename的新键不存在的时候,在进行重命名,如果存在,则重命名返回数字0,而不是返回ok,这样避免了线上的键被覆盖。

除此之外,还有2点需要注意:

1、由于重命名期间会执行del命令删除旧的键,如果键对应的值比较大,则会存在阻塞redis的风险。这一点和MySQL中的rename不同,mysql中的rename操作为原子操作,本质上是对底层文件句柄的操作。

2、如果key和newkey相同,在3.2版本之前返回错误,在3.2版本之后,返回0

2

随机返回一个键

使用randomkey可以随机返回一个键。这个功能可以测试当前redis中是否有键值

3

键过期

expire和expireat

关于键过期,之前说过expire的命令,该命令可以通过:

expire key seconds

来让键在seconds秒之后过期。

但是,这个命令不够精确,我们可以使用expireat命令来指定精确的过期时间:

expireat key timestamp:键在秒级时间戳timestamp之后过期。其中timestamp需要取整数。

ttl和pttl

这两个命令是查看redis的键剩余过期时间的。pttl精度更高,可以达到毫秒级别,有3种返回值:

1、大于0的整数,值得是键剩余过期时间

2、返回1,代表键没有设置过期时间

3、返回-2,代表键不存在

127.0.0.1:6379> set hello world  OK  127.0.0.1:6379> expire hello 10  (integer) 1  127.0.0.1:6379> ttl hello  (integer) 7  127.0.0.1:6379> pttl hello  (integer) 4461  

毫秒级过期方案pexpire和pexpireat

这两兄弟和expire不同之处在于,最后跟的时间是毫秒。其他的使用方法都一样,本质上,redis会将expire的命令转换成pexpire的命令。

几点注意:

a、如果expire的键不存在,则会返回0

b、如果时间为负值,则键会被立即删除。

127.0.0.1:6379> get hello  "world"  127.0.0.1:6379>  127.0.0.1:6379> expire hello -2  (integer) 1  127.0.0.1:6379> get hello  (nil)  127.0.0.1:6379> expire hello 10  (integer) 0  

c、persist命令可以将键的过期时间清除

127.0.0.1:6379> set hello world  OK  127.0.0.1:6379> expire hello 50  (integer) 1  127.0.0.1:6379> ttl hello  (integer) 46  127.0.0.1:6379> persist hello  (integer) 1  127.0.0.1:6379> ttl hello  (integer) -1  127.0.0.1:6379> get hello  "world"  

d、set命令会导致过期时间失败

127.0.0.1:6379> get hello  "world"  127.0.0.1:6379> expire hello 50  (integer) 1  127.0.0.1:6379> ttl hello  (integer) 47  127.0.0.1:6379> set hello world~~  OK  127.0.0.1:6379> ttl hello  (integer) -1  

e、redis不支持二级数据结构(哈希、列表)内部元素的过期功能。

f、setex命令作为set+expire的组合,不但是原子执行,同时减少了一次网络通讯时间。

4

迁移键

redis中,提供了3中迁移键的方法:

move

dump+restore

migrate

下面分别介绍:

1、move

move命令用户在多个数据库中进行键迁移。它的主要功能是将键从一个数据库迁移到另外一个数据库,但是,多数据库的功能,本身是不建议在线上使用的,这个命令大家了解一下即可。

127.0.0.1:6379> get hello  "world~~"  127.0.0.1:6379> move hello 1  (integer) 1  127.0.0.1:6379> get hello  (nil)  127.0.0.1:6379> select 1  OK  127.0.0.1:6379[1]> get hello  "world~~"  

2、dump+restore

dump+restore可以实现在不同的redis实例之间进行数据迁移的功能,整个迁移的过程分为两步:

a、在源redis上,dump命令会将键值序列化,格式采用的是rdb格式。

b、在目标redis上,restore命令将上面序列化的值进行复原,其中ttl参数代表过期时间。

这里有2点需要注意:

第一:dump+restore并非原子性的,而是通过客户端分布完成的。

第二:迁移过程是开启了2个客户端的连接,所以dump的结果不是在源redis和目标redis之间进行传输,需要有个中间过程。

举例如下:

###6379端口  127.0.0.1:6379> get hello  "world~~"  127.0.0.1:6379> dump hello  "x00aworld~~x06x00xe9x02ixcfnxd0xa5:"    ###6380端口  127.0.0.1:6380> get hello  (nil)  127.0.0.1:6380> restore hello 0 "x00aworld~~x06x00xe9x02ixcfnxd0xa5:"  OK  127.0.0.1:6380> get hello  "world~~"  

3、migrate

该命令也是在redis实例间进行数据迁移的,实际上migrate命令就是讲dump、restore、del3个命令进行组合,从而简化了操作流程。

它跟dump+restore的方法有3点不同:

第一、整个过程是源自执行的,不需要要在多个redis实例上开启客户端,只需要在源redis上执行migrate命令即可

第二、migrate命令的数据传输直接在源redis和目标redis上完成的

第三、目标redis完成restore后发送ok给源redis,源redis接受后会根据migrate对应的选项来决定是否在源redis上删除对应的键。

migrate的参数如下:

host:目标redis的IP地址

port:目标redis的端口

key|“” :redis3.0.6之前,migrate只支持迁移一个键,当需要迁移多个键,此处字符串为空

destination-db:目标redis的数据库索引,例如要迁移到0号数据库,此处写0即可。

timeout:迁移的超时时间

copy:添加该参数,迁移之后不删除源键

replace:添加改参数,会覆盖目标端redis的键

keys key [key1 key2]:迁移多个键的时候用,如果要迁移多个,则使用keys key1 key2 key3

下面我们从6379端口将键迁移到6380端口:

127.0.0.1:6379> flushdb  OK  127.0.0.1:6379> set yeyz handsome  OK  127.0.0.1:6379> get yeyz  "handsome"  127.0.0.1:6379> migrate 127.0.0.1 6380 yeyz 0 1000  OK  127.0.0.1:6379> get yeyz  (nil)  127.0.0.1:6379> exit  [root@VM_48_10_centos ~]# redis-cli -p 6380  127.0.0.1:6380> get yeyz  "handsome"  

注意:

a、如果没有加replace参数,但是目标端已经有同名键了,此时会报错,提示busykey target key name already exists.

b、如果源redis没有要迁移的键,则会提示nokey

最后,批量迁移举例:

[root@VM_48_10_centos ~]# redis-cli  127.0.0.1:6379> set key0 value0  OK  127.0.0.1:6379> set key1 value1  OK  127.0.0.1:6379> set key2 value2  OK  127.0.0.1:6379> migrate 127.0.0.1 6380 "" 0 1000 keys key0 key1 key2  OK  127.0.0.1:6379> get key0  (nil)  127.0.0.1:6379> get key1  (nil)  127.0.0.1:6379> get key2  (nil)  127.0.0.1:6379> exit    [root@VM_48_10_centos ~]# redis-cli -p 6380  127.0.0.1:6380> get key0  "value0"  127.0.0.1:6380> get key1  "value1"  127.0.0.1:6380> get key2  "value2"