4

我在下面编写了 bash 脚本来处理 redis 键和值。我的 Redis 中有大约 45-50 百万个键。我想检索所有值并进行一些处理。为此,我的以下脚本需要 1 小时来处理 100 万个密钥。为了处理 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 键和值,输出应该是: Total Count: 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

提前感谢您的帮助!

4

2 回答 2

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 中有更好的方法来做到这一点。

于 2017-10-28T18:55:05.953 回答
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 官方文档中给出了批量插入的示例您可以在类似的行上导出批量读取。

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

于 2017-11-02T08:42:06.043 回答