效率

同一次業(yè)務(wù)操作過程中,往往會出現(xiàn)某種操作被重復(fù)執(zhí)行,邏輯上來講如果只執(zhí)行一次是最理想的。這里所指的操作特指一些IO操作,比如從數(shù)據(jù)庫中獲取登錄人的信息,也就是說如果一次請求中包含5個小邏輯,這5個小邏輯包含3次獲取用戶信息的操作,理想的情況是3次只有一次是從數(shù)據(jù)庫中加載,其余的兩次從緩存中獲取。

  • 多次調(diào)用,每個服務(wù)實現(xiàn)獨自請求用戶信息。

     

  • 一次調(diào)用,多次讀取。首先從Context中加載,如果失敗從數(shù)據(jù)庫中加載,最后將結(jié)果存入Context。

前提

限于非web環(huán)境,這里是dubbo實現(xiàn)的微服務(wù)。如果是web環(huán)境的話解決問題比較簡單,因為我們可以充分利用Spring Framwork中提到的三個bean生命周期的特殊來解決:

  • request
  • session
  • global

案例

將老的價格數(shù)據(jù)遷移成新的價格數(shù)據(jù),這里大概是如下的步驟:

  • 刪除新老價格的關(guān)系,因為需要支持重復(fù)遷移
  • 禁用之前已經(jīng)存在的價格規(guī)則,規(guī)則是描述價格在某種場景下生效的邏輯
  • 創(chuàng)建新的價格
  • 創(chuàng)建新的規(guī)則
  • 啟用新規(guī)則

上面步驟的價格,規(guī)則,關(guān)系數(shù)據(jù)分別屬于三個業(yè)務(wù)對象,自身都具備CRUD的服務(wù)接口,這些CRUD都需要記錄操作人信息,記錄的標(biāo)準(zhǔn)就是接口傳入的操作人所持有的token,我們需要將這個token轉(zhuǎn)換成userId,userName之類的信息與價格,規(guī)則等信息一并存儲。

時序圖如下:

問題:遷移一條價格多次讀取用戶信息效率低

由于遷移價格會涉及到多個對象的操作,而操作這些具體業(yè)務(wù)對象的接口并不支持傳具體的userId,userName只支持token,所以不可避免的會在保存價格等信息時各自去根據(jù)token查詢操作人信息。實測一個價格完成一次數(shù)據(jù)遷移涉及到獲取用戶信息的次數(shù)多達(dá)20+次,效率是比較低,如何去解決呢?

現(xiàn)狀

由于我目前實現(xiàn)的微服務(wù)是無狀態(tài)的,也不是web環(huán)境,所以上面提到的那些bean的作用域功能就使用不上。

目標(biāo)

實現(xiàn)類似request作用域的功能,一次請求僅執(zhí)行一次,其余的請求從緩存中獲取結(jié)果以提高IO操作效率。

方案

可采用TreadLocal來當(dāng)緩存,存儲頻繁讀取的數(shù)據(jù)。增加了CacheContext,獲取用戶首先從CacheContext中取,如果為空則從數(shù)據(jù)庫加載然后回寫到Treadlocal中,下一次再請求用戶信息時就可以命中緩