如何将redis密钥添加到另一个实例

时间:2017-07-23 07:40:08

标签: python redis

我正在尝试将现有密钥从Redis实例(A)移动到另一个实例(B)而不会丢失B的密钥。 我可以使用任何工具,还是应该自己编写代码?

1 个答案:

答案 0 :(得分:0)

根据官方Redis群集教程:“...但是目前redis-trib无法自动重新平衡群集,检查群集节点上的密钥分配,并根据需要智能地移动插槽。此功能将被添加在将来。“

因此,您需要自己编写代码以将密钥分发给Redis实例。如果要将一个或多个密钥从一个节点迁移到另一个节点,则必须首先迁移哈希点,然后再迁移实际密钥,否则会发生错误。

通常,您需要一个执行这些Ruby代码行的代码过程(redis-trib.rb中的原型):

将插槽从源节点迁移到目标节点的代码

target.r.cluster("setslot",slot,"importing",source.info[:name])
source.r.cluster("setslot",slot,"migrating",target.info[:name])

迁移实际密钥的代码

source.r.client.call(["migrate",target.info[:host],target.info[:port],$keys_of_source[i],0,15000]).

您可以从此处使用现有代码进行迁移:https://github.com/projecteru/redis-trib.py

您可以使用以下代码行:

def migrate_slots_stable(src_host, src_port, dst_host, dst_port, slots):

    if src_host == dst_host and src_port == dst_port:
        raise ValueError('The source and the target node are the same.  A good reason is that the key is stored already on target node!')
    with Connection( src_host, src_port ) as t:
        nodes, myself = _list_masters( t, src_host)
    slots = set( slots )
    print('\x1b[6;30;42m' + '*****************************************MIGRATION PROCEDURE******************************************' + '\x1b[0m')
    print('\x1b[6;30;42m' + '******************************************************************************************************' + '\x1b[0m')
    print '* Migrating slots: ', slots , "* \n"
    for n in nodes:
        if n.host == dst_host and n.port == dst_port:
            return _migr_slots_stable( myself, n, slots, nodes )
    #raise ValueError( 'Two nodes are not in the same cluster' )


def _migr_slots_stable(source_node, target_node, slots, nodes):
    key_count = 0
    for slot in slots:
        key_count += _migr_one_slot_stable(source_node, target_node, slot, nodes)
        _migr_one_slot_stable( source_node, target_node, slot, nodes )
        #print "* keys_count that exists in these slot(s): ", key_count,' *'
        #print "\n"
        #print '* Migrated succesfully:',len(slots),'slot(s) and ',key_count,'key(s) from SOURCE NODE --> node_id:',source_node.node_id,'host:',source_node.host,'port:',source_node.port,'to TARGET NODE --> node_id:', target_node.node_id,'host:',target_node.host,'port:',target_node.port,' *'
    #print('\x1b[6;30;42m' + '******************************************************************************************************' + '\x1b[0m')
    print "\n"


def _migr_one_slot_stable(source_node, target_node, slot, nodes):
    def expect_exec_ok(m, conn, slot):
        if m.lower() != 'ok':
            conn.raise_('\n'.join([
            'Error while moving slot [ %d ] between' % slot,
            'Source node - %s:%d' % (source_node.host, source_node.port),
            'Target node - %s:%d' % (target_node.host, target_node.port),
            'Got %s' % m]))

    # Set the new node as the owner of the slot in all the known nodes
    # Bind the hash slot to a different node
    @retry(stop_max_attempt_number=16, wait_fixed=100)
    def setslot_stable(conn, slot, node_id):
        m = conn.execute('cluster', 'setslot', slot, 'node', node_id)
        expect_exec_ok(m, conn, slot)

    source_conn = source_node.get_conn()
    target_conn = target_node.get_conn()

    # Same in Ruby with these lines of code
    # the target node importing the slot and the source node migrating it
    try:
        expect_exec_ok(
        target_conn.execute('cluster', 'setslot', slot, 'importing',
                            source_node.node_id),
        target_conn, slot)
    except hiredis.ReplyError, e:
        if 'already the owner of' not in e.message:
        target_conn.raise_(e.message)

    try:
        expect_exec_ok(
        source_conn.execute('cluster', 'setslot', slot, 'migrating',
                            target_node.node_id),
        source_conn, slot)
    except hiredis.ReplyError, e:
        if 'not the owner of' not in e.message:
        source_conn.raise_(e.message)


    keys = _migr_keys_stable(source_conn, target_node.host, target_node.port, slot)
    setslot_stable(source_conn, slot, target_node.node_id)
    for node in nodes:
        setslot_stable(node.get_conn(), slot, target_node.node_id)
    return keys

def _migr_keys_stable(src_conn, target_host, target_port, slot):
    key_count = 0
    while True:
        keys = src_conn.execute('cluster', 'getkeysinslot', slot, 10)
        if len(keys) == 0:
            return key_count
        key_count += len(keys)
        src_conn.execute_bulk(
        # Same in Ruby with this line of code:    source.r.client.call(["migrate",target.info[:host],target.info[:port],$keys_of_source[i],0,15000])
        [['migrate', target_host, target_port, k, 0, 30000] for k in keys])

触发的第一个函数是def migrate_slots_stable,并且具有源主机,源端口,目标主机,目标端口和要传输的一组哈希映射的参数。