Redis importa rápidamente grandes cantidades de datos

1. Descripción del problema

Hay una gran cantidad de datos almacenados como "clave '\ t'value''value' '……", los ejemplos son los siguientes:

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

Importe unos diez gigabytes de datos a Redis. Si solo se utiliza un bucle simple, el código de muestra es el siguiente:

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)

Lleva mucho tiempo (¿unas pocas horas? Ejecutar en segundo plano, el tiempo específico no está muy claro).

Ahora necesitamos una forma adecuada de importar rápidamente los datos necesarios a Redis .

2. Prueba del método de importación (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

Se puede encontrar que el tercer método toma el tiempo más corto. Pero en el uso real, el tercer método informará el siguiente error:

redis.exceptions.ResponseError: MISCONF Redis está configurado para guardar instantáneas RDB, pero actualmente no puede persistir en el disco. Los comandos que pueden modificar el conjunto de datos están deshabilitados, porque esta instancia está configurada para informar errores durante las escrituras si falla la instantánea de RDB (opción stop-writes-on-bgsave-error). Consulte los registros de Redis para obtener detalles sobre el error de RDB.

El análisis se debe al hecho de que en el almacenamiento de Redis, la lista de compresión ziplist se usa para almacenar primero datos de pequeño volumen, ahorrando memoria. Pero cuando los datos de valor siguen aumentando en el triste proceso, cambiarán para usar hashtable, por lo que se produce un error. (En duda)

3. Análisis de principios

Si el cliente desea obtener o establecer varias claves, puede enviar varios comandos get y set. Pero cada vez que se transmite un comando desde el cliente al servidor Redis, consume tiempo de red. Enviar n veces consumirá tiempo de red n veces (el primer método de importación).

Tiempo de espera del cliente = n tiempos de tiempo de red + n tiempos de tiempo de comando (incluido el tiempo de cola de comandos y el tiempo de ejecución)

Usando mget o mset (* indice, el tercer método de importación), el comando se envió solo una vez.

Tiempo de espera del cliente = 1 tiempo de red + n tiempo de comando (incluido el tiempo de cola de comandos y el tiempo de ejecución)

Con la canalización, puede empaquetar y enviar varios comandos al servidor para el procesamiento por lotes a la vez (el segundo método de importación).

Tiempo de espera del cliente = 1 tiempo de red + n tiempo de comando (incluido el tiempo de cola de comandos y el tiempo de ejecución)

Enlace de referencia: https://blog.csdn.net/weixin_39975366/article/details/113963503

Pregunta: ¿Por qué el segundo método y el tercer método toman un tiempo diferente?

Supongo que te gusta

Origin blog.csdn.net/MaoziYa/article/details/114269129
Recomendado
Clasificación