成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

馬蜂窩推薦系統(tǒng)容災緩存服務的設計與實現(xiàn)

focusj / 1625人閱讀

摘要:馬蜂窩推薦系統(tǒng)對于請求的平均處理時延要求在級別,時延的線保持在以內(nèi)。任務隊列與異步寫入這里我們使用了中的線程池來實現(xiàn)。三優(yōu)化方向基于和,我們在現(xiàn)有的推薦系統(tǒng)中增加了一個本地容災緩存系統(tǒng),當依賴服務或者應用本身突發(fā)異常時可以返回緩存的數(shù)據(jù)。

數(shù)據(jù)庫突然斷開連接、第三方接口遲遲不返回結(jié)果、高峰期網(wǎng)絡發(fā)生抖動...... 當程序突發(fā)異常時,我們的應用可以告訴調(diào)用方或者用戶「對不起,服務器出了點問題」;或者找到更好的方式,達到提升用戶體驗的目的。

一、背景

用戶在馬蜂窩 App 上「刷刷刷」時,推薦系統(tǒng)需要持續(xù)給用戶推薦可能感興趣的內(nèi)容,主要分為根據(jù)用戶特性和業(yè)務場景,召回根據(jù)各種機器學習算法計算過的內(nèi)容,然后對這些內(nèi)容進行排序后返回給前端這幾個步驟。

推薦的過程涉及到 MySQL 和 Redis 查詢、REST 服務調(diào)用、數(shù)據(jù)處理等一系列操作。對于推薦系統(tǒng)來說,對時延的要求比較高。馬蜂窩推薦系統(tǒng)對于請求的平均處理時延要求在 10ms 級別,時延的 99 線保持在 1s 以內(nèi)。

當外部或者內(nèi)部系統(tǒng)出現(xiàn)異常時,推薦系統(tǒng)就無法在限定時間內(nèi)返回數(shù)據(jù)給到前端,導致用戶刷不出來新內(nèi)容,影響用戶體驗。

所以我們希望通過設計一套容災緩存服務,實現(xiàn)在應用本身或者依賴的服務發(fā)生超時等異常情況時,可以返回緩存數(shù)據(jù)給到前端和用戶,來減少空結(jié)果數(shù)量,并且保證這些數(shù)據(jù)盡可能是用戶感興趣的。

二、設計與實現(xiàn)

設計思路和技術選型

不僅僅是推薦系統(tǒng),緩存技術在很多系統(tǒng)中已經(jīng)被廣泛應用,小到 JVM 中的常用整型數(shù),大到網(wǎng)站用戶的 session 狀態(tài)。緩存的目的不盡相同,有些是為了提高效率,有些是為了備份;緩存的要求也高低不一,有些要求一致性,有些則沒有要求。我們需要根據(jù)業(yè)務場景選擇合適的緩存方案。

結(jié)合到我們上面提到的業(yè)務場景和需求,我們采用了基于 OHC 堆外緩存和 SpringBoot 的方案,實現(xiàn)在現(xiàn)有推薦系統(tǒng)中增加本地容災緩存系統(tǒng)。主要是考慮到以下幾點因素:

1. 避免影響線上服務,將業(yè)務邏輯和緩存邏輯隔離

為了不影響線上服務,我們將緩存系統(tǒng)封裝為一個 CacheService,配置在現(xiàn)有流程的末端,并提供讀、寫的 API 給外部調(diào)用,將業(yè)務邏輯和緩存邏輯隔離。

2. 異步寫入緩存,提高性能

讀、寫緩存都會帶來時間消耗,特別是寫入緩存。為了提高性能,我們考慮將寫入緩存做成異步的方式。這部分使用的是 JDK 提供的線程池 ThreadPoolExecutor 來實現(xiàn),主線程只需要提交任務到線程池,由線程池里的 Worker 線程實現(xiàn)寫入緩存。

3. 本地緩存,提高訪問速度

在推薦系統(tǒng)中,給用戶推薦的內(nèi)容應該是千人千面的,甚至同一位用戶每次刷新看到的內(nèi)容都可能不同,這就不要求緩存具有強一致性。因此,我們只需要進行本地緩存,而不需要采用分布式的方式。這里使用到的是開源緩存工具 OHC,緩存的數(shù)據(jù)來源于成功處理過的請求。

4. 備份緩存實例,保證可用性

為了保證緩存的可用性,我們不僅在內(nèi)存中進行緩存,還定時備份到文件系統(tǒng)中,從而保證在可以應用啟動時從文件系統(tǒng)加載到內(nèi)存。具體可以使用 SpringBoot 提供的定時任務、ApplicationRunner 來實現(xiàn)。

整體架構(gòu)

我們保持了推薦系統(tǒng)的現(xiàn)有邏輯,并在現(xiàn)有流程的末端,配置了 CacheModule 和 CacheService,負責所有和緩存相關的邏輯。

其中,CacheService 是緩存的具體實現(xiàn),提供讀寫接口;CacheModule 對本次請求的數(shù)據(jù)進行處理,并決定是否需要調(diào)用 CacheService 對緩存進行操作。

模塊解讀

1. CacheModule

在完成推薦系統(tǒng)的原有流程處理之后,CacheModule 會對得到的響應報文進行判斷,比如是否拋出了異常,響應是否為空等,然后決定是否讀取緩存或者提交緩存任務。

CacheModule 的工作流程如圖所示,其中橘黃色部分代表對 CacheService 的調(diào)用:

提交緩存任務。如果該次請求沒有拋出異常,并且響應結(jié)果也不為空,則會提交一個緩存任務到 CacheService。任務的 key 值為對應的業(yè)務場景,value 為本次響應計算得到的內(nèi)容。提交的動作是非阻塞的,對接口的耗時影響很小。

讀取緩存數(shù)據(jù)。當應用本身或者依賴應用拋出異常時,系統(tǒng)會根據(jù)業(yè)務場景的 key 值從 CacheService 中讀取緩存并返回給調(diào)用方。當出現(xiàn)用戶本身已經(jīng)刷完所有可用數(shù)據(jù)的情況時,就不需要讀取緩存,而是將請求的數(shù)據(jù)及時反饋給用戶。

2. CacheService

在緩存的具體實現(xiàn)上,CacheService 使用到了從 Apache Cassandra 項目中獨立出來的 OHC。另外因為我們整個應用是基于 SpringBoot 的,也用到了 SpringBoot 提供的各種功能。

上文說到對緩存沒有強一致性的要求,所以我們采用的是本地緩存而非分布式緩存,并且抽象出一個 CacheService 類負責對本地緩存進行維護。

(1) 數(shù)據(jù)格式

推薦系統(tǒng)返回數(shù)據(jù)時,根據(jù)業(yè)務場景和用戶特征設定以「屏」為單位返回數(shù)據(jù),每屏可以包含多個內(nèi)容項,所以采取 key-set 的數(shù)據(jù)格式:key 值為業(yè)務場景,比如首頁的「視頻」頻道;緩存內(nèi)容則為「屏」的集合。

(2) 存儲位置

對于 Java 應用,緩存可以存放在內(nèi)存中或者硬盤文件中。而內(nèi)存空間又分為 heap(堆內(nèi)存)和 off-heap(堆外內(nèi)存)。我們對這幾種方式進行了對比:

為了保證較快的讀寫速度,避免緩存 GC 影響線上服務,所以選擇 off-heap 作為緩存空間。OHC 最早包含在 Apache Cassandra 項目中,之后獨立出來,成為了基于 off-heap 的開源緩存工具。它既可以維護大量的 off-heap 內(nèi)存空間,同時也使用于低開銷的小型緩存實體。所以我們使用 OHC 作為 off-heap 的緩存實現(xiàn)。

(3) 文件備份

在應用重啟時,off-heap 中的緩存為空。為了盡快載入緩存,我們使用 SpringBoot 的 Scheduling Tasks 功能,定期將緩存從 off-heap 備份到文件系統(tǒng);通過繼承 SpringBoot 的 ApplicationRunner 監(jiān)聽應用啟動的過程,啟動完成后將硬盤中的備份文件加載到 off-heap,保證緩存數(shù)據(jù)的可用性。

CacheService 維護一個任務隊列,隊列中保存著 CacheModule 通過非阻塞的方式提交的緩存任務,由 CacheService 決定是否要執(zhí)行這些緩存任務。

(4) 對 CacheModule 提供的 API

讀取緩存時,傳入 key 值,緩存模塊隨機從 set 中讀取數(shù)據(jù)返回。

寫入緩存時,將 key 和 value 封裝為一個任務,提交到任務隊列,由任務隊列負責異步寫入緩存。

(5) 任務隊列與異步寫入

這里我們使用了 JDK 中的線程池來實現(xiàn)。在構(gòu)造線程池時,使用 LinkedBlockingQueue 作為任務隊列,可以實現(xiàn)快速增刪元素;因為應用的 QPS 在 100 以內(nèi),所以工作線程數(shù)目固定為 1;隊列寫滿之后,則執(zhí)行 DiscardPolicy,放棄插入隊列。

(6) 緩存數(shù)量控制

如果緩存占用內(nèi)存空間過大,會影響線上應用,我們可以采用為不同的業(yè)務場景配置最大緩存數(shù)量來控制緩存數(shù)量。沒有達到配置值時,將成功處理過的數(shù)據(jù)寫入緩存;達到配置值時可以隨機抽樣覆蓋原有緩存項,來保證緩存的實時性。

綜合考慮以上各個方面,CacheService 的設計如下:

線上表現(xiàn)

為了驗證容災緩存的效果,我們在命中緩存時進行了埋點,并通過 Kibana 查看每小時緩存的命中數(shù)量。如圖所示,在 18:00 到 19:00 系統(tǒng)存在一定的超時,而這段時間由于緩存服務發(fā)揮了作用,使系統(tǒng)的可用性得到提升。

我們還對 OHC 的讀取和寫入速度進行了監(jiān)控。寫入緩存的時延在毫秒級別,并且是異步寫入;讀取緩存的時延在微秒級別?;緵]有給系統(tǒng)增加額外的時間消耗。

踩過的坑

在將緩存寫入 OHC 之前,需要進行序列化,我們使用了開源的 kryo 作為序列化工具。之前在使用 kyro 時,發(fā)現(xiàn)對于沒有實現(xiàn) Serializable 的類,反序列化時可能失敗,比如使用 List#subList 方法返回的內(nèi)部類 java.util.ArrayList$SubList。這里可以手動注冊 Serializer 來解決這個問題,在 Github 上開源的 kryo-serializers 倉庫提供了各種類型的 serializers。

另外一點,需要注意根據(jù)具體使用場景,來配置 OHC 中的 capacity 和 maxEntrySize。如果配置的值太小的話,會導致寫入緩存失敗??梢栽谏暇€之前測算緩存的空間占用,合理設置整個緩存空間的大小和每個緩存 entry 的大小。

三、優(yōu)化方向

基于 SpringBoot 和 OHC,我們在現(xiàn)有的推薦系統(tǒng)中增加了一個本地容災緩存系統(tǒng),當依賴服務或者應用本身突發(fā)異常時可以返回緩存的數(shù)據(jù)。

該緩存系統(tǒng)還存在一些不足,我們近期會針對以下幾點進行重點優(yōu)化:

緩存數(shù)目寫滿之后,目前應用會隨機覆寫已經(jīng)存在的緩存。未來可以進行優(yōu)化,將最老的緩存項替換。

在某些場景下緩存的粒度不夠精細,比如目的地頁推薦共用一個緩存的 key 值。未來可以根據(jù)目的地的 ID,為每個目的地配置一份緩存。

現(xiàn)在推薦系統(tǒng)還有部分配置依賴于 MySQL,未來會考慮將在本地進行文件緩存。

[參考資料]

1. Java Caching Benchmarks 2016 - Part 1

2. On Heap vs Off Heap Memory Usage

3. OHC - An off-heap-cache

4. kryo-serializers

5. scheduling-tasks

本文作者:孫興斌,馬蜂窩推薦和搜索后端研發(fā)工程師。

(馬蜂窩技術原創(chuàng)內(nèi)容,轉(zhuǎn)載務必注明出處保存文末二維碼圖片,謝謝配合。)

關注馬蜂窩技術公眾號,找到更多你需要的內(nèi)容

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/6693.html

相關文章

  • 蜂窩推薦系統(tǒng)容災緩存服務設計實現(xiàn)

    摘要:馬蜂窩推薦系統(tǒng)對于請求的平均處理時延要求在級別,時延的線保持在以內(nèi)。任務隊列與異步寫入這里我們使用了中的線程池來實現(xiàn)。三優(yōu)化方向基于和,我們在現(xiàn)有的推薦系統(tǒng)中增加了一個本地容災緩存系統(tǒng),當依賴服務或者應用本身突發(fā)異常時可以返回緩存的數(shù)據(jù)。 數(shù)據(jù)庫突然斷開連接、第三方接口遲遲不返回結(jié)果、高峰期網(wǎng)絡發(fā)生抖動...... 當程序突發(fā)異常時,我們的應用可以告訴調(diào)用方或者用戶「對不起,服務器出了...

    Dean 評論0 收藏0
  • 蜂窩ABTest多層分流系統(tǒng)設計實現(xiàn)

    摘要:為了解決以上問題,我們的分流系統(tǒng)選擇基于實現(xiàn),通過或者協(xié)議來傳遞分流信息。正交是指用戶進入所有的實驗之間沒有必然關系。流量層內(nèi)實驗分流流量層內(nèi)實驗的因子有設備流量層。統(tǒng)計功效對于置信區(qū)間特征值等產(chǎn)品化功能支持。 什么是 ABTest 產(chǎn)品的改變不是由我們隨便「拍腦袋」得出,而是需要由實際的數(shù)據(jù)驅(qū)動,讓用戶的反饋來指導我們?nèi)绾胃玫馗纳品铡U珩R蜂窩 CEO 陳罡在接受專訪時所說:「有...

    mingzhong 評論0 收藏0
  • 蜂窩ABTest多層分流系統(tǒng)設計實現(xiàn)

    摘要:為了解決以上問題,我們的分流系統(tǒng)選擇基于實現(xiàn),通過或者協(xié)議來傳遞分流信息。正交是指用戶進入所有的實驗之間沒有必然關系。流量層內(nèi)實驗分流流量層內(nèi)實驗的因子有設備流量層。統(tǒng)計功效對于置信區(qū)間特征值等產(chǎn)品化功能支持。 什么是 ABTest 產(chǎn)品的改變不是由我們隨便「拍腦袋」得出,而是需要由實際的數(shù)據(jù)驅(qū)動,讓用戶的反饋來指導我們?nèi)绾胃玫馗纳品?。正如馬蜂窩 CEO 陳罡在接受專訪時所說:「有...

    opengps 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<