在上一篇《7月,redis迷情》提到平時(shí)運(yùn)維中榨崩,重度使用 redis-port颈墅,下面和大家分享下使用場景和心得。redis-port 最初是 codis 項(xiàng)目的附屬工具茫舶,同步 redis 數(shù)據(jù)到 codis 中械巡,現(xiàn)在已經(jīng)拆出來單獨(dú)維護(hù)。感謝作者@斯賓洛克?(spinlock??的意思)饶氏。
一切從需求出發(fā)
需求即場景讥耗,運(yùn)維有很多相似之處,下面列舉的例子不止 redis嚷往,涉及存儲數(shù)據(jù)都會遇到葛账,mysql, pg, mongodb,帶狀態(tài)的存儲大同小異皮仁。
1. redis 集群的擴(kuò)容與收縮籍琳,最經(jīng)典的需求
2. 數(shù)據(jù)異構(gòu)同步菲宴,從 redis 到 mysql等等
3. redis 原有集群的拆分,按業(yè)務(wù)線打散成多個集群
4. redis 當(dāng)前內(nèi)存使用趋急,key占比分析
5. 無用數(shù)據(jù)的檢測和清除
6. 對于 rdb 文件的備份
看了需求喝峦,相信大家都會相視一笑,把 redis 替換成任何數(shù)據(jù)庫呜达,仍然成立谣蠢。新浪對redis這塊重度使用,他們有過分享查近,大家可以谷歌搜一下眉踱。
先來看看redis-port原理
簡單來說,就是把自已偽裝成 slave, 欺騙master來達(dá)到數(shù)據(jù)流同步的目地霜威。
發(fā)送sync命令->接收rdb->解析rdb->過濾->回放rdb->回放master推送的同步數(shù)據(jù)
上面是原理流程谈喳,非常容易理解,解析完rdb后的每一步都可以高度定制戈泼。DBA 看著是不是很熟悉婿禽? 非常像淘寶的canal,基于 binlog 做數(shù)據(jù)的增量消費(fèi)大猛。相比 mysql replication的原理 redis 簡單太多扭倾,增量的數(shù)據(jù)就是普通的命令,需要解析的只有rdb文件挽绩。網(wǎng)上有一篇文章《Redis RDB Dump File Format》講的很贊膛壹,大家可以看看。
概括起來 rdb 格式由如下塊構(gòu)成:
1. 文件開頭是 rdb 版本號唉堪,比如REDIS0005
2. FE 后面跟隨 redis DB 號恢筝,正常 slave 回放時(shí)要使用 select db
3. FD|FC 后面跟隨秒或毫秒過期時(shí)間,緊隨其后 value-type, string-encoded-key, encoded-value巨坊。value-type表示value的類型 set, map, sorted set等等
4. FE 后面跟隨 redis DB 號,同步其它DB數(shù)據(jù)
5. 重復(fù)第3步
6. FF 表示RDB結(jié)束
7. 8 byte checksum crc64較驗(yàn)碼
結(jié)合 redis和redis-port 源代碼會對 rdb 理解更深刻此改。整個流程對應(yīng)代碼 cmd/sync.go 中的cmd.SyncRDBFile 和 cmd.SyncCommand 函數(shù)趾撵。
解決問題
假設(shè)大家有一定go基礎(chǔ),安裝 golang 和下載 redis-port 步驟省略共啃。
以擴(kuò)容為例占调,假如原有集群架構(gòu)是twemproxy模式,那么新建一套空集群移剪,后端實(shí)例成倍究珊。 redis-port默認(rèn)同步到 codis, 使用slotsrestore, 需要改成 restore 命令。
cmd/utils.go ?restoreRdbEntry ?函數(shù)
重新編譯纵苛,生成 redis-port 可執(zhí)行命令剿涮。兩套twemproxy, 后端對應(yīng)的hash策略改變言津,數(shù)據(jù)分布相應(yīng)也會改變,redis-port 同步時(shí)源指定為舊集群后端的master實(shí)例取试,目標(biāo)要指定為新集群的proxy地址悬槽。使用命令如下:
redis-port ?sync --parallel=100 --from=master_host:master_port ?--target=proxy:proxy_port?
這條命令是前臺執(zhí)行,長時(shí)間運(yùn)行nohup即可瞬浓。parallel 指同步 rdb 事件時(shí)并發(fā)的goroutine數(shù)量初婆。
再舉一個打散的例子,將 key 前輟是user_info的遷移到新集群猿棉。根據(jù) redis 同步原理磅叛,只要在sync rdb和sync command時(shí),將 key 前輟是user_info的過濾出來即可萨赁,代碼修改如下:
cmd/utils.go? restoreRdbEntry? 函數(shù)除了修改 slotsrestore弊琴,還要增加 key過濾
上圖代碼增加對 key 的過濾,完成了 sync rdb代碼的修改位迂。還要修改sync command访雪。
cmd/sync.go? SyncCommand? 函數(shù)增加 key過濾
最后使用和擴(kuò)容同樣的命令。遷移出 user_info 后掂林,老集群無效的key需要過濾并刪除臣缀。修改 cmd/utils.go restoreRdbEntry函數(shù),將restore改成del命令泻帮,再將同步自身即可精置。
這兩個例子比較典型,建義使用的同學(xué)仔細(xì)讀讀源代碼锣杂,順便學(xué)好go啊 ~_~
以下引用為作者@斯賓洛克 同學(xué)補(bǔ)充:
1. 支持 psync脂倦,例如 --psync?
2. 從 master 獲取 rdb+backlog 速度過慢,可導(dǎo)致 master 主動關(guān)閉連接元莫。解決方法你提到了一種赖阻,此外,還可以結(jié)合 --sockfile=buffer.tmp --filesize=64GB 參數(shù)踱蠢,這樣能使用一個最大 64GB 的文件作為緩沖(循環(huán)寫火欧,自動釋放),能加速 rdb+backlog 的獲取茎截,口味更佳苇侵。
3. 向 slave restore 的速度,可以通過增加 CPU 以及增加并發(fā)連接數(shù)實(shí)現(xiàn)企锌,分別是 --ncpu=4 --paralle=32
4. 其實(shí)榆浓,使用 psync 的話,port 和 master 之間就有 position 的概念了撕攒,可以減少同步失敗的發(fā)生情況陡鹃,redis-port 會自動重試直到不能烘浦。
注意事項(xiàng)
1. 同步時(shí)有兩個 redis 參數(shù)需要注意
?repl-backlog-size?
Set the replication backlog size. The backlog is a buffer that accumulates??slave data when slaves are disconnected for some time, so that when a slave?wants to reconnect again, often a full resync is not needed, but a partial?resync is enough, just passing the portion of data the slave missed while?disconnected.
The bigger the replication backlog, the longer the time the slave can be?disconnected and later be able to perform a partial resynchronization.
同步buffer的大小,默認(rèn)1mb杉适,根據(jù)當(dāng)前數(shù)據(jù)量大小適當(dāng)調(diào)整谎倔,比如10mb.
?client-output-buffer-limit
The client output buffer limits can be used to force disconnection of clients that are not reading data from the server fast enough for some reason (a common reason is that a Pub/Sub client can't consume messages as fast as the publisher can produce them). The limit can be set differently for the three different classes of clients: normal -> normal clients including MONITOR clients slave? -> slave clients pubsub -> clients subscribed to at least one pubsub channel or pattern The syntax of every client-output-buffer-limit directive is the following: client-output-buffer-limitA client is immediately disconnected once the hard limit is reached, or if?the soft limit is reached and remains reached for the specified number of?seconds (continuously).
So for instance if the hard limit is 32 megabytes and the soft limit is?16 megabytes / 10 seconds, the client will get disconnected immediately?if the size of the output buffers reach 32 megabytes, but will also get?disconnected if the client reaches 16 megabytes and continuously overcomes?the limit for 10 seconds.
client slave 級別的buffer也要調(diào)整,比如 client-output-buffer-limit slave 256mb 128mb 60?
2. restore 操作只要目標(biāo)集群存在指定Key, 就會fatal猿推,如果沒問題可以在代碼中去掉err檢測片习。
3. 使用偽裝slave的機(jī)制,redis-port一定要輪流同步蹬叭,同時(shí)bgsave可不好玩藕咏。
4. 代碼修改成通用的工具,每次改代碼邏輯容易出問題秽五,from和target一定要確認(rèn)好孽查。
5. 同步時(shí)由于源數(shù)據(jù)量太大,可能工具會中斷坦喘,調(diào)整redis-port并發(fā)數(shù)和redis上面提到的兩個buffer就好盲再。
存在的不足
最初 redis-port 只是定位臨時(shí)遷移工具,流處理時(shí)出現(xiàn)異常直接 panic, 同步時(shí)間不建義太久瓣铣。也和 redis replication 實(shí)現(xiàn)機(jī)制有關(guān)答朋,沒有類似 mysql binlog 和 position 的概念。
那么問題來了棠笑,聰明的你梦碗,想想該如何解決?
蠻好玩的工具 大完玩的開心 enjoy ...