效率
同一次業(yè)務(wù)操作過程中,往往會(huì)出現(xiàn)某種操作被重復(fù)執(zhí)行,邏輯上來講如果只執(zhí)行一次是最理想的。這里所指的操作特指一些IO操作,比如從數(shù)據(jù)庫(kù)中獲取登錄人的信息,也就是說如果一次請(qǐng)求中包含5個(gè)小邏輯,這5個(gè)小邏輯包含3次獲取用戶信息的操作,理想的情況是3次只有一次是從數(shù)據(jù)庫(kù)中加載,其余的兩次從緩存中獲取。
- 多次調(diào)用,每個(gè)服務(wù)實(shí)現(xiàn)獨(dú)自請(qǐng)求用戶信息。
- 一次調(diào)用,多次讀取。首先從Context中加載,如果失敗從數(shù)據(jù)庫(kù)中加載,最后將結(jié)果存入Context。
前提
限于非web環(huán)境,這里是dubbo實(shí)現(xiàn)的微服務(wù)。如果是web環(huán)境的話解決問題比較簡(jiǎn)單,因?yàn)槲覀兛梢猿浞掷肧pring Framwork中提到的三個(gè)bean生命周期的特殊來解決:
- request
- session
- global
案例
將老的價(jià)格數(shù)據(jù)遷移成新的價(jià)格數(shù)據(jù),這里大概是如下的步驟:
- 刪除新老價(jià)格的關(guān)系,因?yàn)樾枰С种貜?fù)遷移
- 禁用之前已經(jīng)存在的價(jià)格規(guī)則,規(guī)則是描述價(jià)格在某種場(chǎng)景下生效的邏輯
- 創(chuàng)建新的價(jià)格
- 創(chuàng)建新的規(guī)則
- 啟用新規(guī)則
上面步驟的價(jià)格,規(guī)則,關(guān)系數(shù)據(jù)分別屬于三個(gè)業(yè)務(wù)對(duì)象,自身都具備CRUD的服務(wù)接口,這些CRUD都需要記錄操作人信息,記錄的標(biāo)準(zhǔn)就是接口傳入的操作人所持有的token,我們需要將這個(gè)token轉(zhuǎn)換成userId,userName之類的信息與價(jià)格,規(guī)則等信息一并存儲(chǔ)。
時(shí)序圖如下:
問題:遷移一條價(jià)格多次讀取用戶信息效率低
由于遷移價(jià)格會(huì)涉及到多個(gè)對(duì)象的操作,而操作這些具體業(yè)務(wù)對(duì)象的接口并不支持傳具體的userId,userName只支持token,所以不可避免的會(huì)在保存價(jià)格等信息時(shí)各自去根據(jù)token查詢操作人信息。實(shí)測(cè)一個(gè)價(jià)格完成一次數(shù)據(jù)遷移涉及到獲取用戶信息的次數(shù)多達(dá)20+次,效率是比較低,如何去解決呢?
現(xiàn)狀
由于我目前實(shí)現(xiàn)的微服務(wù)是無狀態(tài)的,也不是web環(huán)境,所以上面提到的那些bean的作用域功能就使用不上。
目標(biāo)
實(shí)現(xiàn)類似request作用域的功能,一次請(qǐng)求僅執(zhí)行一次,其余的請(qǐng)求從緩存中獲取結(jié)果以提高IO操作效率。
方案
可采用TreadLocal來當(dāng)緩存,存儲(chǔ)頻繁讀取的數(shù)據(jù)。增加了CacheContext,獲取用戶首先從CacheContext中取,如果為空則從數(shù)據(jù)庫(kù)加載然后回寫到Treadlocal中,下一次再請(qǐng)求用戶信息時(shí)就可以命中緩