優酷土豆的Redis服務平臺化之路

1、Redis架構的方案經歷階段

1.1. 客戶端分片

優酷土豆的Redis服務平臺化之路

客戶端分片:

優點

不依賴於第三方中間件,實現方法和代碼自己掌控,可隨時調整

這種分片機制的性能比代理式更好(少了一箇中間分發環節)

可控的分發請求,分發壓力落在客戶端,無服務器壓力增加

缺點

不能平滑的水平擴展節點,擴容/縮容時,必須手動調整分片程序

出現故障,不能自動轉移,運維性很差

客戶端得自己維護一套路由算法

升級複雜

1.2. Twemproxy

優酷土豆的Redis服務平臺化之路

Twemproxy:

優點

運維成本低。業務方不用關心後端Redis實例,跟操作Redis一樣

Proxy 的邏輯和存儲的邏輯是隔離的

缺點

代理層多了一次轉發,性能有所損耗

進行擴容/縮容時候,部分數據可能會失效,需要手動進行遷移,對運維要求較高,而且難以做到平滑的擴縮容

出現故障,不能自動轉移,運維性很差

升級複雜

1.3. Redis Cluster

優酷土豆的Redis服務平臺化之路

Redis Cluster:

優點

無中心節點

數據按照Slot存儲分佈在多個Redis實例上

平滑的進行擴容/縮容節點

自動故障轉移(節點之間通過Gossip協議交換狀態信息,進行投票機制完成Slave到Master角色的提升)

降低運維成本,提高了系統的可擴展性和高可用性

缺點

嚴重依賴外部Redis-Trib

缺乏監控管理

需要依賴Smart Client(連接維護, 緩存路由表, MultiOp和Pipeline支持)

Failover節點的檢測過慢,不如“中心節點ZooKeeper”及時

Gossip消息的開銷

無法根據統計區分冷熱數據

Slave“冷備”,不能緩解讀壓力

1.4. Proxy+Redis Cluster

優酷土豆的Redis服務平臺化之路

Smart Client vs Proxy:

優點

Smart Client:

a. 相比於使用代理,減少了一層網絡傳輸的消耗,效率較高。

b. 不依賴於第三方中間件,實現方法和代碼自己掌控,可隨時調整。

Proxy:

a. 提供一套HTTP Restful接口,隔離底層存儲。對客戶端完全透明,跨語言調用。

b. 升級維護較為容易,維護Redis Cluster,只需要平滑升級Proxy。

c. 層次化存儲,底層存儲做冷熱異構存儲。

d. 權限控制,Proxy可以通過秘鑰控制白名單,把一些不合法的請求都過濾掉。並且也可以控制用戶請求的超大Value進行控制,和過濾。

e. 安全性,可以屏蔽掉一些危險命令,比如Keys、Save、Flush All等。

f. 容量控制,根據不同用戶容量申請進行容量限制。

g. 資源邏輯隔離,根據不同用戶的Key加上前綴,來進行資源隔離。

h. 監控埋點,對於不同的接口進行埋點監控等信息。

缺點

Smart Client:

a. 客戶端的不成熟,影響應用的穩定性,提高開發難度。

b. MultiOp和Pipeline支持有限。

c. 連接維護,Smart客戶端對連接到集群中每個結點Socket的維護。

Proxy:

a. 代理層多了一次轉發,性能有所損耗。

b.進行擴容/縮容時候對運維要求較高,而且難以做到平滑的擴縮容。

2、為什麼選擇Nginx開發Proxy


1.單Master多Work模式,每個Work跟Redis一樣都是單進程單線程模式,並且都是基

於Epoll事件驅動的模式。

2.Nginx採用了異步非阻塞的方式來處理請求,高效的異步框架。

3.內存佔用少,有自己的一套內存池管理方式,。將大量小內存的申請聚集到一塊,能夠比Malloc 更快。減少內存碎片,防止內存洩漏。減少內存管理複雜度。

4. 為了提高Nginx的訪問速度,Nginx使用了自己的一套連接池。

5. 最重要的是支持自定義模塊開發。

6. 業界內,對於Nginx,Redis的口碑可稱得上兩大神器。性能也就不用說了。

3、Proxy+Redis Cluster介紹

3.1 Proxy+Redis Cluster架構方案介紹

1. 用戶在ACL平臺申請集群資源,如果申請成功返回秘鑰信息。

2. 用戶請求接口必須包含申請的秘鑰信息,請求至LVS服務器。

3. LVS根據負載均衡策略將請求轉發至Nginx Proxy。

4. Nginx Proxy首先會獲取秘鑰信息,然後根據秘鑰信息去ACL服務上獲取集群的種子信息。(種子信息是集群內任意幾臺IP:PORT節點)

然後把秘鑰信息和對應的集群種子信息緩存起來。並且第一次訪問會根據種子IP:PORT獲取集群Slot對應節點的Mapping路由信息,進行緩存起來。最後根據Key計算SlotId,從緩存路由找到節點信息。

5. 把相應的K/V信息發送到對應的Redis節點上。

6. Nginx Proxy定時(60s)上報請求接口埋點的QPS,RT,Err等信息到Open-Falcon平臺。

7. Redis Cluster定時(60s)上報集群相關指標的信息到Open-Falcon平臺。

優酷土豆的Redis服務平臺化之路

3.2 Nginx Proxy功能介紹

目前支持的功能:

HTTP Restful接口:

解析用戶Post過來的數據, 並且構建Redis協議。客戶端不需要開發Smart Client, 對客戶端完全透明、跨語言調用

權限控制:

根據用戶Post數據獲取AppKey,Uri, 然後去ACL Service服務裡面進行認證。如果認證通過,會給用戶返回相應的集群種子IP,以及相應的過期時間限制等信息

限制數據大小:

獲取用戶Post過來的數據,對Key,Value長度進行限制,避免產生超大的Key,Value,打滿網卡、阻塞Proxy

數據壓縮/解壓:

如果是寫請求,對Value進行壓縮(Snappy),然後在把壓縮後的數據存儲到Redis Cluster。

如果是讀請求,把Value從Redis Cluster讀出來,然後對Value進行解壓,最後響應給用戶。

緩存路由信息:

維護路由信息,Slot對應的節點的Mapping信息

結果聚合:

MultiOp支持

批量指令支持(Pipeline/Redis+Lua+EVALSHA進行批量指令執行)

資源邏輯隔離:

根據用戶Post數據獲取該用戶申請的NameSpace,然後以NameSpace作為該用戶請求Key的前綴,從而達到不同用戶的不同NameSpace,進行邏輯資源隔離

重試策略:

針對後端Redis節點出現Moved,Ask,Err,TimeOut等進行重試,重試次數可配置

連接池:

維護用戶請求的長連接,維護後端服務器的長連接

配額管理:

根據用戶的前綴(NameSpace), 定時的去抓取RANDOMKEY,根據一定的比率,估算出不同用戶的容量大小值,然後在對用戶的配額進行限制管理

過載保護:

通過在Nginx Proxy Limit模塊進行限速,超過集群的承載能力,進行過載保護。從而保證部分用戶可用,不至於壓垮服務器

監控管理:

Nginx Proxy接入了Open-Falcon對系統級別,應用級別,業務級別進行監控和告警

例如: 接口的QPS,RT,ERR等進行採集監控,並且展示到DashBoard上

告警閾值的設置非常靈活,配置化

待開發的功能列表:

層次化存儲:

利用Nginx Proxy共享內存定製化開發一套LRU本地緩存實現,從而減少網絡請求

冷數據Swap到慢存儲,從而實現冷熱異構存儲

主動Failover節點:

由於Redis Cluster是通過Gossip通信, 超過半數以上Master節點通信(cluster-node-timeout)認為當前Master節點宕機,才真的確認該節點宕機。判斷節點宕機時間過長,在Proxy層加入Raft算法,加快失效節點判定,主動Failover

3.3 Nginx Proxy性能優化

3.3.1 批量接口優化方案

1. 子請求變為協程

案例:

用戶需求調用批量接口mget(50Key)要求性能高,吞吐高,響應快。

問題:

由於最早用的Nginx Subrequest來做批量接口請求的處理,性能一直不高,CPU利用率也不高,QPS提不起來。通過火焰圖觀察分析子請求開銷比較大。

解決方案:

子請求效率較低,因為它需要重新從Server Rewrite開始走一遍Request處理的PHASE。並且子請求共享父請求的內存池,子請求同時併發度過大,導致內存較高。

協程輕量級的線程,佔用內存少。經過調研和測試,單機一兩百萬個協程是沒有問題的,

並且性能也很高。

優化前:

a) 用戶請求mget(k1,k2)到Proxy

b) Proxy根據k1,k2分別發起子請求subrequest1,subrequest2

c) 子請求根據key計算slotid,然後去緩存路由表查找節點

d) 子請求請求Redis Cluster的相關節點,然後響應返回給Proxy

e) Proxy會合並所有的子請求返回的結果,然後進行解析包裝返回給用戶

優酷土豆的Redis服務平臺化之路

優化後:

a) 用戶請求mget(k1,k2)到Proxy

b) Proxy根據k1,k2分別計算slotid, 然後去緩存路由表查找節點

c) Proxy發起多個協程coroutine1, coroutine2併發的請求Redis Cluster的相關節點

d) Proxy會合並多個協程返回的結果,然後進行解析包裝返回給用戶

優酷土豆的Redis服務平臺化之路

2. 合併相同槽,批量執行指令,減少網絡開銷

案例:

用戶需求調用批量接口mget(50key)要求性能高,吞吐高,響應快。

問題:

經過上面協程的方式進行優化後,發現批量接口性能還是提升不夠高。通過火焰圖觀察分析網絡開銷比較大。

解決方案:

因為在Redis Cluster中,批量執行的key必須在同一個slotid。所以,我們可以合併相同slotid的key做為一次請求。然後利用Pipeline/Lua+EVALSHA批量執行命令來減少網絡開銷,提高性能。

優化前:

a) 用戶請求mget(k1,k2,k3,k4) 到Proxy。

b) Proxy會解析請求串,然後計算k1,k2,k3,k4所對應的slotid。

c) Proxy會根據slotid去路由緩存中找到後端服務器的節點,併發的發起多個請求到後端服務器。

d) 後端服務器返回結果給Proxy,然後Proxy進行解析獲取key對應的value。

e) Proxy把key,value對應數據包裝返回給用戶。

優酷土豆的Redis服務平臺化之路

優化後:

a) 用戶請求mget(k1,k2,k3,k4) 到Proxy。

b) Proxy會解析請求串,然後計算k1,k2,k3,k4所對應的slotid,然後把相同的slotid進行合併為一次Pipeline請求。

c) Proxy會根據slotid去路由緩存中找到後端服務器的節點,併發的發起多個請求到後端服務器。

d) 後端服務器返回結果給Proxy,然後Proxy進行解析獲取key對應的value。

e) Proxy把key,value對應數據包裝返回給用戶。

優酷土豆的Redis服務平臺化之路

3. 對後端併發度的控制

案例:

當用戶調用批量接口請求mset,如果k數量幾百個甚至幾千個時,會導致Proxy瞬間同時發起幾百甚至幾千個協程同時去訪問後端服務器Redis Cluster。

問題:

Redis Cluster同時併發請求的協程過多,會導致連接數瞬間會很大,甚至超過上限,CPU,連接數忽高忽低,對集群造成不穩定。

解決方案:

單個批量請求對後端適當控制併發度進行分組併發請求,反向有利於性能提升,避免超過Redis Cluster連接數,同時Redis Cluster 波動也會小很多,更加的平滑。

優化前:

a) 用戶請求批量接口mset(200個key)。(這裡先忽略合併相同槽的邏輯)

b) Proxy會解析這200個key,會同時發起200個協程請求併發的去請求Redis Cluster。

c) Proxy等待所有協程請求完成,然後合併所有協程請求的響應結果,進行解析,包裝返回給用戶。

優酷土豆的Redis服務平臺化之路

優化後:

a) 用戶請求批量接口mset(200個key)。 (這裡先忽略合併相同槽的邏輯)

b) Proxy會解析這200個key,進行分組。100個key為一組,分批次進行併發請求。

c) Proxy先同時發起第一組100個協程(coroutine1, coroutine100)請求併發的去請求Redis Cluster。

d) Proxy等待所有協程請求完成,然後合併所有協程請求的響應結果。

e) Proxy然後同時發起第二組100個協程(coroutine101, coroutine200)請求併發的去請求Redis Cluster。

f) Proxy等待所有協程請求完成,然後合併所有協程請求的響應結果。

g) Proxy把所有協程響應的結果進行解析,包裝,返回給用戶。

優酷土豆的Redis服務平臺化之路

4.單Work分散到多Work

案例:

當用戶調用批量接口請求mset,如果k數量幾百個甚至幾千個時,會導致Proxy瞬間同時發起幾百甚至幾千個協程同時去訪問後端服務器Redis Cluster。

問題:

由於Nginx的框架模型是單進程單線程, 所以Proxy發起的協程都會在一個Work上,這樣如果發起的協程請求過多就會導致單Work CPU打滿,導致Nginx 的每個Work CPU使用率非常不均,內存持續暴漲的情況。(nginx 的內存池只能提前釋放大塊,不會提前釋放小塊)

解決方案:

增加一層緩衝層代理,把請求的數據進行拆分為多份,然後每份發起請求,控制併發度,在轉發給Proxy層,避免單個較大的批量請求打滿單Work,從而達到分散多Work,達到Nginx 多個Wrok CPU使用率均衡。

優化前:

a) 用戶請求批量接口mset(200個key)。(這裡先忽略合併相同槽的邏輯)

b) Proxy會解析這200個key,會同時發起200個協程請求併發的去請求Redis Cluster。

c) Proxy等待所有協程請求完成,然後合併所有協程請求的響應結果,進行解析,包裝返回給用戶。

優酷土豆的Redis服務平臺化之路

優化後:

a) 用戶請求批量接口mset(200個key)。(這裡先忽略合併相同槽的key的邏輯)

b) Proxy會解析這200個key,然後進行拆分分組以此來控制併發度。

c) Proxy會根據劃分好的組進行一組一組的發起請求。

d) Proxy等待所有請求完成,然後合併所有協程請求的響應結果,進行解析,包裝返回給用戶。

優酷土豆的Redis服務平臺化之路

總結,經過上面一系列優化,我們可以來看看針對批量接口mset(50個k/v)性能對比圖,Nginx Proxy的響應時間比Java版本的響應時間快了5倍多。

Java版本:

優酷土豆的Redis服務平臺化之路


3.3.2 網卡軟中斷優化

irqbalance根據系統中斷負載的情況,自動遷移中斷保持中斷的平衡。但是在實時系統中會導致中斷自動漂移,對性能造成不穩定因素,在高性能的場合建議關閉。

1、首先關閉網卡軟中斷

service irqbalance stop

service cpuspeed stop

2、查看網卡是隊列

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、綁定網卡軟中斷到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 性能優化神器火焰圖

優酷土豆的Redis服務平臺化之路

3.4 Redis Cluster運維

3.4.1 運維功能

1. 創建集群

2. 集群擴容/縮容

3. 節點宕機

4. 集群升級

5. 遷移數據

6. 副本遷移

7. 手動failover

8. 手動rebalance

以上相關運維功能,目前是通過腳本配置化一鍵式操作,依賴於官方的redis-rebalance.rb進行擴展開發。運維非常方便快捷。

3.5 性能測試報告

3.5.1 測試環境

軟件:

Jmeter

Nginx Proxy(24核)

Redis集群(4 Master,4 Slave)

測試Key(100000)

硬件:

OS: Centos6.6

CPU:24核

帶寬:千兆

內存:62G

優酷土豆的Redis服務平臺化之路

測試結果:

場景:普通K/V

QPS:18W左右

RT: 99都在10ms以內

CPU:Nginx Proxy CPU在50%左右

4、監控告警

4.1 系統級別

通過Open-Falcon Agent採集服務器的CPU、內存、網卡流量、網絡連接、磁盤等信息。

優酷土豆的Redis服務平臺化之路

4.2 應用級別

通過Open-Falcon Plugin採集Nginx/Redis進程級別的CPU,內存,Pid等信息。

優酷土豆的Redis服務平臺化之路

4.3 業務級別

通過在Proxy裡面埋點監控業務接口QPS,RT(50%,99%,999%),請求流量,錯誤次數等信息,定時的上報給Open-Falcon。

優酷土豆的Redis服務平臺化之路

通過Open-Falcon Plugin採集Redis Cluster集群信息,QPS,連接數等相關指標指標信息。

優酷土豆的Redis服務平臺化之路


分享到:


相關文章: