欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

聊一聊在大型分布式系統(tǒng)中緩存應(yīng)該怎么玩?

jf_ro2CN3Fa ? 來(lái)源:黎杜 ? 2023-05-23 14:20 ? 次閱讀

今天我們來(lái)聊一聊在大型分布式系統(tǒng)中,緩存應(yīng)該怎么玩,從畢業(yè)到現(xiàn)在也有三年多了,大大小小的系統(tǒng)也經(jīng)歷了幾十個(gè),今天就從各個(gè)角度來(lái)討論一下,我們的不同的緩存應(yīng)該怎么玩,才能用的高效。

我們團(tuán)隊(duì)現(xiàn)在做的是直播類的產(chǎn)品,就拿抖音來(lái)說(shuō),比如說(shuō)要開發(fā)一個(gè)榜一大哥、榜二大哥等各類大哥的排行榜單,要怎么開發(fā),對(duì)于抖音這個(gè)dau十億級(jí)別的產(chǎn)品,緩存的設(shè)計(jì)肯定是家常便飯。

對(duì)于一個(gè)百萬(wàn)、千萬(wàn)級(jí)別的接口調(diào)用,若是沒(méi)有緩存的設(shè)計(jì),直接打到數(shù)據(jù)持久層,那將是毀滅性的災(zāi)難。之前我就經(jīng)歷過(guò),一個(gè)接口一天幾百萬(wàn)次的調(diào)用,因?yàn)榫彺娴脑O(shè)計(jì)不嚴(yán)謹(jǐn),緩存失效后,瞬間直接打在數(shù)據(jù)庫(kù)層,幸好有告警,及時(shí)修復(fù),差點(diǎn)就領(lǐng)了p0的故障。

大體來(lái)說(shuō)緩存分為客戶端緩存服務(wù)端緩存 ,客戶端緩存我們比較常見的就是瀏覽器緩存,也就是通過(guò)http進(jìn)行控制的緩存。

客戶端緩存

基于請(qǐng)求-應(yīng)答模式下,在大多數(shù)場(chǎng)景下客戶端都是通過(guò)https協(xié)議,請(qǐng)求后臺(tái)獲取數(shù)據(jù),若是高頻的接口一天幾百萬(wàn)次的調(diào)用,即使短時(shí)間的客戶端緩存也會(huì)帶來(lái)高效的收益。

因?yàn)榭蛻舳说椒?wù)端要經(jīng)過(guò)漫長(zhǎng)的網(wǎng)絡(luò)鏈路,多變的網(wǎng)絡(luò)環(huán)境,數(shù)據(jù)包可能小的幾十K到大的數(shù)據(jù)包幾十M,這樣就能夠省去復(fù)雜多變的網(wǎng)絡(luò)請(qǐng)求的時(shí)間。

客戶端緩存減少了客戶端到服務(wù)端之間的通信次數(shù)以及成本,只要緩存可用,就能夠及時(shí)響應(yīng)數(shù)據(jù)。

客戶端緩存常見的也就是瀏覽器緩存,簡(jiǎn)而言之也就是http緩存,不知道大家在實(shí)際開發(fā)過(guò)程中有沒(méi)有用過(guò)這段代碼:

ResponseEntity.ok().cacheControl(CacheControl.maxAge(3,TimeUnit.SECONDS)).body()

看他的包,他就是屬于springframework 框架下http包下的一個(gè)工具類。

importorg.springframework.http.CacheControl;
importorg.springframework.http.ResponseEntity;

在瀏覽器緩存中,http協(xié)議header有這么個(gè)key-value字段進(jìn)行控制,叫做Cache-Control:max-age=30 ,max-age標(biāo)志該資源在客戶端緩存多少秒。

假如max-age=0,表示不緩存數(shù)據(jù),除了max-age可以控制數(shù)據(jù)的緩存狀態(tài),還有以下三個(gè)屬性來(lái)控制緩存狀態(tài)no_store、no_cache、must-revalidate

no_store表示不緩存數(shù)據(jù),每次都去服務(wù)器獲取

no_cache看起來(lái)也是不緩存的意思,但是它表示的意思是可以緩存的,只不過(guò)在使用緩存之前,都要去服務(wù)器驗(yàn)證數(shù)據(jù)是否有效,是否過(guò)期,是否是最新版 。

must-revalidate和no_cache有點(diǎn)類似,就是緩存不過(guò)期的話可以繼續(xù)使用,過(guò)期了就需要去服務(wù)器驗(yàn)證一下

除了Cache-Control可以使用客戶端緩存,在http里面還有一個(gè)條件請(qǐng)求的header更加智能的使用客戶端緩存。

條件請(qǐng)求是基于響應(yīng)報(bào)文返回的“Last-modified ”和“ETag ”實(shí)現(xiàn)的。Last-modified資源最后的一次修改時(shí)間,ETag則表示資源的唯一標(biāo)識(shí),你可以理解為只要資源修改后都不一樣了 。

再次請(qǐng)求的時(shí)候在請(qǐng)求頭里面就會(huì)帶上"If-None-Match:ETag返回的值 ",去驗(yàn)證資源是否有效。

假如有效的話,就會(huì)返回"304 Not Modified ",表示緩存資源有效還可以繼續(xù)使用。

95ba9f84-f920-11ed-90ce-dac502259ad0.png

但是這種方式我較少使用,基本上使用Cache-Control就夠了,控制好實(shí)效的時(shí)間,一般的場(chǎng)景都是允許短暫的不一致。

除了客戶端能夠發(fā)送Cache-Control之外,客戶端也能夠發(fā)送Cache-Control兩者進(jìn)行協(xié)商使用客戶端緩存的方案。

像我在瀏覽器訪問(wèn)一個(gè)連接,在輸入框敲一下回車,Request的Headers里面就有Cache-Control:max-age = 0,表示不使用緩存,直接去后臺(tái)獲取數(shù)據(jù)。

95bf71a8-f920-11ed-90ce-dac502259ad0.png

所以Cache-Control來(lái)控制客戶端緩存也不太好控制,要兩者協(xié)商好,但是Cache-Control有一個(gè)好處就是可以控制CDN緩存。

服務(wù)端緩存

CDN緩存

上面聊到Cache-Control來(lái)控制客戶端緩存,它也同時(shí)影響CDN緩存,告訴CDN客戶緩存這個(gè)接口的數(shù)據(jù)。

CDN服務(wù)一般是由第三方提供的內(nèi)容分發(fā)網(wǎng)絡(luò)服務(wù),主要是用于緩存靜態(tài)的數(shù)據(jù),比如:圖片、音頻、視頻,這些數(shù)據(jù),都是不不變的,那么命中率就很高。

不用回源獲取數(shù)據(jù),效率高,畢竟使用CDN的費(fèi)用高,一般小公司也不會(huì)用,可能大公司采用。

CDN廠商花費(fèi)大價(jià)錢在全國(guó)各地建立CDN的服務(wù)站點(diǎn),用于用戶的就近訪問(wèn),減少響應(yīng)時(shí)間。

95c489c2-f920-11ed-90ce-dac502259ad0.png

所以這個(gè)對(duì)于應(yīng)用層的來(lái)說(shuō)是0開發(fā)的,一般只要在你的服務(wù)治理平臺(tái)針對(duì)某一個(gè)接口配置一下就好了。

除了緩存靜態(tài)數(shù)據(jù),想一些動(dòng)態(tài)數(shù)據(jù),但是不會(huì)經(jīng)常變的數(shù)據(jù)CDN也是可以緩存的,只不過(guò)可能緩存的時(shí)間設(shè)置的比較短,那么在高并發(fā)場(chǎng)井下取得的效益也是比較大的。

好了,關(guān)于CDN的也沒(méi)啥好說(shuō)的,我還沒(méi)接觸過(guò)CDN開發(fā),但是項(xiàng)目中使用到了,就是簡(jiǎn)單而配置一下而已,等我接觸到開發(fā),再和你們?cè)斄?,CDN其實(shí)就是代理源站服務(wù)器緩存數(shù)據(jù)而已。

Redis緩存

在服務(wù)端緩存中Redis緩存可能是我們最常見的緩存,可以說(shuō)Redis已經(jīng)是各大公司常用的緩存中間件選型之首,也不為過(guò)。

我們項(xiàng)目中也是在使用Redis,只不過(guò)在Redis的層面上進(jìn)行封裝,包括Redis哨兵、Redis分片 ,都是基于自己的業(yè)務(wù)情況下進(jìn)行二次開發(fā),然后供自己的業(yè)務(wù)使用。

在Redis的基礎(chǔ)數(shù)據(jù)類型中,有五大類型供大家選擇,包括String、List、Set、SortedSet、Hash 。這五種數(shù)據(jù)類型在百分之九十五的場(chǎng)景下都能夠解決,并且在這五種基本數(shù)據(jù)類型的底層運(yùn)用了高效與省空間的數(shù)據(jù)結(jié)構(gòu),所以Redis的高性能之一也是因?yàn)橛羞@些數(shù)據(jù)結(jié)構(gòu)作為支撐。

95cc0922-f920-11ed-90ce-dac502259ad0.png

圖片來(lái)源于Redis核心技術(shù)與實(shí)戰(zhàn)

比如:要實(shí)現(xiàn)一個(gè)排行榜單,凸顯直播間榜一大哥以及上榜大哥財(cái)大氣粗的實(shí)力。

那么這個(gè)明顯是按照某個(gè)字段進(jìn)行排序,比如刷的抖音幣進(jìn)行排序,那個(gè)在redis中List和Sorted Set都是可以實(shí)現(xiàn)有序的緩存。

List是按照寫入List順序進(jìn)行存儲(chǔ),而Sorted Set是按照某一個(gè)字段的權(quán)重來(lái)排序,并且可以查詢權(quán)重范圍內(nèi)的數(shù)據(jù)。

對(duì)于我們的場(chǎng)景List可能不太適合,因?yàn)槭菍?duì)數(shù)據(jù)每次都是新產(chǎn)生的,并且按照時(shí)間來(lái)順序來(lái)寫入,List集合就比較適合。

我們的場(chǎng)景是某個(gè)在榜大哥不斷的刷禮物,就需要重新對(duì)他進(jìn)行排序,并不是按照每次新增寫入緩存的順序取數(shù),那么按照大哥刷的抖音幣的多少就可以當(dāng)做權(quán)重來(lái)排序,很好的服務(wù)我們的場(chǎng)景,按照時(shí)間來(lái)排序的場(chǎng)景Sorted Set都可以來(lái)做。

還有一些聚合統(tǒng)計(jì)的場(chǎng)景,比如要統(tǒng)計(jì)兩個(gè)key數(shù)據(jù)集的交集、并集、差集可以使用set集合來(lái)做。

假如某一天你的老板讓你開發(fā)一個(gè)統(tǒng)計(jì)每天新增的用戶數(shù)據(jù)功能,其實(shí)那么也就兩個(gè)集合差集,一個(gè)set集合用戶保存所有用戶的id,一個(gè)set用戶保存當(dāng)天用戶的id集合,然后當(dāng)天用戶集合與所有用戶集合的差集就是新增的用戶集合??梢允褂胹et集合中的SDIFFSTORE 命令進(jìn)行實(shí)現(xiàn)。

還有一些二值統(tǒng)計(jì)的場(chǎng)景,也就是基于redis的Bitmap來(lái)統(tǒng)計(jì),他并不記錄數(shù)據(jù)的本身,只能判斷是否存在,有沒(méi)有,Bitmap保存的是bit 位,所以億級(jí)別數(shù)量的存儲(chǔ)只要M級(jí)別的存儲(chǔ)單位就可以了,所以Bitmap非常的節(jié)省空間。

Bitmap中提供SETBIT設(shè)置bit位,以及GETBIT獲取某個(gè)bit位的值,還可以使用BITCOUNT統(tǒng)計(jì)bit位位1的值,比如可以統(tǒng)計(jì)某個(gè)月簽到場(chǎng)景。

Redis高性能的緩存給我們系統(tǒng)帶來(lái)了極大的性能提升,但是同時(shí)也會(huì)有一些類的問(wèn)題,比如數(shù)據(jù)一致性的問(wèn)題、緩存的三大問(wèn)題(擊穿、穿透、雪崩)、與Redis網(wǎng)絡(luò)通信接口超時(shí)、Redis里面緩存的數(shù)據(jù)變多,操作時(shí)間復(fù)雜度大的導(dǎo)致Redis變慢 。

數(shù)據(jù)的一致性

數(shù)據(jù)一致性問(wèn)題指的是緩存與數(shù)據(jù)庫(kù)的一致性問(wèn)題,只要使用緩存就會(huì)有一致性問(wèn)題,現(xiàn)在市場(chǎng)上都不會(huì)要求強(qiáng)一致性,都是追求最終一致性

緩存按照是否可寫分為讀寫緩存與只讀緩存 ,大部分是只讀緩存,現(xiàn)在我們來(lái)討論一下只讀緩存一致性問(wèn)題。

只讀緩存的一致性問(wèn)題包括以下以下兩種場(chǎng)景:

先更新數(shù)據(jù)庫(kù),然后刪除緩存。

先刪除緩存,然后更新數(shù)據(jù)庫(kù)。

但是這兩種場(chǎng)景在高并發(fā)場(chǎng)景下都會(huì)有問(wèn)題,先來(lái)看看第一種場(chǎng)景:先更新數(shù)據(jù)庫(kù),然后刪除緩存。

這種場(chǎng)景也會(huì)有一致性問(wèn)題,當(dāng)我們更新了數(shù)據(jù)庫(kù)后,然后刪除緩存,刪除緩存失敗了,此時(shí)請(qǐng)求讀取的緩存還是舊的值。

這種情況下的解決方案就是重試 ,可以在應(yīng)用層重試,也可以放入消息隊(duì)列里面重試,當(dāng)重試次數(shù)達(dá)到最大的限制,就需要發(fā)送告警進(jìn)行人工排查了。

95d23bf8-f920-11ed-90ce-dac502259ad0.png

或者設(shè)置比較短的緩存失效時(shí)間,短暫的不一致性,也是可以接受的。

第二種場(chǎng)景:先刪除緩存,然后再更新數(shù)據(jù)庫(kù)。在高并發(fā)場(chǎng)景下也有可能數(shù)據(jù)不一致。

假如線程A刪除了緩存,但是還沒(méi)有更新數(shù)據(jù)庫(kù),然后線程B讀取緩存發(fā)現(xiàn)緩存缺失,然后從數(shù)據(jù)庫(kù)里面讀取舊值,并且緩存到Redis中,后面的請(qǐng)求就會(huì)從Redis中讀取舊值。

95d83576-f920-11ed-90ce-dac502259ad0.png

這種場(chǎng)景市面上推薦使用延遲雙刪的方案進(jìn)行解決,就是在請(qǐng)求A刪除緩存后,更新數(shù)據(jù)庫(kù),然后等一段時(shí)間刪除緩存,請(qǐng)求A的sleep的時(shí)間大于請(qǐng)求B的讀取數(shù)據(jù)寫入緩存的時(shí)間。

但是這種一般等的時(shí)間不調(diào)好估計(jì),而且在高并發(fā)場(chǎng)景下,讓線程去等無(wú)疑是降低性能,這個(gè)通常是不允許的。

所以一般建議采用第一種方案,先更新數(shù)據(jù)庫(kù),然后刪除緩存的方式。

我們項(xiàng)目中也會(huì)用到讀寫緩存,之前遇到一個(gè)需求就是,在直播過(guò)程中,主播的公屏的流水,要顯示用戶中獎(jiǎng)的橫幅,也就是“恭喜某某在某某直播間抽中了XXX禮物”。

禮物的抽獎(jiǎng)流水之前就已經(jīng)發(fā)送消息隊(duì)列了,所以只要監(jiān)聽對(duì)應(yīng)抽獎(jiǎng)流水topic就行了,然后將中獎(jiǎng)的流水按照排序規(guī)則放入Redis中。然后客戶端從Redis中讀取,其實(shí)很簡(jiǎn)單,流水也不需要存庫(kù),只要展示就行了。

95dfa180-f920-11ed-90ce-dac502259ad0.png

所以Redis的應(yīng)用場(chǎng)景還是很多的,幾乎可以覆蓋開發(fā)中的95%以上的需求

緩存擊穿、穿透、雪崩

使用分布式緩存還會(huì)涉及到緩存的三大問(wèn)題,也就是緩存擊穿、緩存穿透、緩存雪崩 。

緩存穿透 的解決方案有兩種:

緩存空對(duì)象:代碼維護(hù)較簡(jiǎn)單,但是效果不好。

布隆過(guò)濾器:代碼維護(hù)復(fù)雜,效果很好。

緩存空對(duì)象是指當(dāng)一個(gè)請(qǐng)求過(guò)來(lái)緩存中和數(shù)據(jù)庫(kù)中都不存在該請(qǐng)求的數(shù)據(jù),第一次請(qǐng)求就會(huì)跳過(guò)緩存進(jìn)行數(shù)據(jù)庫(kù)的訪問(wèn),并且訪問(wèn)數(shù)據(jù)庫(kù)后返回為空,此時(shí)也將該空對(duì)象進(jìn)行緩存。

若是再次進(jìn)行訪問(wèn)該空對(duì)象的時(shí)候,就會(huì)直接擊中緩存,而不是再次數(shù)據(jù)庫(kù),緩存空對(duì)象實(shí)現(xiàn)的原理圖如下:

95e529e8-f920-11ed-90ce-dac502259ad0.png

緩存空對(duì)象的實(shí)現(xiàn)代碼如下:

publicclassUserServiceImpl{
@Autowired
UserDAOuserDAO;
@Autowired
RedisCacheredisCache;

publicUserfindUser(Integerid){
Objectobject=redisCache.get(Integer.toString(id));
//緩存中存在,直接返回
if(object!=null){
//檢驗(yàn)該對(duì)象是否為緩存空對(duì)象,是則直接返回null
if(objectinstanceofNullValueResultDO){
returnnull;
}
return(User)object;
}else{
//緩存中不存在,查詢數(shù)據(jù)庫(kù)
Useruser=userDAO.getUser(id);
//存入緩存
if(user!=null){
redisCache.put(Integer.toString(id),user);
}else{
//將空對(duì)象存進(jìn)緩存
redisCache.put(Integer.toString(id),newNullValueResultDO());
}
returnuser;
}
}
}

布隆過(guò)濾器是一種基于概率的數(shù)據(jù)結(jié)構(gòu),主要用來(lái)判斷某個(gè)元素是否在集合內(nèi),它具有運(yùn)行速度快(時(shí)間效率),占用內(nèi)存小的優(yōu)點(diǎn)(空間效率),但是有一定的誤識(shí)別率和刪除困難的問(wèn)題。它只能告訴你某個(gè)元素一定不在集合內(nèi)或可能在集合內(nèi)。

在計(jì)算機(jī)科學(xué)中有一種思想:空間換時(shí)間,時(shí)間換空間。一般兩者是不可兼得,而布隆過(guò)濾器運(yùn)行效率和空間大小都兼得,它是怎么做到的呢?

在布隆過(guò)濾器中引用了一個(gè)誤判率的概念,即它可能會(huì)把不屬于這個(gè)集合的元素認(rèn)為可能屬于這個(gè)集合,但是不會(huì)把屬于這個(gè)集合的認(rèn)為不屬于這個(gè)集合,布隆過(guò)濾器的特點(diǎn)如下:

一個(gè)非常大的二進(jìn)制位數(shù)組 (數(shù)組里只有0和1)

若干個(gè)哈希函數(shù)

空間效率和查詢效率高

不存在漏報(bào)(False Negative):某個(gè)元素在某個(gè)集合中,肯定能報(bào)出來(lái)。

可能存在誤報(bào)(False Positive):某個(gè)元素不在某個(gè)集合中,可能也被爆出來(lái)。

不提供刪除方法,代碼維護(hù)困難。

位數(shù)組初始化都為0,它不存元素的具體值,當(dāng)元素經(jīng)過(guò)哈希函數(shù)哈希后的值(也就是數(shù)組下標(biāo))對(duì)應(yīng)的數(shù)組位置值改為1。

實(shí)際布隆過(guò)濾器存儲(chǔ)數(shù)據(jù)和查詢數(shù)據(jù)的原理圖如下:

95eceed0-f920-11ed-90ce-dac502259ad0.png

緩存擊穿是指一個(gè)key非常熱點(diǎn),在不停的扛著大并發(fā),大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問(wèn),當(dāng)這個(gè)key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)庫(kù),瞬間對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)壓力增大。

緩存擊穿這里強(qiáng)調(diào)的是并發(fā),造成緩存擊穿的原因有以下兩個(gè):

該數(shù)據(jù)沒(méi)有人查詢過(guò) ,第一次就大并發(fā)的訪問(wèn)。(冷門數(shù)據(jù))

添加到了緩存,reids有設(shè)置數(shù)據(jù)失效的時(shí)間 ,這條數(shù)據(jù)剛好失效,大并發(fā)訪問(wèn)(熱點(diǎn)數(shù)據(jù))

對(duì)于緩存擊穿的解決方案:

加鎖,用戶出現(xiàn)大并發(fā)訪問(wèn)的時(shí)候,在查詢緩存的時(shí)候和查詢數(shù)據(jù)庫(kù)的過(guò)程加鎖,只能第一個(gè)進(jìn)來(lái)的請(qǐng)求進(jìn)行執(zhí)行,當(dāng)?shù)谝粋€(gè)請(qǐng)求把該數(shù)據(jù)放進(jìn)緩存中,接下來(lái)的訪問(wèn)就會(huì)直接集中緩存,防止了緩存擊穿。

95f23f52-f920-11ed-90ce-dac502259ad0.png

不設(shè)置熱點(diǎn)key的失效時(shí)間

緩存雪崩 是指在某一個(gè)時(shí)間段,緩存集中過(guò)期失效。此刻無(wú)數(shù)的請(qǐng)求直接繞開緩存,直接請(qǐng)求數(shù)據(jù)庫(kù)。

造成緩存雪崩的可能原因有:

reids宕機(jī)

大部分?jǐn)?shù)據(jù)失效

對(duì)于緩存雪崩的解決方案有以下兩種:

搭建高可用的集群,防止單機(jī)的redis宕機(jī)。

設(shè)置不同的過(guò)期時(shí)間,防止同一時(shí)間內(nèi)大量的key失效。

接口超時(shí)&操作時(shí)間復(fù)雜度高

Redis數(shù)據(jù)第三方緩存中間件,要與Redis通信,必須經(jīng)過(guò)網(wǎng)絡(luò),那么經(jīng)過(guò)網(wǎng)絡(luò)就有可能出現(xiàn)網(wǎng)絡(luò)超時(shí)的現(xiàn)象。

之前我們也出現(xiàn)過(guò),某個(gè)機(jī)房因?yàn)榫W(wǎng)絡(luò)波動(dòng),出現(xiàn)了一系列的Redis查詢網(wǎng)絡(luò)超時(shí)的告警。

所以為了解決一時(shí)的網(wǎng)絡(luò)超時(shí),我們有可能還要做好接口重試的機(jī)制,提高接口的可用性。

并且對(duì)Redis五種基本數(shù)據(jù)類型的底層數(shù)據(jù)結(jié)構(gòu)熟悉的,Redis中對(duì)集合類型的操作HGETALL、SMEMBERS,以及對(duì)集合進(jìn)行聚合統(tǒng)計(jì) 等,時(shí)間復(fù)雜度都是O(N)

那么Redis中存儲(chǔ)的數(shù)據(jù)越多,這個(gè)N就越大,操作的復(fù)雜度就越高,這就是所謂的bidkey現(xiàn)象,已經(jīng)出現(xiàn)查詢阻塞了。

當(dāng)然出現(xiàn)這種問(wèn)題時(shí),可以將bigkey按照一定規(guī)律進(jìn)行拆分,這樣分成多個(gè)key進(jìn)行存儲(chǔ),查詢的效率就會(huì)變高。

當(dāng)然Redis的數(shù)據(jù)分片解決方案也可以,將原來(lái)一個(gè)實(shí)例中存儲(chǔ)全量數(shù)據(jù),按照16384進(jìn)行crc16(key) % 16384 決定數(shù)據(jù)存儲(chǔ)于哪個(gè)槽中。

這樣擴(kuò)展性也比較好,不過(guò)一般優(yōu)先推薦拆分key的方案,這樣實(shí)現(xiàn)成本低,實(shí)現(xiàn)簡(jiǎn)單。

緩存消息隊(duì)列玩法

有一些場(chǎng)景還可以使用消息隊(duì)列進(jìn)行更新緩存,用戶更新數(shù)據(jù),異步的發(fā)送消息隊(duì)列,消費(fèi)者就可以監(jiān)聽消息隊(duì)列的消息,消費(fèi)消息后更新緩存。

因?yàn)橛行?shù)據(jù)的更新是需要發(fā)送消息隊(duì)列的,被其他消費(fèi)者監(jiān)聽使用,所以你只要監(jiān)聽消息隊(duì)列就行了。

并且消息的隊(duì)列的消息由消息隊(duì)列的方式來(lái)保證,包括生產(chǎn)者可靠的發(fā)送消息隊(duì)列,通過(guò)ack以及重試保證,消息隊(duì)列本身通過(guò)持久化機(jī)制來(lái)保證,而消費(fèi)者也是通過(guò)消費(fèi)后手動(dòng)ack來(lái)確認(rèn)消息消費(fèi)。

95f74196-f920-11ed-90ce-dac502259ad0.png

消息對(duì)壘更新緩存

定時(shí)任務(wù)

定時(shí)任務(wù)其實(shí)就是本地緩存了,在分布式系統(tǒng)中,定時(shí)任務(wù)就是每個(gè)服務(wù)中都會(huì)緩存一份,這樣數(shù)據(jù)不一致性也會(huì)加大。

但是在某些場(chǎng)景下,他帶來(lái)的收益也是非常可觀的,比如說(shuō)某個(gè)場(chǎng)景下你要查詢一些安全中臺(tái)的白名單/黑名單列表,而且這些列表不會(huì)經(jīng)常變,可能需求上線后只要配置一下就ok了,后面的更改頻率也是非常的低。

但是你的接口可能是高流量接口,每次用戶進(jìn)來(lái)都會(huì)請(qǐng)求一次,進(jìn)行判斷,而且用戶是千萬(wàn)級(jí)別的,那有可能一天的請(qǐng)求就是上百萬(wàn)次的請(qǐng)求。

那你有兩種選擇來(lái)請(qǐng)求安全中臺(tái)的白名單/黑名單列表,要么就是實(shí)時(shí)請(qǐng)求,要么就是定時(shí)任務(wù)請(qǐng)求本地緩存一份,然后查詢只要從本地獲取就行了。

在這種情況下肯定是定時(shí)任務(wù)請(qǐng)求,帶來(lái)的效益更大,在SprngBoot項(xiàng)目中開啟定時(shí)任務(wù)很簡(jiǎn)單,只需要在你的啟動(dòng)主類上加上這個(gè)注解:**@EnableScheduling**

然后在需要定時(shí)任務(wù)的執(zhí)行類的方法上加上這個(gè)注解:**@Scheduled(cron = "0 0 2 * * ?")** , 其實(shí)就是cron表達(dá)式,執(zhí)行的規(guī)律隔多久執(zhí)行一次。

只要你的時(shí)間配置的足夠短,這樣數(shù)據(jù)也是近實(shí)時(shí)的,不會(huì)差太遠(yuǎn),你可以配置成30秒或者幾十秒執(zhí)行一次,或者幾分鐘執(zhí)行一次都可以,這個(gè)可以和產(chǎn)品進(jìn)行協(xié)商,看產(chǎn)品可以接受多久的延遲。

然后,查詢的中臺(tái)的列表數(shù)據(jù)緩存在本地的一個(gè)map里面,用戶的uid作為map的key,然后后面需要查詢的時(shí)候,直接從map里面獲取。

這樣就不用每次請(qǐng)求過(guò)來(lái)都會(huì)實(shí)時(shí)的調(diào)用中臺(tái)的http/rpc接口查詢數(shù)據(jù),直接從本地獲取提高效率,這也是空間換時(shí)間的思想。

接口超時(shí)

這里需要注意的是,就是要提高你的接口調(diào)用的可用性 ,畢竟中臺(tái)屬于另一個(gè)服務(wù),那么服務(wù)之間涉及遠(yuǎn)程調(diào)用,就有可能存在超時(shí)的現(xiàn)象。

那么你就要確保你的接口99.9%可用,對(duì)于接口超時(shí),你可以就要設(shè)置接口重試 。

因?yàn)橛袝r(shí)候可能是網(wǎng)絡(luò)的原因?qū)е碌囊粫r(shí)超時(shí),設(shè)置被調(diào)用方一時(shí)因?yàn)榫W(wǎng)絡(luò)抖動(dòng)導(dǎo)致超時(shí),那么重試成功的概率就可能比較高。

一般重試的次數(shù)會(huì)設(shè)置為2-3 次比較合理,除非網(wǎng)絡(luò)故障了或者接口一直調(diào)不通,這樣的話就需要及時(shí)告警,通知到開發(fā)人員,及時(shí)檢查到底是哪里的問(wèn)題,確保好接口的兜底方案。

并且還要設(shè)置每次的超時(shí)時(shí)間,設(shè)置超時(shí)時(shí)間也是非常的重要,假如超時(shí)時(shí)間設(shè)置的太短,還沒(méi)有查出來(lái)就已經(jīng)超時(shí)了,這樣就會(huì)導(dǎo)致頻繁超時(shí),浪費(fèi)資源。

要是設(shè)置的超時(shí)間太長(zhǎng),那么線程就會(huì)一直阻塞在那里等待調(diào)用的結(jié)果返回,這樣在高并發(fā)場(chǎng)景下,就會(huì)資源耗盡,系統(tǒng)崩潰。

所以我給你的建議就是可以結(jié)合線上服務(wù)所在服務(wù)器的配置以及qps進(jìn)行配置,配置一個(gè)合理的超時(shí)時(shí)間,合理的時(shí)間內(nèi)能夠超時(shí)返回并且不會(huì)導(dǎo)致資源耗盡。

重試這種機(jī)制,在很多中間件的思想中都會(huì)涉及到,比如:在分布式事務(wù)中2PC和3PC 。

2PC在第二階段提交失敗,那么只能不斷重試,直到所有參與者都成功(回滾或者提交成功)。

95ff3248-f920-11ed-90ce-dac502259ad0.png

因?yàn)槌酥卦嚕瑳](méi)有更好的辦法,只能不斷重試直到都成功,而且多數(shù)情況可能都是一時(shí)的網(wǎng)絡(luò)抖動(dòng)的原因?qū)е碌?,這樣重試成功的概率就非常高。

批量查詢數(shù)據(jù)

定時(shí)任務(wù)緩存其實(shí)也是一種集中式緩存 ,假如緩存的數(shù)據(jù)量也比較大,那么在接口調(diào)用時(shí)就需要批量獲取,但是一次性又不能查詢太多,一般嚴(yán)謹(jǐn)?shù)闹信_(tái)設(shè)計(jì),都會(huì)都傳參進(jìn)行參數(shù)校驗(yàn)。

因?yàn)閷?duì)于調(diào)用方完全是透明的,不可信任的 ,什么參數(shù)都有可能傳過(guò)來(lái),假如調(diào)用方一下子查幾萬(wàn)個(gè)或者是幾萬(wàn)個(gè)數(shù)據(jù)集,那不是接口都爆了。

所以,必須要做好分批調(diào)用,調(diào)用方分批、分頁(yè)調(diào)用 ,中臺(tái)對(duì)參數(shù)做校驗(yàn)一次只能查詢幾百個(gè),這樣子去規(guī)定,保證接口的可用性。

調(diào)用方的偽代碼如下:

booleanend=true;
intpage=1;
intpageSize=500;
while(end){
//設(shè)置好超時(shí),失敗重試
Datadata=getData(page,pageSize);

Mapmap=data.getDataMap();
//data里面的字段hashMore表示查詢下一個(gè)分頁(yè)是否還有數(shù)據(jù)
end=Objects.equals(data.getHasMore(),1);
page++;
}

本地緩存@Cacheable

@Cacheable是springframework下提供的緩存注解類,在spring中定義了 org.springframework.cache.Cacheorg.springframework.cache.CacheManager 接口來(lái)統(tǒng)一實(shí)現(xiàn)cache。

除了@Cacheable用戶緩存數(shù)據(jù),也可以使用@CachePut用于緩存更新,這兩個(gè)是比較常用的。

他們緩存的數(shù)據(jù)也是緩存在本地和定時(shí)任務(wù)一樣,除了使用@Cacheable還可使用谷歌研發(fā)的cache工具類LoadingCache ,他也是本地緩存的一種,并且可以設(shè)置緩存的大小,重新刷新的時(shí)間。

相對(duì)比Cacheable會(huì)更加方便,因?yàn)槟惆l(fā)現(xiàn)Cacheable還缺少緩存時(shí)間和緩存更新的屬性配置實(shí)現(xiàn),可能還需要自己再二級(jí)開發(fā),比如加入緩存失效時(shí)間、多少秒后自動(dòng)更新更新緩存,這樣Cacheable才能更加完善。

privatefinalLoadingCache>tagCache=CacheBuilder.newBuilder()
.concurrencyLevel(4)
.expireAfterWrite(5,TimeUnit.SECONDS)
.initialCapacity(8)
.maximumSize(10000)
.build(newCacheLoader>(){

@Override
publicListload(StringcacheKey){
returnget(cacheKey);
}

@Override
publicListenableFuture>reload(Stringkey,ListoldValue){
ListenableFutureTask>task=ListenableFutureTask.create(()->get(key));
executorService.execute(task);
returntask;
}
}
);

相比@Cacheable就是代碼比較冗余,注解方式會(huì)更加直觀簡(jiǎn)潔,不過(guò)LoadingCache的靈活性更高。

我們自己對(duì)Cacheable進(jìn)行了擴(kuò)展,加入了實(shí)效時(shí)間以及自動(dòng)更新的方案,這樣的Cacheable更加適用于我們的業(yè)務(wù)。

9604d27a-f920-11ed-90ce-dac502259ad0.png

總結(jié)

在項(xiàng)目中可能多種緩存并行使用,使用不同的緩存都要基于業(yè)務(wù)進(jìn)行考量,包括成本,數(shù)據(jù)一致性,性能問(wèn)題等,不同的緩存方式有不同的特點(diǎn)。

redis緩存分布式系統(tǒng)中共享數(shù)據(jù),性能高效,擴(kuò)展性強(qiáng),redis可以基于數(shù)據(jù)分片、哨兵模式進(jìn)行擴(kuò)展,但是要額外的費(fèi)用進(jìn)行運(yùn)維,并且引入第三方中間件,系統(tǒng)的復(fù)雜度也高,排查困難,而且每次都要經(jīng)過(guò)網(wǎng)絡(luò)調(diào)用,有可能存在網(wǎng)絡(luò)超時(shí)的現(xiàn)象,數(shù)據(jù)丟失,所以要做好數(shù)據(jù)兼容,兜底方案。

本地緩存使用簡(jiǎn)單方便,低成本,每個(gè)服務(wù)實(shí)例都會(huì)冗余一份數(shù)據(jù),一致性問(wèn)題加大,但是效率非常高效,不用通過(guò)網(wǎng)絡(luò)傳輸獲取數(shù)據(jù)。

一般我們的項(xiàng)目中都會(huì)分配6-8G的內(nèi)存,所以一般本地緩存都?jí)蚴褂玫?,所以一般能用本地緩存的話,都可以?yōu)先使用本地緩存。

一些場(chǎng)景不得不使用分布式緩存的,就是用Redis緩存來(lái)共享數(shù)據(jù),綜合使用不同的緩存來(lái)解決項(xiàng)目中的問(wèn)題。

從上面的幾種緩存方案中可以看到重試方案,重試是解決很多問(wèn)題的重要手段之一,但是重試次數(shù),重試的超時(shí)時(shí)間也要控制,防止資源耗盡,在大多數(shù)場(chǎng)景下,重試都可以解決,要是重試次數(shù)達(dá)到限制都不成功,就有可能是網(wǎng)絡(luò)故障或者接口問(wèn)題,此時(shí)就需要應(yīng)用發(fā)送告警通知開發(fā)人員進(jìn)行排查,這是兜底方案。

客戶端緩存和CDN緩存這兩個(gè)對(duì)于服務(wù)端來(lái)說(shuō),比較少使用,一般公司都是用不到,大家可以把關(guān)注點(diǎn)放在服務(wù)端緩存中。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 過(guò)濾器
    +關(guān)注

    關(guān)注

    1

    文章

    433

    瀏覽量

    19760
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    379

    瀏覽量

    10967

原文標(biāo)題:大型分布式系統(tǒng)中,緩存就該這么玩

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    分布式軟件系統(tǒng)

    數(shù)據(jù)庫(kù)管理員為基礎(chǔ)的分層控制結(jié)構(gòu),但是每個(gè)局部數(shù)據(jù)庫(kù)管理員都具有高度的自主權(quán)。 2、分布式數(shù)據(jù)庫(kù)系統(tǒng)數(shù)據(jù)獨(dú)立性概念也同樣重要,然而增加了個(gè)新的概念,就是
    發(fā)表于 07-22 14:53

    基于Java的分布式緩存優(yōu)化在網(wǎng)絡(luò)管理系統(tǒng)的應(yīng)用

    基于Java的分布式緩存優(yōu)化在網(wǎng)絡(luò)管理系統(tǒng)的應(yīng)用討論建立JMX管理框架上的網(wǎng)絡(luò)性能管理系統(tǒng)
    發(fā)表于 09-19 09:20

    淺談分布式緩存技術(shù)

    視圖,API接口簡(jiǎn)單,與拓?fù)洌瑒?dòng)態(tài)擴(kuò)展或故障恢復(fù)無(wú)關(guān),無(wú)需手動(dòng)配置,自動(dòng)選擇備份節(jié)點(diǎn),大多數(shù)緩存系統(tǒng)提供圖形化管理控制臺(tái),簡(jiǎn)單易用保持。分布式緩存優(yōu)勢(shì)1,提高數(shù)據(jù)讀取速度2,提高
    發(fā)表于 11-16 15:45

    分布式系統(tǒng)的優(yōu)勢(shì)是什么?

    當(dāng)討論分布式系統(tǒng)時(shí),我們面臨許多以下這些形容詞所描述的 同類型: 分布式的、刪絡(luò)的、并行的、并發(fā)的和分散的。分布式處理是個(gè)相對(duì)較新的領(lǐng)域,
    發(fā)表于 03-31 09:01

    來(lái)AltiumFill,Polygon Pour,Plane的區(qū)別和用法

    Fill會(huì)造成短路,為什么還用它呢?來(lái)AltiumFill,Polygon Pour,Plane的區(qū)別和用法
    發(fā)表于 04-25 06:29

    stm32的低功耗調(diào)試

    ,stm32l15x系列最大運(yùn)行在32M;如果在最大頻率下運(yùn)行,那么mcu功耗是214uA*32=6848uA=6.8mA,如果還有外設(shè),那么整個(gè)系統(tǒng)功耗可能會(huì)更多。因此,調(diào)試功耗的時(shí)候,可以用上面的6.8mA當(dāng)做個(gè)參考,判
    發(fā)表于 08-11 08:18

    分布式KVM系統(tǒng)解決方案,坐席協(xié)作管理有什么用怎么用哪里用

    分布式坐席成為國(guó)內(nèi)眾多廠商集體發(fā)力的領(lǐng)域,也是國(guó)內(nèi)各行業(yè)中小型指揮中心應(yīng)用最廣泛的指揮控制系統(tǒng)解決方案。那么我們控制室的
    發(fā)表于 03-12 15:09 ?3854次閱讀

    分布式系統(tǒng)的數(shù)據(jù)庫(kù)和緩存操作順序

    分布式系統(tǒng),緩存和數(shù)據(jù)庫(kù)同時(shí)存在時(shí),如果有寫操作的時(shí)候,先操作數(shù)據(jù)庫(kù)還是先操作緩存呢?先思考
    的頭像 發(fā)表于 05-03 14:36 ?2279次閱讀
    <b class='flag-5'>分布式</b><b class='flag-5'>系統(tǒng)</b><b class='flag-5'>中</b>的數(shù)據(jù)庫(kù)和<b class='flag-5'>緩存</b>操作順序

    分布式系統(tǒng)的CAP理論

    CAP理論最早發(fā)表于2000年,由加州伯克利的教授首先在ACM PODC會(huì)議上提出猜想,兩年之后,被麻省理工學(xué)院的教授Seth Gilbert和Nancy Lynch從理論上證明。從此之后,它成了分布式系統(tǒng)領(lǐng)域的公認(rèn)定理。
    的頭像 發(fā)表于 05-03 18:00 ?2705次閱讀
    <b class='flag-5'>聊</b><b class='flag-5'>一</b><b class='flag-5'>聊</b><b class='flag-5'>分布式</b><b class='flag-5'>系統(tǒng)</b>的CAP理論

    干貨:解決分布式緩存與數(shù)據(jù)庫(kù)的雙存儲(chǔ)雙寫

    分布式緩存是現(xiàn)在很多分布式應(yīng)用必不可少的組件,但是用到了分布式緩存,就可能會(huì)涉及到
    的頭像 發(fā)表于 09-03 10:58 ?2647次閱讀
    干貨:解決<b class='flag-5'>分布式</b><b class='flag-5'>緩存</b>與數(shù)據(jù)庫(kù)的雙存儲(chǔ)雙寫

    為什么需要分布式鎖 基于Zookeeper鎖安全嗎

    這篇文章我想和你,關(guān)于 Redis 分布式鎖的「安全性」問(wèn)題。 Redis 分布式鎖的話題,很多文章已經(jīng)寫爛了,我為什么還要寫這篇文章
    的頭像 發(fā)表于 08-10 18:06 ?5663次閱讀

    分布式系統(tǒng)架構(gòu)設(shè)計(jì)異地多活是什么

    軟件開發(fā)領(lǐng)域,「異地多活」是分布式系統(tǒng)架構(gòu)設(shè)計(jì)的座高峰,很多人經(jīng)常聽過(guò)它,但很少人理解其中的原理。 異地多活到底是什么?為什么需要異地多活?它到底解決了什么問(wèn)題?究竟是怎么解決的?
    的頭像 發(fā)表于 11-12 09:42 ?1924次閱讀
    <b class='flag-5'>分布式</b><b class='flag-5'>系統(tǒng)</b>架構(gòu)設(shè)計(jì)<b class='flag-5'>中</b>異地多活是什么

    【職場(chǎng)雜談】與嵌入物聯(lián)網(wǎng)架構(gòu)師幾個(gè)話題

    【職場(chǎng)雜談】與嵌入物聯(lián)網(wǎng)架構(gòu)師幾個(gè)話題
    的頭像 發(fā)表于 08-23 09:19 ?1407次閱讀
    【職場(chǎng)雜談】與嵌入<b class='flag-5'>式</b>物聯(lián)網(wǎng)架構(gòu)師<b class='flag-5'>聊</b><b class='flag-5'>一</b><b class='flag-5'>聊</b>幾個(gè)話題

    Redis分布式鎖真的安全嗎?

    今天我們來(lái)Redis分布式鎖。
    的頭像 發(fā)表于 11-02 14:07 ?1050次閱讀

    芯片設(shè)計(jì)的NDR是什么?

    今天突然想route相關(guān)的問(wèn)題,講講NDR是什么,我也梳理總結(jié)下我對(duì)NDR的認(rèn)識(shí)。
    的頭像 發(fā)表于 12-06 15:14 ?2336次閱讀