www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]什么是靜態(tài)數(shù)據(jù)為什么需要緩存通用緩存機(jī)制總結(jié)后記在分布式系統(tǒng)中,特別是最近很火的微服務(wù)架構(gòu)下,有沒有或者能不能總結(jié)出一個(gè)業(yè)務(wù)靜態(tài)數(shù)據(jù)的通用緩存處理機(jī)制或方案,這篇文章將結(jié)合一些實(shí)際的研發(fā)經(jīng)驗(yàn),嘗試?yán)砬迤渲写嬖诘年P(guān)鍵問題以及探尋通用的解決之道。什么是靜態(tài)數(shù)據(jù)這里靜態(tài)數(shù)據(jù)是指不經(jīng)常發(fā)...

微服務(wù)架構(gòu)下的靜態(tài)數(shù)據(jù)通用緩存機(jī)制!
    • 什么是靜態(tài)數(shù)據(jù)

    • 為什么需要緩存

    • 通用緩存機(jī)制

    • 總結(jié)

    • 后記

在分布式系統(tǒng)中,特別是最近很火的微服務(wù)架構(gòu)下,有沒有或者能不能總結(jié)出一個(gè)業(yè)務(wù)靜態(tài)數(shù)據(jù)的通用緩存處理機(jī)制或方案,這篇文章將結(jié)合一些實(shí)際的研發(fā)經(jīng)驗(yàn),嘗試?yán)砬迤渲写嬖诘年P(guān)鍵問題以及探尋通用的解決之道。


什么是靜態(tài)數(shù)據(jù)




這里靜態(tài)數(shù)據(jù)是指不經(jīng)常發(fā)生變化或者變化頻率比較低的數(shù)據(jù),比如車型庫(kù)、用戶基本信息、車輛基本信息等,車型庫(kù)這種可能每個(gè)月會(huì)更新一次,用戶和車輛基本信息的變化來源于用戶注冊(cè)、修改,這個(gè)操作的頻率相對(duì)也是比較低的。

另外這類數(shù)據(jù)的另一個(gè)特點(diǎn)是要求準(zhǔn)確率和實(shí)時(shí)性都比較高,不能出現(xiàn)丟失、錯(cuò)誤,以及過長(zhǎng)時(shí)間的陳舊讀。

具體是不是應(yīng)該歸類為靜態(tài)數(shù)據(jù)要看具體的業(yè)務(wù),以及對(duì)變化頻率高低的劃分標(biāo)準(zhǔn)。在這里的業(yè)務(wù)定義中,上邊這幾類數(shù)據(jù)都?xì)w為靜態(tài)數(shù)據(jù)。


為什么需要緩存



在面向用戶或車聯(lián)網(wǎng)的業(yè)務(wù)場(chǎng)景中,車型信息、用戶基本信息和車輛基本信息有著廣泛而高頻的業(yè)務(wù)需求,很多數(shù)據(jù)都需要對(duì)其進(jìn)行關(guān)聯(lián)處理。在這里緩存的目的就是為了提高數(shù)據(jù)查詢效率。

靜態(tài)數(shù)據(jù)通常都保存在關(guān)系型數(shù)據(jù)庫(kù)中,這類數(shù)據(jù)庫(kù)的 IO 效率普遍不高,應(yīng)對(duì)高并發(fā)的查詢往往捉襟見肘。使用緩存可以極大的提升讀操作的吞吐量,特別是 KV 類的緩存,沒有復(fù)雜的關(guān)系操作,時(shí)間復(fù)雜度一般都在 O(1)。注意這里說的緩存指內(nèi)存緩存。

當(dāng)然除了使用緩存,還可以通過其它手段來提高 IO 吞吐量,比如讀寫分離,分庫(kù)分表,但是這類面向關(guān)系型數(shù)據(jù)庫(kù)的方案更傾向于同時(shí)提高讀寫效率,對(duì)于單純提升讀吞吐量的需求,這類方案不夠徹底,不能在有限的資源情況下發(fā)揮更好的作用。


通用緩存機(jī)制



下面將直接給出一個(gè)我認(rèn)為的通用處理機(jī)制,然后會(huì)對(duì)其進(jìn)行分析。

微服務(wù)架構(gòu)下的靜態(tài)數(shù)據(jù)通用緩存機(jī)制!
對(duì)于某個(gè)具體的業(yè)務(wù),其涉及到六個(gè)核心程序:

業(yè)務(wù)服務(wù):?提供對(duì)某種業(yè)務(wù)數(shù)據(jù)的操作接口,比如車輛服務(wù),提供對(duì)車輛基本信息的增刪改查服務(wù)。

關(guān)系數(shù)據(jù)庫(kù):?使用若干表持久化業(yè)務(wù)數(shù)據(jù),比如 SQLServer、MySQL、Oracle 等。

持久化隊(duì)列:?可獨(dú)立部署的隊(duì)列程序,支持?jǐn)?shù)據(jù)持久化,比如 RabbitMQ、RocketMQ、Kafka 等。

緩存處理程序:?從隊(duì)列接收數(shù)據(jù),然后寫入緩存。

數(shù)據(jù)一致處理程序:?負(fù)責(zé)檢查緩存數(shù)據(jù)庫(kù)和關(guān)系型數(shù)據(jù)庫(kù)中數(shù)據(jù)是否一致,如果不一致則使用關(guān)系數(shù)據(jù)庫(kù)進(jìn)行更新。

緩存數(shù)據(jù)庫(kù)(Redis):?支持持久化的緩存數(shù)據(jù)庫(kù),這里直接選了 Redis,這個(gè)基本是業(yè)界標(biāo)準(zhǔn)了。

以及兩個(gè)外部定義:

數(shù)據(jù)生產(chǎn)者:業(yè)務(wù)靜態(tài)數(shù)據(jù)的來源,可以理解為前端 APP、Web 系統(tǒng)的某個(gè)功能或者模塊。

數(shù)據(jù)消費(fèi)者:需要使用這些業(yè)務(wù)靜態(tài)數(shù)據(jù)的服務(wù)或者系統(tǒng),比如報(bào)警系統(tǒng)需要獲取車輛對(duì)應(yīng)的用戶信息以便發(fā)送報(bào)警。

下面以問答的形式來說明為什么是這樣一種機(jī)制。


為什么需要業(yè)務(wù)服務(wù)?



既然是微服務(wù)架構(gòu),當(dāng)然離不開服務(wù)了,因?yàn)檫@里探討的是業(yè)務(wù)靜態(tài)數(shù)據(jù),所以是業(yè)務(wù)服務(wù)。不過為了更好的理解,這里還是簡(jiǎn)單說下服務(wù)出現(xiàn)的原因。

當(dāng)今業(yè)務(wù)往往需要在多個(gè)終端進(jìn)行使用,比如 PC、手機(jī)、平板等,既有網(wǎng)頁(yè)的形式,又有 APP 的形式,另外某個(gè)數(shù)據(jù)可能在多種不同的業(yè)務(wù)被需要

如果將數(shù)據(jù)操作分布在多個(gè)程序中很可能產(chǎn)生數(shù)據(jù)不一致的情況,另外代碼不可避免的冗余,讀寫性能更很難控制,變更也基本上是不敢變的。

通過一個(gè)業(yè)務(wù)服務(wù)可以將對(duì)業(yè)務(wù)數(shù)據(jù)的操作有序的管理起來,并通過接口的形式對(duì)外提供操作能力,代碼不用冗余了,性能也好優(yōu)化了,數(shù)據(jù)不一致也得到了一定的控制,編寫上層應(yīng)用的人也舒服了。


為什么不是進(jìn)程內(nèi)緩存?



很多開發(fā)語言都提供了進(jìn)程內(nèi)緩存的支持,即使沒有提供直接操作緩存的包或庫(kù),也可以通過靜態(tài)變量的方式來實(shí)現(xiàn)。對(duì)數(shù)據(jù)的查詢請(qǐng)求直接在進(jìn)程內(nèi)存完成,效率可以說是杠杠滴了。但是進(jìn)程內(nèi)緩存存在兩個(gè)問題:

緩存數(shù)據(jù)的大小:進(jìn)程可以緩存數(shù)據(jù)的大小受限于系統(tǒng)可用內(nèi)存,同時(shí)如果機(jī)器上部署了多個(gè)服務(wù),某個(gè)服務(wù)使用了太多的內(nèi)存,則可能會(huì)影響其它服務(wù)的正常訪問,因此不適合大量數(shù)據(jù)的緩存。

緩存雪崩:緩存同時(shí)大量過期或者進(jìn)程重啟的情況下,可能產(chǎn)生大量的緩存穿透,過多的請(qǐng)求打到關(guān)系數(shù)據(jù)庫(kù)上,可能導(dǎo)致關(guān)系數(shù)據(jù)庫(kù)的崩潰,引發(fā)更大的不可用問題。


為什么是 Redis?



Redis 這類數(shù)據(jù)庫(kù)可以解決進(jìn)程內(nèi)緩存的兩個(gè)問題:

1、?獨(dú)立部署,不影響其它業(yè)務(wù),還可以做集群,內(nèi)存擴(kuò)容比較方便。

2、?支持?jǐn)?shù)據(jù)持久化,即使 Redis 重啟了,緩存的數(shù)據(jù)自身就可以很快恢復(fù)。

另外 Redis 提供了很好的讀寫性能,以及方便的水平擴(kuò)容能力,還支持多種常用數(shù)據(jù)結(jié)構(gòu),使用起來比較方便,可以說是通用緩存首選。


為什么需要隊(duì)列?



隊(duì)列在這里的目的是為了解耦,坦白的說這個(gè)方案中可以沒有隊(duì)列,業(yè)務(wù)服務(wù)在關(guān)系數(shù)據(jù)庫(kù)操作完成后,直接更新到緩存也是可以的。

之所以加上這個(gè)隊(duì)列是由于當(dāng)前的業(yè)務(wù)開發(fā)有很明顯的系統(tǒng)拆分的需求,特別是在微服務(wù)架構(gòu)下,為了降低服務(wù)之間的耦合,使用隊(duì)列是個(gè)常用選擇,在某些開發(fā)模型中也是很推崇的,比如 Actor 模型。

舉個(gè)例子,比如新注冊(cè)一個(gè)用戶,需要贈(zèng)送其 300 積分,同時(shí)還要給其發(fā)個(gè)注冊(cè)成功的郵件,如果將注冊(cè)用戶、贈(zèng)送積分、發(fā)成功郵件都寫到一起執(zhí)行,會(huì)產(chǎn)生兩個(gè)問題:

一是注冊(cè)操作耗時(shí)增加,二是其中某個(gè)處理引發(fā)整體不可用的幾率增大,三是程序的擴(kuò)展性不好;

通過引入隊(duì)列,將注冊(cè)信息分別發(fā)到積分隊(duì)列和通知隊(duì)列,然后由積分模塊和通知模塊分別處理,用戶、積分、通知三個(gè)模塊的耦合降低了,相互影響變小了,以后再增加注冊(cè)后的其它處理也就是增加個(gè)隊(duì)列的事,整體的擴(kuò)展性得到了增強(qiáng)。

隊(duì)列作為一種常用的解耦方案,在緩存這里雖然產(chǎn)生的影響不大,但是除了緩存難免同時(shí)還會(huì)有其它業(yè)務(wù)處理,所以為了統(tǒng)一處理機(jī)制,這里保留了下來。(既然用了,就把它發(fā)揚(yáng)光大)


為什么隊(duì)列需要持久化?



持久化是為了解決網(wǎng)絡(luò)抖動(dòng)或者崩潰導(dǎo)致數(shù)據(jù)丟失的問題,在數(shù)據(jù)從業(yè)務(wù)服務(wù)到隊(duì)列,隊(duì)列自身處理,再?gòu)年?duì)列到緩存處理程序,中間都可能丟失數(shù)據(jù)。

為了解決丟失數(shù)據(jù)的問題,需要發(fā)送時(shí)確認(rèn)、隊(duì)列自身持久化、接收時(shí)確認(rèn)

但是需要注意確認(rèn)機(jī)制可能會(huì)導(dǎo)致重復(fù)數(shù)據(jù)的產(chǎn)生,因?yàn)樵谖词盏酱_認(rèn)時(shí)就需要重新發(fā)送或接收,而數(shù)據(jù)實(shí)際上可能被正常處理,只是確認(rèn)丟失了

確認(rèn)機(jī)制還會(huì)降低隊(duì)列的吞吐量,但是根據(jù)我們的定義業(yè)務(wù)靜態(tài)數(shù)據(jù)的變更頻率應(yīng)該不高,如果同時(shí)還需要較高的并發(fā)分片是個(gè)不錯(cuò)的選擇。

這里持久化隊(duì)列推薦選擇 RabbitMQ,雖然吞吐量支持的不是很大,但是各方面綜合不錯(cuò),并發(fā)夠用就好。


為什么需要數(shù)據(jù)一致檢查程序?



在業(yè)務(wù)服務(wù)操作完關(guān)系數(shù)據(jù)庫(kù)后,數(shù)據(jù)發(fā)送到隊(duì)列之前(或者不用隊(duì)列就是直接寫入緩存之前),業(yè)務(wù)服務(wù)崩潰了,這時(shí)候數(shù)據(jù)就不能更新到緩存了。

還有一種情況是 Redis 發(fā)生了故障轉(zhuǎn)移,master 中的更新沒有同步到 slaver。通過引入這么一個(gè)檢查程序,定時(shí)的檢查關(guān)系數(shù)據(jù)庫(kù)數(shù)據(jù)和緩存數(shù)據(jù)的差別,如果緩存數(shù)據(jù)比較陳舊,則更新之。這樣提供了一種極端情況下的挽救措施。

這個(gè)檢查程序的運(yùn)行頻率需要綜合考慮數(shù)據(jù)庫(kù)壓力和能夠承受的數(shù)據(jù)陳舊時(shí)間,不能把數(shù)據(jù)庫(kù)查死了,也不能陳舊太久導(dǎo)致大量數(shù)據(jù)不一致??梢酝ㄟ^設(shè)置上次檢查時(shí)間點(diǎn)的方式,每次只檢查從上次檢查時(shí)間點(diǎn)(或者最近幾次,防止 Redis 故障轉(zhuǎn)移數(shù)據(jù)未同步的問題)到本次檢查時(shí)間點(diǎn)發(fā)生變更的數(shù)據(jù),這樣每次檢查只對(duì)增量變更,效率更高。

同時(shí)需要理解在分布式系統(tǒng)中,微服務(wù)架構(gòu)下,數(shù)據(jù)不一致是經(jīng)常出現(xiàn)的,必須在一致性和可用性之間做出權(quán)衡,盡力去降低影響,比如使用準(zhǔn)實(shí)時(shí)或最終一致性。


只要數(shù)據(jù)一致檢查程序是不是就夠了?



假設(shè)沒有緩存處理程序,通過定時(shí)同步關(guān)系數(shù)據(jù)庫(kù)和緩存數(shù)據(jù)庫(kù)是不是就夠了呢?

這還是取決于業(yè)務(wù),如果是車型庫(kù)這種數(shù)據(jù),增加一個(gè)新的車型,本來之前就沒有,時(shí)間上并不是很敏感,這個(gè)是可以的。但是對(duì)于新增了用戶或者車輛,數(shù)據(jù)消費(fèi)者還是希望能夠馬上使用最新的數(shù)據(jù)進(jìn)行處理,越快越好,這時(shí)使用同步或者準(zhǔn)同步更新就能更加貼近需求。


為什么不用緩存過期機(jī)制?



使用緩存過期機(jī)制可以不需要緩存處理程序和數(shù)據(jù)一致檢查程序,業(yè)務(wù)服務(wù)首先從 Redis 查詢數(shù)據(jù),如果數(shù)據(jù)存在就直接返回,如果不存在則從關(guān)系數(shù)據(jù)庫(kù)查詢,然后寫入 Redis,然后再返回,這也是一種常用的緩存處理機(jī)制,網(wǎng)上可以查詢到很多,很多人用的也很好。

但是緩存的過期時(shí)間是個(gè)問題:緩存多長(zhǎng)時(shí)間過期,設(shè)置的短可以降低數(shù)據(jù)的陳舊,但是會(huì)增加緩存穿透的概率,即使采用隨機(jī)的緩存過期時(shí)間,在 Redis 重啟或者故障轉(zhuǎn)移的情況下還是會(huì)可能導(dǎo)致緩存雪崩,雪崩的情況下采用數(shù)據(jù)預(yù)熱機(jī)制,也可能會(huì)導(dǎo)致服務(wù)更長(zhǎng)時(shí)間的不可用;

設(shè)置的長(zhǎng)可以提升緩存的使用率,但是增加了數(shù)據(jù)陳舊,在上邊對(duì)靜態(tài)數(shù)據(jù)的定義中對(duì)其準(zhǔn)確率和實(shí)時(shí)性都有較高的要求,業(yè)務(wù)上能不能接受需要考慮。而且如果操作數(shù)據(jù)和查詢存在波動(dòng)的峰谷,是不是要引入動(dòng)態(tài) TTL 的機(jī)制,以達(dá)到緩存使用和直接訪問數(shù)據(jù)庫(kù)的一種平衡,這就需要權(quán)衡業(yè)務(wù)需求和技術(shù)方案。


總結(jié)



通過上邊的這些問題問答,再來看看上面提出的微服務(wù)架構(gòu)下靜態(tài)數(shù)據(jù)通用緩存處理機(jī)制。

1、?通過業(yè)務(wù)服務(wù)來包裝對(duì)數(shù)據(jù)的操作,不管是操作關(guān)系數(shù)據(jù)庫(kù)還是緩存數(shù)據(jù)庫(kù),數(shù)據(jù)消費(fèi)者其實(shí)不需要關(guān)心,它只關(guān)心業(yè)務(wù)服務(wù)能不能提供高并發(fā)實(shí)時(shí)數(shù)據(jù)的查詢能力

2、?利用分布式系統(tǒng)中經(jīng)常使用隊(duì)列進(jìn)行解耦的方式,業(yè)務(wù)服務(wù)不干寫入緩存的事,增加一個(gè)隊(duì)列訂閱數(shù)據(jù)變更,然后從隊(duì)列取數(shù)據(jù)寫入緩存數(shù)據(jù)庫(kù)。

3、?對(duì)于絕大部分正常的情況,通過隊(duì)列更新緩存數(shù)據(jù)和業(yè)務(wù)服務(wù)中更新緩存數(shù)據(jù),其實(shí)時(shí)性是差不多的,同時(shí)實(shí)現(xiàn)了業(yè)務(wù)操作和寫緩存的解耦。

4、?在極端崩潰導(dǎo)致數(shù)據(jù)不一致的情況下,通過數(shù)據(jù)一致檢查程序進(jìn)行補(bǔ)救,盡快更新緩存數(shù)據(jù)。

5、?現(xiàn)在業(yè)務(wù)服務(wù)可以通過訪問 Redis 緩存來提供對(duì)靜態(tài)數(shù)據(jù)的高并發(fā)準(zhǔn)實(shí)時(shí)查詢能力,緩存中不存在的數(shù)據(jù)就是不存在,沒有緩存穿透。

對(duì)于微服務(wù)架構(gòu)而言,這個(gè)機(jī)制借助隊(duì)列這種通用的解耦方式,獨(dú)立了緩存更新處理,通過準(zhǔn)實(shí)時(shí)更新和定時(shí)檢查,保證了緩存的實(shí)時(shí)性和極端情況下較短時(shí)間內(nèi)達(dá)到最終一致,通過緩存的持久化機(jī)制消除了緩存穿透和雪崩,在緩存的數(shù)據(jù)較大或讀取并發(fā)較高時(shí)支持水平擴(kuò)容,可以認(rèn)為對(duì)業(yè)務(wù)靜態(tài)數(shù)據(jù)提供了一種廣泛適用的緩存處理機(jī)制。

這個(gè)方案在某些情況下可能是沒有必要的,比如你要緩存一個(gè)全國(guó)限行的城市列表,使用一個(gè)進(jìn)程內(nèi)緩存就夠了。

最后剩下的就是工作量的問題了,這個(gè)會(huì)給開發(fā)和維護(hù)帶來復(fù)雜性,隊(duì)列有沒有用的順手的,人手是不是夠,業(yè)務(wù)需求是什么樣的,需要考慮清楚。


后記



Redis 耦合問題:?圖中業(yè)務(wù)服務(wù)直接訪問了 Redis,如果要實(shí)現(xiàn)業(yè)務(wù)服務(wù)對(duì) Redis 的完全透明,這個(gè)還比較復(fù)雜,可以考慮采用 AOP 的方式,對(duì)關(guān)系數(shù)據(jù)庫(kù)和 Redis 保持相同的類型定義,分別采用 ORM 和反序列化的方式標(biāo)準(zhǔn)化輸出,這是個(gè)想法我也沒有實(shí)現(xiàn);同時(shí)緩存數(shù)據(jù)是準(zhǔn)實(shí)時(shí)的,如果要求完全一致,還是應(yīng)該提供從關(guān)系數(shù)據(jù)庫(kù)查詢的版本。另外如果要擺脫對(duì) Redis 的直接依賴,還可以通過 OpenResty 來實(shí)現(xiàn)對(duì)資源的透明訪問,這個(gè)不是本文的重點(diǎn)。

服務(wù)可用性問題:?這篇文章沒有關(guān)注服務(wù)可用性問題,為了保證服務(wù)的高可用,每個(gè)服務(wù)或者程序都應(yīng)該有多份部署的,無論是負(fù)載均衡的方案,或者傳統(tǒng)的主備方案,在部分部署不可用時(shí)仍能夠繼續(xù)提供服務(wù)。

寫的比較快,有些理解不免偏頗,歡迎指正。

作者:波斯碼

cnblogs.com/bossma/p/9858847.html

本文版權(quán)歸作者所有??

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉