[NewLife.XCode]實體列表緩存(最土的方法實現百萬級性能)

NewLife.XCode是一個有10多年曆史的開源數據中間件,支持nfx/netcore,由新生命團隊(2002~2019)開發完成並維護至今,以下簡稱XCode。

整個系列教程會大量結合示例代碼和運行日誌來進行深入分析,蘊含多年開發經驗於其中,代表作有百億級大數據實時計算項目。

開源地址:https://github.com/NewLifeX/X (求star, 765+)

 

全表緩存

在實際項目開發中,經常遇到有一些表數據很少(1000行以內),不會頻繁修改(平均每行幾個小時纔會修改一次),例如配置表、分類表等。

這樣的表,往往可以接受三五秒甚至更長的延遲,正是最適合使用緩存的地方。

 

實體緩存:一次性加載全表數據進入內存,供上層多維度查詢!

 

來看一個例程:

 

根據查詢日誌可以看到,雖然執行了1000萬次查詢,實際上只有一行select日誌輸出,也就是隻查了一次數據庫,其它9,999,999次從緩存中查找。

實體緩存的查詢速度只取決於 CPU主頻,在這臺AMD古董機上也可以輕鬆得到百萬級速度。

最後一行是實體緩存統計日誌,10秒輸出第一次,然後每10分鐘輸出一次,統計了緩存數、請求數、命中率。

如上,7億多次查詢,命中率在99%以上。

 

使用實體緩存

實體緩存本質上就是一個實體列表 IList<TEntity>,可通過 Meta.Cache 快速訪問。

該列表位於 Meta.Cache.Entities,在 Meta.Cache 上提供了 Find/FindAll 方法。

因爲是 IList<TEntity>,所以適用所有Linq方法,如上面例子可以改爲:Meta.Cache.Entities.FirstOrDefault(e => e.Name.EqualIgnoreCase(name))

 

XCode在生成實體類擴展查詢代碼時,默認都會帶有實體緩存用法,當錶行數小於1000時,走實體緩存:

if (Meta.Count < 1000) return Meta.Cache.Find(e => e.Name.EqualIgnoreCase(name));

如果不想使用實體緩存,註釋這一行即可。除此之外,XCode內部任何地方不會主動使用實體緩存。

 

使用緩存的閾值

1000是一個大量實踐得到的值:

小於1000時,內存搜索遠勝於數據庫,畢竟數據庫還有網絡開銷和序列化爲實體對象的開銷;

大於10000時,內存搜索就不如數據庫了;

1000到10000之間,內存搜索速度逐步下降,可根據場景決定閾值大小,例如數據極少修改且又需要進行範圍搜索時甚至可以設爲大於10000;

 

擴展屬性優化

在前面《擴展屬性》中提到過,XCode不支持多表關聯,而是建議拆分爲多次單表查詢。查詢簡單化以後,就可以更容易的實現緩存優化。

還是學生班級的例子,爲了在學生列表頁展示班級名稱,而學生表student只有班級編號classid字段,當時的做法是建立Class擴展屬性,藉助Class.FindByID查詢。

因爲班級數量不會特別多,更是極少修改,因此我們可以在Class.FindByID內部使用實體緩存,把所有班級都緩存起來。

至此,學生班級的多表關聯查詢,藉助擴展屬性和列表緩存,成功轉化成爲學生表單表查詢,班級名稱的匹配幾乎毫無壓力!

 

過期策略

所有緩存都必須有過期策略。實體緩存的過期策略有以下:

  • 初始化。首次訪問緩存時,加鎖阻塞所有訪問線程,直到加載完全表數據。
  • 定時過期。緩存過期後,開異步線程更新並同時返回舊數據,確保應用層性能。設置文件的 EntityCacheExpire, 默認10秒
  • 添刪改過期。對實體類的添刪改操作完成後,都會直接修改實體緩存對應項,而不會清空整個列表。

顯然,首次加載以後,將來訪問的永遠是定時更新的緩存數據,應用層可以得到非常好的性能!

由於實體緩存的添刪改過期跟實體操作綁定在一起,因此,越過實體類直接DAL執行更新操作,或者其它服務器修改數據,此時無法影響實體緩存,導致數據更新不及時。

早期版本XCode實體緩存默認過期時間60秒,隨着數據庫性能提升,默認值修改爲10秒,可根據實際場景設置。

 

系列教程

NewLife.XCode教程系列[2019版]

  1. 增刪改查入門。快速展現用法,代碼配置連接字符串
  2. 數據模型文件。建立表格字段和索引,名字以及數據類型規範,推薦字段(時間,用戶,IP)
  3. 實體類詳解。數據類業務類,泛型基類,接口
  4. 功能設置。連接字符串,調試開關,SQL日誌,慢日誌,參數化,執行超時。代碼與配置文件設置,連接字符串局部設置
  5. 反向工程。自動建立數據庫數據表
  6. 數據初始化。InitData寫入初始化數據
  7. 高級增刪改。重載攔截,自增字段,Valid驗證,實體模型(時間,用戶,IP)
  8. 髒數據。如何產生,怎麼利用
  9. 增量累加。高併發統計
  10. 事務處理。單表和多表,不同連接,多種寫法
  11. 擴展屬性。多表關聯,Map映射
  12. 高級查詢。複雜條件,分頁,自定義擴展FieldItem,查總記錄數,查彙總統計
  13. 數據層緩存。Sql緩存,更新機制
  14. 實體緩存。全表整理緩存,更新機制
  15. 對象緩存。字典緩存,適用用戶等數據較多場景。
  16. 百億級性能。字段精煉,索引完備,合理查詢,充分利用緩存
  17. 實體工廠。元數據,通用處理程序
  18. 角色權限。Membership
  19. 導入導出。Xml,Json,二進制,網絡或文件
  20. 分表分庫。常見拆分邏輯
  21. 高級統計。聚合統計,分組統計
  22. 批量寫入。批量插入,批量Upsert,異步保存
  23. 實體隊列。寫入級緩存,提升性能。
  24. 備份同步。備份數據,恢復數據,同步數據
  25. 數據服務。提供RPC接口服務,遠程執行查詢,例如SQLite網絡版
  26. 大數據分析。ETL抽取,調度計算處理,結果持久化

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章