如何优化redis cli脚本来处理5000万个密钥

时间:2017-10-28 15:58:14

标签: bash redis query-performance redis-cli redisclient

我写了下面的bash脚本来处理redis键和值。我的Redis中有大约45-50万个密钥。我想检索所有值并进行一些处理。为此,我的下面脚本需要1个小时来处理1百万个密钥。为了处理5000万个密钥需要花费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)有两条记录。

因此对于bove键和值,输出应为: 总人数:8

同样,我为所有5000万个密钥做了 - 这花费了太多时间。

我的代码:

#!/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

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

你在循环中分配太多次,即使对于像Bash内置函数可以完成的算术之类的简单事情也是如此。当你在循环中运行这样的东西几百万次时,它会减慢速度。例如:

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

我不是redis专家。根据我对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中有更好的方法可以做到这一点。

答案 1 :(得分:1)

根据这条线,您的大部分时间都被浪费在5000万个网络电话中,需要5000万个密钥:

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官方文档中给出了大量插入的示例here,您可以在类似的行上获得批量读取。

这肯定会为您提供所需的提升并将您的脚本转换为几个小时而不是50小时。您可以将批量列表的值调整为1000,10000或100000,以根据您的值数据大小查看最佳效果。