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

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
