隨機高併發查詢結果一致性設計實踐

来源:https://www.cnblogs.com/Jcloud/archive/2023/02/01/17083011.html
-Advertisement-
Play Games

物流合約中心是京東物流合同管理的唯一入口。為商家提供合同的創建,蓋章等能力,為不同業務條線提供合同的定製,歸檔,查詢等功能。由於各個業務條線眾多,為各個業務條線提供高可用查詢能力是物流合約中心重中之重。同時計費系統在每個物流單結算時,都需要查詢合約中心,確保商家簽署的合同內容來保證計費的準確性。 ...


作者:京東物流 趙帥 姚再毅 王旭東 孟偉傑 孔祥東

1 前言

物流合約中心是京東物流合同管理的唯一入口。為商家提供合同的創建,蓋章等能力,為不同業務條線提供合同的定製,歸檔,查詢等功能。由於各個業務條線眾多,為各個業務條線提供高可用查詢能力是物流合約中心重中之重。同時計費系統在每個物流單結算時,都需要查詢合約中心,確保商家簽署的合同內容來保證計費的準確性。

2 業務場景

1.查詢維度分析

從業務調用的來源來看,合同的大部分是計費系統在每個物流單計費的時候,需要調用合約中心來判斷,該商家是否簽署合同。

31

從業務調用的入參來看,絕大部分是多個條件來查詢合同,但基本都是查詢某個商家,或通過商家的某個屬性(例如業務賬號)來查詢合同。

從調用的結果來看,40%的查詢是沒有結果的,其中絕大部分是因為商家沒有簽署過合同,導致查詢為空。其餘的查詢結果,每次返回的數量較少,一般一個商家只有3到5個合同。

2.調用量分析

調用量
目前合同的調用量,大概是在每天2000W次。

一天的調用量統計:
32

調用時間
每天高峰期為上班時間,最高峰為4W/min。

一個月的調用量統計:

由上可以看出,合同每日的調用量比較平均,主要集中在9點到12點和13點到18點,也就是上班時間,整體調用量較高,基本不存在調用暴增的情況。

總體分析來看,合約中心的查詢,調用量較高,且較平均,基本都是隨機查詢,也並不存在熱點數據,其中無效查詢占比較多,每次查詢條件較多,返回數據量比不大。

3 方案設計

從整體業務場景分析來看,我們決定做三層防護來保證調用量的支撐,同時需要對數據一致性做好處理。第一層是布隆過濾器,來攔截絕大部分無效的請求。第二層是redis緩存數據,來保證各種查詢條件的查詢儘量命中redis。第三層是直接查詢資料庫的兜底方案。同時再保證數據一致性的問題,我們藉助於廣播mq來實現。
35

1.第一層防護

由於近一半的查詢都是空,我們首先這是緩存穿透的現象。

緩存穿透問題

緩存穿透(cache penetration)是用戶訪問的數據既不在緩存當中,也不在資料庫中。出於容錯的考慮,如果從底層資料庫查詢不到數據,則不寫入緩存。這就導致每次請求都會到底層資料庫進行查詢,緩存也失去了意義。當高併發或有人利用不存在的Key頻繁攻擊時,資料庫的壓力驟增,甚至崩潰,這就是緩存穿透問題。

常規解決方案

緩存特定值

一般對於緩存穿透我們比較常規的做法就是,將不存在的key 設置一個固定值,比如說NULL,&&等等,在查詢返回這個值的時候,我們應用就可以認為這是一個不存在的key,那我們應用就可以決定是否繼續等待,還是繼續訪問,還是直接放棄,如果繼續等待訪問的話,設置一個輪詢時間,再次請求,如果取到的值不再是我們預設的,那就代表已經有值了,從而避免了透傳到資料庫,從而把大量的類似請求擋在了緩存之中。

緩存特定值並同步更新

特定值做了緩存,那就意味著需要更多的記憶體存儲空間。當存儲層數據變化了,緩存層與存儲層的數據會不一致。有人會說,這個問題,給key 加上一個過期時間不就可以了,確實,這樣是最簡單的,也能在一定程度上解決這兩個問題,但是當併發比較高的時候(緩存併發),其實我是不建議使用緩存過期這個策略的,我更希望緩存一直存在;通過後臺系統來更新緩存中的數據一致性的目的。

布隆過濾器

布隆過濾器的核心思想是這樣的,它不保存實際的數據,而是在記憶體中建立一個定長的點陣圖用0,1來標記對應數據是否存在系統;過程是將數據經過多個哈希函數計算出不同的哈希值,然後用哈希值對點陣圖的長度進行取模,最後得到點陣圖的下標位,然後在對應的下標位上進行標記;找數的時候也是一樣,先通過多個哈希函數得到哈希值,然後哈希值與點陣圖的長度進行取模得到多個下標。如果多個下標都被標記成1了,那麼說明數據存在於系統,不過只要有一個下標為0那麼就說明該數據肯定不存在於系統中。

在這裡先通過一個示例介紹一下布隆過濾器的場景:

以ID查詢文章為例,如果我們要知道資料庫是否存在對應的文章,那麼最簡單的方式就是我們把所有資料庫存在的ID都保存到緩存去,這個時候當請求過進入系統,先從這個緩存數據里判斷系統是否存在對應的數據ID,如果不存在的話直接返回出去,避免請求進入到資料庫層,存在的話再從獲取文章的信息。但是這個不是最好的方式,因為當文章的數量很多很多的時候,那緩存中就需要存大量的文檔id而且只能持續增長,所以我們得想一種方式來節省記憶體資源當又能是請求都能命中緩存,這個就是布隆過濾器要做的。

36

我們分析布隆過濾器的優缺點

優點

1.不需要存儲數據,只用比特表示,因此在空間占用率上有巨大的優勢
2.檢索效率高,插入和查詢的時間複雜度都為 O(K)(K 表示哈希函數的個數)
3.哈希函數之間相互獨立,可以在硬體指令層次並行計算,因此效率較高。

缺點

1.存在不確定的因素,無法判斷一個元素是否一定存在,所以不適合要求 100% 準確率的場景
2.只能插入和查詢元素,不能刪除元素。

布隆過濾器分析:面對優點,完全符合我們的訴求,針對缺點1,會有極少的數據穿透對系統來說並無壓力。針對缺點2,合同的數據,本來就是不可刪除的。如果合同過期,我們可以查出單個商家的所有合同,從合同的結束時間來判斷合同是否有效,並不需要取刪除布隆過濾器里的元素。

考慮到調用redis布隆過濾器,會走一次網路,而我們的查詢近一半都是無效查詢,我們決定使用本地布隆過濾器,這樣就可以減少一次網路請求。但是如果是本地布隆過濾器,在更新時,就需要對所有機器的本地布隆過濾器更新,我們監聽合同的狀態來更新,通過mq的廣播模式,來對布隆過濾器插入元素,這樣就做到了所有機器上的布隆過濾器統一元素插入。

2.第二層防護

面對高併發,我們首先想到的是緩存。

引入緩存,我們就要考慮緩存穿透,緩存擊穿,緩存雪崩的三大問題。

其中緩存穿透,我們已再第一層防護中處理,這裡只解決緩存擊穿,緩存雪崩的問題。

緩存擊穿(Cache Breakdown)緩存雪崩是指只大量熱點key同時失效的情況,如果是單個熱點key,在不停的扛著大併發,在這個key失效的瞬間,持續的大併發請求就會擊破緩存,直接請求到資料庫,好像蠻力擊穿一樣。這種情況就是緩存擊穿。

常規解決方案

緩存失效分散

這個問題其實比較好解決,就是在設置緩存的時效時間的時候增加一個隨機值,例如增加一個1-3分鐘的隨機,將失效時間分散開,降低集體失效的概率;把過期時間控制在系統低流量的時間段,比如凌晨三四點,避過流量的高峰期。

加鎖

加鎖,就是在查詢請求未命中緩存時,查詢資料庫操作前進行加鎖,加鎖後後面的請求就會阻塞,避免了大量的請求集中進入到資料庫查詢數據了。

永久不失效

我們可以不設置過期時間來保證緩存永遠不會失效,然後通過後臺的線程來定時把最新的數據同步到緩存里去

解決方案:使用分散式鎖,針對同一個商家,只讓一個線程構建緩存,其他線程等待構建緩存執行完畢,重新從緩存中獲取數據。

緩存雪崩(Cache Avalanche)當緩存中大量熱點緩存採用了相同的實效時間,就會導致緩存在某一個時刻同時實效,請求全部轉發到資料庫,從而導致資料庫壓力驟增,甚至宕機。從而形成一系列的連鎖反應,造成系統崩潰等情況,這就是緩存雪崩。

解決方案:緩存雪崩的解決方案是將key的過期設置為固定時間範圍內的一個隨機數,讓key均勻的失效即可。

我們考慮使用redis緩存,因為每次查詢的條件都不一樣,返回的結果數據又比較少,我們考慮限制查詢都必須有一個固定的查詢條件,商家編碼。如果查詢條件中沒有查商家編碼,我們可以通過商家名稱,商家業務賬號這些條件來反查查商家編碼。

這樣我們就可以緩存單個商家編碼的所有合同,然後再通過代碼使用filter對其他查詢條件做支持,避免不同的查詢條件都去緩存數據而引發的緩存數據更新,緩存數據淘汰已經緩存數據一致等問題。

同時只緩存單個商家編碼的所有合同,緩存的數據量也是可控,每個緩存的大小也可控,基本不會出現redis大key的問題。

引入緩存,我們就要考慮緩存數據一致性的問題。

有關緩存一致性問題,可自行百度,這個就不在敘述。

如圖所示 對於商家編碼維度的緩存數據,我們通過監聽合同的狀態,使用mq廣播來刪除對應商家的緩存,從而避免出現緩存和數據一致性的相關問題。

38

3.第三層防護

第三層防護,自然是資料庫,如果有查詢經過了第一層和第二層,那我們需要直接查詢資料庫來返回結果,同時,我們對直接調用到資料庫的線程進行監控。

37

為避免一些未知的查詢大量查詢涌入,導致資料庫調用保證的問題,尤其是大促時,我們可以提前對資料庫里的所有商家合同進行提前緩存。在緩存時,為避免緩存雪崩問題,我們對將key的過期設置為固定時間範圍內的一個隨機數,讓key均勻的失效。

同時,為避免依然存在意外的情況,有大量查詢涌入。我們通過ducc開關控制資料庫的查詢,如調用量太高導致無法支撐,則直接關閉資料庫的調用,保證資料庫不會直接宕機導致整個業務不可用。

4 總結

本文主要分析了面對高併發調用的調用場景設計及的技術方案,在引入緩存的同時,也要考慮實際的調用入參及結果,面對增加的網路請求,是否可以進一步減少。面對redis緩存,是否可以通過一些手段避免所有查詢條件都需要緩存,帶來的緩存爆炸,緩存淘汰策略等問題,以及解決緩存與數據一致等一系列問題。

本方案是根據具體的查詢業務場景設計具體的技術方案,針對不同的業務場景,對應的技術方案也是不一樣的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Taier 介紹 Taier 是袋鼠雲開源項目之一,是一個分散式可視化的DAG任務調度系統。 旨在降低ETL開發成本、提高大數據平臺穩定性,大數據開發人員可以在 Taier 直接進行業務邏輯的開發,而不用關心任務錯綜複雜的依賴關係與底層的大數據平臺的架構實現,將工作的重心更多地聚焦在業務之中。 項目 ...
  • 0.前言 MySQL由於開源的原因,有各式各樣的中件間Proxy ,極大的豐富了做高可用或遷移的方案,習慣了MySQL生態圈的靈活和便利,Oracle官方不開源代碼和協議,沒有中間件proxy,顯得很笨重。 比如以下的方案就會很不好辦: 實時抓取Oralce的訪問SQL日誌 慢日誌捕獲和收集 高可用 ...
  • 有相當一部分 iPhone 用戶會拒絕iOS更新最新系統,不管是因為各種BUG還是因為其他優化方面的問題,他們都會選擇一個自己覺得均衡的系統版本,安逸養老。 但是蘋果 iOS 系統如果你不及時更新推送版本的話,就會在手機桌面「設置」上方出現角標數字紅點,系統設置中也會出現紅點提示。強迫症患者表示簡直 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 可視化大屏該如何做?有可能一天完成嗎?廢話不多說,直接看效果,線上 Demo 地址 lxfu1.github.io/large-scree…。 看完這篇文章(這個項目),你將收穫: 全局狀態真的很簡單,你只需 5 分鐘就能上手 如何 ...
  • 1.CSS、SCSS、SASS CSS是開發人員熟知的一種用於頁面樣式開發的語言,可以通過內容的分離控制減少代碼的重覆性,降低代碼的複雜程度。 SASS 與 SCSS 都是 CSS 預處理器,可包含在基於 CSS 的 UI(用戶界面)或前端框架中以簡化開發。這些 SASS 與 SCSS 框架在高級別 ...
  • 鑒於阮一峰老師的技術文章,在此做一個轉載記錄。轉戰react技術一年,希望在技術上可以不斷精進,日後成為一位大牛! 引子:《準備工作》 知識準備 環境準備 第一講:《前端開發的歷史和趨勢》 前端開發的歷史演變 前端MVC框架的興起 前後端分離 全棧工程師 前端開發的未來 第二講:《React 技術棧 ...
  • 前言 先說幾句廢話,本人是一名 web 後端開發,主語言是 java,在學 Electron 之前,只會一點點 HTML和 JavaScript。本文講的也是我學習 Electron 的過程,而非教程,請酌情參考。 Electron是什麼 Electron是一個使用 JavaScript、HTML ...
  • 隨著業務變化的速度越來越快各類IT系統的建設也越來越複雜大規模研發團隊的管理問題日益突出如何提升研發效能成為時下各類技術團隊面臨的重要挑戰 京東雲DevOps專家將帶您深入研發一線揭秘支撐京東集團萬人級研發管理的行雲DevOps平臺 分享企業應該如何規劃DevOps落地與演進 嘉賓介紹 孫長虹 京東 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...