1. 為什么Redis性能這么強(qiáng)
支持?jǐn)?shù)十萬的并發(fā)(32G可以Set操作達(dá)到30W的QPS, Get操作40W的QPS),pipline則更高x2
內(nèi)存存儲(chǔ):Redis是使用內(nèi)存(in-memeroy)存儲(chǔ),沒有磁盤IO上的開銷
單線程實(shí)現(xiàn):Redis使用單個(gè)線程處理請求,避免了多個(gè)線程之間線程切換和鎖資源爭用的開銷
非阻塞IO:Redis使用多路復(fù)用IO技術(shù),在poll,epolll,kqueue選擇最優(yōu)IO實(shí)現(xiàn)(參考netty篇章)
優(yōu)化的數(shù)據(jù)結(jié)構(gòu):Redis有諸多可以直接應(yīng)用的優(yōu)化數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),應(yīng)用層可以直接使用原生的數(shù)據(jù)結(jié)構(gòu)提升性能
2. 為什么用Redis
高性能:mysql數(shù)據(jù)存儲(chǔ)磁盤,訪問較慢。 redis存內(nèi)存,訪問快。50ms,10ms
大并發(fā):mysql并發(fā)能力有限(8C32G的mysql,8000的最大連接數(shù),可以達(dá)到3W的QPS,1.5K的TPS),在大并發(fā)情況下需要引入redis來緩沖數(shù)據(jù)訪問(4 50W的QPS),避免擊穿mysql。
3. Redis數(shù)據(jù)結(jié)構(gòu)
String
List
Hash
Set
Sorted Set
-
Bitmap
boomfilter
Redis為什么單線程
https://draveness.me/whys-the-design-redis-single-thread/
單線程模型,基于多路復(fù)用IO模型監(jiān)聽多個(gè)連接。
-
使用單線程模型能帶來更好的可維護(hù)性,方便開發(fā)和調(diào)試;
不需要引入鎖之類機(jī)制來控制同步。(比如變量被并發(fā)讀寫了,那么需要加鎖之類,不然訪問結(jié)果無法確定)
-
使用單線程模型也能并發(fā)的處理客戶端的請求;
多路復(fù)用IO也能同時(shí)監(jiān)聽多個(gè)FD,當(dāng)監(jiān)聽到有相關(guān)事件發(fā)生時(shí)就調(diào)用相應(yīng)的事件處理器進(jìn)行處理。https://draveness.me/redis-io-multiplexing/
-
Redis 服務(wù)中運(yùn)行的絕大多數(shù)操作的性能瓶頸都不是 CPU;
Redis 并不是 CPU 密集型的服務(wù),如果不開啟 AOF 備份,所有 Redis 的操作都會(huì)在內(nèi)存中完成不會(huì)涉及任何的 I/O 操作,這些數(shù)據(jù)的讀寫由于只發(fā)生在內(nèi)存中,所以處理速度是非??斓?。
整個(gè)服務(wù)的瓶頸在于網(wǎng)絡(luò)傳輸帶來的延遲和等待客戶端的數(shù)據(jù)傳輸,也就是網(wǎng)絡(luò) I/O。
在普通的linux上,redis也可以在1S內(nèi)處理100W的請求。 如果這種還不夠的話就做集群。
Redis引入多線程
redis4.0之后引入了一些命令,例如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC 等非阻塞的刪除操作,這些命令會(huì)使用主線程外的線程執(zhí)行。
刪除操作如果刪除的KV對占用比較小,那么同步也沒什么問題。但是如果是幾十幾百M(fèi)B的那么會(huì)消耗較多時(shí)間,不能在幾MS內(nèi)處理完,影響Redis的可用性。UNLINK命令將鍵從元數(shù)據(jù)中刪除,無法再被訪問到,真正的刪除操作會(huì)在后臺(tái)異步執(zhí)行。
Redis持久化機(jī)制
RDB 快照持久化
創(chuàng)建快照后獲得某個(gè)時(shí)間點(diǎn)上完整的數(shù)據(jù)副本,快照可以用來復(fù)制到其他Redis從服務(wù)器來創(chuàng)建相同數(shù)據(jù),或者用來重啟服務(wù)時(shí)候進(jìn)行恢復(fù)數(shù)據(jù)。
快照持久化是 Redis 默認(rèn)采用的持久化方式,在 Redis.conf 配置文件中默認(rèn)有此下配置:
save 900 1 #在900秒(15分鐘)之后,如果至少有1個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
save 300 10 #在300秒(5分鐘)之后,如果至少有10個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
save 60 10000 #在60秒(1分鐘)之后,如果至少有10000個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
AOF(append-only file)持久化
AOF模式實(shí)時(shí)性更強(qiáng),默認(rèn)沒有開啟,需要配置appendonly yes來開啟。每執(zhí)行一條修改數(shù)據(jù)的命令都會(huì)將命令寫入硬盤的AOF文件。
appendfsync always #每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫入AOF文件,這樣會(huì)嚴(yán)重降低Redis的速度
appendfsync everysec #每秒鐘同步一次,顯示地將多個(gè)寫命令同步到硬盤 推薦
appendfsync no #讓操作系統(tǒng)決定何時(shí)進(jìn)行同步
AOF重寫:
執(zhí)行BGREWRITEAOF會(huì)創(chuàng)建一個(gè)子進(jìn)程進(jìn)行AOF重寫,但是其實(shí)不會(huì)讀取當(dāng)前的AOF文件,是通過讀取現(xiàn)在數(shù)據(jù)庫中KV數(shù)據(jù)生成新的AOF文件。新的AOF文件體積更加小。
Redis事務(wù)
Redis 過期機(jī)制
Redis集群模式
Redis pipeline、script、mass insertion
Redis配置修改
config set 可以不重啟redis,實(shí)時(shí)生效配置
CONFIG SET protected-mode no
緩存相關(guān)
https://mp.weixin.qq.com/s/TBCEwLVAXdsTszRVpXhVug
https://segmentfault.com/a/1190000008931971
緩存穿透
指查詢不存在的數(shù)據(jù),緩存層沒有命中,導(dǎo)致每次都查詢數(shù)據(jù)庫層,使得緩存層失去了保護(hù)存儲(chǔ)層的意義,產(chǎn)生原因可能如下:
業(yè)務(wù)自身代碼或者數(shù)據(jù)出現(xiàn)問題
一些惡意攻擊、爬蟲等造成大量空命中
可以進(jìn)行分析統(tǒng)計(jì)方法調(diào)用次數(shù),緩存命中次數(shù),儲(chǔ)存層命中次數(shù),判斷是否出現(xiàn)了緩存穿透的情況。
解決方案1. 緩存空對象
在存儲(chǔ)層也返回空時(shí),把空對象也保存到緩存,這樣下次查詢就會(huì)命中緩存。
問題:占用更多存儲(chǔ)空間,而且如果是惡意攻擊則會(huì)更加嚴(yán)重。
解決:
- 添加一個(gè)較小的TTL ,使其自動(dòng)過期刪除
2. 空對象緩存放到另外單獨(dú)的一個(gè)緩存服務(wù),避免空間不夠回收時(shí)LRU算法剔除了正常的KV而沒有過期空對象
問題: 數(shù)據(jù)不一致,如果緩存了空對象,然后業(yè)務(wù)操作導(dǎo)致存儲(chǔ)層有把數(shù)據(jù)添加上了,那么在空對象緩存過期之前兩邊數(shù)據(jù)產(chǎn)生了不一致。
解決:
1. 如果是redis緩存,則更新數(shù)據(jù)后直接刪除緩存
- 如果是本地緩存,則需要引入消息中間件之類通知機(jī)制,通知?jiǎng)h除
解決方案2. 布隆過濾器
在訪問緩存層之前,先訪問布隆過濾器,如果miss,那就是不存在直接返回空對象。如果命中再繼續(xù)查詢緩存和存儲(chǔ)層。
boomfilter命中可能誤判,但是不命中必定是真的不命中。
缺點(diǎn):需要額外維護(hù)boomfilter,刪除數(shù)據(jù)時(shí)候需要重建,添加數(shù)據(jù)時(shí)候需要通知插入。如果是本地緩存構(gòu)建的boomfilter那也還需要引入消息通知機(jī)制。如果是使用redis bitmap實(shí)現(xiàn)的那還簡單點(diǎn)。
緩存雪崩
緩存正常起著承擔(dān)大量請求,保護(hù)存儲(chǔ)層的作用,但是由于某些情況導(dǎo)致緩存層無法提供服務(wù),那么所有請求到達(dá)了存儲(chǔ)層,導(dǎo)致存儲(chǔ)層掛掉宕機(jī)。
產(chǎn)生的原因:
- 緩存層服務(wù)可用性不高,重啟,或者網(wǎng)絡(luò)等各種故障導(dǎo)致一段時(shí)間內(nèi)無法提供服務(wù)
- 熱點(diǎn)key,大量緩存同時(shí)失效過期
解決:
- 針對可用性問題可以構(gòu)建集群+主備來提高可用性
- 大量緩存同時(shí)失效問題可以在存儲(chǔ)層讀寫時(shí)候進(jìn)行隊(duì)列,加鎖,信號(hào)量等控制并發(fā)數(shù)量。(hystrix對訪問進(jìn)行熔斷限流)
- 大量緩存同時(shí)失效問題也可以對key設(shè)置分散的過期時(shí)間
- 針對熱點(diǎn)key過期,可以設(shè)置永不過期,然后異步單獨(dú)的線程來更新重建熱點(diǎn)key數(shù)據(jù)
- 針對熱點(diǎn)key過期,也可以在過期重建數(shù)據(jù)時(shí)候加鎖,只允許一個(gè)線程進(jìn)行重建,其他線程進(jìn)行等待重建完成。分布式環(huán)境下可以用redis setnx鎖。