前言
部門培訓的時候讓我講緩存,然而平時用緩存也比較少,這邊特意整理下相關的資料,僅概念性的,不深入
一、什么是緩存
緩存就是數據交換的緩沖區,位于速度相差較大的兩種硬件/軟件之間的,用于協調兩者數據傳輸速度差異的結構。
軟件中的緩存就是指,將會被頻繁使用的數據保存到內存上,加快讀取速度。
二、為什么要使用緩存
- 減少交互的通訊量——緩存數據能有效減少在進程和機器間的傳輸量
- 降低系統中的處理量——減少處理次數
- 降低需要做的磁盤訪問次數——比如緩存在內存中的數據
IO的讀寫速度相對內存來說是比較慢的,通常一個web應用的瓶頸就出現在磁盤IO的讀寫上。
一般情況下,一個網站或者應用的形式是這樣的,用戶的請求通過用戶層來到業務層,業務層再從數據層獲取數據,返回給用戶層。在用戶量和數據量不大的情況下,這個系統運行得很順暢。但是隨著用戶量越來越大,數據庫中的數據越來越多,系統的響應速度就越來越慢。系統的瓶頸一般都在數據庫訪問上。
那么,如果我們在內存中建立一個存儲區,將數據緩存起來,當瀏覽器端由請求到達的時候,直接從內存中獲取相應的數據,這樣一來可以降低服務器的壓力,二來,可以提高請求的響應速度,提升用戶體驗。
綜上,使用緩存是為了提高系統運行速度,將用戶頻繁訪問的內容存放在訪問速度快的地方,來提高系統的響應速度。
三、緩存的屬性
命中率
命中率是指請求緩存次數和緩存返回正確結果次數的比例,比例越高,就證明緩存的使用率越高。最大元素
緩存中可以存放得最大元素得數量,一旦緩存中元素數量超過這個值,那么將會起用緩存清空策略,根據不同的場景合理的設置最大元素值往往可以一定程度上提高緩存的命中率,從而更有效的時候緩存。清空策略
- FIFO ,first in first out ,最先進入緩存得數據在緩存空間不夠情況下被首先清理出去。
- LFU , Less Frequently Used ,一直以來最少被使用的元素會被被清理掉。這就要求緩存的元素有一個hit 屬性,在緩存空間不夠得情況下,hit 值最小的將會被清出緩存。
- LRU ,Least Recently Used ,最近最少使用的,緩存的元素有一個時間戳,當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那么現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存。
四、哪些數據需要被緩存
查詢比較高的熱點數據、可以允許丟失的。
比如:平臺管理中的平臺配置、配置文件里的配置項、熱門文章、點贊、閱讀數等。
五、實現緩存的方式
java應用的緩存分兩種,一是進程內緩存,就是使用java應用的虛擬機內存來進行緩存;另一個是進程外緩存,比如:redis。
相比較而言,進程內緩存比進程外緩存快很多,而且編碼也簡單;但是,進程內緩存的存儲量有限,使用的是java應用虛擬機的內存,而且每個應用都要存儲一份,有一定的資源浪費。進程外緩存相比進程內緩存,會慢些,但是,存儲空間可以橫向擴展,不受限制。
5.1 進程內緩存
Ehcache
Cacheonix
ASimpleCache
JBoss Cache
Voldemort
5.2 進程外緩存
Redis
Mencached
六、ehcache
EhCache 是一個純Java的進程內緩存框架,具有快速、精干等特點,是Hibernate中默認的CacheProvider。
主要的特性有:
- 快速、簡單,提供多種緩存策略
- 緩存數據有兩級:內存和磁盤,因此無需擔心容量問題
- 緩存數據會在虛擬機重啟的過程中寫入磁盤
- 可以通過RMI、可插入API等方式進行分布式緩存
- 具有緩存和緩存管理器的偵聽接口
- 支持多緩存管理器實例,以一個實例的多個緩存區域
七、Redis
redis是一個遠程內存數據庫,可以存儲鍵(key)與5種不同類型的值(value)之間的映射,可以將存儲在內存中的鍵值對數據持久化到硬盤,可以使用復制特性擴展讀性能,還可以使用客戶端分片來擴展寫性能。
主要的特性有:
- redis的數據完全存儲在內存中,磁盤只用于持久性,所以redis的速度非???;
- redis擁有較為豐富的數據類型;
- redis的操作都是原子性的,所以在異步的時候也是安全的;
- redis可以將數據復制到任意數量的從機。
7.1 redis數據類型
結構類型 | 結構存儲的值 | 結構的讀寫能力 |
---|---|---|
STRING | 可以是字符串、整數或者浮點數 | 對整個字符串或者字符串的其中一部分執行操作;對整數和浮點數執行自增或者自減 |
LIST | 一個鏈表,鏈表上的每個節點都包含了一個字符串 | 從鏈表的兩端推入或者彈出元素;根據偏移量對鏈表進行修剪;讀取單個或者多個元素;根據值查找或者移除元素 |
SET | 包含字符串的無序收集器,并且被包含的每個字符串都是獨一無二、各不相同的 | 添加、獲取、移除單個元素;檢查一個元素是否存在于集合中;計算交集、并集、差集;從集合里面隨機獲取元素 |
HASH | 包含鍵值對的無序散列表 | 添加、獲取、移除單個鍵值對;獲取所有鍵值對 |
ZSET | 字符串成員與浮點數分值之間的有序映射,元素的排列順序由分值的大小決定 | 添加、獲取、刪除單個元素;根據分值范圍或者成員來獲取元素 |
7.2 使用場景
STRING
String是最常用的一種數據類型,普通的key/value存儲都可以使用此類型。比如分布式系統下,用戶登錄信息的共享,使用userguid
鍵 | 值 |
---|---|
userid | token |
LIST
List就是鏈表,可以存儲有先后順序的數據,比如:文章列表、最新消息。也可以基于此實現消息隊列。
鍵 | 值 |
---|---|
msglist | {msg1, msg2,...} |
SET
與list類似是一個列表的功能,特殊之處在于set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇。比如:用戶關注
鍵 | 值 |
---|---|
userid | [followid1, followid2,...] |
HASH
存儲一些結構化的數據,比如:用戶信息
鍵 | 值 |
---|---|
userid | {"name":"n", "age":"20"} |
ZSET
sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,并且是插入有序的,即自動排序。當你需要一個有序的并且不重復的集合列表,那么可以選擇sorted set數據結構,比如:文章熱度排行
鍵 | 值 |
---|---|
hot_article | [(id1, 20), (id2, 30),...] |