【问题标题】:Batch Rename Keys批量重命名键
【发布时间】:2017-01-21 19:22:42
【问题描述】:

我有一个相当大的数据库(5 个数据库,每个数据库大约有一百万个键),每个键都有环境命名空间。例如:"datamine::production::crosswalk==foobar"

我需要将我的开发环境与从生产 RDB 快照复制的数据同步。

所以我要做的是批量重命名每个键,将命名空间从datamine::production 更改为datamine::development。有没有好的方法来实现这一点?

到目前为止我已经尝试过什么

  • keys "datamine::production*" 的 redis-cli 命令,通过管道传输到 sed,然后返回到 redis-cli。这需要很长时间,并且由于某种原因在许多键上炸弹(偶尔在同一行中组合几个)。我希望有更好的选择。

  • Perl 搜索/替换 .rdb 文件。我的本地 redis-server flat 拒绝加载修改后的 RDB。

【问题讨论】:

  • 我会选择“获取所有密钥并将它们扔给 RENAME 命令”。只有我会使用 SCAN 而不是 KEYS (更有效)。另外,我会使用 ruby​​ 而不是 sed
  • 好的,我要为此创建一个 ruby​​ 脚本,我会把它放在这里供全世界使用......(除非有人想打败我!)跨度>

标签: redis


【解决方案1】:

解决办法:

好的,这是我为解决此问题而编写的脚本。它需要“Redis” gem。希望其他人觉得这很有用...

#!/usr/bin/env ruby

# A script to translate the current redis database into a namespace for another environment
# GWI's Redis keys are namespaced as "datamine::production", "datamine::development", etc.
# This script connects to redis and translates these key names in-place.
#
# This script does not use Rails, but needs the "redis" gem available
require 'Benchmark'
require 'Redis'

FROM_NAMESPACE = "production"
TO_NAMESPACE = "development"
NAMESPACE_PREFIX = "datamine::"
REDIS_SERVER = "localhost"
REDIS_PORT   = "6379"
REDIS_DBS = [0,1,2,3,4,5]

redis = Redis.new(host: REDIS_SERVER, port: REDIS_PORT, timeout: 30)

REDIS_DBS.each do |redis_db|
  redis.select(redis_db)
  puts "Translating db ##{redis_db}..."
  seconds = Benchmark.realtime do
    dbsize = redis.dbsize.to_f
    inc_threshold = (dbsize/100.0).round
    i = 0
    old_keys = redis.keys("#{NAMESPACE_PREFIX}#{FROM_NAMESPACE}*")
    old_keys.each do |old_key|
      new_key = old_key.gsub(FROM_NAMESPACE, TO_NAMESPACE)
      redis.rename(old_key, new_key)
      print "#{((i/dbsize)*100.0).round}% complete\r" if (i % inc_threshold == 0) # on whole # % only
      i += 1
    end
  end
  puts "\nDone. It took #{seconds} seconds"
end

【讨论】:

  • 对于像这样的批处理操作,我建议使用流水线。如果您每 500 次左右的迭代刷新/执行一次,您很可能会毫不费力地将性能提高 40 到 50 倍。
【解决方案2】:

我有一个可行的解决方案:

EVAL "local old_prefix_len = string.len(ARGV[1])
local keys = redis.call('keys', ARGV[1] .. '*')
for i = 1, #keys do
    local old_key = keys[i]
    local new_key = ARGV[2] .. string.sub(old_key, old_prefix_len + 1)
    redis.call('rename', old_key, new_key)
end" 0 "datamine::production::" "datamine::development::"

最后两个参数分别是旧前缀和新前缀。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-17
    • 2014-09-10
    • 1970-01-01
    • 2012-11-15
    • 2013-12-19
    • 2013-07-01
    • 2012-07-12
    相关资源
    最近更新 更多