redis,如何选择性加载key数据?

几十个key数据占用几十G内存,99的key数据都暂时用不到,如何只加载一个key数据到内存使用? 不要一启动把所有的key都加载到内存中,内存都没了
最新回答
天空有点灰

2023-10-21 06:22:25

官方在2.6版本推出了一个新的功能-pipe mode,即将支持Redis协议的文本文件直接通过pipe导入到服务端。

说来拗口,具体实现步骤如下:

1. 新建一个文本文件,包含redis命令

SET Key0 Value0
SET Key1 Value1
...
SET KeyN ValueN

如果有了原始数据,其实构造这个文件并不难,譬如shell,python都可以

2. 将这些命令转化成Redis Protocol。

因为Redis管道功能支持的是Redis Protocol,而不是直接的Redis命令。

如何转化,可参考后面的脚本。

3. 利用管道插入

cat data.txt | redis-cli --pipe

Shell VS Redis pipe

下面通过测试来具体看看Shell批量导入和Redis pipe之间的效率。

测试思路:分别通过shell脚本和Redis pipe向数据库中插入10万相同数据,查看各自所花费的时间。

Shell

脚本如下:

#!/bin/bashfor ((i=0;i<100000;i++))doecho -en "helloworld" | redis-cli -x set name$i >>redis.log
done

每次插入的值都是helloworld,但键不同,name0,name1...name99999。

Redis pipe

Redis pipe会稍微麻烦一点

1> 首先构造redis命令的文本文件

在这里,我选用了python

#!/usr/bin/pythonfor i in range(100000):    print 'set name'+str(i),'helloworld'

# python 1.py > redis_commands.txt

# head -2 redis_commands.txt 

set name0 helloworld
set name1 helloworld

2> 将这些命令转化成Redis Protocol

在这里,我利用了github上一个shell脚本,

#!/bin/bashwhile read CMD; do
# each command begins with *{number arguments in command}\r\n
XS=($CMD); printf "*${#XS[@]}\r\n"
# for each argument, we append ${length}\r\n{argument}\r\n  for X in $CMD; do printf "\$${#X}\r\n$X\r\n"; donedone < redis_commands.txt

# sh 20.sh > redis_data.txt

# head -7 redis_data.txt 

*3$3set
$5name0
$10helloworld

至此,数据构造完毕。

测试结果

如下:

时间消耗完全不是一个量级的。

最后,来看看pipe的实现原理,

  • redis-cli --pipe tries to send data as fast as possible to the server.

  • At the same time it reads data when available, trying to parse it.

  • Once there is no more data to read from stdin, it sends a special ECHO command with a random 20 bytes string: we are sure this is the latest command sent, and we are sure we can match the reply checking if we receive the same 20 bytes as a bulk reply.

  • Once this special final command is sent, the code receiving replies starts to match replies with this 20 bytes. When the matching reply is reached it can exit with success.

  • 即它会尽可能快的将数据发送到Redis服务端,并尽可能快的读取并解析数据文件中的内容,一旦数据文件中的内容读取完了,它会发送一个带有20个字节的字符串的echo命令,Redis服务端即根据此命令来确认数据已插入完毕。

    总结:

    后续有童鞋好奇,构造redis命令的时间和将命令转化为protocol的时间,这里一并贴下:

  • [root@mysql-server1 ~]# time python 1.py > redis_commands.txt


  • real    0m0.110s

  • user    0m0.070s

  • sys    0m0.040s

  • [root@mysql-server1 ~]# time sh 20.sh > redis_data.txt


  • real    0m7.112s

  • user    0m5.861s

  • sys    0m1.255s