新聞中心
背景
分布式、緩存、異步和多線程被稱為互聯(lián)網(wǎng)開發(fā)的四大法寶。今天我總結(jié)一下項(xiàng)目開發(fā)中常接觸的四種緩存實(shí)際項(xiàng)目中遇到過的問題。

創(chuàng)新互聯(lián)專注于企業(yè)營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、潁上網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、商城網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為潁上等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
JVM 堆內(nèi)緩存
JVM 堆內(nèi)緩存因?yàn)榭梢员苊?Memcached、Redis 等集中式緩存網(wǎng)絡(luò)通信故障問題,目前還在項(xiàng)目中廣泛使用。
堆內(nèi)緩存需要注意 GC 的問題。假如我們的設(shè)計(jì)是定時(shí)的從遠(yuǎn)程來拉取數(shù)據(jù)更新本地緩存。一定要注意兩點(diǎn):第一不要全量拉取覆蓋,第二不要把一個(gè)大對(duì)象整體替換為新對(duì)象。
先說全量拉取覆蓋。全量拉取會(huì)有很大的網(wǎng)絡(luò)開銷,會(huì)造成網(wǎng)絡(luò)流量尖刺。有人說沒事,我們帶寬很足,內(nèi)網(wǎng)訪問,不怕不怕。但是穩(wěn)定性需要修煉的一項(xiàng)是削峰填谷。讓系統(tǒng)在平穩(wěn)的環(huán)境中運(yùn)行。不然,在拉取大緩存新數(shù)據(jù)的數(shù)據(jù)突然來了個(gè)突發(fā)流量?根據(jù)墨菲定律,凡是有幾率會(huì)發(fā)生的事情就一定會(huì)發(fā)生。編程需謹(jǐn)慎。
再說大對(duì)象整體替換的問題,這會(huì)造成 GC 問題。偽代碼如下:
ListoldList = initList();
public void refresh() {
ListnewList = dataFromNetworkService.getAll();
oldList = new List();
for(POJO pojo : newList) {
oldList.add(pojo);
}
}
如果從網(wǎng)上拉取的數(shù)據(jù)和在緩存里存儲(chǔ)的數(shù)據(jù),對(duì)象類型沒有發(fā)生改變。引起的轉(zhuǎn)換開銷還稍微小點(diǎn)。因?yàn)楸热鐚?duì)象 POJO 存在一個(gè)列表里。這個(gè)列表雖然很大,但是里面存的都是對(duì)象的引用。實(shí)際的 POJO 并沒有發(fā)生變化。上面?zhèn)未a雖然新建一個(gè) List 對(duì)象,遍歷添加新對(duì)象比直接 oldList=newList 要傻些。但是遍歷過程實(shí)際上 POJO 對(duì)象沒有發(fā)生改變。所以這里影響 GC 的只是 oldList 這個(gè)對(duì)象(不包括從網(wǎng)絡(luò)上拉取回來數(shù)據(jù)的過程)。
但是如果代碼這樣寫:
ListoldList = initList();
public void refresh() {
ListnewList = dataFromNetworkService.getAll();
oldList = new List();
for(POJO2 pojo : newList) {
oldList.add(Beanutils.copy(new POJO2(), pojo));
}
}
遍歷過程將會(huì)將原來的 POJO1 全部新建一遍,這些對(duì)象一般情況下全部先進(jìn)入堆內(nèi)存的新生代,再經(jīng)過數(shù)次 Young GC 后進(jìn)入老年代。會(huì)造成GC頻繁。
我所做過的項(xiàng)目,一般認(rèn)為一天一到兩次 Full GC 為合理值。這樣,如果比如預(yù)先知道某個(gè)時(shí)間點(diǎn)有大促,可通過提前觸發(fā) GC 等方式避免高峰期爆發(fā) Full GC。Young GC 至少是 5 分鐘一次,甚至更久觸發(fā)認(rèn)為是正常。這樣可以通過控制避過秒殺等場(chǎng)景。
JVM 堆外緩存
堆外緩存的內(nèi)存回收原理使用的是 Java 的虛引用 。這個(gè)設(shè)計(jì)可以避免 JVM 的 GC 問題,但是處理不好可能會(huì)造成更嚴(yán)重的后果:整個(gè)機(jī)器內(nèi)存被打滿,機(jī)器可能會(huì)掛掉。 其實(shí)掛掉一臺(tái)在一般企業(yè)的生產(chǎn)環(huán)境還好,因?yàn)橐话愣紩?huì)有容災(zāi)的冗余機(jī)器。 但是更常見的一種情況是機(jī)器忙于 swap 內(nèi)存交換,機(jī)器活著但是響應(yīng)很慢。 屬于半死不活。 這個(gè)問題我沒在線上遇到過,但是我同事之前在超級(jí)大廠的時(shí)候遇到過。
有的同學(xué)說那我嚴(yán)格算好內(nèi)存,做好監(jiān)控。這里面要就要依賴人為的因素來做緊急處理。而人是穩(wěn)定性中最不可靠的。因?yàn)閱栴}通常不發(fā)生在人清醒、手里事情很少的時(shí)候。而是一種雪上加霜的存在。比如大促時(shí),流量上來了,線程數(shù)會(huì)增多,每個(gè)線程都會(huì)申請(qǐng)線程棧資源,系統(tǒng)處理 IO,這時(shí)候系統(tǒng)會(huì)申請(qǐng)更多的 buffers/cached 內(nèi)存。
Linux 的 buffers/cached
Linux 系統(tǒng)上運(yùn)行一下 top 命令或者 free 命令,都能夠看到 buffers 和 cached 相關(guān)的數(shù)據(jù)。需要注意的是通常我們看到的監(jiān)控?cái)?shù)據(jù)空閑內(nèi)存百分比,并非是下面顯示的 free/total,而是 (free+buffers+cached)/total。
buffers 在 Linux 系統(tǒng)中通常被作為與塊存儲(chǔ)的 IO 緩存使用。所謂塊存儲(chǔ)可簡(jiǎn)單理解為將數(shù)據(jù)直接寫到裸磁盤。而 cached 則一般會(huì)用于文件系統(tǒng)的 IO 緩存。比如 page cache 這種內(nèi)存換頁功能。
聽不明白也沒關(guān)系,因?yàn)槭聦?shí)上它們兩個(gè)經(jīng)常配合使用。比如與磁盤交換數(shù)據(jù)、進(jìn)行網(wǎng)絡(luò)通信時(shí)都會(huì)用。buffers 和 cached 是實(shí)實(shí)在在被操作系統(tǒng)的系統(tǒng)進(jìn)程在使用的,但是如果用戶進(jìn)程需要可以很快釋放。所以通常會(huì)將它算到剩余可用內(nèi)存里。
但是這個(gè)也要注意了。比如在 IO 密集型的系統(tǒng),如果 buffers/cached 被大幅占用,會(huì)降低 IO 速度,進(jìn)而降低系統(tǒng)吞吐。甚至有可能一個(gè)請(qǐng)求幾秒才能到達(dá)應(yīng)用程序,造成請(qǐng)求超時(shí)。
集中式緩存
Redis 緩存其實(shí)也有本機(jī)代理,可以緩存一些活躍的數(shù)據(jù)在本機(jī)上,本機(jī)可以在取 不 到數(shù)據(jù)時(shí)不需要跨網(wǎng)絡(luò)通信。但是因?yàn)?Redis 本質(zhì)是 key-value 的結(jié)構(gòu)。如果需要根據(jù)通配符取數(shù)據(jù)全量,如果網(wǎng)絡(luò)出現(xiàn)故障,可能會(huì)影響數(shù)據(jù)的完整性。
但是 Redis 緩存最讓人擔(dān)心的是不規(guī)范的使用方法。比如存一個(gè)很大的 value。具體這個(gè)對(duì)網(wǎng)絡(luò)和存儲(chǔ)造成的問題就不詳細(xì)說了??梢韵胂笙埋R桶堵了的情景。
總結(jié)
貝爾實(shí)驗(yàn)室的面向?qū)ο缶幊虒<?Tom Cargill 說:
最初 90% 的開發(fā)工作將會(huì)用去你最初 90% 的開發(fā)時(shí)間,剩下的 10% 的開發(fā)量將會(huì)用去你另外一個(gè) 90% 的開發(fā)時(shí)間。
我理解剩下 10% 占用了 90% 的時(shí)間是由于超出了原有知識(shí)貯備,需要臨時(shí)抱佛腳,甚至需要拿著錘子找釘子造成的。所以或者也可以這樣做:
每周持續(xù)投入 5% 的學(xué)習(xí)時(shí)間,10% 的思考時(shí)間,再用 100% 的時(shí)間去完成 100% 的開發(fā)。
分享文章:四種緩存的避坑總結(jié)
鏈接URL:http://fisionsoft.com.cn/article/ccshsgc.html


咨詢
建站咨詢
