突然發(fā)現(xiàn)我們的redis 已經(jīng)用了30G了,好吧這是個(gè)很尷尬的數(shù)字因?yàn)槲覀兊木彺鏅C(jī)器的內(nèi)存目前是32G的,內(nèi)存已經(jīng)告竭。幸好上上周公司采購(gòu)了90G的機(jī)器,現(xiàn)在已經(jīng)零時(shí)遷移到其中的一臺(tái)機(jī)器上了。(跑題下,90G的內(nèi)存太爽了是我除了koding.com 之外第二次用到90G的
突然發(fā)現(xiàn)我們的redis 已經(jīng)用了30G了,好吧這是個(gè)很尷尬的數(shù)字因?yàn)槲覀兊木彺鏅C(jī)器的內(nèi)存目前是32G的,內(nèi)存已經(jīng)告竭。幸好上上周公司采購(gòu)了90G的機(jī)器,現(xiàn)在已經(jīng)零時(shí)遷移到其中的一臺(tái)機(jī)器上了。(跑題下,90G的內(nèi)存太爽了是我除了koding.com 之外第二次用到90G的機(jī)器,koding 是個(gè)好網(wǎng)站,在線編程IDE。) 但是隨著數(shù)據(jù)量越來(lái)越大單機(jī)始終無(wú)法承受的,改造勢(shì)在必行。經(jīng)過(guò)初步思考我們得出了很簡(jiǎn)單的方案 概括起來(lái)就是 "內(nèi)外兼修"
1.內(nèi)功修煉
先從我們的應(yīng)用層說(shuō)起 看看redis 使用情況 ,有沒(méi)有辦法回收一些key ,先進(jìn)入redis 服務(wù)器執(zhí)行 info ,有刪減
1: redis 127.0.0.1:6391> info
2: used_memory_human:35.58G
3: keyspace_hits:2580207188
4: db0:keys=2706740,expires=1440700
目前我們只使用了1個(gè)DB 但是key 太多了 有270W個(gè)key,已經(jīng)過(guò)期的有144W。第一個(gè)想到的就是我勒個(gè)去,怎么會(huì)有這么多key ,第二個(gè)想法就是可能存在過(guò)大的key
看看能不能針對(duì)過(guò)大的key 做優(yōu)化?可是遺憾的是官方并沒(méi)有命令顯示db 的key 大小,我們只能自己想辦法了
Google 一番,發(fā)現(xiàn)國(guó)外友人已經(jīng)寫(xiě)好了shell
傳送門(mén): https://gist.github.com/epicserve/5699837
可以列出每個(gè)key 大小了。可是這并不適用我們,因?yàn)槲覀僰ey 太大了 執(zhí)行了9個(gè)小時(shí)都沒(méi)跑完,無(wú)力吐槽了。 其實(shí)還有一個(gè)選擇就是用另外一個(gè)工具
傳送門(mén):https://github.com/sripathikrishnan/redis-rdb-tools
可惜這個(gè)太重了 ,不想麻煩ops ,我們就只能撩起袖子,造輪子。
把shell 代碼簡(jiǎn)單看了下發(fā)件DEBUG OBJECT 是個(gè)好東西啊 ,google 下發(fā)現(xiàn)官網(wǎng)
已經(jīng)有簡(jiǎn)單的調(diào)試信息了,剩下的就好處理了
1: #coding=utf-8 2: import redis 3: 4: COLOR_RED = "\033[31;49;1m %s \033[31;49;0m" 5: 6: COLOR_GREED = "\033[32;49;1m %s \033[39;49;0m" 7: 8: COLOR_YELLOW = "\033[33;49;1m %s \033[33;49;0m" 9: 10: COLOR_BLUE = "\033[34;49;1m %s \033[34;49;0m" 11: 12: COLOR_PINK = "\033[35;49;1m %s \033[35;49;0m" 13: 14: COLOR_GREENBLUE = "\033[36;49;1m %s \033[36;49;0m" 15: 16: 17: def getHumanSize(value): 18: gb = 1024 * 1024 * 1024.0 19: mb = 1024 * 1024.0 20: kb = 1024.0 >= gb: 22: return COLOR_RED % (str(round(value / gb, 2)) + " gb") 23: elif value >= mb: 24: return COLOR_YELLOW % (str(round(value / mb, 2)) + " mb") 25: elif value >= kb: 26: return COLOR_BLUE % (str(round(value / kb, 2)) + " kb") 27: else: 28: return COLOR_GREED % (str(value) + "b") 29: 30: 31: month = 3600 * 24 * 30 32: result = [] 33: client = redis.Redis(host="XXXXX", port=XXXX) 36: client.info() 37: 38: count = 0 39: for key in client.keys('*'): 40: try: 41: count += 1 42: idleTime = client.object('idletime', key) 43: refcount = client.object('refcount', key) 44: length = client.debug_object(key)['serializedlength'] 45: value = idleTime * refcount 46: print "%s key :%s , idletime : %s,refcount :%s, length : %s , humSize :%s" % (count, key, idleTime, refcount, length, getHumanSize(length)) 47: except Exception: 48: pass
寫(xiě)了個(gè)簡(jiǎn)單的python 腳本輸出每個(gè)key 的大小和idle time,和refer count 。有了這么多數(shù)據(jù)結(jié)合awk 就可以很好的統(tǒng)計(jì)每個(gè)key 的使用情況。有一點(diǎn)要注意的是這個(gè)size 是key 在redis 中的大小,并非實(shí)際的大小,這個(gè)是經(jīng)過(guò)redis 壓縮的。經(jīng)過(guò)分析之后發(fā)現(xiàn)不存在過(guò)大的key ,但是存在有些key 半年都沒(méi)有被訪問(wèn)過(guò) Orz 。
接下來(lái)就很好處理了,我們?yōu)槊總€(gè)key 設(shè)置的過(guò)期時(shí)間,若key 被hit 上則更新這個(gè)expire time 。這樣可以逐步淘汰冷數(shù)據(jù),達(dá)到冷熱分離
2. 外功修煉
我們對(duì)內(nèi)清理了無(wú)效的key,對(duì)外我們要做到水平擴(kuò)展,單機(jī)的承載始終有限,于是我們開(kāi)始了傳說(shuō)中的分布式改造
分布式這東西看起來(lái)很唬人做起來(lái)更唬人,幸好我們是緩存服務(wù) CAP約束有限。 緩存服務(wù)做分布式最好的當(dāng)然是一致性hash 咯。其實(shí)當(dāng)我們改造完成之后,才發(fā)現(xiàn)官方已經(jīng)準(zhǔn)備做這個(gè)分布式的緩存體系了(流口水?。?只是現(xiàn)在還在開(kāi)發(fā)中 給了個(gè)備用的響當(dāng)當(dāng)?shù)?Twemproxy 奈何我們已經(jīng)做好了,就先用著,坐等官方測(cè)試之后再說(shuō)
傳送門(mén):
我們實(shí)現(xiàn)了數(shù)據(jù)的平滑遷移,而且對(duì)server 的修改實(shí)現(xiàn)了最小影響。 因?yàn)樵瓉?lái)是用的是phpredis 所以就擴(kuò)展了下,代碼可以平滑過(guò)渡。
我們自己的實(shí)現(xiàn):https://github.com/trigged/redis_con_hash
其實(shí)扯了這么多就是要把redis 的數(shù)據(jù)分散開(kāi),單機(jī)的承載始終是個(gè)瓶頸,但是redis 在這方面沒(méi)有Memcached 完善,不過(guò)以后會(huì)越來(lái)越好
,聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com