自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

高并發(fā)系統(tǒng)三大利器之緩存

存儲(chǔ) 存儲(chǔ)軟件
隨著互聯(lián)網(wǎng)的高速發(fā)展,市面上也出現(xiàn)了越來(lái)越多的網(wǎng)站和app。我們判斷一個(gè)軟件是否好用,用戶體驗(yàn)就是一個(gè)重要的衡量標(biāo)準(zhǔn)。

[[339502]]

 引言

隨著互聯(lián)網(wǎng)的高速發(fā)展,市面上也出現(xiàn)了越來(lái)越多的網(wǎng)站和app。我們判斷一個(gè)軟件是否好用,用戶體驗(yàn)就是一個(gè)重要的衡量標(biāo)準(zhǔn)。比如說(shuō)我們經(jīng)常用的微信,打開(kāi)一個(gè)頁(yè)面要十幾秒,發(fā)個(gè)語(yǔ)音要幾分鐘對(duì)方才能收到。相信這樣的軟件大家肯定是都不愿意用的。軟件要做到用戶體驗(yàn)好,響應(yīng)速度快,緩存就是必不可少的一個(gè)神器。緩存又分進(jìn)程內(nèi)緩存和分布式緩存兩種:分布式緩存如redis、memcached等,還有本地(進(jìn)程內(nèi))緩存如ehcache、GuavaCache、Caffeine等。

緩存特征

緩存作為一個(gè)數(shù)據(jù)數(shù)據(jù)模型對(duì)象,那么它有一些什么樣的特征呢?下面我們分別來(lái)介紹下這些特征。

命中率

命中率=命中數(shù)/(命中數(shù)+沒(méi)有命中數(shù))當(dāng)某個(gè)請(qǐng)求能夠通過(guò)訪問(wèn)緩存而得到響應(yīng)時(shí),稱為緩存命中。緩存命中率越高,緩存的利用率也就越高。

最大空間

緩存中可以容納最大元素的數(shù)量。當(dāng)緩存存放的數(shù)據(jù)超過(guò)最大空間時(shí),就需要根據(jù)淘汰算法來(lái)淘汰部分?jǐn)?shù)據(jù)存放新到達(dá)的數(shù)據(jù)。

淘汰算法

緩存的存儲(chǔ)空間有限制,當(dāng)緩存空間被用滿時(shí),如何保證在穩(wěn)定服務(wù)的同時(shí)有效提升命中率?這就由緩存淘汰算法來(lái)處理,設(shè)計(jì)適合自身數(shù)據(jù)特征的淘汰算法能夠有效提升緩存命中率。常見(jiàn)的淘汰算法有:

FIFO(first in first out)

「先進(jìn)先出」。最先進(jìn)入緩存的數(shù)據(jù)在緩存空間不夠的情況下(超出最大元素限制)會(huì)被優(yōu)先被清除掉,以騰出新的空間接受新的數(shù)據(jù)。策略算法主要比較緩存元素的創(chuàng)建時(shí)間。「適用于保證高頻數(shù)據(jù)有效性場(chǎng)景,優(yōu)先保障最新數(shù)據(jù)可用」。

LFU(less frequently used)

「最少使用」,無(wú)論是否過(guò)期,根據(jù)元素的被使用次數(shù)判斷,清除使用次數(shù)較少的元素釋放空間。策略算法主要比較元素的hitCount(命中次數(shù))?!高m用于保證高頻數(shù)據(jù)有效性場(chǎng)景」。

LRU(least recently used)

「最近最少使用」,無(wú)論是否過(guò)期,根據(jù)元素最后一次被使用的時(shí)間戳,清除最遠(yuǎn)使用時(shí)間戳的元素釋放空間。策略算法主要比較元素最近一次被get使用時(shí)間?!副容^適用于熱點(diǎn)數(shù)據(jù)場(chǎng)景,優(yōu)先保證熱點(diǎn)數(shù)據(jù)的有效性?!?/p>

進(jìn)程緩存

為什么需要引入本地緩存,本地緩存的應(yīng)用場(chǎng)景有哪些?本地緩存的話是我們的應(yīng)用和緩存都在同一個(gè)進(jìn)程里面,獲取緩存數(shù)據(jù)的時(shí)候純內(nèi)存操作,沒(méi)有額外的網(wǎng)絡(luò)開(kāi)銷,速度非??臁Km用于緩存一些應(yīng)用中基本不會(huì)變化的數(shù)據(jù),比如(國(guó)家、省份、城市等)。

項(xiàng)目中一般如何使用、怎么樣加載、怎么樣更新?

進(jìn)程緩存的話,一般可以在應(yīng)用啟動(dòng)的時(shí)候,把需要的數(shù)據(jù)加載到系統(tǒng)中。更新緩存的話可以采取定時(shí)更新(實(shí)時(shí)性不高)。具體實(shí)現(xiàn)的話就是在應(yīng)用中起一個(gè)定時(shí)任務(wù)(「ScheduledExecutorService」、「TimerTask」等),讓它每隔多久去加載變更(數(shù)據(jù)變更之后可以修改數(shù)據(jù)庫(kù)最后修改的時(shí)間,每次查詢變更數(shù)據(jù)的時(shí)候都可以根據(jù)這個(gè)最后變更時(shí)間加上半小時(shí)大于當(dāng)前時(shí)間的數(shù)據(jù))的數(shù)據(jù)重新到緩存里面來(lái)。如果覺(jué)得這個(gè)比較麻煩的話,還可以直接全部全量更新(就跟項(xiàng)目啟動(dòng)加載數(shù)據(jù)一樣)。這種方式的話,對(duì)數(shù)據(jù)更新可能會(huì)有點(diǎn)延遲??赡苓@臺(tái)機(jī)器看到的是更新后的數(shù)據(jù),那臺(tái)機(jī)器看到的數(shù)據(jù)還是老的(機(jī)器發(fā)布時(shí)間可能不一樣)。所以這種方式比較適用于對(duì)數(shù)據(jù)實(shí)時(shí)性要求不高的數(shù)據(jù)。如果對(duì)實(shí)時(shí)性有要求的話可以通過(guò)廣播訂閱mq消息。如果有數(shù)據(jù)更新mq會(huì)把更新數(shù)據(jù)推送到每一臺(tái)機(jī)器,這種方式的話實(shí)時(shí)性會(huì)比前一種「定時(shí)更新」的方法會(huì)好。但是實(shí)現(xiàn)起來(lái)會(huì)比較復(fù)雜。

 

本地緩存有哪些實(shí)現(xiàn)方式?常見(jiàn)本地緩存有以下幾種實(shí)現(xiàn)方式:

從上述表格我們看出性能最佳的是Caffeine。關(guān)于這個(gè)本地緩存的話我還是強(qiáng)烈推薦的,里面提供了豐富的api,以及各種各樣的淘汰算法。如需了解更加詳細(xì)的話可以看下以前寫(xiě)的這個(gè)篇文章《本地緩存性能之王Caffeine》。

 

本地緩存

缺點(diǎn)本地緩存與業(yè)務(wù)系統(tǒng)耦合在一起,應(yīng)用之間無(wú)法直接共享緩存的內(nèi)容。需要每個(gè)應(yīng)用節(jié)點(diǎn)單獨(dú)的維護(hù)自己的緩存。每個(gè)節(jié)點(diǎn)都需要一份一樣的緩存,對(duì)服務(wù)器內(nèi)存造成一種浪費(fèi)。本地緩存機(jī)器重啟、或者宕機(jī)都會(huì)丟失。

分布式緩存

分布式緩存是與應(yīng)用分離的緩存組件或服務(wù),其最大的優(yōu)點(diǎn)是自身就是一個(gè)獨(dú)立的應(yīng)用,與本地應(yīng)用隔離,多個(gè)應(yīng)用可直接的共享緩存。常見(jiàn)的分布式緩存有redis、MemCache等。

分布式緩存的應(yīng)用在高并發(fā)的環(huán)境下,比如春節(jié)搶票大戰(zhàn),一到放票的時(shí)間節(jié)點(diǎn),分分鐘大量用戶以及黃牛的各種搶票軟件流量進(jìn)入12306,這時(shí)候如果每個(gè)用戶的訪問(wèn)都去數(shù)據(jù)庫(kù)實(shí)時(shí)查詢票的庫(kù)存,大量讀的請(qǐng)求涌入到數(shù)據(jù)庫(kù),瞬間Db就會(huì)被打爆,cpu直接上升100%,服務(wù)馬上就要宕機(jī)或者假死。即使進(jìn)行了分庫(kù)分表也是無(wú)法避免的。為了減輕db的壓力以及提高系統(tǒng)的響應(yīng)速度。一般都會(huì)在數(shù)據(jù)庫(kù)前面加上一層緩存,甚至可能還會(huì)有多級(jí)緩存。

緩存常見(jiàn)問(wèn)題

緩存雪崩

指大量緩存同一時(shí)間段集體失效,或者緩存整體不能提供服務(wù),導(dǎo)致大量的請(qǐng)求全部到達(dá)數(shù)據(jù)庫(kù) 對(duì)數(shù)據(jù)CPU和內(nèi)存造成巨大壓力,嚴(yán)重的會(huì)造成數(shù)據(jù)庫(kù)宕機(jī)。因此而形成的一系列連鎖反應(yīng)造成整個(gè)系統(tǒng)奔潰。解決這個(gè)問(wèn)題可以從以下方面入手:

  • 保證緩存的高可用。使用redis的集群模式,即使個(gè)別redis節(jié)點(diǎn)下線,緩存還是可以用。一般稍微大點(diǎn)的公司還可能會(huì)在多個(gè)機(jī)房部署Redis。這樣即使某個(gè)機(jī)房突然停電,或者光纖又被挖斷了,這時(shí)候緩存還是可以使用。
  • 使用多級(jí)緩存。不同級(jí)別緩存時(shí)間過(guò)時(shí)時(shí)間不一樣,即使某個(gè)級(jí)別緩存過(guò)期了,還有其他緩存級(jí)別 兜底。比如我們Redis緩存過(guò)期了,我們還有本地緩存。這樣的話即使沒(méi)有命中redis,有可能會(huì)命中本地緩存。
  • 緩存永不過(guò)期。Redis中保存的key永久不失效,這樣的話就不會(huì)出現(xiàn)大量緩存同時(shí)失效的問(wèn)題,但是這種做法會(huì)浪費(fèi)更多的存儲(chǔ)空間,一般應(yīng)該也不會(huì)推薦這種做法。
  • 使用隨機(jī)過(guò)期時(shí)間。為每一個(gè)key都合理的設(shè)計(jì)一個(gè)過(guò)期時(shí)間,這樣可以避免大量的key在同一時(shí)刻集體失效。
  • 異步重建緩存。這樣的話需要維護(hù)每個(gè)key的過(guò)期時(shí)間,定時(shí)去輪詢這些key的過(guò)期時(shí)間。例如一個(gè)key的value設(shè)置的過(guò)期時(shí)間是30min,那我們可以為這個(gè)key設(shè)置它自己的一個(gè)過(guò)期時(shí)間為20min。所以當(dāng)這個(gè)key到了20min的時(shí)候我們就可以重新去構(gòu)建這個(gè)key的緩存,同時(shí)也更新這個(gè)key的一個(gè)過(guò)期時(shí)間。

緩存穿透

指查詢一個(gè)不存在的數(shù)據(jù),每次通過(guò)接口或者去查詢數(shù)據(jù)庫(kù)都查不到這個(gè)數(shù)據(jù),比如黑客的惡意攻擊,比如知道一個(gè)訂單號(hào)后,然后就偽造一些不存在的訂單號(hào),然后并發(fā)來(lái)請(qǐng)求你這個(gè)訂單詳情。這些訂單號(hào)在緩存中都查詢不到,然后會(huì)導(dǎo)致把這些查詢請(qǐng)求全部打到數(shù)據(jù)庫(kù)或者SOA接口。這樣的話就會(huì)導(dǎo)致數(shù)據(jù)庫(kù)宕機(jī)或者你的服務(wù)大量超時(shí)。這種查詢不存在的數(shù)據(jù)就是緩存擊穿。解決這個(gè)問(wèn)題可以從以下方面入手:

  • 緩存空值,對(duì)于這些不存在的請(qǐng)求,仍然給它緩存一個(gè)空的結(jié)果,這種方式簡(jiǎn)單粗暴,但是如果后續(xù)這個(gè)請(qǐng)求有新值了需要把原來(lái)緩存的空值刪除掉(所以一般過(guò)期時(shí)間可以稍微設(shè)置的比較短)。
  • 通過(guò)布隆過(guò)濾器。查詢緩存之前先去布隆過(guò)濾器查詢下這個(gè)數(shù)據(jù)是否存在。如果數(shù)據(jù)不存在,然后直接返回空。這樣的話也會(huì)減少底層系統(tǒng)的查詢壓力。
  • 緩存沒(méi)有直接返回。這種方式的話要根據(jù)自己的實(shí)際業(yè)務(wù)來(lái)進(jìn)行選擇。比如固定的數(shù)據(jù),一些省份信息或者城市信息,可以全部緩存起來(lái)。這樣的話數(shù)據(jù)有變化的情況,緩存也需要跟著變化。實(shí)現(xiàn)起來(lái)可能比較復(fù)雜。

緩存擊穿

是指緩存里面的一個(gè)熱點(diǎn)key(拼多多的五菱宏光神車的秒殺)在某個(gè)時(shí)間點(diǎn)過(guò)期。針對(duì)于這一個(gè)key有大量并發(fā)請(qǐng)求過(guò)來(lái)然后都會(huì)同時(shí)去數(shù)據(jù)庫(kù)請(qǐng)求數(shù)據(jù),瞬間對(duì)數(shù)據(jù)庫(kù)造成巨大的壓力。這個(gè)的話可以用緩存雪崩的幾種解決方法來(lái)避免:

  • 緩存永不過(guò)期。Redis中保存的key永久不失效,這樣的話就不會(huì)出現(xiàn)大量緩存同時(shí)失效的問(wèn)題,但是這種做法會(huì)浪費(fèi)更多的存儲(chǔ)空間,一般應(yīng)該也不會(huì)推薦這種做法。
  • 異步重建緩存。這樣的話需要維護(hù)每個(gè)key的過(guò)期時(shí)間,定時(shí)去輪詢這些key的過(guò)期時(shí)間。例如一個(gè)key的value設(shè)置的過(guò)期時(shí)間是30min,那我們可以為這個(gè)key設(shè)置它自己的一個(gè)過(guò)期時(shí)間為20min。所以當(dāng)這個(gè)key到了20min的時(shí)候我們就可以重新去構(gòu)建這個(gè)key的緩存,同時(shí)也更新這個(gè)key的一個(gè)過(guò)期時(shí)間。
  • 互斥鎖重建緩存。這種情況的話只能針對(duì)于同一個(gè)key的情況下,比如你有100個(gè)并發(fā)請(qǐng)求都要來(lái)取A的緩存,這時(shí)候我們可以借助redis分布式鎖來(lái)構(gòu)建緩存,讓只有一個(gè)請(qǐng)求可以去查詢DB其他99個(gè)(沒(méi)有獲取到鎖)都在外面等著,等A查詢到數(shù)據(jù)并且把緩存構(gòu)建好之后其他99個(gè)請(qǐng)求都只需要從緩存取就好了。原理就跟我們java的DCL(double checked locking)思想有點(diǎn)類似。

 

緩存更新

我們一般的緩存更新主要有以下幾種更新策略:

  • 先更新緩存,再更新數(shù)據(jù)庫(kù)
  • 先更新數(shù)據(jù)庫(kù),再更新緩存
  • 先刪除緩存,再更新數(shù)據(jù)庫(kù)
  • 先更新數(shù)據(jù)源庫(kù),再刪除緩存 至于選擇哪種更新策略的話,沒(méi)有絕對(duì)的選擇,可以根據(jù)自己的業(yè)務(wù)情況來(lái)選擇適合自己的不過(guò)一般推薦的話是選擇 「先更新數(shù)據(jù)源庫(kù),再刪除緩存」。

總結(jié)

如果想要真正的設(shè)計(jì)好一個(gè)緩存,我們還是必須要掌握很多的知識(shí),對(duì)于不同場(chǎng)景,緩存有各自不同的用法。比如實(shí)際工作中我們對(duì)于訂單詳情的一個(gè)緩存。我們可能會(huì)根據(jù)訂單的狀態(tài)來(lái)來(lái)構(gòu)建緩存。我們就以機(jī)票訂單為例,已出行、或者已經(jīng)取消的訂單我們基本上是不會(huì)去管的(訂單狀態(tài)已經(jīng)終止了),這種的話數(shù)據(jù)基本也不會(huì)變了,所以對(duì)于這種訂單我們?cè)O(shè)置的過(guò)期時(shí)間是不是就可以久一點(diǎn),比如7天或者30天。對(duì)于未出行即將起飛的訂單,這時(shí)候顧客是不是就會(huì)頻繁的去刷新訂單看看,看看有沒(méi)有晚點(diǎn)什么的,或者登機(jī)口是在哪。對(duì)于這種實(shí)時(shí)性要求比較高的訂單我們過(guò)期時(shí)間還是要設(shè)置的比較短的,如果是需要更改訂單的狀態(tài)查詢的時(shí)候可以直接不走緩存,直接查詢master庫(kù)。畢竟這種更改訂單狀態(tài)的操作還是比較有限的。大多數(shù)情況都是用來(lái)展示的。展示的話是可以允許實(shí)時(shí)性要求沒(méi)那么高??偟膩?lái)說(shuō)需要開(kāi)具體的業(yè)務(wù),沒(méi)有通用的方案??茨愕臉I(yè)務(wù)需求的容忍度,畢竟脫離了業(yè)務(wù)來(lái)談技術(shù)都是耍流氓,是業(yè)務(wù)驅(qū)動(dòng)技術(shù)。

本文轉(zhuǎn)載自微信公眾號(hào)「 java金融」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 java金融公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: java金融
相關(guān)推薦

2021-03-11 00:05:55

Java高并發(fā)編程

2021-03-18 00:14:29

JavaCyclicBarri高并發(fā)

2021-03-04 07:24:24

JavaSemaphore高并發(fā)

2016-11-28 09:00:10

瀏覽器瀏覽器緩存服務(wù)端

2017-12-12 14:51:15

分布式緩存設(shè)計(jì)

2016-11-28 08:40:17

系統(tǒng)降級(jí)服務(wù)

2016-11-25 00:45:37

隊(duì)列數(shù)據(jù)

2020-09-21 06:53:41

NoSQL高并發(fā)面試

2016-11-28 08:58:43

系統(tǒng)限流算法

2016-11-28 08:58:43

系統(tǒng)限流

2019-08-13 15:36:57

限流算法令牌桶

2016-11-28 09:08:43

java系統(tǒng)異步非阻塞

2018-10-23 10:47:03

高并發(fā)系統(tǒng)緩存

2017-02-20 07:47:04

緩存HASH高并發(fā)

2019-12-03 10:46:07

PHP高并發(fā)架構(gòu)

2018-05-15 10:54:33

NginxRedisEhcache

2018-09-15 04:59:01

2021-02-14 18:26:25

高并發(fā)大對(duì)象代碼

2023-12-10 14:24:41

緩存Go語(yǔ)言

2019-12-05 15:22:25

高可用網(wǎng)關(guān)配置
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)