看一粒沙中的世界,
一朵野花中的天堂。
把無(wú)限握于掌中,
把永恒握于瞬間。
——
威廉
?
布萊克
開(kāi)始討論緩存之前
,
讓我們先來(lái)討論討論另外一個(gè)問(wèn)題
:
理論和實(shí)踐
.
從
ahuaxuan
接觸的程序員來(lái)看
,
有的程序員偏實(shí)踐
,
有的程序員偏理論
,
但
是這都是不好的行為
,
理論和實(shí)踐同樣重要
,
我們?cè)谧龊芏嗪诵牡乃惴ǖ臅r(shí)候
,
沒(méi)有理論根本無(wú)從下手
,
而在我們多年的實(shí)踐中
,
不總結(jié)理論就不能加深自己的理
解
.
所以理論和實(shí)踐同等重要
.
緩存是當(dāng)今各種軟件或者硬件系統(tǒng)中不可缺少的技術(shù)之一
,
所以對(duì)每個(gè)程序員來(lái)說(shuō)都顯得異常重要
,
對(duì)
ahuaxuan
來(lái)說(shuō)亦是如此
.
如果說(shuō)用
dfa
實(shí)現(xiàn)文字過(guò)濾是從理論到實(shí)踐
,
那么本文便是從實(shí)踐中總結(jié)出得理論
.
在討論緩存功能之前
,
我們首先來(lái)了解一下緩存這個(gè)東西本身
.ahuaxuan
根據(jù)自己的經(jīng)驗(yàn)把緩存問(wèn)題細(xì)分為
4
類小問(wèn)題
.
1
緩存為什么要存在
?
2
緩存可以存在于什么地方
?
3
緩存有哪些屬性
?
4
緩存介質(zhì)
?
搞清楚這
4
個(gè)問(wèn)題
,
那么我們就可以隨意的通過(guò)應(yīng)用的場(chǎng)景來(lái)判斷使用何種緩存了
.
1.
緩存為什么要存在
?
一般情況下
,
一個(gè)網(wǎng)站
,
或者一個(gè)應(yīng)用
,
它的一般形式是
,
瀏覽器請(qǐng)求應(yīng)用服務(wù)器
,
應(yīng)用服務(wù)器做一堆計(jì)算后再請(qǐng)求數(shù)據(jù)庫(kù)
,
數(shù)據(jù)庫(kù)收到請(qǐng)求后再作一堆計(jì)
算后把數(shù)據(jù)返回給應(yīng)用服務(wù)器
,
應(yīng)用服務(wù)器再作一堆計(jì)算后把數(shù)據(jù)返回給瀏覽器
.
這個(gè)是一個(gè)標(biāo)準(zhǔn)流程
.
但是隨著互連網(wǎng)的普及
,
上網(wǎng)的人越來(lái)越多
,
網(wǎng)上的信息量
也越來(lái)越多
,
在這兩個(gè)越來(lái)越多的情況下
,
我們的應(yīng)用需要支撐的并發(fā)量就越來(lái)越多
.
然后我們的應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器所做的計(jì)算也越來(lái)越多
,
但是往往我們
的應(yīng)用服務(wù)器資源是有限的
,
數(shù)據(jù)庫(kù)每秒中接受請(qǐng)求的次數(shù)也是有限的
(
誰(shuí)叫俺們的硬盤(pán)轉(zhuǎn)速有限呢
).
如果利用有限的資源來(lái)提供盡可能大的吞吐量呢
,
一個(gè)辦
法
:
減少計(jì)算量
,
縮短請(qǐng)求流程
(
減少網(wǎng)絡(luò)
io
或者硬盤(pán)
io),
這時(shí)候緩存就可以大展手腳了
.
緩存的基本原理就是打破上圖中所描繪的標(biāo)準(zhǔn)流程
,
在這個(gè)標(biāo)準(zhǔn)流
程中
,
任何一個(gè)環(huán)節(jié)都可以被切斷
.
請(qǐng)求可以從緩存里取到數(shù)據(jù)直接返回
.
這樣不但節(jié)省了時(shí)間
,
提高了響應(yīng)速度
,
而且也節(jié)省了硬件資源
.
可以讓我們有限的硬件
資源來(lái)服務(wù)更多的用戶
.
2?
緩存可以存在于什么地方
?
Java 代碼
數(shù)據(jù)庫(kù) ?? à 分過(guò)層的 app- à 瀏覽器和 app 之間 --- à 瀏覽器 ---
數(shù)據(jù)庫(kù) à 分過(guò)層的 app- à 瀏覽器和 app 之間 --- à 瀏覽器 ---
?
在上圖中
,
我們可以看到一次請(qǐng)求的一般流程
,
下面我們重新繪制這張圖
,
讓我們的結(jié)構(gòu)稍微復(fù)雜一點(diǎn)點(diǎn)
.
(
將
app
分層
)
數(shù)據(jù)庫(kù)
à
分過(guò)層的
app-
à
瀏覽器和
app
之間
---
à
瀏覽器
---
理論上來(lái)將
,
請(qǐng)求的任何一個(gè)環(huán)節(jié)都是緩存可以作用的地方
.
第一個(gè)環(huán)節(jié)
,
瀏覽器
,
如果數(shù)據(jù)存在瀏覽器上
,
那么對(duì)用戶來(lái)說(shuō)速度是最快的
,
因?yàn)檫@個(gè)時(shí)候
根本無(wú)需網(wǎng)絡(luò)請(qǐng)求
.
第二個(gè)環(huán)節(jié)
,
瀏覽器和
app
之間
,
如果緩存加在這個(gè)地方
,
那么緩存對(duì)
app
來(lái)說(shuō)是透明的
.
而且這個(gè)緩存中存放的是完整的頁(yè)面
.
第三個(gè)節(jié)
點(diǎn)
,app
中本身就有幾個(gè)層次
,
那么緩存也可以放在不同的層次上
,
這一部分是情況或者場(chǎng)景比較復(fù)雜的部分
.
選擇緩存時(shí)需要謹(jǐn)慎
.
第四個(gè)環(huán)節(jié)
,
數(shù)據(jù)庫(kù)中也可
以有緩存
,
比如說(shuō)
mysql
的
querycache.
那么也就是說(shuō)在整個(gè)請(qǐng)求流程的任何一點(diǎn)
,
我們都可以加緩存
.
但是是所有的數(shù)據(jù)都可以放進(jìn)緩存的嗎
.
當(dāng)然不是
,
需要放進(jìn)緩存的數(shù)據(jù)總是有一些特征的
,
要清楚的判斷數(shù)據(jù)是否可以被緩存
,
可以被怎樣緩存就必須要從數(shù)據(jù)的變化特征下手
.
數(shù)據(jù)有哪些變化特征
?
最簡(jiǎn)單的就是兩種
,
變和不變
.
我們都知道
,
不會(huì)變化的數(shù)據(jù)不需要每次都進(jìn)行計(jì)算
.
問(wèn)題是難道所有的數(shù)據(jù)理論上來(lái)講都會(huì)變化
,
變化是世界永恒的主題
.
也就是說(shuō)我們把數(shù)據(jù)分為變和不變兩種是不對(duì)的
,
那么就讓我們?cè)偌右粋€(gè)條件
:
時(shí)間
.
那么我們就可以把數(shù)據(jù)特征總結(jié)為一段時(shí)間內(nèi)變或者
不變
.
那么根據(jù)這個(gè)數(shù)據(jù)特征
,
我們就可以在合適的位置和合適的緩存類型中緩存該數(shù)據(jù)
.
3
緩存有哪些屬性
從面向?qū)ο蟮慕嵌葋?lái)看
,
緩存就是一個(gè)對(duì)象
,
那么是對(duì)象
,
必然有屬性
.
那么下面我們來(lái)探討一下緩存有哪些屬性
.
以下列舉我們常用到的
3
個(gè)屬性
.
(1)
命中率
命中率是指請(qǐng)求緩存次數(shù)和緩存返回正確結(jié)果次數(shù)的比例
.
比例越高
,
就證明緩存的使用率越高
.
命中率問(wèn)題是緩存中的一個(gè)非常重要的問(wèn)題
,
我們都希望自己緩存的命中率能達(dá)到
100%,
但是往往事與愿違
,
而且緩存命中率是衡量緩存有效性的重要指標(biāo)
.
(2)
最大元素
緩存中可以存放得最大元素得數(shù)量
,
一旦緩存中元素?cái)?shù)量超過(guò)這個(gè)值
,
那么將會(huì)起用緩存清空策略
,
根據(jù)不同的場(chǎng)景合理的設(shè)置最大元素值往往可以一定程度上提高緩存的命中率
.
從而更有效的時(shí)候緩存
.
(3)
清空策略
1 FIFO
,
first in first out
,最先進(jìn)入緩存得數(shù)據(jù)在緩存空間不夠情況下
(
超出最大元素限制時(shí)
)
會(huì)被首先清理出去
2 LFU
,
Less Frequently Used
,一直以來(lái)最少被使用的元素會(huì)被被清理掉。這就要求緩存的元素有一個(gè)
hit
屬性,在緩存空間不夠得情況下
,hit
值最小的將會(huì)被清出緩存。
2 LRU
,
Least Recently Used
,最近最少使用的,緩存的元素有一個(gè)時(shí)間戳,當(dāng)緩存容量滿了,而又需要騰出地方來(lái)緩存新的元素的時(shí)候,那么現(xiàn)有緩存元素中時(shí)間戳離當(dāng)前時(shí)間最遠(yuǎn)的元素將被清出緩存。
4
緩存介質(zhì)
從硬件介質(zhì)上來(lái)將無(wú)非就是兩種
,
內(nèi)存和硬盤(pán)
(
對(duì)應(yīng)應(yīng)用層的程序來(lái)講不用考慮寄存器等問(wèn)題
).
但是往往我們不會(huì)從硬件上來(lái)劃分
,
一般的劃分方法是從技術(shù)上劃分
,
可以分成幾種
,
內(nèi)存
,
硬盤(pán)文件
.
數(shù)據(jù)庫(kù)
.
(1)
內(nèi)存
.
將緩存放在內(nèi)存中是最快的選擇
,
任何程序直接操作內(nèi)存都比操作硬盤(pán)要快的多
,
但是如果你的數(shù)據(jù)要考慮到
break down
的問(wèn)題
,
因?yàn)榉旁趦?nèi)存中的數(shù)據(jù)我們稱之為沒(méi)有持久話的數(shù)據(jù)
,
如果硬盤(pán)上沒(méi)有備份
,
機(jī)器
down
機(jī)之后
,
很難或者無(wú)法恢復(fù)
.
(2)
硬盤(pán)
.
一般來(lái)說(shuō)
,
很多緩存框架會(huì)結(jié)合使用內(nèi)存和硬盤(pán)
,
比如給內(nèi)存分配的空間有滿了之后
,
會(huì)讓用戶選擇把需要退出內(nèi)存空間的數(shù)據(jù)持久化到硬盤(pán)
.
當(dāng)然也選擇直接把數(shù)據(jù)放一份到硬盤(pán)
(
內(nèi)存中一份
,
硬盤(pán)中一份
,down
機(jī)也不怕
).
也有其他的緩存是直接把數(shù)據(jù)放到硬盤(pán)上
.
(3)
數(shù)據(jù)庫(kù)
.
說(shuō)到數(shù)據(jù)庫(kù)
,
可能有的人會(huì)想
,
之前不是講到要減少數(shù)據(jù)庫(kù)查詢的次數(shù)
,
減少數(shù)據(jù)庫(kù)計(jì)算的壓力嗎
,
現(xiàn)在怎么又用數(shù)據(jù)庫(kù)作為緩存的介質(zhì)了呢
.
這是因?yàn)閿?shù)
據(jù)庫(kù)又很多種類型
,
比如
berkleydb,
這種
db
不支持
sql
語(yǔ)句
,
沒(méi)有
sql
引擎
,
只是
key
和
value
的存儲(chǔ)結(jié)構(gòu)
,
所以速度非常的快
,
在當(dāng)代一
般的
pc
上
,
每秒中十幾
w
次查詢都是沒(méi)有問(wèn)題的
(
當(dāng)然這個(gè)是根據(jù)業(yè)務(wù)特征來(lái)決定的
,
如果您訪問(wèn)的數(shù)據(jù)在分布上是均勻的
,
那
ahuaxuan
可不能保證這個(gè)
速度了
).
除了緩存介質(zhì)之外
,ahuaxuan
根據(jù)緩存和應(yīng)用的耦合程度將其劃分為
local cache
和
remote cache.
Local cache
是指包含在應(yīng)用之中的緩存組件
.
而
remote cache
指和應(yīng)用解耦在應(yīng)用之外的緩存組件
.
典型的
local cache
有
ehcache,oscache,
而
remote cache
有大名鼎鼎的
memcached.
Localcache
最大的優(yōu)點(diǎn)是應(yīng)用和
cache
的時(shí)候是在同一個(gè)進(jìn)程內(nèi)部
,
請(qǐng)求緩存非常快速
,
完全不需要網(wǎng)絡(luò)開(kāi)銷等
.
所以單應(yīng)用
,
不需要集群
或者集群情況下
cache node
不需要相互通知的情況下使用
local cache
比較合適
.
這也是
java
中
ehcache
和
oscache
這么流行的原因
.
但是
Local cache
是有一定的缺點(diǎn)的
,
一般這種緩存框架
(
比如
java
中的
ehcache
或者
oscache)
都是
local cache.
也就是跟著應(yīng)用程序走的
,
多個(gè)應(yīng)用程序無(wú)法直接共享緩存
,
應(yīng)用集群的情況下這個(gè)問(wèn)題更加明顯
,
當(dāng)然也有的緩存組件提供了集群節(jié)點(diǎn)相互通知緩存
更新的功能
,
但是由于這個(gè)是廣播
,
或者是環(huán)路更新
,
在緩存更新頻繁的情況下會(huì)導(dǎo)致網(wǎng)絡(luò)
io
開(kāi)銷非常大
,
嚴(yán)重的時(shí)候會(huì)影響應(yīng)用的正常運(yùn)行
.
而且如果緩存中數(shù)
據(jù)量較大得情況下使用
localcache
意味著每個(gè)應(yīng)用都有一份這么大得緩存
,
著絕對(duì)是對(duì)內(nèi)存的浪費(fèi)
.
所以這個(gè)情況下
,
往往我們會(huì)選擇
remote cache,
比如
memcached.
這樣集群或者分布式的情況下各個(gè)應(yīng)用都可以共享
memcached
中的數(shù)據(jù)
,
這些應(yīng)用都通過(guò)
socket
和基于
tcp/ip
協(xié)議上層的
memcached
協(xié)議直接連接到
memcached,
有一個(gè)
app
更新了
memcached
中的值
,
所有的應(yīng)用都能拿到最新的
值
.
雖然這個(gè)時(shí)候多了很多了網(wǎng)絡(luò)上的開(kāi)銷
,
但是往往這種方案要比
localcache
廣播或環(huán)路更新
cache
節(jié)點(diǎn)要普遍的多
,
而且性能也比后者高
.
由于
數(shù)據(jù)只需要保存一份
,
所以也提高了內(nèi)存的使用率
.
通過(guò)以上分析可以看出
,
不管是
local cache,
還是
remote cache
在緩存領(lǐng)域都有自己的一席之地
,
所以
ahuaxuan
建議在選擇或者使用緩存時(shí)一定要根據(jù)緩存的特征和我們的業(yè)務(wù)場(chǎng)景準(zhǔn)確判斷使用何種緩存
.
這樣才能充分發(fā)揮緩存的功能
.
Ahuaxuan
認(rèn)為
,
緩存的使用是架構(gòu)師的必備技能
,
好的架構(gòu)師能夠根據(jù)數(shù)據(jù)的類型
,
業(yè)務(wù)的場(chǎng)景來(lái)準(zhǔn)確的判斷出使用何種類型的緩存
,
并且如何使
用這種類型的緩存
.
在緩存的世界里也沒(méi)有銀彈
,
目前還沒(méi)有一種緩存可以解決任何的業(yè)務(wù)場(chǎng)景或者數(shù)據(jù)類型
,
如果這種技術(shù)出現(xiàn)了
,
那架構(gòu)師就又更不值錢(qián)了
.
呵
呵
.
本文是
ahuaxuan
從自己的實(shí)踐中總結(jié)出來(lái)的一些小小的心得
,
未參考任何文章
,,
所以可能未必好
,
未必全面
,
未必令您滿意
,
歡迎拍磚
.
最后說(shuō)一說(shuō)寫(xiě)這篇文章的初衷
,
周末有人讓我說(shuō)說(shuō)我對(duì)緩存的理解
,
我的回答的是對(duì)緩存的理解無(wú)法用一句話來(lái)表述
,
起碼寫(xiě)
5
篇文章
.
那本文只是第一篇
.
待續(xù)
-------------
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

