當前位置:
首頁 > 最新 > 緩存技術在洋碼頭商品領域中的應用

緩存技術在洋碼頭商品領域中的應用

作者介紹

王旭東,洋碼頭高級架構師

長期從事軟體研發及系統架構設計,目前負責洋碼頭用戶、資金、商品等電商核心業務系統研發與管理。

本文約3000字,可參閱下面的大綱閱讀。

1.數據的存在形式

2.洋碼頭的商品數據架構

3.應用數據緩存設計

4.緩存面臨的幾個問題

5. 結束語

6. 參考文檔


1. 數據的存在形式

我們的故事是從關係型數據開始的,在應用開始設計時流量不大關係型資料庫顯然是首選,於是品牌、品類、產地、規格、庫存、價格、圖文詳情等等圍繞商品展開的一系列設計開始落入資料庫中。隨著數據量和流量的不斷增大,我們逐漸發現DBA的優化已經到了極限,儘管我們設計了各種索引也做了讀寫分離,可到最後資料庫自己都無法分析出最優的執行計劃(由於索引選擇錯誤造成BadQuery)。

業務的發展逼著我們思考數據的存在形式,關係型數據已經出現了瓶頸,我們需要將關係型數據拍平,將KV查詢和模糊查詢分離,於是平面數據帶領我們走上了一個新的台階。然而消費者的熱情再一次把MongoDB的連接數撐爆、CPU飆升,堆機器的方式不行了,我們要在應用里做緩存,我們甚至要把緩存做到消費者的APP里、瀏覽器里,好吧我們開始了應用數據和呈現數據的緩存,下圖總結了這個過程。


2. 洋碼頭的商品數據架構

在了解了我們的基本故事之後,希望你還有興趣看看後面的乾貨,好吧至少我是這麼認為的。

下圖描述了目前洋碼頭的商品數據架構,我們依然沒有放棄關係型資料庫,它最擅長的還是對複雜數據結構的表達,用它來做商品管理那是再好不過了。不過顯然消費者理解不了這樣的數據,將它拍平的任務落在了消息匯流排和商品同步服務身上,同步指令從商品管理的各個操作中發出,它代表了商品的新增或者變更,這很重要,所以我們不但將它發送給了消息匯流排也把它落到資料庫里(萬一匯流排掛了呢),消息匯流排負責通知同步服務將數據拍平到MongoDB或者ElasticSearch中。

我剛才似乎說了匯流排的壞話,必須承認目前的匯流排還是非常棒的(參見洋碼頭消息匯流排架構一文),我想指出的是在從鐵板一塊的單一系統到SOA架構的服務化過程中,數據一致性操作經常是重構面臨的重大挑戰。這裡我提出一個基本原則:服務的調用方對數據的最終一致性負有100%的責任,而服務的提供方則必須確保操作的冪等性和100%的答覆正確率。匯流排是落實這個原則的最佳工具,它可以保證99.999%的到達率,剩下的0.001%需要被檢測到並且通過JOB補單完成,資料庫中的同步指令表就是這一步驟的關鍵。


3. 應用數據緩存設計

關於我和JOB不得不說的故事會在以後的文章里提到,而黑五帶來的MongoDB 連接數和CPU飆升卻是必須要解決的問題了。前面我們通過艱苦的工作完成了關係數據向平面數據的轉換,時效性和一致性上都有不錯的表現。基於ElasticSearch的應用為大首頁提供了搜索、千人前面、猜你喜歡等一系列服務和各種聚合列表,驚喜的消費者急切希望看到櫥櫃背後的商品信息,有哪些規格、價格是多少、產地在哪裡、能不能包郵保稅、買手是否靠譜,還有讓消費者剁手、讓各種存儲們避之不及的圖文詳情(大IO),在我的印象中沒有那個高效的存儲對大IO情有獨鐘的,網路也不堪重負。

消費者可不理會存儲們的偏好,他們買買買的熱情依舊高漲,好吧既然消費者要,我們就加班給。Nginx、CDN和前端呈現數據緩存的故事留給運維和前端的兄弟們,這裡重點聚焦一下應用數據的緩存設計。先來看看商品領域的數據有哪些。下表按照數據量、變化頻率和訪問頻率等維度做了一些歸納。消費者相關是指數據的呈現和用戶有關聯,比如新客和老客能夠看到不同的商品價格。時間相關是指數據本身設置時間屬性,比如直播設置了開始和結束時間,那麼隨著時間的流逝直播會自然開始和自然結束。佔比是指數據針對商品數量的比重,比如每個商品都有基本屬性、規格信息,那麼基本屬性、規格信息相對商品數量的佔比就是100%;然而不是每個商品都會加入直播或者參與活動的,因此直播信息、活動信息的佔比就低;而進行限購的商品就更少了,所以限購信息的佔比極低。

好了,我們對數據有了一個基本的認識,現在可以按照不同特性為它們選擇合適的存儲和緩存演算法了。想想看你會把燒烤魷魚或者大米放入冰箱存儲嗎,這想法簡直太愚蠢了,但是如果我們不去做細緻的分析就會在緩存的設計中犯下這樣的錯誤,直到從冰箱里拿出燒烤魷魚的那一刻才發現悲劇了。

數據量、變化頻率、訪問頻率可以幫助我們選擇合適的存儲,消費者相關、時間相關、佔比則提醒我們選擇合適的緩存演算法,避免踩坑。快照數據訪問率低,無需緩存。變化頻率高、訪問頻率高、數據量小的數據是Redis的最愛,限購就是這樣的數據。再來看看IO量高、變化頻率低的圖文詳情。圖文詳情分成圖片和文字,圖片顯然要通過CDN存儲到離消費者最近的地方,文字部分也要以呈現數據的形式在Nginx做一級緩存。佔比低、訪問高的數據有直播信息和活動信息,這樣的數據提醒我們需要注意緩存穿透的問題,大量的商品沒有參加直播所以緩存里沒有數據,請求將會直接穿透到資料庫上。時間相關的數據則提醒我們要注意緩存中的數據隨時可能失效,資料庫中的數據則隨著時間的流逝可能成為我們需要的數據。

在對數據分析後我們得到了一個基於時間戳的商品緩存架構設計,如下圖所示。在收到查詢請求後商品查詢服務首先檢查時間戳,如果這個商品的時間戳不存在二話不說直接返回。如果時間戳存在,則查看本地緩存(Guava)是否有商品數據,如果有且時間戳沒變,直接返回本地商品數據。如果時間戳變了,則從MongoDB中獲取到最新的商品數據緩存到本地然後返回。為什麼要選擇這樣的架構呢,這就要從緩存面臨的一些問題說起,有興趣的小夥伴加油往下翻。


4. 緩存面臨的幾個問題

如何讓緩存儘快感知到DB里數據的變化,主流的做法有定期更新、設置緩存失效時間等,這些做法需要在數據的新鮮度和IO壓力間獲取一個平衡,對於大量的商品數據而言,採用時間戳作為商品緩存的失效依據既經濟(IO友好)又能夠保持數據足夠的新鮮度,我們利用這一策略到達了毫秒級的數據延時並節省了三分之二的IO開銷。


存儲空間和插入/查詢時間都是常數。

不需要存儲KEY值。

存在誤報(報告KEY存在,但是實際上不存在),不存在漏報(報告KEY不存在,實際存在)。

不能刪除元素。

大家能發現布隆過濾器的最大特點是它可以確定KEY不存在,從而避免無效的請求打在DB上,這一點實在是令人興奮,然而不能刪除的特性又使得我們敬而遠之。回顧一下商品領域的數據特點,存在以下三種穿透的場景:

惡意流量攻擊帶來的無效商品,穿透商品表

沒有參加活動的商品,穿透活動商品表

沒有參加直播的商品,穿透直播商品表

然而這些數據都會隨時間流逝而失效需要從緩存里刪除,所以布隆過濾器並不適合,基於時間戳的緩存則很好解決了這些穿透場景。


坦率的說時間戳不能解決雪崩的問題,然而下圖描述了四種緩存失效更新的線程模型並指出了造成雪崩的原因,多數情況方案2已經夠用了,方案3可以帶來無阻塞的查詢體驗,然而如果沒有緩存數據的情況下還是要回到方案2的,方案4可以用在變化小、可以全量緩存、訪問極其頻繁的場景。

5. 結束語

俗話說「他山之石可以攻玉」,我們在商品領域中的緩存運用也參考了很多業界優秀的設計,比如Guava提供的LRU策略就為我們節省了大量的內存空間,希望此文能為同行提供一些借鑒。藉此感謝在洋碼頭商品領域奮鬥的同仁們!

6. 參考文檔:

1)介紹緩存的基本概念和常用的緩存技術(https://blog.csdn.net/li_yu_hai/article/details/3014987)

3)布隆過濾器(Bloom Filter)詳解(https://www.cnblogs.com/liyulong1982/p/6013002.html)

4)Guava本地緩存托底緩存以及非同步更新緩存(https://www.cnblogs.com/woshidalao/p/7979455.html)

全文完

近期分享預告:

洋碼頭自動化發布系統介紹

洋碼頭推薦系統架構

洋碼頭搜索應用架構

每周我們都會推送一篇由洋碼頭一線工程師寫的技術分享。關注【洋碼頭技術】,第一時間獲取我們最新的技術分享推送吧。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 洋碼頭技術 的精彩文章:

洋碼頭應用安全架構
洋碼頭技術演進之路

TAG:洋碼頭技術 |