個人做的好的淘寶客網(wǎng)站網(wǎng)站推廣開戶
緩存
- Memcached
- redis
- Redis常見數(shù)據(jù)類型和使用
- Redis緩存持久化
- RDB-快照
- AOF-追加文件
- Redis數(shù)據(jù)過期機(jī)制
- 惰性刪除
- 定期刪除
- Redis緩存淘汰策略(8種)
- 算法
- LRU (Least Recently Used):最近最少使用
- LFU(Least Frequently Used):最近最少頻率使用
- Redis事務(wù)
- Redis為什么要用分布式緩存
- Redis集群
- 主從模式 - 最簡單的
- 哨兵模式
- Redis Cluster
- Redis常見問題及解決方案
- 緩存擊穿
- 緩存穿透
- 緩存雪崩
- bigKey
- 熱Key
- 慢查詢命令
- 如何保障數(shù)據(jù)庫和緩存數(shù)據(jù)的一致性
- 延時雙刪
- 異步更新緩存
- 假如 Redis 里面有 1 億個 key,其中有 10w 個 key 是以某個固定的已知的前綴開頭的,如果將它們?nèi)空页鰜?#xff1f;
- 什么情況下可能會導(dǎo)致 Redis 阻塞
- 怎么提高緩存命中率
- 怎么實(shí)現(xiàn)分布式鎖
- 分布式點(diǎn)這里
- MongDB
- 數(shù)據(jù)庫點(diǎn)這里
- 消息隊列
- Spring、SpringBoot、SpringCloud點(diǎn)這里
Memcached
簡潔的key-value存儲系統(tǒng),其實(shí)是內(nèi)存中維護(hù)一張巨大的Hash表。不支持集群,Memcached彼此之間不進(jìn)行通信,所以,可能會造成數(shù)據(jù)丟失。
和redis對比
Memcached | Redis | |
---|---|---|
數(shù)據(jù)類型 | 只支持key-value | |
數(shù)據(jù)持久化 | Memcached 把數(shù)據(jù)全部存在內(nèi)存之中 | Redis 支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中,重啟的時候可以再次加載進(jìn)行使用 |
集群模式支持 | 沒有原生的集群模式 | 3.0 版本起是原生支持集群模式的 |
線程模型 | 多線程,非阻塞 IO 復(fù)用的網(wǎng)絡(luò)模型 | 單線程的多路 IO 復(fù)用模型 |
特性支持 | Redis 支持發(fā)布訂閱模型、Lua 腳本、事務(wù)等功能 | |
過期數(shù)據(jù)刪除 | 只用了惰性刪除策略 | 惰性刪除策略、定期刪除策略 |
redis
redis是一個緩存中間件。
數(shù)據(jù)基于內(nèi)存,內(nèi)存的訪問速度比磁盤快很多
單線程,基于I/O多路復(fù)用
- 6.0后支持多線程,但是命令執(zhí)行還是單線程
Redis 除了可以用作緩存之外,還可以用于分布式鎖、限流、消息隊列、延時隊列等>場景
- 延時隊列:Redisson 內(nèi)置了延時隊列(基于 Sorted Set 實(shí)現(xiàn)的)
- 消息隊列:Redis 自帶的 List 數(shù)據(jù)結(jié)構(gòu)可以作為一個簡單的隊列使用。(Rpush +Lpop)
Redis 5.0 中增加的 Stream 類型的數(shù)據(jù)結(jié)構(gòu)更加適合用來做消息隊列。- 限流: 通過 Redis + Lua 腳本的方式來實(shí)現(xiàn)限流。key是ip,value是訪問次數(shù)
- redis搜索引擎:借助 RediSearch
- redis延時任務(wù)
Redis常見數(shù)據(jù)類型和使用
5 種基礎(chǔ)數(shù)據(jù)類型
String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
- String,二進(jìn)制安全的,可以存儲圖片或者序列化的對象,值最大存儲為512M
set key value
get key
- Hash
hset key field value
hget key field
- List
lpush key value [value ...]
lrange key start end
- Set(集合)
sadd key element [element ...]
smembers key
- ZSet(有序集合)
zadd key score member [score member ...]
zrank key member
3 種特殊數(shù)據(jù)類型
HyperLogLog(基數(shù)統(tǒng)計)、Bitmap (位圖)、Geospatial
(地理位置)。除了上面提到的之外,還有一些其他的比如 Bloom filter(布隆過濾器)open in new
window、Bitfield(位域)。
場景應(yīng)用:排行耪
選用ZSet,這是一個有序集合。根據(jù)score來排序
Zrange (從小到大排序)、 ZrevRange (從大到小排序)、ZrevRank (指定元素排名)。
Redis緩存持久化
4.0之后,RDB 和 AOF 混合使用實(shí)現(xiàn)持久化
RDB-快照
定時將redis中的所有鍵值對數(shù)據(jù)保存到到一個臨時文件中,這個文件就是dump.rdb文件?;謴?fù)時候?qū)⑦@個臨時文件替換上次持久化的文件即可。
AOF-追加文件
每次操作命令時候,將這次的操作通過Write函數(shù)追加到文件中。恢復(fù)時候,會自動執(zhí)行備份文件中的所有命令,達(dá)到恢復(fù)上次數(shù)據(jù)的效果。
總結(jié):
- RDB是默認(rèn)持久化方式,當(dāng)兩種方式同時開啟時,數(shù)據(jù)恢復(fù)Redis會優(yōu)先選擇AOF恢復(fù)。
- 持久化機(jī)制: 當(dāng)Redis重啟后通過把硬盤文件重新加載到內(nèi)存
- 實(shí)現(xiàn):單獨(dú)創(chuàng)建fork()一個子進(jìn)程,將當(dāng)前父進(jìn)程的數(shù)據(jù)庫數(shù)據(jù)復(fù)制到子進(jìn)程的內(nèi)存中,然后由子進(jìn)程寫入到臨時文件中,持久化的過程結(jié)束了,再用這個臨時文件替換上次的快照文件,然后子進(jìn)程退出,內(nèi)存釋放。
Redis數(shù)據(jù)過期機(jī)制
設(shè)置expire(過期時間)后才會觸發(fā)。
Redis 采用的是 定期刪除+惰性/懶漢式刪除 結(jié)合的策略
惰性刪除
當(dāng)查詢key時候,先看該key是否過期,沒有過期就返回數(shù)據(jù);負(fù)責(zé),刪除該key,且不返回數(shù)據(jù)
定期刪除
在一定時間,隨機(jī)抽取設(shè)置過期時間的key,若這些含的key大部分過期,就刪除這些過期key
-
Redis 的定期刪除過程是隨機(jī)的(周期性地隨機(jī)從設(shè)置了過期時間的 key 中抽查一批),所以并不保證所有過期鍵都會被立即刪除。這也就解釋了為什么有的 key 過期了,并沒有被刪除。
-
并且,執(zhí)行時間已經(jīng)超過了閾值,那么就中斷這一次定期刪除循環(huán),以避免使用過多的 CPU 時間
-
可在配置文件中設(shè)置頻率
由 hz 參數(shù)控制的。hz 默認(rèn)為 10,代表每秒執(zhí)行 10 次
Redis緩存淘汰策略(8種)
當(dāng)redis內(nèi)存不夠用的時候,當(dāng)一個新key需要存放時候就會按某種規(guī)則將內(nèi)存中的數(shù)據(jù)刪掉,這個刪除規(guī)則就是淘汰策略。
- noeviction:默認(rèn)策略。不刪除任何key,新增的key也不寫入,內(nèi)部不足直接報錯
- volatile-ttl:對設(shè)置TTL時間的key,剩余時間越短的先刪除
- allkeys-random:對全體key隨機(jī)淘汰
- volatile-random:對設(shè)置TTL時間的key隨機(jī)淘汰
- allkeys-LRU:對全體key使用LRU短發(fā)淘汰
有明顯冷熱數(shù)據(jù)區(qū)分- volatile-LRU: 對設(shè)置TTL時間的key使用LRU短發(fā)淘汰
數(shù)據(jù)有置頂?shù)男枨?— 置頂數(shù)據(jù)不設(shè)置過期時間,這些數(shù)據(jù)就一直不被刪除,會淘汰其他設(shè)置過期時間的數(shù)據(jù)- allkeys-LFU:對全體key使用LFU短發(fā)淘汰
- volatile-LFU: 對設(shè)置TTL時間的key使用LFU短發(fā)淘汰
算法
LRU (Least Recently Used):最近最少使用
用當(dāng)前時間減去最后一次訪問時間,這個值越大則淘汰優(yōu)先級越高。
public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int CACHE_SIZE;// 這里就是傳遞進(jìn)來最多能緩存多少數(shù)據(jù)public LRUCache(int cacheSize) {super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);//這塊就是設(shè)置一個hashmap的初始大小,//同時最后一個true指的是讓linkedhashmap按照訪問順序來進(jìn)行排序//即 最近訪問的放在頭,最老訪問的就在尾CACHE_SIZE = cacheSize;}@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return size() > CACHE_SIZE; // 這個意思就是說當(dāng)map中的數(shù)據(jù)量大于指定的緩存?zhèn)€數(shù)的時候,就自動刪除最老的數(shù)據(jù)}}
LFU(Least Frequently Used):最近最少頻率使用
會統(tǒng)計每個key的訪問頻率,值越小淘汰優(yōu)先級越高。
Redis的數(shù)據(jù)淘汰策略有哪些 ?- 以下回答背熟,大概用時1min。
redis有個策略叫數(shù)據(jù)淘汰策略,具體指的是當(dāng)Redis中的內(nèi)存不夠用時,此時在向Redis中添加新的key,那么Redis就會按照某一種規(guī)則將內(nèi)存中的數(shù)據(jù)刪除掉。這個策略redis提供了8種方案,默認(rèn)的叫noeviction,就是不刪除任何數(shù)據(jù),內(nèi)部不足直接報錯。方案的切換是可以在redis的配置文件中進(jìn)行設(shè)置的,里面有兩個非常重要的概念,一個是LRU,另外一個是LFU。
LRU,即Least Recently Used,意思就是最近最少使用,我們用當(dāng)前時間減去最后一次訪問時間,這個值越大則淘汰優(yōu)先級越高。
LFU,即Least Frequently Used,意思就是最近最少頻率使用。我們會統(tǒng)計每個key的訪問頻率,值越小淘汰優(yōu)先級越高。
Redis事務(wù)
- redis提供了一種命令,可以將多個命令打包一起后按順序執(zhí)行,執(zhí)行途中不會被影響
- MULTI(開始事務(wù)),EXEC(執(zhí)行事務(wù))直接包著命令集
不能保證原子性。可以這么說,是一種比較弱的事務(wù)。原子性就是要么都成功,要么都失敗,對應(yīng)到redis中,批量命令執(zhí)行時候,假如中間出錯了,前面執(zhí)行過的無法回滾
Redis為什么要用分布式緩存
Redis集群
https://segmentfault.com/a/1190000043133394
主從模式 - 最簡單的
這里是引用
Redis主從復(fù)制優(yōu)點(diǎn): 做到讀寫分離,提高服務(wù)器性能;
Redis主從復(fù)制缺點(diǎn): 在主從模式中,一旦Master節(jié)點(diǎn)由于故障不能提供服務(wù),需要人工將Slave節(jié)點(diǎn)晉升為Master節(jié)點(diǎn)
哨兵模式
當(dāng)主服務(wù)器宕機(jī)后,需要手動把一臺從服務(wù)器切換為主服務(wù)器,需要人工干預(yù)費(fèi)事費(fèi)力,為了解決這個問題出現(xiàn)了哨兵模式
哨兵模式優(yōu)點(diǎn):最大的優(yōu)點(diǎn)就是主從可以自動切換,系統(tǒng)更健壯,可用性更高;哨兵模式缺點(diǎn):最大的缺點(diǎn)就是還要多維護(hù)一套哨兵模式,實(shí)現(xiàn)起來也變的更加復(fù)雜增加維護(hù)成本;
Redis Cluster
主要是針對海量數(shù)據(jù)+高并發(fā)+高可用的海量數(shù)據(jù)場景,Redis集群模式的性能和高可用性均優(yōu)于哨兵模式。
Redis常見問題及解決方案
緩存擊穿
熱key在緩存中過期了,所以不在緩存中,會導(dǎo)致瞬時大量的請求直接打到了數(shù)據(jù)庫上,對數(shù)據(jù)庫造成了巨大的壓力,可能直接就被這么多請求弄宕機(jī)了。
解決方案:
- 永不過期(不推薦):設(shè)置熱點(diǎn)數(shù)據(jù)永不過期或者過期時間比較長。
- 提前預(yù)熱(推薦):針對熱點(diǎn)數(shù)據(jù)提前預(yù)熱,將其存入緩存中并設(shè)置合理的過期時間比如秒殺場景下的數(shù)據(jù)在秒殺結(jié)束之前不過期。
- 加鎖(看情況);:在緩存失效后,通過設(shè)置互斥鎖確保只有一個請求去查詢數(shù)據(jù)庫并更新緩存
緩存穿透
大量請求的 key 是不合理的,根本不存在于緩存中,也不存在于數(shù)據(jù)庫中 。導(dǎo)致這些請求直接到了數(shù)據(jù)庫上對數(shù)據(jù)庫造成了巨大的壓力,可能直接就被這么多請求弄宕機(jī)了。
解決方案:
- 首先做好參數(shù)校驗(yàn),不合法的參數(shù)請求直接拋出異常信息返回給客戶端
- 緩存無效 key,SET key value EX 10086 設(shè)置過期時間
- 布隆過濾器
- 接口限流,用戶或者 IP 對接口進(jìn)行限流,對于異常頻繁的訪問行為,還可以采取黑名單機(jī)制
緩存雪崩
緩存在同一時間大面積的失效,導(dǎo)致大量的請求都直接落到了數(shù)據(jù)庫上,對數(shù)據(jù)庫造成了巨大的壓力
解決方案:
- 針對 Redis 服務(wù)不可用的情況:
Redis 集群
多級緩存(本地緩存+Redis 緩存的二級緩存組合)- 針對大量緩存同時失效的情況
設(shè)置隨機(jī)失效時間
針對熱點(diǎn)數(shù)據(jù)提前預(yù)熱,并設(shè)置合理的時間
對于某些關(guān)鍵性和變化不頻繁的數(shù)據(jù),持久緩存永不過期
bigKey
一個 key 對應(yīng)的 value 所占用的內(nèi)存比較大,那這個 key 就可以看作是 bigkey.
- String 類型的 value 超過 1MB
- 復(fù)合類型(List、Hash、Set、Sorted Set 等)的 value 包含的元素超過 5000 個
產(chǎn)生原因:
- 設(shè)計不當(dāng)---- 使用string存儲較大文件的二進(jìn)制流
- 數(shù)據(jù)規(guī)模考慮不到位---- 使用集合類型沒有考慮到數(shù)據(jù)量的快速增長
帶來什么問題 — 阻塞
- 客戶端超時阻塞:redis是單線程的,操作大key時候耗時
如果解決
- bigkeys 命令去掃描(redis-cli -p 6379 --bigkeys -i 3 表示掃描過程中每次掃描后休息的時間間隔為 3 秒)
- 找到后,手動清理;用合適的數(shù)據(jù)結(jié)構(gòu)
熱Key
訪問頻率較高的Key。
會出現(xiàn)的問題
- 某個熱點(diǎn)數(shù)據(jù)訪問量暴增 占用大量的 CPU 和帶寬,影響redis的其他請求處理;嚴(yán)重情況下,導(dǎo)致宕機(jī)
如果查看
- 可以通過hotkeys 參數(shù)來查找
如果解決
- 讀寫分離:主節(jié)點(diǎn)處理寫請求,從節(jié)點(diǎn)處理讀請求。
- 使用 Redis Cluster:將熱點(diǎn)數(shù)據(jù)分散存儲在多個 Redis 節(jié)點(diǎn)上
- 二級緩存:hotkey 采用二級緩存的方式進(jìn)行處理,將 hotkey 存放一份到 JVM 本地內(nèi)存中(可以用 Caffeine)。
慢查詢命令
為什么會有慢
如何保障數(shù)據(jù)庫和緩存數(shù)據(jù)的一致性
就是通常討論的淘汰緩存和更新數(shù)據(jù)庫的順序怎么樣比較合適,下文是較好的方案:
延時雙刪
寫入庫的前后,都刪除緩存【redis.del(key)操作】
步驟
先刪除緩存 —> 再寫數(shù)據(jù)庫 —> 休眠 500 毫秒 —> 再次刪除緩存
缺點(diǎn):
最差的情況就是在超時時間內(nèi)數(shù)據(jù)存在不一 致,而且又增加了寫請求的耗時。
異步更新緩存
MySQL binlog 增量訂閱消費(fèi)+消息隊列+增量數(shù)據(jù)更新到 redis
步驟
假如 Redis 里面有 1 億個 key,其中有 10w 個 key 是以某個固定的已知的前綴開頭的,如果將它們?nèi)空页鰜?#xff1f;
keys 命令和 scan 命令,使用 scan 更好
什么情況下可能會導(dǎo)致 Redis 阻塞
Redis 主機(jī)的 CPU 負(fù)載過高;
數(shù)據(jù)持久化占用資源過多;
使用Redis時 API 或 指令不合理
怎么提高緩存命中率
怎么實(shí)現(xiàn)分布式鎖
分布式點(diǎn)這里
MongDB
分布式文件儲存的數(shù)據(jù)庫
- 存儲數(shù)據(jù):數(shù)據(jù)庫中存儲的對象設(shè)計BSON,一種類似json的二進(jìn)制文件,由鍵值對組成
- 鏈接方式(默認(rèn)為27017)
mongodb://[username:password@]host1[:port1][,host2[:port2]- 庫簡單認(rèn)識
文檔 - row
集合 - table
數(shù)據(jù)庫 - database- 復(fù)制工作
MongoDB的復(fù)制工作是基于主從復(fù)制實(shí)現(xiàn)的。其中一個節(jié)點(diǎn)被定義為主節(jié)點(diǎn),其他的節(jié)點(diǎn)被定義為備份節(jié)點(diǎn),數(shù)據(jù)會進(jìn)行實(shí)時同步。在某些情況下,主節(jié)點(diǎn)可能會失效或消失,這時候從節(jié)點(diǎn)將被提升為主節(jié)點(diǎn)繼續(xù)工作。- 支持存儲過程嗎
支持,它是javascript寫的,保存在db.system.js表中。