Как оптимизировать скрипт Redis cli для обработки 50 миллионов ключей

Ниже я написал сценарий bash для обработки ключа и значения Redis. У меня в Redis около 45-50 миллионов ключей. Я хочу получить все значения и выполнить некоторую обработку. Для этого мой приведенный ниже скрипт обрабатывает 1 миллион ключей за 1 час. Чтобы обработать 50 миллионов ключей, потребуется 50 часов, чего я не хочу делать. Я новичок в Redis cli - может ли кто-нибудь помочь мне оптимизировать приведенный ниже скрипт, или было бы очень здорово, если бы кто-нибудь мог дать какое-то предложение.

Моя схема "ключ-значение" Redis:

Keys - 123.item.media
Values - 93839,abc,98,829 | 38282,yiw,282,282 | 8922,dux,382,993 |

Keys - 234.item.media
Values - 2122,eww,92,211 | 8332,uei,902,872 | 9039,uns,892,782 |

Keys - 839.item.media
Values - 7822,nkp,77,002 | 7821,mko,999,822 |

В приведенном ниже сценарии я передаю все свои ключи и вычисляю, сколько записей у меня есть для каждого ключа. Например - этот ключ (123.item.media) имеет 3 записи, а этот (839.item.media) имеет две записи.

Таким образом, для вышеуказанных ключей и значений вывод должен быть: Total Count: 8

То же самое я делаю для всех 50 миллионов ключей, что занимает слишком много времени.

Мой код:

#!/bin/sh
cursor=-1
keys=""
recordCount=0
while [ $cursor -ne 0 ];
do
        if [ $cursor -eq -1 ]
        then
        cursor=0
    fi
    reply=`redis-cli SCAN $cursor MATCH "*" COUNT 100`
    #echo $reply
    cursor=`expr "$reply" : '\([0-9]*[0-9 ]\)'`
    keys=${reply#[0-9]*[[:space:]]}
    for i in $keys
    do
    #echo $i
    #echo $keys
    value=$(redis-cli GET $i)
    temCount=`echo $value | awk -F\| '{print NF}'`
    #echo $temCount
    recordCount=`expr ${temCount} + ${recordCount}`
    done
done

echo "Total Count: " $recordCount

Заранее оцените вашу помощь!


person learn java    schedule 28.10.2017    source источник
comment
Подумайте о том, чтобы сделать это на другом языке, потому что вы создаете новые процессы и соединения для каждой команды — попробуйте C, C++, Python, Perl, PHP или что-то подобное.   -  person Mark Setchell    schedule 29.10.2017


Ответы (2)


Вы слишком много раз выполняете ветвление в цикле, даже для таких простых вещей, как арифметика, которую можно выполнить с помощью встроенных функций Bash. Когда у вас есть такие вещи в цикле, который выполняется несколько миллионов раз, это замедляет работу. Например:

  • cursor=$(expr "$reply" : '\([0-9]*[0-9 ]\)')
  • temCount=$(echo $value | awk -F\| '{print NF}')
  • recordCount=$(expr ${temCount} + ${recordCount})

Я не эксперт по редису. Основываясь на моем поверхностном понимании redis-cli, вы можете сделать это:

redis-cli --scan | sort -u > all.keys
while read -r key; 
  value=$(redis-cli get "$key")
  # do your processing
done < all.keys

Если это не ускорит процесс, следующей идеей будет разбить файл all.keys на куски по несколько тысяч строк и запустить параллельный цикл для каждого подмножества ключей. Если это работает недостаточно быстро, я рекомендую изучить команду mget и изменить цикл так, чтобы мы получали значения партиями, а не по одному.

Кроме того, Bash может быть не лучшим выбором для этого. Я уверен, что есть лучшие способы сделать это в Python или Ruby.

person codeforester    schedule 28.10.2017

Много вашего времени тратится впустую на 50 миллионов сетевых вызовов для 50 миллионов ключей в соответствии с этой строкой:

value=$(redis-cli GET $i)

Чтобы выполнить массовый запрос, вы можете просто добавить команды GET в список, скажем, 1000, и выполнить массовый запрос, используя параметр --pipe.

  --pipe             Transfer raw Redis protocol from stdin to server.
  --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.
                     no reply is received within <n> seconds.

Пример массовой вставки приведен здесь в официальной документации redis, вы можете получить массовое чтение в аналогичных строках. .

Это, безусловно, даст вам необходимый импульс и превратит ваш скрипт в пару часов вместо 50 часов. Вы можете настроить значение своего массового списка на 1000, 10000 или 100000, чтобы увидеть, что лучше всего работает в зависимости от размера данных вашего значения.

person DhruvPathak    schedule 02.11.2017