泡泡後臺Couchbase緩存使用經驗分享

1、導讀linux

愛奇藝的社交業務「泡泡」,擁有日活用戶6千萬+,後臺系統每日高峯期間接口QPS能夠達到80K+,與視頻業務的主要區別是泡泡業務更多地引入了與用戶互動相關的數據,讀、寫的量均很大。不管是龐大的數據量,仍是相對較高的QPS,使得咱們在絕大多數場景下都依賴於高可靠、高性能、以及存儲量巨大的在線緩存系統。本文介紹了一些咱們在使用緩存方面的經驗以及優化的方法,但願對你們有所幫助。nginx

2、Couchbase簡介算法

Couchbase(下文簡稱CB)是由CouchOne(創辦人包括CouchDB的設計者)和Membase(由memcached的主要開發人員創建)兩家公司在2011年初合併而來。Membase公司有一個名爲Membase的產品,它是個鍵/值、持久化、可伸縮的解決方案,使用了memcached wire協議和SqlLite嵌入式存儲引擎。CouchOne支持的CouchDB是個文檔數據庫,提供了端到端的複製方法,這對於移動與分佈在不一樣位置的數據中心來講是頗有用的。Couchbase是基於Membase與CouchDB開發的一款新產品,綜合了二者的優勢。數據庫

3、Couchbase vs Redisjson

Couchbase和Redis均是很是優秀的緩存產品,愛奇藝泡泡社交後臺根據不一樣的適用場景大量地使用了它們,總的來說它們各有優劣,總結以下:後端

Redis優點:api

(1)Redis可以支持更多的數據結構;緩存

(2)Redis支持更多的應用場景(隊列、發佈訂閱、排行榜);tomcat

(3)Redis不少操做能夠放到服務端作,減小了網絡io;服務器

(4)Redis社區更繁榮一點,文檔比較豐富,解決問題更快捷;

(5)Redis支持事務。

Couchbase優點:

(1)CB能支撐更大的容量,Redis最好低於20G,不然failover以後恢復很是慢;

(2)CB有一個比較專業的管理界面;

(3)一致性hash發生在客戶端,性能更高;

(4)某臺server宕機不影響業務方使用,只是可用內存受影響,可用性更高;

(5)可擴展性強。

Redis 的亮點在於業務契合度高,CB 的亮點在於高可用。如下節選一些具體的功能點對比:

4、基礎知識:CB中的vBucket

在 CB 中,咱們所操做的每個bucket會邏輯劃分爲1024個vBucket,其數據的儲存是基於每一個vBucket儲存,而且每一個 vBucket都會映射到相對應的服務器節點,這種儲存結構的方式叫作集羣映射。如圖所示,當應用與Couchbase服務器交互時,會經過SDK與服務器數據進行交互,當應用操做某一個bucket的key值時,在SDK中會經過哈希的方式計算,使用公式crc32(key)%1024肯定key 值是屬於1024個vBucket中的某個,而後根據vBucket所映射的節點服務器對數據進行操做。

爲了保證分佈式存儲系統的高可靠性和高可用性,數據在系統中通常存儲多個副本。當某個副本所在的存儲節點出現故障時,分佈式存儲系統可以自動將服務切換到其它的副本,從而實現自動容錯。

5、友善的Web console

CB自帶了一套很是友善的Web console,使得運維及監控操做很是地方便。

6、案例1: 點贊系統緩存優化

首先介紹一下點贊系統業務場景:

點贊系統承載了兩種業務的點贊,第一種叫作feed點贊:咱們管泡泡圈子承載的信息流叫作feed流,而其中的每一篇帖子叫作一條feed。爲了便於理解,你們能夠把微信朋友圈當作是個feed流,而其中的每一條狀態帖子就是一條feed。這類業務系統的要求是,有feed流漏出的地方就會查詢點贊系統,查詢方式是一個uid(全站用戶惟一id)+一組[feedid]列表;

第二種業務是評論業務的點贊,評論列表漏出的地方就會查詢點贊系統,查詢方式是一個uid+一組[commentid]列表(每條評論也有一個全局惟一id叫commentid)。

階段一:Redis緩存

使用Redis作爲緩存,緩存30G打滿,經過LRU置換key。

點贊系統的第一個階段,緩存結構中的key是實體id(即feedid或commentid),value是點贊過該實體的uid 集合。按照實體id查詢全部給這個實體點過讚的uid,而且更新Redis緩存。採用這種設計的系統狀況是成功率常常抖動,響應時間不穩定。

經過業務日誌分析,發現hbase穿透很頻繁,緩存命中率不高,緣由是緩存容量太低。因爲公司雲平臺提供的是主從模式非集羣的Redis,理論上最大緩存量(max_memory)不宜過大(30G已是上限了),不然會引發主節點故障後failover到備用節點時間過長、甚至循環failover的狀況。

當時考慮了兩種可能的優化方案:使用CB;或使用 Redis cluster。調研以後發現,原生的Redis cluster不支持批量查詢,而若是使用Redis cluster proxy的話可能會有較大性能損耗,而且Redis cluster不支持cluster集羣之間的數據同步(咱們的場景會用到三個IDC之間的集羣同步),因此最終捨棄掉這個方案,考慮使用CB。

階段二:使用CB替換Redis

緩存key的考慮:uid維度,浪費空間,不少過期的數據會被加載到內存,而且受制於hbase表結構,沒法實時拿到某用戶點過的所實體。而使用實體id維度,CB不支持server端查詢,須要把數據拉到客戶端來判斷,對於比較熱門的實體,uid可能成千上萬,數據量太大。uid+實體id維度,CB用量可能比較大,不過查詢數據量很小。

最終咱們的key採用了uid+實體id的維度,value爲是否點過贊。根據uid+實體id進行exist操做(緩存沒命中則找不到key,命中的話會返回true或false代表是否點過贊),查詢結果更新緩存。

可是很快發現了一些問題:因爲緩存命中率低(同一我的再次訪問同一個feed纔會命中,這種狀況比較少見),形成hbase壓力過大。不過由於查詢hbase使用exist操做,不須要讀取數據,因此響應時間很短,成功率基本沒有受影響。同時分析了當時的緩存用量的增加趨勢,發現CB容量可能扛不住。

階段三:key的優化

採用實體id+shard方式存儲(shard=uid%factor ,實體id維度的變種)

緩存中key使用實體id+shard的方式,value是點過讚的用戶列表。穿透到hbase後,根據實體id查詢出全部給該實體id點過讚的uid,而後分shard更新緩存,沒有數據的shard也要更新上標識。這種方案須要考慮shard個數,在空間和時間上取一個平衡。shard數越大,浪費的CB空間越多,可是每次查詢結果集越小。

下面用一個例子來解釋兩種方案:實體id爲e1,factor=20。

優化後的效果以下圖,可見成功率相對趨於穩定,且緩存命中率已經高於了99%。

至此優化告一段落了,在這個案例中,有個事情是值得思考的:怎樣才能得到更高的命中率呢?咱們的答案是誰重複的次數多,以誰爲維度緩存。某一個用戶可能瀏覽的feed個數是有限的幾十個或者幾百個,而某個feed能夠被幾百萬甚至幾千萬的用戶看到。很明顯實體重複次數多,因此咱們是以實體id爲維度(key)來存儲。

7、案例2: 投票系統緩存優化

項目背景:投票計數器緩存結構,一個投票能夠簡單理解爲vid(投票id)+多個oid(選項),須要以下緩存,用作計數器。

這次優化主要是針對某熱門綜藝活動暴露出來的問題。該活動的投票分多個渠道(4個),每一個渠道對應一個投票,同時還有一個彙總的投票,每一個渠道的選項數是70個。每次業務查詢投票接口,各渠道帶過來的投票vid都是本身渠道的投票vid,後端須要查詢子渠道投票和彙總投票信息,整合以後返回給App端上。

計數器讀寫模型以下:

之因此每一個選項都是一個key,是由於這裏考慮到分佈式併發操做,須要用到原子的incr操做來增長投票計數。該模式的問題是業務高峯期間對CB的OPS達到到1,400,000次/秒,CB物理機CPU報警。經排查監控分析,發現該綜藝活動查詢接口QPS有明顯變化,而且發現問題時候,大部分流量來自該接口。分析該接口相關代碼,發現若是選項過多,一次業務查詢,該段邏輯須要批量查300個左右的key,若是業務QPS達到5k(其實並不高),那麼CB的OPS將達到1,400,000次/秒左右,確認OPS增長是致使該問題的緣由。

定位了緣由,優化就很簡單了:用一個異步task任務,每隔3s(具體時間間隔需根據業務狀況確認)彙總一次全部CB的key,至關於業務的一次查詢請求,只須要讀一次CB的彙總key的操做,而寫請求基本不變(只多了每3秒一次的彙總操做,基本能夠忽略),OPS大大下降,減輕物理機CPU壓力。

優化後效果很是明顯,對CB的OPS大幅下降:

8、案例3: CB客戶端SDK版本升級

項目背景:低版本SDK在CB集羣rebalance完以後,須要重啓,不然可能會有不少超時狀況,此爲第一個緣由。此外,某些後臺系統發現新擴容的worker機常常拋出以下異常,而後自動重連,而且不斷重複這個過程,致使接口成功率降低。對比了新老機器的nginx、tomcat、代碼、jdk、能想到的linux系統參數、QPS、目標訪問數據等等,都是徹底一致的,且夜間QPS低時候,該問題沒有那麼明顯。在找不到具體觸發該異常緣由的狀況下,因爲異常是在CB的SDK中拋出來的(看起來像是讀取某個buffer時候越界),所以最直接的方法確定是嘗試升級SDK。

最後咱們的方案是將老版本的SDK 1.4.11 升級到 2.3.2。因爲操做的都是線上系統,所以升級時須要考慮幾點:

(1)新老API兼容問題;

(2)升級不能污染老數據,保證有問題能夠回滾;

(3)因爲新版本SDK提供了不少新功能,能夠考慮順便優化緩存設計

最終咱們根據兩個系統的不一樣狀況,採用了兩種不一樣的升級策略:

系統A:緩存中的value都是string,能夠跟CB 2.x中的StringDocument完美兼容,因此直接在原來的CB集羣上面操做上線。

系統B:緩存中的value類型比較多,若是直接在線上CB集羣操做,風險較大,可能會形成數據被污染,且沒法回滾,而且由於歷史緣由線上集羣中有一些ttl=0的髒數據,因此採用切換到臨時集羣的方式:

9、其它注意事項

1.關於熱緩存中的數據,有兩種方式

須要根據具體業務來選擇:

方式1:用線上虛機熱數據,即挑選1~2臺worker機切換到新CB,至關於一上來這幾臺worker機的請求是100%到存儲上的,可是穿透完後會將數據種回緩存。待緩存命中率達到80%左右就能夠繼續增長worker機,直到全部worker機都切換到新緩存上。這種方案的優勢是簡單,缺點就是過程可能會有點慢,且切換過程當中可能由於新、舊緩存不一致致使不一樣worker查出來的數據短暫不一樣步。

方式2:用做業熱緩存。根據指定的規則跑MapReduce做業(好比持久化數據是像咱們同樣存在hbase中的),一次性把數據刷到緩存中,而且須要把刷存量數據期間產生的增量數據作一個特殊記錄,在刷完存量數據後再刷一遍增量的數據。這種方案的優勢是過程比較快,缺點是複雜度高。

2.關於跨IDC數據同步的經常使用兩種方式

Couchbase自己就是集羣,但一般所謂的集羣指的是單一IDC內部的集羣,因爲機制的限制一般也不會推薦一個集羣中存在跨IDC的CB實例。所以像咱們這樣比較大型的、牽扯到多IDC的後臺系統,就須要考慮CB的跨IDC同步問題了。一般有兩種方案:

(1)使用CB自帶的XDCR,簡單快捷,對業務方透明,一致性有保障。比較推薦

(2)業務本身作同步數據。如使用kafka等消息服務來同步數據,即更新CB的worker機發送一條消息到kafka隊列,每一個IDC都部署一臺consumer消費這條kafka消息,種本身本地IDC的CB緩存。這樣,至關於多個IDC之間的CB集羣自己是獨立的,僅僅經過業務方本身的consumer來進行數據同步。該方式比較依賴消息服務,穩定性不是很高,一致性保障難度比較高,業務方需衡量。在早期的XDCR不是很穩定時咱們曾有業務系統使用了這種方案,後續也逐步切換成了XDCR的方案。

3.關於遍歷全部key

CB不像Redis那樣有個keys(*)方法,能夠用於遍歷全部緩存中的key。所以識別並清除CB中的髒數據(好比早期存了一些ttl=0的數據,後來又不用了)是一件比較難的事情。可是有一種替代方案:同步線上數據到離線CB集羣(能夠用XDCR),構建view,使用restful api分頁查詢,遍歷全部key。找到髒數據,刪除在線集羣對應的key。注意該方式value必須是json。

對於value爲非json類型的數據,處理起來就很麻煩了。若是業務上有其它可以用來索引key的方式,那麼能夠採用這樣的業務上的數據來遍歷全部key。不然,只有像前文所述,申請一個新的CB集羣->熱緩存->廢棄舊的CB集羣。

4.開發運維的注意事項

還有一些開發的注意事項,再此一併分享一下:

(1)incr方法,要用String;

(2)ttl超過一個月,須要設置爲絕對時間;

(3)新業務請用新版本client,功能更強大,bug更少,低版本坑太多

運維注意事項:

(1)最好裝一個ping工具監控worker機與CB集羣之間的ping延時;

(2)訂閱報警,將問題解決在萌芽狀態;

(3)關注CB容量,CB使用內存要低於分配內存的75%,當bucket使用內存達到分配內存的75%時,因爲內存不足,Couchbase會經過LRU算法將部分數據從內存中踢出,只存儲在磁盤上,下一次讀取這部分數據時,再從磁盤取出並加載到內存。從磁盤取數據會使Couchbase的讀取性能下降。當bucket使用內存達到或接近分配內存的85%時,bucket可能會出現寫不進數據的狀況,同時集羣讀取性能受到較大影響。

10、總結

講了這麼多,最後總結一下對Couchbase緩存優化,其實通常就是指:

(1)提升緩存命中率:每每須要很是瞭解業務層面的用戶行爲(如點贊系統須瞭解用戶如何刷feed)

(2)儘可能減小OPS vs 一次獲取或寫入的數據量:取一個平衡

(3)優化緩存用量 vs 提升緩存命中率:取一個平衡

(4)業務複雜,空間不足:按照業務來拆分!

(5)節省空間:先考慮key的設計,再考慮使用protobuf等方式壓縮數據(較麻煩)。

相關文章
相關標籤/搜索