1. 程式人生 > >Cash Loan(十三):Redis百萬級別資料遷移

Cash Loan(十三):Redis百萬級別資料遷移

【前言】

       我們是做的國外的專案,最開始的時候調研在國外亞馬遜雲在可靠性等方面還是具有很大優勢,於是我們的專案都部署在亞馬遜雲上;

       我們業務發展十分不錯,隨著專案越來越大,用到的機器越來越多,同時亞馬遜的成本也在不斷攀升;最近一段時間我們又針對國外市場進行了各方面(成本,可靠性等)進行調研,最終決定將所有業務及資料從亞馬遜雲遷移至阿里雲;當然遷移也是個有挑戰的事情;要做到不能出任何差錯,各個技術團隊配合(運維負責進行環境搭建,資料遷移;開發負責各個工程的檢查;測試負責迴歸測試.....)

       今天與大家分享的是我們資料遷移其中的一部分Redis資料遷移的一種備用方案;

【遷移方法】

       一、資料量:

資料條數:550萬+,資料大小:450MB 

       二、遷移:

1、亞馬遜自帶redis--->阿里雲自帶redis

            2、自帶redis和自建redis區別:自帶redis是雲伺服器上本身應用,自建redis是在雲伺服器上自己安裝redis服務;自帶redis的優點:可靠,省事,出故障後恢復快;自建redis優點:可控;

            3、Redis遷移標準:(1)資料不能丟失錯亂;(2)遷移時間必須夠快(按照整體遷移的進度來看,redis遷移必須控制在一個半小時以內);

       三、兩種方案及實現:

              1、兩種方案:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 把redis裡面一個數據庫的東西,遷移到另外一個數據庫裡面
# 建立兩個redis連線
# 獲取到所有的key .keys()
# 判斷key的型別 string\hash\list\set

import redis
#redis_from源資料,redis_to目標資料  redis_from——>redis_to
redis_from = redis.StrictRedis(host='ip',port=6379,password='',db=10)
redis_to = redis.StrictRedis(host='ip',port=6379,password='',db=10)

if __name__ == '__main__':
    cnt = 0
    scnt = 0
    lcnt = 0
    setcnt = 0
    hcnt = 0
    
    for k in redis_from.keys():
        # 迴圈keys裡面每一個key

        data_type = redis_from.type(k)
        # 判斷key的型別 string\hash\list\set

        if data_type == 'string':
            v = redis_from.get(k)
            t = redis_from.ttl(k)
            redis_to.set(k, v)
            if int(t) > 0:
                redis_to.expire(k,t)

            scnt = scnt + 1

        elif data_type == 'list':
            values = redis_from.lrange(k, 0, -1)
            t = redis_from.ttl(k)           
            redis_to.lpush(k, values)
            if int(t) > 0:
                redis_to.expire(k,t)

            lcnt = lcnt + 1
        elif data_type == 'set':
            values = redis_from.smembers(k)
            t = redis_from.ttl(k)
            redis_to.sadd(k, values)

            if int(t) > 0:
                redis_to.expire(k,t)
            setcnt = setcnt + 1
        elif data_type == 'hash':
            hcnt = hcnt + 1
            keys = redis_from.hkeys(k)                        
            for key in keys:
                value = redis_from.hget(k, key)
                t = redis_from.ttl(k)
                redis_to.hset(k, key, value)
                if int(t) > 0:
                    redis_to.expire(k,t)

        else:
            print 'not known type'
            print data_type
            file_object = open('/data/thefile.txt','a+')
            file_object.write(data_type)
            file_object.write('\n')
            file_object.close( )



        cnt = cnt + 1

    print 'total', cnt
    print 'string', scnt
    print 'list', lcnt
    print 'set', setcnt
    print 'hash', hcnt

                 (3)兩種方案各自優點:

                          ①rdb方案:簡單,速度快,可靠性高

                          ②程式方案:rdb不能用的情況下備胎

              2、最終方案確認                

(1)考慮到各個方面肯定是rdb方案是首選,遇到問題:

                          當時運維初步研究發現亞馬遜自帶Redis不支援匯出rdb檔案,而且阿里雲自帶的redis不支援rdb檔案匯入;

                 (2)直接用程式將亞馬遜雲的自帶redis資料讀到阿里雲自帶redis中,遇到問題:

                          資料量大,時時刻刻需要跨網傳輸,需要時間長;

(3)經過和運維一起溝通,確定一種解決方案:

                          ①在亞馬遜上搭一個自建redis;

                          ②通過程式將生產自帶redis值讀到自建redis;

                          ③備份亞馬遜自建redis的rdb檔案,拷貝並恢復到阿里雲的自建redis上;

                          ④通過阿里雲自帶redis-sync-manager工具將阿里雲的自建redis資料遷移至阿里雲自帶redis;

(4)最終多次用最終方案做實驗,發現將550W+線上資料從亞馬遜雲自帶redis同步到阿里雲自帶redis中用時1.2小時左右符合預期目標;

(5)實驗中的個小疑惑:同步完後在阿里雲自帶redis中檢視發現總少幾萬個key;通過將redis同步前後的key值匯出來(參考《Cash Loan(十):檢視redis的Value值大小》)對比發現少的這幾萬個key正好是失效時間在1.2小時內的。

(6)後來運維進行深入研究後發現亞馬遜雲自帶redis和阿里雲自帶redis都支援rdb檔案的匯入和匯出,所以我們最終的方案是第一種方案用rdb方案進行備份和恢復,以上說的方案則為第二備用方案。                               

【總結】

          1、大資料時代已然來臨,處理大資料量越來越成為我們程式設計師必須面對;

          2、不斷迎接新的挑戰,增加自身能力。