從優(yōu)化性能到應(yīng)對(duì)峰值流量:微博緩存服務(wù)化的設(shè)計(jì)與實(shí)踐

從優(yōu)化性能到應(yīng)對(duì)峰值流量:微博緩存服務(wù)化的設(shè)計(jì)與實(shí)踐

導(dǎo)讀:高可用架構(gòu) 8 月 20 日在深圳舉辦了『互聯(lián)網(wǎng)架構(gòu):從 1 到 100』為主題的閉門私董會(huì)研討及技術(shù)沙龍,本文是陳波分享的微博緩存服務(wù)的演進(jìn)歷程。

陳波,08 年加入新浪,參與 IM 系統(tǒng)的后端研發(fā)。09 年之后從事新浪微博的系統(tǒng)研發(fā)及架構(gòu)工作,在海量數(shù)據(jù)存儲(chǔ)、峰值訪問(wèn)、規(guī)模化緩存服務(wù)及開放平臺(tái)等方面參與技術(shù)架構(gòu)改進(jìn),當(dāng)前主要負(fù)責(zé)微博平臺(tái)的基礎(chǔ)設(shè)施、中間件的研發(fā)及架構(gòu)優(yōu)化工作,經(jīng)歷新浪微博從起步到成為數(shù)億用戶的大型互聯(lián)網(wǎng)系統(tǒng)的技術(shù)演進(jìn)過(guò)程。

在所有介紹微博架構(gòu)演進(jìn)的使用場(chǎng)景都離不開緩存,今天上午騰訊分享的 CKV 也同樣提到了緩存服務(wù)在騰訊社交產(chǎn)品的重要性。緩存的設(shè)計(jì)為什么重要,我們先介紹其使用場(chǎng)景。

1

微博的緩存業(yè)務(wù)場(chǎng)景

微博幾乎所有的接口都是實(shí)時(shí)組裝的,用戶請(qǐng)求最終轉(zhuǎn)化到資源后端可能會(huì)存在 1 - 2 個(gè)數(shù)量級(jí)的讀放大,即一個(gè)用戶請(qǐng)求可能需要獲取幾十上百個(gè)以上的資源數(shù)據(jù)進(jìn)行動(dòng)態(tài)組裝。

比如大家刷微博的時(shí)候,會(huì)觸發(fā)一個(gè) friends_timeline 的接口請(qǐng)求,然后服務(wù)端會(huì)聚合并組裝最新若干條(比如 15 條)微博給用戶,那這個(gè)過(guò)程后端服務(wù)需要到資源層拿哪些數(shù)據(jù)來(lái)組裝?

首先是后端服務(wù)會(huì)從資源層去獲取用戶的關(guān)注列表;

然后根據(jù)關(guān)注列表獲取每一個(gè)被關(guān)注者的最新微博 ID 列表 以及 用戶自己收到的微博 ID 列表(即 inbox);

通過(guò)對(duì)這些 ID 列表進(jìn)行聚合、排序和分頁(yè)等處理后,拿到需要展現(xiàn)的微博 ID 列表;

再根據(jù)這些 ID 獲取對(duì)應(yīng)的微博內(nèi)容;

如果是轉(zhuǎn)發(fā)微博還要獲取源微博的內(nèi)容;

然后需要獲取用戶設(shè)置的過(guò)濾詞并進(jìn)行過(guò)濾。

此后還需要獲取微博作者、包括源微博作者的 user 信息進(jìn)行組裝;

還需要獲取這個(gè)用戶對(duì)這些微博是不是有收藏、是否贊,

最后還需要獲取這些微博的轉(zhuǎn)發(fā)、評(píng)論、贊的計(jì)數(shù)等進(jìn)行組裝。

(點(diǎn)擊圖片可放大瀏覽)

從以上過(guò)程可以看到,用戶的一個(gè)首頁(yè)請(qǐng)求,最終后端 server 可能需要從資源層獲取幾百甚至幾千個(gè)數(shù)據(jù)進(jìn)行組裝才能得到返回的數(shù)據(jù)。

微博線上業(yè)務(wù)的很多核心接口響應(yīng)需要在毫秒級(jí),可用性要求達(dá)到 4 個(gè) 9。因此,為了保證資源數(shù)據(jù)的獲取性能和可用性,微博內(nèi)部大量使用緩存,而且對(duì)緩存是重度依賴的,不少核心業(yè)務(wù)的單端口緩存訪問(wèn) QPS 已經(jīng)達(dá)到了百萬(wàn)級(jí)以上。

微博使用的緩存主要是 Memcache 和 Redis,因?yàn)镸emcache的使用場(chǎng)景、容量更大,而且目前推的緩存服務(wù)化也是優(yōu)先基于Memcache,然后再擴(kuò)展到 Redis、 ssdcache 等其他緩存,所以今天的緩存服務(wù)討論也是以Memcache為存儲(chǔ)標(biāo)的來(lái)展開的。我們最早使用的緩存架構(gòu)就是直接利用開源版本的 Memcache 運(yùn)行在物理機(jī)上,我們稱之為裸資源。

2

緩存的裸資源架構(gòu)演進(jìn)

首先看一下微博Memcache緩存的裸資源架構(gòu)的演進(jìn)過(guò)程。微博上線之初,我們就對(duì)核心業(yè)務(wù)數(shù)據(jù)進(jìn)行分池、分端口的,把 size 接近的數(shù)據(jù)放在相同的池子里面。業(yè)務(wù)方通過(guò) Hash 算法訪問(wèn)緩存池里的節(jié)點(diǎn)。同時(shí),每個(gè) IDC 部署使用獨(dú)立的緩存資源,為了加速,業(yè)務(wù)前端也會(huì)在本地啟用 local-Cache。

上線幾個(gè)月之后,隨著業(yè)務(wù)量和用戶量的急聚增加,緩存節(jié)點(diǎn)數(shù)很快增加到數(shù)百個(gè)。這段時(shí)間,時(shí)常會(huì)因?yàn)榫W(wǎng)絡(luò)異常、機(jī)器故障等,導(dǎo)致一些緩存節(jié)點(diǎn)不可用,從而導(dǎo)致緩存 miss。這些 miss 的請(qǐng)求最終會(huì)穿透到 DB 中。

如果某個(gè)時(shí)間點(diǎn),核心業(yè)務(wù)的多個(gè)緩存節(jié)點(diǎn)不可用,大量請(qǐng)求穿透會(huì)給 DB 帶來(lái)巨大的壓力,極端情況會(huì)導(dǎo)致雪崩場(chǎng)景。于是我們引入 Main-HA 雙層架構(gòu)。

對(duì)后端的緩存訪問(wèn)時(shí),會(huì)先訪問(wèn) Main 層,如果 miss 繼續(xù)訪問(wèn) HA 層,從而在獲得更高的命中率的同時(shí),即便部分 Main 節(jié)點(diǎn)不可用,也可以保證緩存的命中率,并減少 DB 壓力。

這一階段我們對(duì)業(yè)務(wù)資源進(jìn)一步的分拆,每一種核心數(shù)據(jù)都分拆到獨(dú)立的端口。同時(shí),根據(jù)不同的訪問(wèn)頻率、容量進(jìn)行緩存搭配部署,對(duì)Memcache資源的端口進(jìn)行統(tǒng)一規(guī)劃,確保緩存層的性能和可用性。同時(shí)我們發(fā)現(xiàn),在各種海量業(yè)務(wù)數(shù)據(jù)的沖刷下,前端使用 local-Cache,命中率不高,性能提升不明顯,所以我們把 local Cache 層去掉了。

隨著業(yè)務(wù)訪問(wèn)量進(jìn)一步增加,特別是一些突發(fā)事件爆發(fā)式的出現(xiàn)并傳播, Main-HA 結(jié)構(gòu)也出現(xiàn)了一些問(wèn)題,主要是很多緩存節(jié)點(diǎn)的帶寬被打滿,Memcache的 CPU 比較高,Memcache響應(yīng)變慢。

通過(guò)分析,我們發(fā)現(xiàn)主要是大量熱數(shù)據(jù)的集中訪問(wèn)導(dǎo)致的服務(wù)過(guò)載,單個(gè)端口不能承載熱數(shù)據(jù)的訪問(wèn)(比如明星發(fā)的微博所在的端口),于是我們引入了 L1 結(jié)構(gòu)。

通過(guò)部署 3 - 4 組以上的小容量 L1 緩存,每個(gè) L1 組等價(jià)存儲(chǔ)熱數(shù)據(jù),來(lái)滿足業(yè)務(wù)要求。

總結(jié)一下微博的緩存架構(gòu)演進(jìn)過(guò)程:

在直接使用裸緩存資源的過(guò)程中,我們通過(guò) Main-HA 雙層結(jié)構(gòu),消除了單點(diǎn)問(wèn)題;

通過(guò)熱數(shù)據(jù)的多 L1 副本,可以用較低的成本即可應(yīng)對(duì)高峰、突發(fā)流量;

L1s-M-H 三層緩存結(jié)構(gòu)消除了緩存層出現(xiàn)的帶寬和 CPU 過(guò)載的情況,使整個(gè)系統(tǒng)的讀取性都、可用性得了很大的提高。

在以上 3 階段的演進(jìn)過(guò)程中,我們較好的解決了訪問(wèn)性能與訪問(wèn)峰值的壓力,不過(guò)在服務(wù)的可管理性方面依然存在可管理空間。不同業(yè)務(wù)之間只有經(jīng)驗(yàn)可以復(fù)用,在緩存的實(shí)現(xiàn)方面經(jīng)常需要各種重復(fù)的勞動(dòng)。我們需要把緩存的使用服務(wù)化才能把可管理性帶到一個(gè)新的階段。

3

緩存服務(wù)的設(shè)計(jì)與實(shí)踐

直接使用裸緩存資源也存在一系列問(wèn)題:

首先,隨著業(yè)務(wù)的發(fā)展,微博緩存的訪問(wèn)量、容量都非常大。線上有數(shù)千個(gè)緩存節(jié)點(diǎn),都需要在業(yè)務(wù)前端要去配置,導(dǎo)致緩存配置文件很大也很復(fù)雜。

同時(shí),如果發(fā)生緩存節(jié)點(diǎn)擴(kuò)容或切換,需要運(yùn)維通知業(yè)務(wù)方,由業(yè)務(wù)方對(duì)配置做修改,然后進(jìn)行業(yè)務(wù)重啟,這個(gè)過(guò)程比較長(zhǎng),而且會(huì)影響服務(wù)的穩(wěn)定性。

另外,微博平臺(tái)主要采用 Java 語(yǔ)言開發(fā),我們定制了 JavaMemcache緩存層來(lái)訪問(wèn)三層緩存結(jié)構(gòu),內(nèi)置了不少訪問(wèn)策略。這時(shí)候,如果公司其他部門也想使用,但由于用的是其他開發(fā)語(yǔ)言如 PHP,就沒(méi)法簡(jiǎn)單推廣了。

最后,資源的可運(yùn)維性也不足,基于 IP、端口運(yùn)維復(fù)雜性比較高。比如一個(gè)線上機(jī)器宕機(jī),在這個(gè)機(jī)器上部署了哪些端口、對(duì)應(yīng)了哪些業(yè)務(wù)調(diào)用,沒(méi)有簡(jiǎn)單直觀的查詢、管理入口。

于是我們開始考慮緩存的服務(wù)化,主要的過(guò)程及策略如下:

首先是對(duì)Memcache緩存引入了一個(gè) proxy 層,基于 Twitter 的 twemproxy 進(jìn)行改造。

引入 cluster,并內(nèi)嵌了MemcacheCluster 訪問(wèn)策略,包括三層的一些更新、讀取,以及 miss 后的穿透、回寫等。

我們通過(guò)單進(jìn)程單端口來(lái)對(duì)多個(gè)業(yè)務(wù)進(jìn)行訪問(wèn),不同業(yè)務(wù)通過(guò) namespace Prefix 進(jìn)行區(qū)分。

在 Cache-proxy 也引入了 LRU,在某些業(yè)務(wù)場(chǎng)景減少熱點(diǎn)數(shù)據(jù)的穿透。

通過(guò) cacheProxy,簡(jiǎn)化了業(yè)務(wù)前端的配置,簡(jiǎn)化了開發(fā),業(yè)務(wù)方只需要知道 cacheProxy 的 IP 和端口,即可實(shí)現(xiàn)對(duì)后端各種業(yè)務(wù)的多層緩存進(jìn)行訪問(wèn)。

我們對(duì)緩存服務(wù)的服務(wù)治理也做了不少工作。

接入配置中心

首先,把 Cache 層接入了配置中心 configServer(內(nèi)部叫 vintage)。實(shí)現(xiàn)了Memcache緩存、 cacheProxy 的動(dòng)態(tài)注冊(cè)和訂閱,運(yùn)維把Memcache資源的 IP 端口、Memcache訪問(wèn)的 hash 方式、分布式策略等也以配置的形式注冊(cè)在配置中心, cacheProxy 啟動(dòng)后通過(guò)到配置中心訂閱這些資源 IP 及訪問(wèn)方式,從而正確連接并訪問(wèn)后端Memcache緩存資源。而且 cacheProxy 在啟動(dòng)后,也動(dòng)態(tài)的注冊(cè)到配置中心, client 端即可到配置中心訂閱這些 cacheProxy 列表,然后選擇最佳的 cacheProxy 節(jié)點(diǎn)訪問(wèn)Memcache資源。同時(shí),運(yùn)維也可以在線管理Memcache資源,在網(wǎng)絡(luò)中斷、Memcache宕機(jī),或業(yè)務(wù)需要進(jìn)行擴(kuò)容時(shí),運(yùn)維啟動(dòng)新的Memcache節(jié)點(diǎn),同時(shí)通知配置中心修改資源配置,就可以使新資源快速生效,實(shí)現(xiàn)緩存資源管理的 API 化、腳本化。

監(jiān)控體系

其次,把 cacheProxy、后端Memcache資源也納入到了 Graphite 體系,通過(guò) logtailer 工具將緩存的訪問(wèn)日志、內(nèi)部狀態(tài)推送到 Graphite 系統(tǒng),用 dashboard 直接展現(xiàn)或者按需聚合后展現(xiàn)。

Web 化管理

同時(shí),我們也開發(fā)了緩存層管理組件 clusterManager(內(nèi)部也叫 captain),把之前的 API 化、腳本化管理進(jìn)一步的升級(jí)為界面化管理。運(yùn)維可以通過(guò) clusterManager,界面化管理緩存的整個(gè)生命周期,包括業(yè)務(wù)緩存的申請(qǐng)、審核,緩存資源的變更、擴(kuò)縮容、上下線等。

監(jiān)控與告警

ClusterManager 同時(shí)對(duì)緩存資源、 cacheProxy 等進(jìn)行狀態(tài)探測(cè)及聚合分析,監(jiān)控緩存資源的 SLA,必要時(shí)進(jìn)行監(jiān)控報(bào)警。

我們也準(zhǔn)備將 clusterManager 整合公司內(nèi)部的 jpool(編排發(fā)布系統(tǒng))、 DSP(混合云管理平臺(tái)) 等系統(tǒng),實(shí)現(xiàn)了對(duì) cacheProxy、Memcache節(jié)點(diǎn)的一鍵部署和升級(jí)。

開發(fā)工具

對(duì)于 client 端,我們基于 Motan(微博已開源的 RPC 框架)擴(kuò)展了Memcache協(xié)議,使 client 的配置、獲取服務(wù)列表、訪問(wèn)策略更加簡(jiǎn)潔。方便開發(fā)者實(shí)現(xiàn)面向服務(wù)編程,比如開發(fā)者在和運(yùn)維確定好緩存的 SLA 之后,通過(guò) spring 配置

部署方式

對(duì)于 cacheProxy 的部署,目前有兩種方式,一種是本地化部署,就是跟業(yè)務(wù)前端部署在一起的,在對(duì) cacheProxy 構(gòu)建 Docker 鏡像后,然后利用 jpool 管理系統(tǒng)進(jìn)行動(dòng)態(tài)部署。另外一種是集中化部署,即 cacheProxy 在獨(dú)立的機(jī)器上部署,由相同的業(yè)務(wù)數(shù)據(jù)獲取方進(jìn)行共享訪問(wèn)。

Cache 服務(wù)化后的業(yè)務(wù)處理流程如圖。

首先運(yùn)維通過(guò) captain 把Memcache資源的相關(guān)配置注冊(cè)到 configServer, cacheProxy 啟動(dòng)后通過(guò) configServer 獲取Memcache資源配置并預(yù)建連接; cacheProxy 在啟動(dòng)準(zhǔn)備完畢后將自己也注冊(cè)到 configServer,業(yè)務(wù)方 client 通過(guò)到 configServer 獲取 cacheProxy 列表,并選擇最佳的 cacheProxy 發(fā)送請(qǐng)求指令, cacheProxy 收到請(qǐng)求后,根據(jù) namespace 選擇緩存的 cluster,并按照配置中的 hash 及分布策略進(jìn)行請(qǐng)求的路由、穿透、回寫。 Captain 同時(shí)主動(dòng)探測(cè) cacheProxy、Memcache緩存資源,同時(shí)到 Graphite 獲取歷史數(shù)據(jù)進(jìn)行展現(xiàn)和分析,發(fā)現(xiàn)異常后進(jìn)行報(bào)警。

(點(diǎn)擊圖片可放大瀏覽)

在業(yè)務(wù)運(yùn)行中,由于各個(gè)業(yè)務(wù)的訪問(wèn)量的不斷變化、熱點(diǎn)事件的應(yīng)對(duì),需要根據(jù)需要對(duì)緩存資源進(jìn)行擴(kuò)縮,有兩種擴(kuò)縮方式:集群內(nèi)的擴(kuò)縮 和 集群的增減。

對(duì)于集群內(nèi)的擴(kuò)縮,線上操作最多的是增減 L1 組或擴(kuò)容 main 層。

對(duì)于 L1,通常直接進(jìn)行上下線資源,并通過(guò) captain 對(duì)配置中心的配置做變更即可生效。而 main 層擴(kuò)縮有兩種方式,一是通過(guò) L1、 Main 的切換,即新的 main 層先做為 L1 上線,命中率達(dá)到要求后,再變更一次配置,去掉老的 main,使用新的 main 層 ; 另外一種方式是使用 main-elapse 策略,直接上線 main,把老的 main 改為 main-elapse, main 層 miss 后先訪問(wèn) main_elapse 并回種, set 時(shí)對(duì) main-elapse 做刪除操作。

對(duì)于集群的增減,我們?cè)黾恿艘粋€(gè)新組件 updateServer,然后通過(guò)復(fù)制來(lái)實(shí)現(xiàn),目前還在內(nèi)部開發(fā)測(cè)試狀態(tài)。為什么會(huì)有集群增減,因?yàn)槲⒉┑脑L問(wèn)存在時(shí)間上的規(guī)律性,比如晚上 9 點(diǎn)到 0 點(diǎn)的高峰期、節(jié)假日、奧運(yùn)等熱點(diǎn)出現(xiàn),流量可能會(huì)有 30-50% 以上 變化,原有集群可能撐不住這么大的量,我們可能需要新建一個(gè)前端 + 資源集群,來(lái)滿足業(yè)務(wù)需要,這時(shí)可以提前 1-2 個(gè)小時(shí)在公有云部署資源服務(wù)并加熱,供新集群的業(yè)務(wù)方使用,待峰值過(guò)去后,再做下線處理,在提供更好地服務(wù)的同時(shí),也可以降低成本。

如何 updateServer 進(jìn)行集群間復(fù)制?可以結(jié)合下面這張圖來(lái)看。

緩存集群分為 master 集群、 slave 集群。Master 集群的 cacheProxy 收到 client 的請(qǐng)求后,對(duì)于讀請(qǐng)求直接訪問(wèn) L1-m-h 三層結(jié)構(gòu),但對(duì)寫請(qǐng)求會(huì)發(fā)往本地的 updateServer ; slave 集群的 cacheProxy 除了做 master 集群的相同的動(dòng)作,還會(huì)同時(shí)將寫請(qǐng)求路由到 master 集群的 updateServer。只要 cacheProxy 更新 master、 local 集群中任何一個(gè) updateServer 成功則返回成功,否則返回失敗。 updateServer 收到寫請(qǐng)求,在路由到后端緩存資源的同時(shí),會(huì)日志記錄到 aof 文件, slave 集群的緩存即通過(guò) updateServer 進(jìn)行同步。為什么引入 updateServer 這個(gè)角色,主要是更好的應(yīng)對(duì)前端本地部署,由于本地部署方式 cacheProxy 節(jié)點(diǎn)特別多,前端機(jī)器配置較差,更重要的原因前端 Docker 鏡像隨時(shí)可能會(huì)被下線清理,所以需要把寫請(qǐng)求發(fā)送到獨(dú)立部署的 updateServer 進(jìn)行更新。而對(duì)于集中化部署, Cache proxy 和 updateServer 的角色也可以合二為一,變?yōu)橐粋€(gè)進(jìn)程。

(點(diǎn)擊圖片可放大瀏覽)

緩存服務(wù)化的推進(jìn),性能也是業(yè)務(wù)方考慮的一個(gè)重要因素。

我們對(duì)原來(lái)的 pipeline 請(qǐng)求中的讀取類請(qǐng)求,進(jìn)行了請(qǐng)求合并,通過(guò) merge req 機(jī)制提高性能;

把單進(jìn)程升級(jí)為多進(jìn)程(這一塊也在內(nèi)部開發(fā)中);

對(duì)于 LRU 我們升級(jí)為 LS4LRU,線上數(shù)據(jù)分析發(fā)現(xiàn),相同容量及過(guò)期時(shí)間,LS4LRU 總體命中率能進(jìn)一步提高 5% - 7%

LS4LRU 簡(jiǎn)介

這里對(duì) LS4LRU 做個(gè)簡(jiǎn)單地介紹。首先介紹 S4LRU,它是分成四個(gè)子 LRU: LRU0-LRU3。 Key miss 或新寫入一個(gè) key 時(shí),把這個(gè) key 放在第一層 LRU0,如果后來(lái)被命中則移到 LRU1 ;如果在 LRU1 又一次被命中則移到 LRU2,依此類推,一直升級(jí)到 LU3。如果它四次以上命中,就會(huì)一直把它放在 LU3。如果發(fā)現(xiàn) LU3 的數(shù)據(jù)量太多需要 evict,我們先把待 evict 的 key 降級(jí)到 LU2 上,如此類推。同時(shí)每個(gè) kv 有過(guò)期時(shí)間,如果發(fā)現(xiàn)它過(guò)期就清理。

而 LS4LRU 是在 S4LRU 的基礎(chǔ)上增加一個(gè)分級(jí)的過(guò)期時(shí)間,每個(gè) KV 有兩個(gè)過(guò)期時(shí)間 exp1 和 exp2。比如說(shuō)某業(yè)務(wù), exp1 是一秒, xep2 是三秒, LS4LRU 被命中的時(shí)候,如果發(fā)現(xiàn)它是在一秒內(nèi)的數(shù)據(jù),則直接反給客戶端的,如果是在 1 秒到 3 秒的時(shí)候,則會(huì)首先返回到客戶端,然后再?gòu)漠惒将@取最新的數(shù)據(jù)并更新。如果是 3 秒以上的,就直接去清理,走 key miss 流程。

服務(wù)化的總結(jié)

我們?cè)倏匆幌路?wù)化的其他一些方面的實(shí)踐總結(jié)。

對(duì)于容災(zāi),Memcache部分節(jié)點(diǎn)故障,我們有多級(jí) Cache 解決;

對(duì)于 proxy/Memcache較多節(jié)點(diǎn)異常,我們通過(guò)重新部署新節(jié)點(diǎn),并通過(guò) captain 在線通知配置中心,進(jìn)而使新節(jié)點(diǎn)快速生效;

對(duì)于配置中心的故障,可以訪問(wèn)端的 snapshot 機(jī)制,利用之前的 snapshot 信息來(lái)訪問(wèn) Cache proxy 或后端緩存資源。

對(duì)于運(yùn)維,我們可以通過(guò) Graphite、 captain,實(shí)現(xiàn)標(biāo)準(zhǔn)化運(yùn)維;對(duì)于節(jié)點(diǎn)故障、擴(kuò)縮容按標(biāo)準(zhǔn)流程進(jìn)行界面操作即可。運(yùn)維在處理資源變更時(shí),不再依賴開發(fā)修改配置和業(yè)務(wù)重啟,可以直接在后端部署及服務(wù)注冊(cè)。對(duì)于是否可以在故障時(shí)直接部署并進(jìn)行配置變更,實(shí)現(xiàn)自動(dòng)化運(yùn)維,這個(gè)我們也還在探索中。

歷年的演進(jìn)經(jīng)驗(yàn)可以看到,緩存服務(wù)化的道路還是很長(zhǎng),未來(lái)還需要進(jìn)一步的對(duì)各 Cache 組件進(jìn)行打磨和升級(jí),我們也會(huì)在這條路上不斷前行。大家對(duì)于緩存的設(shè)計(jì)有各種建議的,歡迎在文后留言進(jìn)行探討。

Q&A

提問(wèn): L1 和 main 是如何協(xié)作的,什么時(shí)候可以把數(shù)據(jù)升級(jí)到了 L1,什么時(shí)候淘汰?為什么要使用這樣的機(jī)制, L1 和 main 的訪問(wèn)速度應(yīng)該差不了很多吧?為什么要另外再加一個(gè)熱點(diǎn)數(shù)據(jù)放在 L1 里面? L1 跟 main 怎么做數(shù)據(jù)同步?

陳波:首先 L1 的容量比 Main 小很多,同時(shí) L1 會(huì)有很多組,線上核心也有一般在 4-6 組以上,每組 L1 的數(shù)據(jù)基本上是熱數(shù)據(jù)。如果部署了 L1,所有的寫請(qǐng)求、 L1 的讀 miss 后的回寫,都會(huì)把數(shù)據(jù)寫入 L1,淘汰方式是 L1 組在容量滿了之后由Memcache自動(dòng)剔除。

對(duì)于為什么需要 L1,因?yàn)閷?duì)于微博業(yè)務(wù)來(lái)說(shuō),它是一個(gè)冷熱非常明顯的業(yè)務(wù)場(chǎng)景,一般來(lái)講,新發(fā)的微博請(qǐng)求量大,之前發(fā)的微博請(qǐng)求量小,另外在峰值期請(qǐng)求量會(huì)特別大,在高峰訪問(wèn)期間、節(jié)假日時(shí),核心業(yè)務(wù)單端口的訪問(wèn) QPS 會(huì)有百萬(wàn)級(jí),這時(shí)單層或雙層 main-ha 結(jié)構(gòu)的Memcache緩存性能上無(wú)法滿足要求,主要表現(xiàn)就是帶寬被打滿、 CPU 過(guò)高、請(qǐng)求耗時(shí)增加。另外在突發(fā)事件爆發(fā)時(shí),比如最近的寶寶事件,如果對(duì)部分熱 key 有數(shù)十萬(wàn)級(jí)以上的并發(fā)訪問(wèn),再加上其他不同 key 的請(qǐng)求,雙層緩存結(jié)構(gòu)是完全無(wú)法滿足性能要求的,緩存節(jié)點(diǎn)過(guò)載,讀取性能下降,超時(shí)會(huì)???量出現(xiàn)。因此我們?cè)黾?L1 層,通過(guò)多個(gè) L1 組,把這些熱數(shù)據(jù)分散到不到 L1 組來(lái)訪問(wèn),從而避免 Cache 層過(guò)載。這樣 L1 層就分擔(dān)了 Main 層對(duì)熱數(shù)據(jù)的大部分訪問(wèn),一些溫?zé)岬臄?shù)據(jù)訪問(wèn)才會(huì)落到 Main 和 slave 層,為了保持 main 層數(shù)據(jù)的熱度,實(shí)際線上運(yùn)行中,我們也會(huì)把 main 層作為一個(gè) L1 組來(lái)分擔(dān)部分熱數(shù)據(jù)的訪問(wèn),只是這種情況下, key miss 后會(huì)直接訪問(wèn) slave。

數(shù)據(jù)同步是通過(guò)多寫和穿透回寫的方式進(jìn)行。在更新數(shù)據(jù)的時(shí)候,直接對(duì)所有的 L1、 Main、 slave 層進(jìn)行更新,從而保證各層的數(shù)據(jù)是最新的。另外,進(jìn)行數(shù)據(jù)讀取的時(shí)候,存在 L1-main-ha、 DB 四層的穿透回寫機(jī)制,如果前面讀取的緩存層 miss 了,后面緩存層、 DB 層命中了,然后就可以進(jìn)行原路回寫,從而對(duì)前面的緩存層都寫入相同的 kv。

提問(wèn):什么樣的數(shù)據(jù)放在 L1 里面?

陳波:最熱的數(shù)據(jù)存在 L1 中,它通過(guò)Memcache層的淘汰機(jī)制進(jìn)行的。因?yàn)?L1 容量比 main 小很多,最熱的數(shù)據(jù)、訪問(wèn)頻率最高的數(shù)據(jù)基本都在 L1 里面,而稍冷的數(shù)據(jù)會(huì)很快的從 L1 里面踢走。所以直觀上,你可以認(rèn)為最熱的、當(dāng)前訪問(wèn)量最大數(shù)據(jù)就在 L1 層。比如說(shuō)可以認(rèn)為姚晨、寶強(qiáng)的最新數(shù)據(jù)都在 L1 層,我們普通用戶的數(shù)據(jù)大多靠 Main 層命中。

提問(wèn):你們線上 Redis 的內(nèi)存碎片情況如何?

陳波:我們?nèi)ツ旰颓澳陮?duì)部分業(yè)務(wù)的 Redis 有做過(guò)分析,一般有效內(nèi)存負(fù)荷在 85% 到 90% 以上,也就是碎片率小于 1.1-1.2,很多是 1.0x,有些跑了半年或者一年以上的部分實(shí)例可能會(huì)稍微高一點(diǎn)。

提問(wèn): Redis 碎片率過(guò)高的話你們是怎么來(lái)優(yōu)化的?

陳波:如果發(fā)現(xiàn)碎片率比較高,比如 master,我們會(huì)切換一個(gè)新 maste,然后把老的 maste 進(jìn)行下線,然后通過(guò)重啟解決,也可以通過(guò)我們的熱升級(jí)機(jī)制解決。

相關(guān)閱讀

(點(diǎn)擊標(biāo)題可直接閱讀)

用最少的機(jī)器支撐萬(wàn)億級(jí)訪問(wèn),微博6年Redis優(yōu)化歷程

微博數(shù)據(jù)庫(kù)那些事兒:3個(gè)變遷階段背后的設(shè)計(jì)思想

官方:支撐微博千億調(diào)用的輕量級(jí)RPC框架Motan正式開源

微博基于Docker的混合云平臺(tái)設(shè)計(jì)與實(shí)踐

本文及本次沙龍相關(guān) PPT 鏈接如下,也可點(diǎn)擊閱讀原文直接下載

https://pan.baidu.com/s/1geTJtZX

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,694評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,026評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,193評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,668評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,846評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,394評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容