不少人看到 J2Cache 第一眼時(shí),會(huì)認(rèn)為這就是一個(gè)普普通通的緩存框架,和例如 Ehcache、Caffeine 、Spring Cache 之類的項(xiàng)目沒什么區(qū)別,無非是造了一個(gè)新的輪子而已。事實(shí)上完全不是一回事!
目前緩存的解決方案一般有兩種:
內(nèi)存緩存(如 Ehcache) —— 速度快,進(jìn)程內(nèi)可用
集中式緩存(如 Redis)—— 可同時(shí)為多節(jié)點(diǎn)提供服務(wù)
現(xiàn)有的緩存框架已經(jīng)非常成熟而且優(yōu)秀,J2Cache 無心造一個(gè)新的輪子,它要解決的幾個(gè)問題如下:
使用內(nèi)存緩存時(shí),一旦應(yīng)用重啟后,由于緩存數(shù)據(jù)丟失,緩存雪崩,給數(shù)據(jù)庫造成巨大壓力,導(dǎo)致應(yīng)用堵塞
使用內(nèi)存緩存時(shí),多個(gè)應(yīng)用節(jié)點(diǎn)無法共享緩存數(shù)據(jù)
使用集中式緩存,由于大量的數(shù)據(jù)通過緩存獲取,導(dǎo)致緩存服務(wù)的數(shù)據(jù)吞吐量太大,帶寬跑滿?,F(xiàn)象就是 Redis 服務(wù)負(fù)載不高,但是由于機(jī)器網(wǎng)卡帶寬跑滿,導(dǎo)致數(shù)據(jù)讀取非常慢
在遭遇問題1、2 時(shí),很多人自然而然會(huì)想到使用 Redis 來緩存數(shù)據(jù),因此就難以避免的導(dǎo)致了問題3的發(fā)生。
當(dāng)發(fā)生問題 3 時(shí),又有很多人想到 Redis 的集群,通過集群來降低緩存服務(wù)的壓力,特別是帶寬壓力。
但其實(shí),這個(gè)時(shí)候的 Redis 上的數(shù)據(jù)量并不一定大,僅僅是數(shù)據(jù)的吞吐量大而已。
咱們假設(shè)這樣一個(gè)場景:
有這么一個(gè)網(wǎng)站,某個(gè)頁面每天的訪問量是 1000萬,每個(gè)頁面從緩存讀取的數(shù)據(jù)是 50K。緩存數(shù)據(jù)存放在一個(gè) Redis 服務(wù),機(jī)器使用千兆網(wǎng)卡。那么這個(gè) Redis 一天要承受 500G 的數(shù)據(jù)流,相當(dāng)于平均每秒鐘是 5.78M 的數(shù)據(jù)。而網(wǎng)站一般都會(huì)有高峰期和低峰期,兩個(gè)時(shí)間流量的差異可能是百倍以上。我們假設(shè)高峰期每秒要承受的流量比平均值高 50 倍,也就是說高峰期 Redis 服務(wù)每秒要傳輸超過 250 兆的數(shù)據(jù)。請(qǐng)注意這個(gè) 250 兆的單位是 byte,而千兆網(wǎng)卡的單位是“bit” ,你懂了嗎? 這已經(jīng)遠(yuǎn)遠(yuǎn)超過 Redis 服務(wù)的網(wǎng)卡帶寬。
所以如果你能發(fā)現(xiàn)這樣的問題,一般你會(huì)這么做:
升級(jí)到萬兆網(wǎng)卡?—— 這個(gè)有多麻煩,相信很多人知道,特別是一些云主機(jī)根本沒有萬兆網(wǎng)卡給你使用(運(yùn)維工程師一般會(huì)給這樣的建議)
多個(gè) Redis 搭建集群,將流量分?jǐn)偠喽嗯_(tái)機(jī)器上
如果你采用第2種方法來解決上述的場景中碰到的問題,那么你最好準(zhǔn)備 5 個(gè) Redis 服務(wù)來支撐。在緩存服務(wù)這塊成本直接攀升了 5 倍。你有錢當(dāng)然沒任何問題,但是結(jié)構(gòu)就變得非常復(fù)雜了,而且可能你緩存的數(shù)據(jù)量其實(shí)不大,1000 萬高頻次的緩存讀寫 Redis 也能輕松應(yīng)付,可是因?yàn)閹挼膯栴},你不得不付出 5 倍的成本。
那么 J2Cache 的用武之處就在這里。
如果我們不用每次頁面訪問的時(shí)候都去 Redis 讀取數(shù)據(jù),那么 Redis 上的數(shù)據(jù)流量至少降低 1000 倍甚至更多,以至于一臺(tái) Redis 可以輕松應(yīng)付。
J2Cache 其實(shí)不是一個(gè)緩存框架,它是一個(gè)緩存框架的橋梁。它利用現(xiàn)有優(yōu)秀的內(nèi)存緩存框架作為一級(jí)緩存,而把 Redis 作為二級(jí)緩存。所有數(shù)據(jù)的讀取先從一級(jí)緩存中讀取,不存在時(shí)再從二級(jí)緩存讀取,這樣來確保對(duì)二級(jí)緩存 Redis 的訪問次數(shù)降到最低。
有人會(huì)質(zhì)疑說,那豈不是應(yīng)用節(jié)點(diǎn)的內(nèi)存占用要飆升?我的答案是 —— 現(xiàn)在服務(wù)器的內(nèi)存都是幾十 G 打底,多則百 G 數(shù)百 G,這點(diǎn)點(diǎn)的內(nèi)存消耗完全不在話下。其次一級(jí)緩存框架可以通過配置來控制在內(nèi)存中存儲(chǔ)的數(shù)據(jù)量,所以不用擔(dān)心內(nèi)存溢出的問題。
剩下的另外一個(gè)問題就是,當(dāng)緩存數(shù)據(jù)更新的時(shí)候,怎么確保每個(gè)節(jié)點(diǎn)內(nèi)存中的數(shù)據(jù)是一致的。而這一點(diǎn)算你問到點(diǎn)子上了,這恰恰是 J2Cache 的核心所在。
J2Cache 目前提供兩種節(jié)點(diǎn)間數(shù)據(jù)同步的方案 —— Redis Pub/Sub 和 JGroups 。當(dāng)某個(gè)節(jié)點(diǎn)的緩存數(shù)據(jù)需要更新時(shí),J2Cache 會(huì)通過 Redis 的消息訂閱機(jī)制或者是 JGroups 的組播來通知集群內(nèi)其他節(jié)點(diǎn)。當(dāng)其他節(jié)點(diǎn)收到緩存數(shù)據(jù)更新的通知時(shí),它會(huì)清掉自己內(nèi)存里的數(shù)據(jù),然后重新從 Redis 中讀取最新數(shù)據(jù)。
這就完成了 J2Cache 緩存數(shù)據(jù)讀寫的閉環(huán)。
為什么不用 Ehcache 的集群方案?
對(duì) Ehcache 比較熟悉的人還會(huì)問的就是這個(gè)問題,Ehcache 本身是提供集群模式的,可以在多個(gè)節(jié)點(diǎn)同步緩存數(shù)據(jù)。但是 Ehcache 的做法是將整個(gè)緩存數(shù)據(jù)在節(jié)點(diǎn)間進(jìn)行傳輸。如咱們前面的說的,一個(gè)頁面需要讀取 50K 的緩存數(shù)據(jù),當(dāng)這 50K 的緩存數(shù)據(jù)有更新時(shí),那么需要在幾個(gè)節(jié)點(diǎn)間傳遞整個(gè) 50K 的數(shù)據(jù)。這也會(huì)造成應(yīng)用節(jié)點(diǎn)間大量的數(shù)據(jù)傳輸,這個(gè)情況完全不可控。
補(bǔ)充:當(dāng)然這個(gè)單個(gè)數(shù)據(jù)傳輸量本身并不比使用 J2Cache 多,但是 ehcache 利用 jgroups 來同步數(shù)據(jù)的做法,在實(shí)際測試過程中發(fā)現(xiàn)可靠性還是略低,而且 jgroups 的同步數(shù)據(jù)在云主機(jī)上無法使用。
而 J2Cache 傳輸?shù)膬H僅是緩存的 key 而已,因此相比 Ehcache 的集群模式,J2Cache 要傳輸?shù)臄?shù)據(jù)極其小,對(duì)節(jié)點(diǎn)間的數(shù)據(jù)通信完全不會(huì)產(chǎn)生大的影響。
那如何學(xué)習(xí)才能快速入門并精通呢?
當(dāng)真正開始學(xué)習(xí)的時(shí)候難免不知道從哪入手,導(dǎo)致效率低下影響繼續(xù)學(xué)習(xí)的信心。
但最重要的是不知道哪些技術(shù)需要重點(diǎn)掌握,學(xué)習(xí)時(shí)頻繁踩坑,最終浪費(fèi)大量時(shí)間,所以有一套實(shí)用的視頻課程用來跟著學(xué)習(xí)是非常有必要的。
為了讓學(xué)習(xí)變得輕松、高效,今天給大家免費(fèi)分享一套阿里架構(gòu)師傳授的一套教學(xué)資源。加群:874811168免費(fèi)獲取以下資料?幫助大家在成為架構(gòu)師的道路上披荊斬棘。
這套視頻課程詳細(xì)講解了(Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu))等成為架構(gòu)師必備的內(nèi)容!