1
Redis架構(gòu)的方案經(jīng)歷階段
1.1.?客戶端分片
客戶端分片:
優(yōu)點
不依賴于第三方中間件蹋订,實現(xiàn)方法和代碼自己掌控澜驮,可隨時調(diào)整
這種分片機制的性能比代理式更好(少了一個中間分發(fā)環(huán)節(jié))
可控的分發(fā)請求,分發(fā)壓力落在客戶端,無服務(wù)器壓力增加
缺點
不能平滑的水平擴展節(jié)點,擴容/縮容時祈秕,必須手動調(diào)整分片程序
出現(xiàn)故障渺贤,不能自動轉(zhuǎn)移,運維性很差
客戶端得自己維護一套路由算法
升級復(fù)雜
1.2.?Twemproxy
Twemproxy:
優(yōu)點
運維成本低请毛。業(yè)務(wù)方不用關(guān)心后端Redis實例志鞍,跟操作Redis一樣
Proxy 的邏輯和存儲的邏輯是隔離的
缺點
代理層多了一次轉(zhuǎn)發(fā),性能有所損耗
進行擴容/縮容時候方仿,部分?jǐn)?shù)據(jù)可能會失效固棚,需要手動進行遷移,對運維要求較高兼丰,而且難以做到平滑的擴縮容
出現(xiàn)故障玻孟,不能自動轉(zhuǎn)移,運維性很差
升級復(fù)雜
1.3.?Redis Cluster
Redis Cluster:
優(yōu)點
無中心節(jié)點
數(shù)據(jù)按照Slot存儲分布在多個Redis實例上
平滑的進行擴容/縮容節(jié)點
自動故障轉(zhuǎn)移(節(jié)點之間通過Gossip協(xié)議交換狀態(tài)信息,進行投票機制完成Slave到Master角色的提升)
降低運維成本鳍征,提高了系統(tǒng)的可擴展性和高可用性
缺點
嚴(yán)重依賴外部Redis-Trib
缺乏監(jiān)控管理
需要依賴Smart Client(連接維護, 緩存路由表, MultiOp和Pipeline支持)
Failover節(jié)點的檢測過慢黍翎,不如“中心節(jié)點ZooKeeper”及時
Gossip消息的開銷
無法根據(jù)統(tǒng)計區(qū)分冷熱數(shù)據(jù)
Slave“冷備”,不能緩解讀壓力
1.4.?Proxy+Redis Cluster
Smart Client vs Proxy:
優(yōu)點
Smart Client:
a.?相比于使用代理艳丛,減少了一層網(wǎng)絡(luò)傳輸?shù)南南坏В瘦^高。
b.?不依賴于第三方中間件氮双,實現(xiàn)方法和代碼自己掌控碰酝,可隨時調(diào)整。
Proxy:
a.?提供一套HTTP Restful接口戴差,隔離底層存儲送爸。對客戶端完全透明,跨語言調(diào)用暖释。
b.?升級維護較為容易袭厂,維護Redis Cluster,只需要平滑升級Proxy球匕。
c.?層次化存儲纹磺,底層存儲做冷熱異構(gòu)存儲。
d.?權(quán)限控制亮曹,Proxy可以通過秘鑰控制白名單橄杨,把一些不合法的請求都過濾掉。并且也可以控制用戶請求的超大Value進行控制照卦,和過濾式矫。
e.?安全性,可以屏蔽掉一些危險命令窄瘟,比如Keys衷佃、Save、Flush All等蹄葱。
f.?容量控制氏义,根據(jù)不同用戶容量申請進行容量限制。
g.?資源邏輯隔離图云,根據(jù)不同用戶的Key加上前綴惯悠,來進行資源隔離。
h.?監(jiān)控埋點竣况,對于不同的接口進行埋點監(jiān)控等信息克婶。
缺點
Smart Client:
a.?客戶端的不成熟,影響應(yīng)用的穩(wěn)定性丹泉,提高開發(fā)難度情萤。
b.?MultiOp和Pipeline支持有限。
c.?連接維護摹恨,Smart客戶端對連接到集群中每個結(jié)點Socket的維護筋岛。
Proxy:
a. ?代理層多了一次轉(zhuǎn)發(fā),性能有所損耗晒哄。
b.進行擴容/縮容時候?qū)\維要求較高睁宰,而且難以做到平滑的擴縮容。
2
為什么選擇Nginx開發(fā)Proxy
1.單Master多Work模式寝凌,每個Work跟Redis一樣都是單進程單線程模式柒傻,并且都是基
于Epoll事件驅(qū)動的模式。
2.Nginx采用了異步非阻塞的方式來處理請求较木,高效的異步框架红符。
3.內(nèi)存占用少,有自己的一套內(nèi)存池管理方式,伐债。將大量小內(nèi)存的申請聚集到一塊预侯,能夠比Malloc 更快。減少內(nèi)存碎片泳赋,防止內(nèi)存泄漏雌桑。減少內(nèi)存管理復(fù)雜度。
4. ?為了提高Nginx的訪問速度祖今,Nginx使用了自己的一套連接池校坑。
5. ?最重要的是支持自定義模塊開發(fā)。
6. ?業(yè)界內(nèi)千诬,對于Nginx耍目,Redis的口碑可稱得上兩大神器。性能也就不用說了徐绑。
3
Proxy+Redis Cluster介紹
3.1??Proxy+Redis Cluster架構(gòu)方案介紹
1.?用戶在ACL平臺申請集群資源邪驮,如果申請成功返回秘鑰信息。
2.?用戶請求接口必須包含申請的秘鑰信息傲茄,請求至LVS服務(wù)器毅访。
3.?LVS根據(jù)負(fù)載均衡策略將請求轉(zhuǎn)發(fā)至Nginx Proxy沮榜。
4.?Nginx Proxy首先會獲取秘鑰信息,然后根據(jù)秘鑰信息去ACL服務(wù)上獲取集群的種子信息喻粹。(種子信息是集群內(nèi)任意幾臺IP:PORT節(jié)點)
然后把秘鑰信息和對應(yīng)的集群種子信息緩存起來蟆融。并且第一次訪問會根據(jù)種子IP:PORT獲取集群Slot對應(yīng)節(jié)點的Mapping路由信息,進行緩存起來守呜。最后根據(jù)Key計算SlotId型酥,從緩存路由找到節(jié)點信息。
5.?把相應(yīng)的K/V信息發(fā)送到對應(yīng)的Redis節(jié)點上查乒。
6.?Nginx?Proxy定時(60s)上報請求接口埋點的QPS,RT,Err等信息到Open-Falcon平臺弥喉。
7.?Redis?Cluster定時(60s)上報集群相關(guān)指標(biāo)的信息到Open-Falcon平臺。
3.2??Nginx Proxy功能介紹
目前支持的功能:
HTTP Restful接口:
解析用戶Post過來的數(shù)據(jù)玛迄, 并且構(gòu)建Redis協(xié)議由境。客戶端不需要開發(fā)Smart Client,?對客戶端完全透明憔晒、跨語言調(diào)用
權(quán)限控制:
根據(jù)用戶Post數(shù)據(jù)獲取AppKey,Uri, 然后去ACL Service服務(wù)里面進行認(rèn)證藻肄。如果認(rèn)證通過,會給用戶返回相應(yīng)的集群種子IP拒担,以及相應(yīng)的過期時間限制等信息
限制數(shù)據(jù)大朽谕汀:
獲取用戶Post過來的數(shù)據(jù),對Key从撼,Value長度進行限制州弟,避免產(chǎn)生超大的Key,Value,打滿網(wǎng)卡低零、阻塞Proxy
數(shù)據(jù)壓縮/解壓:
如果是寫請求婆翔,對Value進行壓縮(Snappy),然后在把壓縮后的數(shù)據(jù)存儲到Redis Cluster掏婶。
如果是讀請求啃奴,把Value從Redis Cluster讀出來,然后對Value進行解壓雄妥,最后響應(yīng)給用戶最蕾。
緩存路由信息:
維護路由信息,Slot對應(yīng)的節(jié)點的Mapping信息
結(jié)果聚合:
MultiOp支持
批量指令支持(Pipeline/Redis+Lua+EVALSHA進行批量指令執(zhí)行)
資源邏輯隔離:
根據(jù)用戶Post數(shù)據(jù)獲取該用戶申請的NameSpace老厌,然后以NameSpace作為該用戶請求Key的前綴瘟则,從而達(dá)到不同用戶的不同NameSpace,進行邏輯資源隔離
重試策略:
針對后端Redis節(jié)點出現(xiàn)Moved,Ask,Err,TimeOut等進行重試枝秤,重試次數(shù)可配置
連接池:
維護用戶請求的長連接醋拧,維護后端服務(wù)器的長連接
配額管理:
根據(jù)用戶的前綴(NameSpace), 定時的去抓取RANDOMKEY,根據(jù)一定的比率,估算出不同用戶的容量大小值丹壕,然后在對用戶的配額進行限制管理
過載保護:
通過在Nginx Proxy Limit模塊進行限速庆械,超過集群的承載能力,進行過載保護雀费。從而保證部分用戶可用干奢,不至于壓垮服務(wù)器
監(jiān)控管理:
Nginx Proxy接入了Open-Falcon對系統(tǒng)級別痊焊,應(yīng)用級別盏袄,業(yè)務(wù)級別進行監(jiān)控和告警
例如:?接口的QPS,RT,ERR等進行采集監(jiān)控,并且展示到DashBoard上
告警閾值的設(shè)置非常靈活薄啥,配置化
待開發(fā)的功能列表:
層次化存儲:
利用Nginx Proxy共享內(nèi)存定制化開發(fā)一套LRU本地緩存實現(xiàn)辕羽,從而減少網(wǎng)絡(luò)請求
冷數(shù)據(jù)Swap到慢存儲,從而實現(xiàn)冷熱異構(gòu)存儲
主動Failover節(jié)點:
由于Redis Cluster是通過Gossip通信, 超過半數(shù)以上Master節(jié)點通信(cluster-node-timeout)認(rèn)為當(dāng)前Master節(jié)點宕機垄惧,才真的確認(rèn)該節(jié)點宕機刁愿。判斷節(jié)點宕機時間過長,在Proxy層加入Raft算法到逊,加快失效節(jié)點判定铣口,主動Failover
3.3??Nginx Proxy性能優(yōu)化
3.3.1??批量接口優(yōu)化方案
1. 子請求變?yōu)閰f(xié)程
案例:
用戶需求調(diào)用批量接口mget(50Key)要求性能高,吞吐高觉壶,響應(yīng)快脑题。
問題:
由于最早用的Nginx Subrequest來做批量接口請求的處理,性能一直不高铜靶,CPU利用率也不高叔遂,QPS提不起來。通過火焰圖觀察分析子請求開銷比較大争剿。
解決方案:
子請求效率較低已艰,因為它需要重新從Server Rewrite開始走一遍Request處理的PHASE。并且子請求共享父請求的內(nèi)存池蚕苇,子請求同時并發(fā)度過大哩掺,導(dǎo)致內(nèi)存較高。
協(xié)程輕量級的線程涩笤,占用內(nèi)存少嚼吞。經(jīng)過調(diào)研和測試,單機一兩百萬個協(xié)程是沒有問題的辆它,
并且性能也很高誊薄。
優(yōu)化前:
a)?用戶請求mget(k1,k2)到Proxy
b)?Proxy根據(jù)k1,k2分別發(fā)起子請求subrequest1,subrequest2
c)?子請求根據(jù)key計算slotid,然后去緩存路由表查找節(jié)點
d)?子請求請求Redis Cluster的相關(guān)節(jié)點锰茉,然后響應(yīng)返回給Proxy
e)?Proxy會合并所有的子請求返回的結(jié)果呢蔫,然后進行解析包裝返回給用戶
優(yōu)化后:
a)?用戶請求mget(k1,k2)到Proxy
b)?Proxy根據(jù)k1,k2分別計算slotid, 然后去緩存路由表查找節(jié)點
c)?Proxy發(fā)起多個協(xié)程coroutine1,?coroutine2并發(fā)的請求Redis Cluster的相關(guān)節(jié)點
d)?Proxy會合并多個協(xié)程返回的結(jié)果,然后進行解析包裝返回給用戶
2. 合并相同槽,批量執(zhí)行指令片吊,減少網(wǎng)絡(luò)開銷
案例:
用戶需求調(diào)用批量接口mget(50key)要求性能高绽昏,吞吐高,響應(yīng)快俏脊。
問題:
經(jīng)過上面協(xié)程的方式進行優(yōu)化后全谤,發(fā)現(xiàn)批量接口性能還是提升不夠高。通過火焰圖觀察分析網(wǎng)絡(luò)開銷比較大爷贫。
解決方案:
因為在Redis Cluster中认然,批量執(zhí)行的key必須在同一個slotid。所以漫萄,我們可以合并相同slotid的key做為一次請求卷员。然后利用Pipeline/Lua+EVALSHA批量執(zhí)行命令來減少網(wǎng)絡(luò)開銷,提高性能腾务。
優(yōu)化前:
a)?用戶請求mget(k1,k2,k3,k4) 到Proxy毕骡。
b)?Proxy會解析請求串,然后計算k1,k2,k3,k4所對應(yīng)的slotid岩瘦。
c)?Proxy會根據(jù)slotid去路由緩存中找到后端服務(wù)器的節(jié)點未巫,并發(fā)的發(fā)起多個請求到后端服務(wù)器。
d)?后端服務(wù)器返回結(jié)果給Proxy,然后Proxy進行解析獲取key對應(yīng)的value启昧。
e)?Proxy把key,value對應(yīng)數(shù)據(jù)包裝返回給用戶叙凡。
優(yōu)化后:
a)?用戶請求mget(k1,k2,k3,k4) 到Proxy。
b)?Proxy會解析請求串箫津,然后計算k1,k2,k3,k4所對應(yīng)的slotid狭姨,然后把相同的slotid進行合并為一次Pipeline請求。
c)?Proxy會根據(jù)slotid去路由緩存中找到后端服務(wù)器的節(jié)點苏遥,并發(fā)的發(fā)起多個請求到后端服務(wù)器饼拍。
d)?后端服務(wù)器返回結(jié)果給Proxy,然后Proxy進行解析獲取key對應(yīng)的value。
e)?Proxy把key,value對應(yīng)數(shù)據(jù)包裝返回給用戶田炭。
3.?對后端并發(fā)度的控制
案例:
當(dāng)用戶調(diào)用批量接口請求mset师抄,如果k數(shù)量幾百個甚至幾千個時,會導(dǎo)致Proxy瞬間同時發(fā)起幾百甚至幾千個協(xié)程同時去訪問后端服務(wù)器Redis Cluster教硫。
問題:
Redis?Cluster同時并發(fā)請求的協(xié)程過多叨吮,會導(dǎo)致連接數(shù)瞬間會很大,甚至超過上限瞬矩,CPU,連接數(shù)忽高忽低茶鉴,對集群造成不穩(wěn)定。
解決方案:
單個批量請求對后端適當(dāng)控制并發(fā)度進行分組并發(fā)請求景用,反向有利于性能提升涵叮,避免超過Redis Cluster連接數(shù),同時Redis Cluster 波動也會小很多,更加的平滑割粮。
優(yōu)化前:
a)?用戶請求批量接口mset(200個key)盾碗。(這里先忽略合并相同槽的邏輯)
b)?Proxy會解析這200個key,會同時發(fā)起200個協(xié)程請求并發(fā)的去請求Redis Cluster舀瓢。
c)?Proxy等待所有協(xié)程請求完成廷雅,然后合并所有協(xié)程請求的響應(yīng)結(jié)果,進行解析京髓,包裝返回給用戶航缀。
優(yōu)化后:
a)?用戶請求批量接口mset(200個key)。 (這里先忽略合并相同槽的邏輯)
b)?Proxy會解析這200個key朵锣,進行分組谬盐。100個key為一組,分批次進行并發(fā)請求诚些。
c)?Proxy先同時發(fā)起第一組100個協(xié)程(coroutine1,?coroutine100)請求并發(fā)的去請求Redis Cluster。
d)?Proxy等待所有協(xié)程請求完成皇型,然后合并所有協(xié)程請求的響應(yīng)結(jié)果诬烹。
e)?Proxy然后同時發(fā)起第二組100個協(xié)程(coroutine101,?coroutine200)請求并發(fā)的去請求Redis Cluster。
f)?Proxy等待所有協(xié)程請求完成弃鸦,然后合并所有協(xié)程請求的響應(yīng)結(jié)果绞吁。
g)?Proxy把所有協(xié)程響應(yīng)的結(jié)果進行解析,包裝唬格,返回給用戶家破。
4.單Work分散到多Work
案例:
當(dāng)用戶調(diào)用批量接口請求mset,如果k數(shù)量幾百個甚至幾千個時购岗,會導(dǎo)致Proxy瞬間同時發(fā)起幾百甚至幾千個協(xié)程同時去訪問后端服務(wù)器Redis Cluster汰聋。
問題:
由于Nginx的框架模型是單進程單線程, 所以Proxy發(fā)起的協(xié)程都會在一個Work上,這樣如果發(fā)起的協(xié)程請求過多就會導(dǎo)致單Work CPU打滿,導(dǎo)致Nginx 的每個Work CPU使用率非常不均喊积,內(nèi)存持續(xù)暴漲的情況烹困。(nginx 的內(nèi)存池只能提前釋放大塊,不會提前釋放小塊)
解決方案:
增加一層緩沖層代理乾吻,把請求的數(shù)據(jù)進行拆分為多份髓梅,然后每份發(fā)起請求,控制并發(fā)度绎签,在轉(zhuǎn)發(fā)給Proxy層枯饿,避免單個較大的批量請求打滿單Work,從而達(dá)到分散多Work诡必,達(dá)到Nginx 多個Wrok CPU使用率均衡奢方。
優(yōu)化前:
a)?用戶請求批量接口mset(200個key)。(這里先忽略合并相同槽的邏輯)
b)?Proxy會解析這200個key,會同時發(fā)起200個協(xié)程請求并發(fā)的去請求Redis Cluster袱巨。
c)?Proxy等待所有協(xié)程請求完成阁谆,然后合并所有協(xié)程請求的響應(yīng)結(jié)果,進行解析愉老,包裝返回給用戶场绿。
優(yōu)化后:
a)?用戶請求批量接口mset(200個key)。(這里先忽略合并相同槽的key的邏輯)
b)?Proxy會解析這200個key嫉入,然后進行拆分分組以此來控制并發(fā)度焰盗。
c)?Proxy會根據(jù)劃分好的組進行一組一組的發(fā)起請求。
d)?Proxy等待所有請求完成咒林,然后合并所有協(xié)程請求的響應(yīng)結(jié)果熬拒,進行解析,包裝返回給用戶垫竞。
總結(jié)澎粟,經(jīng)過上面一系列優(yōu)化,我們可以來看看針對批量接口mset(50個k/v)性能對比圖欢瞪,Nginx?Proxy的響應(yīng)時間比Java版本的響應(yīng)時間快了5倍多活烙。
Java版本:
Nginx版本:
3.3.2??網(wǎng)卡軟中斷優(yōu)化
irqbalance根據(jù)系統(tǒng)中斷負(fù)載的情況,自動遷移中斷保持中斷的平衡遣鼓。但是在實時系統(tǒng)中會導(dǎo)致中斷自動漂移啸盏,對性能造成不穩(wěn)定因素,在高性能的場合建議關(guān)閉骑祟。
1.?首先關(guān)閉網(wǎng)卡軟中斷
service irqbalance stop
service?cpuspeed?stop
2.?查看網(wǎng)卡是隊列
grep eth /proc/interrupts | awk '{print $1, $NF}'
77: eth0
78: eth0-TxRx-0
79: eth0-TxRx-1
80: eth0-TxRx-2
81: eth0-TxRx-3
82: eth0-TxRx-4
83: eth0-TxRx-5
84: eth0-TxRx-6
85: eth0-TxRx-7
3.?綁定網(wǎng)卡軟中斷到CPU0-2號上
(注意這里的echo 是十六進制)
echo "1" > /proc/irq/78/smp_affinity
echo "1" > /proc/irq/79/smp_affinity
echo "2" > /proc/irq/80/smp_affinity
echo "2" > /proc/irq/81/smp_affinity
echo "2" > /proc/irq/82/smp_affinity
echo "4" > /proc/irq/83/smp_affinity
echo "4" > /proc/irq/84/smp_affinity
echo "4" > /proc/irq/85/smp_affinity
3.3.3??綁定進程到指定的CPU
綁定nginx或者redis的pid到cpu3-cpu10上:
taskset -cp 3 1900
taskset -cp 4 1901
taskset -cp 5 1902
taskset -cp 6 1903
taskset -cp 7 1904
taskset -cp 8 1905
taskset -cp 9 1902
taskset -cp 10 1902
或者通過Nginx Proxy配置:
worker_cpu_affinity 綁定CPU親緣性
3.3.4??性能優(yōu)化神器火焰圖
3.4??Redis Cluster運維
3.4.1?運維功能
1. 創(chuàng)建集群
2. 集群擴容/縮容
3.?節(jié)點宕機
4. 集群升級
5. 遷移數(shù)據(jù)
6. 副本遷移
7. 手動failover
8. 手動rebalance
以上相關(guān)運維功能回懦,目前是通過腳本配置化一鍵式操作,依賴于官方的redis-rebalance.rb進行擴展開發(fā)次企。運維非常方便快捷怯晕。
3.5??性能測試報告
3.5.1??測試環(huán)境
軟件:
Jmeter
Nginx Proxy(24核)
Redis集群(4?Master,4 Slave)
測試Key(100000)
硬件:
OS: Centos6.6
CPU:24核
帶寬:千兆
內(nèi)存:62G
測試結(jié)果:
場景:普通K/V
QPS:18W左右
RT: 99都在10ms以內(nèi)
CPU:Nginx Proxy CPU在50%左右
4
監(jiān)控告警
4.1?系統(tǒng)級別
通過Open-Falcon Agent采集服務(wù)器的CPU捅厂、內(nèi)存费坊、網(wǎng)卡流量、網(wǎng)絡(luò)連接殖氏、磁盤等信息蛉谜。
4.2?應(yīng)用級別
通過Open-Falcon?Plugin采集Nginx/Redis進程級別的CPU稚晚,內(nèi)存,Pid等信息型诚。
4.3?業(yè)務(wù)級別
通過在Proxy里面埋點監(jiān)控業(yè)務(wù)接口QPS客燕,RT(50%,99%,999%),請求流量狰贯,錯誤次數(shù)等信息也搓,定時的上報給Open-Falcon赏廓。
通過Open-Falcon?Plugin采集Redis?Cluster集群信息,QPS傍妒,連接數(shù)等相關(guān)指標(biāo)指標(biāo)信息幔摸。
作者介紹:
李航: 5年多互聯(lián)網(wǎng)工作經(jīng)驗,先后在58同城颤练,汽車之家既忆,優(yōu)酷土豆集團工作。目前主要在優(yōu)酷土豆集團任職高級開發(fā)工程師嗦玖,目前主要負(fù)責(zé)大數(shù)據(jù)基礎(chǔ)平臺Redis集群開發(fā)及運維等工作患雇。主要關(guān)注領(lǐng)域Nginx,Redis宇挫,分布式系統(tǒng)苛吱,分布式存儲。如果對redis/hbase/spark/storm/kafka等大數(shù)據(jù)領(lǐng)域有深厚的興趣器瘪,可以發(fā)送簡歷給gaosong@youku.com翠储。
本文來源自“Redis技術(shù)交流群”線上分享。李航ID:Lucien_168娱局。群主ID:gnuhpc彰亥。后期的分享我們會同期進行。