Redis 快速导入大量数据

1. 问题描述

有大量以“key’\t’value’ ‘value’ '……”存储的数据,示例如下:

0000    0475_48070 0477_7204 0477_7556 0480_33825 0481_206660 0482_76734 0436_33682 0484_13757 0538_217492 0727_83721 0910_39874 0436_82813 0421_24138 0433_
113233 0425_67342 0475_56710 0438_83702 0421_14436 0451_15490 0456_51031 0475_126541 0459_64108 0475_28238 0475_73706 0425_67481 0481_70285 0482_40188 0482_
95188 0484_13346 0484_13940 0538_164341 0538_183629 0545_163319 0545_165272 0546_30724 0730_32196 0910_96866 0427_12847 0425_23173 0424_25451 0475_114926 04
28_44669 0421_14377 0422_27895 0428_79517 0454_26686 0477_76526 0481_51805 0539_22388 0545_86479 0546_23459 0450_30062 0546_31676 0437_820 0740_6902 0740_90
53 0436_75434 0427_5396 0425_65534 0433_113207 0479_42501 0450_41529 0456_63985 0457_503 0458_20159 0470_30141
0001    0481_206403 0732_17231 0730_5902 0425_21756 0437_32744 0450_30493 0457_1339 0475_21591 0475_43849 0475_48123 0481_129436

将大概十几G的数据导入Redis,如果只用单纯的循环,示例代码如下:

r = redis.Redis(host='localhost', port=6379, decode_responses=True, db=1)

with open('data/news.txt', 'r', encoding='utf-8') as f:
    data = f.read().strip().split('\n')

for line in data:
    line = line.split('\t')
    indice = line[1].split(' ')
    for index in indice:
        r.sadd(line[0], index)

要花费很长时间(大概几个小时?放后台跑,具体时间不是很清楚)。

现在需要合适的方式,快速将所需数据导入Redis

2. 导入方法测试(3)

import redis
from timeUtil import TimeDuration

'''
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> info keyspace
# Keyspace
127.0.0.1:6379>
'''

t = TimeDuration()

r = redis.Redis(host='localhost', port=6379, decode_responses=True, db=1)


with open('data/news.txt', 'r', encoding='utf-8') as f:
    data = f.read().strip().split('\n')

t.start()
for line in data[:1000]:
    line = line.split('\t')
    indice = line[1].split(' ')
    for index in indice:
        r.sadd(line[0], index)

t.stop()
# 0:00:01.974389


r = redis.Redis(host='localhost', port=6379, decode_responses=True, db=2)

t.start()
with r.pipeline(transaction=False) as p:
    for line in data[:1000]:
        line = line.split('\t')
        indice = line[1].split(' ')
        for index in indice:
            p.sadd(line[0], index)
    p.execute()
t.stop()
# 0:00:00.285798


r = redis.Redis(host='localhost', port=6379, decode_responses=True, db=3)

t.start()
for line in data[:1000]:
    line = line.split('\t')
    indice = line[1].split(' ')
    r.sadd(line[0], *indice)

t.stop()
# 0:00:00.166977

# 127.0.0.1:6379> info keyspace
# # Keyspace
# db1:keys=1000,expires=0,avg_ttl=0
# db2:keys=1000,expires=0,avg_ttl=0
# db3:keys=1000,expires=0,avg_ttl=0
# timeUtil.py
# 时间统计封装类
# 参考:https://blog.csdn.net/a_flying_bird/article/details/46431061

import datetime
import time


class TimeDuration(object):
    
    def __init__(self):
        pass

    def start(self):
        self.sTime = datetime.datetime.now()
        self.eTime = None

    def stop(self):
        if self.sTime is None:
            print("ERROR: start() must be called before stop().")
            return
        self.eTime = datetime.datetime.now()
        delta = self.eTime - self.sTime
        print(delta)

0:00:01.974389
0:00:00.285798
0:00:00.166977

可以发现第三种方法耗时最短。但在实际使用过程中,第三种方法会报如下错误:

redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

分析是由于Redis存储中,会先使用ziplist压缩列表存储小体积数据,节约内存。但当value数据在sadd过程中不断增大,会转变使用hashtable,因此出现错误。(存疑)

3. 原理分析

客户端如果想获取或者设置多个key,可以发送多次get,set命令。但是每次命令从客户端传到redis服务端都要消耗网络时间。发送n次会消耗n次网络时间(第一种导入方法)。

客户端等待的时间 = n次网络时间+n次命令时间(包括命令排队时间和执行时间)

使用mget或者mset(*indice,第三种导入方法),只发送了一次命令。

客户端等待的时间 = 1次网络时间+n次命令时间(包括命令排队时间和执行时间)

使用pipeline,可以将上述多条命令打包并一次性发送给服务端批量处理(第二种导入方法)。

客户端等待的时间 = 1次网络时间+n次命令时间(包括命令排队时间和执行时间)

参考链接:https://blog.csdn.net/weixin_39975366/article/details/113963503

问题:为什么第二种方法和第三种方法用时不同?

猜你喜欢

转载自blog.csdn.net/MaoziYa/article/details/114269129
今日推荐