企業(yè)緩存產(chǎn)品介紹
Memcached
優(yōu)點(diǎn):高性能讀寫啡氢、單一數(shù)據(jù)類型、支持客戶端式分布式集群掰曾、一致性hash旭蠕、多核結(jié)構(gòu)、多線程讀寫性能高
缺點(diǎn):無(wú)持久化旷坦、節(jié)點(diǎn)故障可能出現(xiàn)緩存穿透掏熬、分布式需要客戶端實(shí)現(xiàn)、跨機(jī)房數(shù)據(jù)同步困難塞蹭、架構(gòu)擴(kuò)容復(fù)雜度高
Redis
優(yōu)點(diǎn):高性能讀寫孽江、多數(shù)據(jù)類型支持、數(shù)據(jù)持久化番电、高可用架構(gòu)岗屏、支持自定義虛擬內(nèi)存辆琅、支持分布式分片集群、單線程讀寫性能極高
缺點(diǎn):多線程讀寫較Memcached慢
結(jié)論
Memcached適合多用戶訪問这刷,每個(gè)用戶少量的rw
Redis適合婉烟,少用戶訪問,每個(gè)用戶大量的rw
安裝和部署
Redis下載地址暇屋,一般使用3.x版本
Redis持久化(內(nèi)存數(shù)據(jù)保存到磁盤)
介紹
兩種持久化方式:RDB似袁、AOF
RDB持久化:
- 可以在制定的時(shí)間間隔內(nèi)生成數(shù)據(jù)集的時(shí)間點(diǎn)快照(point-in-time snapshot),新快照會(huì)覆蓋老快照
- 優(yōu)點(diǎn):速度快咐刨,適合做備份昙衅,主從復(fù)制也是基于RDB持久化功能實(shí)現(xiàn)的
- 缺點(diǎn):會(huì)有數(shù)據(jù)丟失
AOF持久化(Append-only log file)
- 記錄服務(wù)器執(zhí)行的所有寫操作命令,并在服務(wù)器啟動(dòng)時(shí)定鸟,通過重新執(zhí)行這些命令來還原數(shù)據(jù)集
- AOF文件中的命令全部以Redis協(xié)議的格式來保存而涉,新命令會(huì)被追加到文件的末尾
- 優(yōu)點(diǎn):可以最大程度保證數(shù)據(jù)不丟
- 缺點(diǎn):日志記錄量級(jí)比較大
持久化觸發(fā)方式比較
save和bgsave的區(qū)別
- 共同點(diǎn):都能實(shí)現(xiàn)RDB持久化功能
- 不同點(diǎn):
- SAVE:前臺(tái)使用,會(huì)阻塞redis正常寫入联予,直到持久化完成
- BGSAVE:后臺(tái)使用啼县,開啟子線程,異步的持久化功能沸久,不會(huì)阻塞redis正常寫入
配置持久化
RDB持久化配置:
$> vim ?/redis.conf
dir /data/...
dbfilename dump.rdb
save 900 1
save 300 10
save 60 10000
AOF持久化配置
$> vim ?/redis.conf
dir /data/...
dbfilename dump.rdb
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync always
appendfsync everysec
Redis 持久化磁盤 IO 方式及其帶來的問題
有 Redis 線上運(yùn)維經(jīng)驗(yàn)的人會(huì)發(fā)現(xiàn) Redis 在物理內(nèi)存使用比較多季眷,但還沒有超過實(shí)際物理內(nèi)存總?cè)萘繒r(shí)就會(huì)發(fā)生不穩(wěn)定甚至崩潰的問題,有人認(rèn)為是基于快照方式持久化的 fork 系統(tǒng)調(diào)用造成內(nèi)存占用加倍而導(dǎo)致的卷胯,這種觀點(diǎn)是不準(zhǔn)確的子刮,因?yàn)?fork 調(diào)用的 copy-on-write 機(jī)制是基于操作系統(tǒng)頁(yè)這個(gè)單位的,也就是只有有寫入的臟頁(yè)會(huì)被復(fù)制窑睁,但是一般你的系統(tǒng)不會(huì)在短時(shí)間內(nèi)所有的頁(yè)都發(fā)生了寫入而導(dǎo)致復(fù)制话告,那是什么原因?qū)е?Redis 崩潰呢?
答案是 Redis 的持久化使用了 Buffer IO 造成的卵慰,所謂 Buffer IO 是指 Redis 對(duì)持久化文件的寫入和讀取操作都會(huì)使用物理內(nèi)存的 Page Cache沙郭,而大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)會(huì)使用 Direct IO 來繞過這層 Page Cache 并自行維護(hù)一個(gè)數(shù)據(jù)的 Cache,而當(dāng) Redis 的持久化文件過大(尤其是快照文件)裳朋,并對(duì)其進(jìn)行讀寫時(shí)病线,磁盤文件中的數(shù)據(jù)都會(huì)被加載到物理內(nèi) 存中作為操作系統(tǒng)對(duì)該文件的一層 Cache,而這層 Cache 的數(shù)據(jù)與 Redis 內(nèi)存中管理的數(shù)據(jù)實(shí)際是重復(fù)存儲(chǔ)的鲤嫡,雖然內(nèi)核在物理內(nèi)存緊張時(shí)會(huì)做 Page Cache 的剔除工作送挑,但內(nèi)核很可能認(rèn)為某塊 Page Cache 更重要,而讓你的進(jìn)程開始 Swap暖眼,這時(shí)你的系統(tǒng)就會(huì)開始出現(xiàn)不穩(wěn)定或者崩潰了惕耕。我們的經(jīng)驗(yàn)是當(dāng)你的 Redis 物理內(nèi)存使用超過內(nèi)存總?cè)萘康?3/5 時(shí)就會(huì)開始比較危險(xiǎn)了。
Redis數(shù)據(jù)類型(多數(shù)據(jù)類型支持)
介紹
Memcached:只有鍵值對(duì)的方式(key: value)
Redis:
- string: 字符串
- hash: 字典
- list: 列表
- set: 集合
- sortset: 有序集合
數(shù)據(jù)類型存儲(chǔ)結(jié)構(gòu)
數(shù)據(jù)類型 | 名字 | Key | Value |
---|---|---|---|
string | 字符串 | name | zhangsan |
hash | 字典 | stu_1 | id:101 name:zhangsan |
list | 列表 | [day10, day9..., day1] | |
set | 集合 | seta | (張三, 李四, ...)->有下標(biāo)索引 |
sortset | 有續(xù)集合 | ssa | (張三, 李四, ...)->有下標(biāo)索引诫肠,自排序 |
數(shù)據(jù)的應(yīng)用場(chǎng)景
- string 字符串類型
- 特點(diǎn):Key: Value
- 應(yīng)用場(chǎng)景:會(huì)話緩存司澎、計(jì)數(shù)器
- hash 字典類型
- 特點(diǎn):Key: Value
- value也是鍵值對(duì)的形式欺缘,
stu_1|id:101 name:zhangsan
- value也是鍵值對(duì)的形式欺缘,
- 應(yīng)用場(chǎng)景:數(shù)據(jù)庫(kù)緩存
- 數(shù)據(jù)庫(kù)緩存的手工模擬:
- MySQL中拼接
hmset
語(yǔ)句 - 將數(shù)據(jù)導(dǎo)入redis
- 檢查數(shù)據(jù)
- MySQL中拼接
- 特點(diǎn):Key: Value
- list 類表類型
- 特點(diǎn):Key: Value
- value是一個(gè)反向列表:
[day10, day9..., day1]
- 是一個(gè)反向列表,每一個(gè)值都有自己的下標(biāo)索引
- 實(shí)現(xiàn)為一個(gè)雙向鏈表挤安,即可以支持反向查找和遍歷谚殊,更方便操作,不過帶來了部分額外的內(nèi)存開銷
- value是一個(gè)反向列表:
- 應(yīng)用場(chǎng)景:微信朋友圈的即時(shí)消息展示
- 特點(diǎn):Key: Value
- set 集合類型
- 特點(diǎn):Key: Value
- 當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù)蛤铜,又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí)嫩絮,set是一個(gè)很好的選擇,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口围肥,這個(gè)也是list所不能提供的剿干。可以基于 set 輕易實(shí)現(xiàn)交集
SINTER
穆刻、并集SUNION
怨愤、差集SDIFF
的操作
- 當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù)蛤铜,又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí)嫩絮,set是一個(gè)很好的選擇,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口围肥,這個(gè)也是list所不能提供的剿干。可以基于 set 輕易實(shí)現(xiàn)交集
- 應(yīng)用場(chǎng)景:好友系統(tǒng)(共同好友)
- 特點(diǎn):Key: Value
- sortset/zset 有續(xù)集合
- 特點(diǎn):Key: Value
- 應(yīng)用場(chǎng)景:排行榜
Redis消息模式
介紹
一種架構(gòu)設(shè)計(jì)理念,幫助解決在架構(gòu)中蛹批,資源有效利用方面提供有效的協(xié)調(diào)。
redis的消息模式有兩種:消息隊(duì)列篮愉、發(fā)布訂閱
發(fā)布訂閱
publisher 發(fā)布者:PUBLISH
channel 頻道
subscriber 訂閱者:SUBSCRIBE
Redis 事務(wù)
Redis事務(wù)和MySQL事務(wù)的區(qū)別:
- Redis的事務(wù)是基于隊(duì)列實(shí)現(xiàn)的腐芍,redis是樂觀鎖機(jī)制,僅實(shí)現(xiàn)了原子性的保證试躏,屬于弱事務(wù)支持
- MySQL的事務(wù)是基于事務(wù)日志和悲觀鎖機(jī)制猪勇、MVCC、ISOLASTION等機(jī)制一起保證颠蕴,強(qiáng)事務(wù)支持
底層工作原理:
- Redis事務(wù)是執(zhí)行語(yǔ)句通過隊(duì)列挨個(gè)執(zhí)行泣刹,最終通過
EXEC
命令傳入內(nèi)存中- Redis多個(gè)事務(wù)可以同時(shí)修改某一個(gè)值,這是沒有關(guān)系的犀被,因?yàn)橹灰獩]有執(zhí)行
EXEC
命令椅您,事務(wù)對(duì)值的修改就都沒有寫入到內(nèi)存中。多個(gè)事務(wù)根據(jù)EXEC
命令執(zhí)行的先后順序寡键,先后將自己隊(duì)列中的操作寫入內(nèi)存中掀泳。
- Redis多個(gè)事務(wù)可以同時(shí)修改某一個(gè)值,這是沒有關(guān)系的犀被,因?yàn)橹灰獩]有執(zhí)行
- MySQL事務(wù)執(zhí)行過程分為:
為避免Redis中多個(gè)事務(wù)同時(shí)修改一個(gè)鍵值對(duì)的值,造成業(yè)務(wù)邏輯混亂西轩,使用WATCH
命令:
WATCH
命令:
- 在事務(wù)開始前员舵,監(jiān)控事物中想要操作的鍵值對(duì)的名
- 如果在提交時(shí),發(fā)現(xiàn)這個(gè)鍵值對(duì)被修改過藕畔,那么提交會(huì)失敗
- 變相的保證了事務(wù)的隔離性马僻、數(shù)據(jù)的一致性
Key的通用操作
命令 | 作用 | 示例 |
---|---|---|
KEYS |
查看已存在的鍵的名字 | KEYS *, KEYS a, KEYS a* |
TYPE |
返回鍵所存儲(chǔ)值的類型 | TYPE a |
EXPIRE/PEXPIRE |
以秒/毫秒設(shè)定生存時(shí)間 | EXPIRE test 100 |
TTL/PTTL |
以秒/毫秒為單位返回生存時(shí)間 | TTL test |
PEPRSIST |
取消生存時(shí)間設(shè)置 | PEPRSIST test |
DEL |
刪除一個(gè)key
|
DEL test |
EXISTS |
檢查是否存在,0-不存在 | EXISTS test |
RENAME |
變更key 的名字 |
RENAME test a |
INFO |
查看數(shù)據(jù)庫(kù)信息 |
info memory ->監(jiān)控內(nèi)存, info cpu ->監(jiān)控cpu, info replication -監(jiān)控主從 |
Client list |
查看正在連接的會(huì)話 | |
Client kill ip:port |
關(guān)閉連接 | |
CONFIG GET * |
查看數(shù)據(jù)庫(kù)信息 | |
CONFIG RESETSTAT |
重修統(tǒng)計(jì) | |
CONFIG GET/SET/REWRITE |
動(dòng)態(tài)修改 | |
DBSIZE |
返回當(dāng)前鍵值對(duì)數(shù)量 | |
FLUSHALL |
清空所有的鍵值對(duì)->全局 | |
SELECT |
進(jìn)入庫(kù)注服,默認(rèn)0 | SELECT 0~15 |
FLUSHDB |
清空全部的鍵值對(duì)->庫(kù)級(jí)別 | Redis一共有16個(gè)庫(kù)韭邓,默認(rèn)使用0 |
MONITOR |
監(jiān)控實(shí)時(shí)指令 |
MONITOR >>/tmp/mom.log ->只監(jiān)控成功的操作 |
SHUTDOWN |
關(guān)閉服務(wù)器 | redis-cli -a root shutdown |
Redis主從復(fù)制
原理
- 副本庫(kù)通過
slaveof 10.0.0.51 6379
命令措近,連接主庫(kù),并發(fā)送SYNC
給主庫(kù) - 主庫(kù)收到
SYNC
仍秤,會(huì)立即觸發(fā)BGSAVE
熄诡,后臺(tái)保存RDB
,發(fā)送給副本庫(kù) - 副本庫(kù)接收后會(huì)應(yīng)用
RDB
快照 - 主庫(kù)會(huì)陸續(xù)將中間產(chǎn)生的新的操作诗力,保存并發(fā)送給副本庫(kù)
- 到此凰浮,主復(fù)制集就正常工作了
- 以后,主庫(kù)只要發(fā)生新的操作苇本,都會(huì)以命令傳播的的形式自動(dòng)發(fā)送給副本庫(kù)
- 所有復(fù)制相關(guān)信息袜茧,從info信息中都可以查到,即使重啟任何節(jié)點(diǎn)瓣窄,它的主從關(guān)系依然都在
- 如果發(fā)生主從關(guān)系斷開時(shí)笛厦,從庫(kù)數(shù)據(jù)沒有任何損壞,在下次重連之后俺夕,從庫(kù)發(fā)送
PSYNC
給主庫(kù) - 主庫(kù)只會(huì)將從庫(kù)缺失部分的數(shù)據(jù)同步給從庫(kù)應(yīng)用裳凸,達(dá)到快速恢復(fù)主從的目的
主從數(shù)據(jù)一致性保證
min-slaves-to-write 1
min-slaves-max-lag 3
主庫(kù)是否需要開啟持久化
如果不開,有可能主庫(kù)重啟操作劝贸,造成所有主從數(shù)據(jù)丟失姨谷。
實(shí)操
- 創(chuàng)建多個(gè)節(jié)點(diǎn)
- 開啟主從
- 查詢主從狀態(tài)
- 解除主從
redis-cli -p 6391 -a 123 SLAVEOF no one
Redis高可用:Sentinel
- 監(jiān)控
- 自動(dòng)選主,切換(
6381 slaveof no one
) - 2號(hào)從庫(kù)(6382)指向新主庫(kù)(6381)
- 應(yīng)用透明
- 自動(dòng)處理故障節(jié)點(diǎn)
Sentinel搭建過程
- 配置文件
> mkdir /data/26380
> cd /data/26380
> vim sentinel.conf
port 26380
dir "/data/26380"
sentinel monitor mymaster 127.0.0.1 6380 1 // 1 表示多sentinel情況下映九,判定閾值
sentinel down-after-milliseconds mymaster 5000 // 5000ms 之后沒有響應(yīng)梦湘,認(rèn)為宕機(jī)
sentinel auth-pass mymaster 123
-
啟動(dòng)
redis-sentinel /data/26380/sentinel.conf &>/tmp/sentinel.log &
-
如果存在問題
- 重新準(zhǔn)備1主2從環(huán)境
- kill掉sentinel進(jìn)程
- 刪除sentinel目錄下的所有文件
- 重新搭建sentinel
停主庫(kù)測(cè)試
啟動(dòng)源主庫(kù)(6380),查看狀態(tài)
Redis Cluster->Redis集群
介紹
- Redis數(shù)據(jù)存儲(chǔ)形式是key:value形式
- 將全部的數(shù)據(jù)件甥,均勻分布到slot中
- 一整套集群中捌议,slot總共16384個(gè),平均分配在各個(gè)分片節(jié)點(diǎn)上(一般為3組)
- slot編號(hào):0~16383
高性能
- 在多分片節(jié)點(diǎn)中引有,將16384個(gè)槽位瓣颅,均勻分布到多個(gè)分片節(jié)點(diǎn)中
- 存數(shù)據(jù)時(shí),將key做crc16(key)譬正,然后對(duì)16384取模弄捕,得出槽位值(0~16383)
- 根據(jù)計(jì)算得出的槽位值,找到相應(yīng)的分片節(jié)點(diǎn)的主節(jié)點(diǎn)导帝,存儲(chǔ)到相應(yīng)的槽位上
- 如果客戶端當(dāng)時(shí)連接的節(jié)點(diǎn)不是將來要存儲(chǔ)的分片節(jié)點(diǎn)守谓,分片集群會(huì)將客戶端連接切換到真正存儲(chǔ)節(jié)點(diǎn)進(jìn)行數(shù)據(jù)存儲(chǔ)
高可用
- 在搭建集群時(shí),會(huì)為每一個(gè)分片的主節(jié)點(diǎn)您单,對(duì)應(yīng)一個(gè)從節(jié)點(diǎn)
- 實(shí)現(xiàn)slaveof的功能斋荞,同時(shí)當(dāng)主節(jié)點(diǎn)down,實(shí)現(xiàn)類似于sentinel的自動(dòng)failover功能
- 如果有多臺(tái)物理機(jī)虐秦,最好將主從節(jié)點(diǎn)分布在不同主機(jī)上平酿,防止宕機(jī)
自動(dòng)轉(zhuǎn)向
- redis集群每一個(gè)分片節(jié)點(diǎn)上會(huì)存儲(chǔ)其余節(jié)點(diǎn)的分片信息
- 如果連接到一個(gè)分片節(jié)點(diǎn)凤优,但是想要的信息不再這個(gè)節(jié)點(diǎn)上,則會(huì)根據(jù)存儲(chǔ)的分片信息蜈彼,重新連上正確的分片節(jié)點(diǎn)
Redis如何將每一個(gè)鍵值對(duì)分配到唯一的slot中
對(duì)于一個(gè)key:value
鍵值對(duì):
root = crc16(key)%16384
0<=root<=16383
- root即為slot號(hào)碼
如何應(yīng)對(duì)hash碰撞筑辨?
分布式集群管理
添加分片節(jié)點(diǎn)
- 增加新的節(jié)點(diǎn)
- 添加主節(jié)點(diǎn)
- 轉(zhuǎn)移slot(重新分片)
- 添加一個(gè)從節(jié)點(diǎn)
刪除一個(gè)分片節(jié)點(diǎn)
刪除master節(jié)點(diǎn)之前,首先使用reshard移除master的全部slot幸逆,然后再刪除當(dāng)前節(jié)點(diǎn)
Redis一些概念
緩存穿透
概念: 緩存穿透是指緩存和數(shù)據(jù)庫(kù)中都沒有的數(shù)據(jù)棍辕,而用戶不斷發(fā)起請(qǐng)求,如發(fā)起為id為“-1”的數(shù)據(jù)或id為特別大不存在的數(shù)據(jù)还绘。這時(shí)的用戶很可能是攻擊者楚昭,攻擊會(huì)導(dǎo)致數(shù)據(jù)庫(kù)壓力過大。
解決方案:
- 采用布隆過濾器拍顷,使用一個(gè)足夠大的bitmap抚太,用于存儲(chǔ)可能訪問的key,不存在的key直接過濾掉
- 訪問key未在DB查詢到值昔案,也將空值寫進(jìn)緩存尿贫,但可以設(shè)置較短過期時(shí)間
- 接口層增加校驗(yàn),如用戶鑒權(quán)校驗(yàn)踏揣,id做基礎(chǔ)校驗(yàn)庆亡,id<=0的直接攔截
緩存雪崩
概念: 大量的key設(shè)置了相同的過期時(shí)間,導(dǎo)致緩存在同一時(shí)刻全部失效呼伸,造成瞬時(shí)DB請(qǐng)求量大、壓力驟增钝尸,引起雪崩括享。
解決方案: 可以給緩存設(shè)置過期時(shí)間時(shí)加上一個(gè)隨機(jī)值時(shí)間,使得每個(gè)key的過期時(shí)間分布開來珍促,不會(huì)集中在同一時(shí)刻失效铃辖。
緩存擊穿
概念: 一個(gè)存在的key,在緩存使其的一刻猪叙,同時(shí)有大量的請(qǐng)求娇斩,這些請(qǐng)求都會(huì)擊穿到DB,造成瞬時(shí)DB請(qǐng)求量大穴翩、壓力驟增犬第。
解決方案:
- 在訪問key之前,采用
SETNX(set if not exists)
來設(shè)置另一個(gè)短期key來鎖住當(dāng)前key的訪問芒帕,訪問結(jié)束再刪除該短期key - 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期