為什么使用Redis
-
高性能:
假如用戶第一次訪問數(shù)據(jù)庫中的某些數(shù)據(jù)壤圃。這個過程會比較慢,因為是從硬盤上讀取的琅轧。將該用戶訪問的數(shù)據(jù)存在數(shù)緩存中伍绳,這樣下一次再訪問這些數(shù)據(jù)的時候就可以直接從緩存中獲取了。操作緩存就是直接操作內(nèi)存乍桂,所以速度相當(dāng)快冲杀。如果數(shù)據(jù)庫中的對應(yīng)數(shù)據(jù)改變的之后,同步改變緩存中相應(yīng)的數(shù)據(jù)即可睹酌!
-
高并發(fā):
直接操作緩存能夠承受的請求是遠(yuǎn)遠(yuǎn)大于直接訪問數(shù)據(jù)庫的权谁,所以我們可以考慮把數(shù)據(jù)庫中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶的一部分請求會直接到緩存這里而不用經(jīng)過數(shù)據(jù)庫憋沿。
使用redis的好處旺芽?
速度快,因為數(shù)據(jù)存在內(nèi)存中卤妒,類似于HashMap甥绿,HashMap的優(yōu)勢就是查找和操作的時間復(fù)雜度都是O(1)
支持豐富數(shù)據(jù)類型,支持string则披,list共缕,set,sorted set士复,hash
支持事務(wù) :redis對事務(wù)是部分支持的图谷,如果是在入隊時報錯,那么都不會執(zhí)行阱洪;在非入隊時報錯便贵,那么成功的就會成功執(zhí)行。 redis監(jiān)控:鎖的介紹
豐富的特性:可用于緩存冗荸,消息承璃,按key設(shè)置過期時間,過期后將會自動刪除蚌本。
分布式緩存和本地緩存有啥區(qū)別盔粹?讓你自己設(shè)計本地緩存怎么設(shè)計隘梨?如何解決緩存過期問題?如何解決內(nèi)存溢出問題舷嗡?
分布式緩存和本地緩存的區(qū)別
分布式緩存一致性更好一點轴猎,本地緩存 每個實例都有自己的緩存,可能會存在不一致的情況进萄。
本地緩存會占用堆內(nèi)存捻脖,影響垃圾回收、影響系統(tǒng)性能中鼠。分布式緩存兩大開銷會導(dǎo)致其慢于本地緩存可婶,網(wǎng)絡(luò)延遲和對象序列化
進(jìn)程內(nèi)緩存適用于較小且頻率可見的訪問場景,尤其適用于不變對象援雇,對于較大且不可預(yù)見的訪問扰肌,最好采用分布式緩存。
如何解決緩存過期問題
緩存失效:
引起這個原因的主要因素是高并發(fā)下熊杨,我們一般設(shè)定一個緩存的過期時間時,可能有一些會設(shè)置5分鐘啊盗舰,10分鐘這些晶府;并發(fā)很高時可能會出在某一個時間同時生成了很多的緩存,并且過期時間在同一時刻钻趋,這個時候就可能引發(fā)——當(dāng)過期時間到后川陆,這些緩存同時失效,請求全部轉(zhuǎn)發(fā)到DB蛮位,DB可能會壓力過重较沪。
處理方法:
一個簡單方案就是將緩存失效時間分散開,不要所以緩存時間長度都設(shè)置成5分鐘或者10分鐘失仁;比如我們可以在原有的失效時間基礎(chǔ)上增加一個隨機(jī)值尸曼,比如1-5分鐘隨機(jī),這樣每一個緩存的過期時間的重復(fù)率就會降低萄焦,就很難引發(fā)集體失效的事件控轿。
緩存失效時產(chǎn)生的雪崩效應(yīng),將所有請求全部放在數(shù)據(jù)庫上拂封,這樣很容易就達(dá)到數(shù)據(jù)庫的瓶頸茬射,導(dǎo)致服務(wù)無法正常提供。盡量避免這種場景的發(fā)生冒签。
redis和memcached的區(qū)別
Redis和Memcache都是將數(shù)據(jù)存放在內(nèi)存中在抛,都是內(nèi)存數(shù)據(jù)庫。不過memcache還可用于緩存其他東西萧恕,例如圖片刚梭、視頻等等肠阱;
Memcached僅支持簡單的key-value結(jié)構(gòu)的數(shù)據(jù)記錄。Redis不僅僅支持簡單的k/v類型的數(shù)據(jù)望浩,同時還提供list辖所,set,hash等數(shù)據(jù)結(jié)構(gòu)的存儲磨德;
虛擬內(nèi)存--Redis當(dāng)物理內(nèi)存用完時缘回,可以將一些很久沒用到的value 交換到磁盤;
過期策略--memcache在set時就指定典挑,例如set key1 0 0 8,即永不過期酥宴。Redis可以通過例如expire 設(shè)定,例如expire name 10您觉;
分布式--設(shè)定memcache集群拙寡,利用magent做一主多從;redis可以做一主多從。都可以一主一從琳水;
存儲數(shù)據(jù)安全--memcache掛掉后肆糕,數(shù)據(jù)沒了;redis可以定期保存到磁盤(持久化)在孝;
災(zāi)難恢復(fù)--memcache掛掉后诚啃,數(shù)據(jù)不可恢復(fù); redis數(shù)據(jù)丟失后可以通過aof恢復(fù);
Redis支持?jǐn)?shù)據(jù)的備份私沮,即master-slave模式的數(shù)據(jù)備份始赎;
redis常用數(shù)據(jù)結(jié)構(gòu)和使用場景
-
String(字符串)
set 鍵 值 (設(shè)置鍵值對)
get 鍵 (根據(jù)鍵取值)
String結(jié)構(gòu)又存在3種類型,分別是字符串仔燕、數(shù)值造垛、bitmap。
使用場景:
字符串:分布式鎖
數(shù)值:在一些系統(tǒng)中看似不是很重要的統(tǒng)計晰搀,搶購五辽,秒殺,詳情頁中數(shù)據(jù)統(tǒng)計厕隧,點贊奔脐,評論等∮跆郑可以規(guī)避并發(fā)情況下對數(shù)據(jù)庫的事務(wù)操作髓迎,完全由redis內(nèi)存操作代替。
bitmap:用戶簽到建丧、在線用戶統(tǒng)計排龄、統(tǒng)計活躍用戶。
-
Hash(哈希)
hset 鍵 字段 值
hmset 鍵 字段1 值1 字段2 值2 字段3 值3 字段n 值n
hger 鍵 字段
hmget 鍵 字段1 字段2 字段3 字段n
-
hgetall 鍵
容量:每個hash可以存儲4294967295個鍵值對(2的32次方-1)
使用場景:點贊、收藏橄维、詳情頁等
-
Set(集合)
sadd 鍵 值1 值2 值3 值n
smembers 鍵
使用場景:
關(guān)注集合:共同關(guān)注尺铣、二度好友
點贊集合
抽獎集合
用戶標(biāo)簽
-
List(列表)
lpush 鍵 值1 值2 值3 值n
-
lrange 鍵 開始下標(biāo) 結(jié)束下標(biāo)
容量:每個hash可以存儲4294967295個鍵值對(2的32次方-1)
使用場景:
棧
隊列,比如:關(guān)注隊列、粉絲隊列
消息隊列
-
Zset(Sorted Set: 有序集合)
zadd 鍵 分?jǐn)?shù)1 值1 分?jǐn)?shù)2 值2 分?jǐn)?shù)n 值n
zrange 鍵 開始下標(biāo) 結(jié)束下標(biāo)
zrangebyscore 鍵 開始分值 結(jié)束分值
使用場景:
排行榜
時間軸
優(yōu)先級隊列
Zset底層實現(xiàn)争舞?跳表搜索插入刪除過程凛忿?
zset的編碼有ziplist和skiplist兩種。 底層分別使用ziplist(壓縮鏈表)和skiplist(跳表)實現(xiàn)竞川。
當(dāng)zset滿足以下兩個條件的時候店溢,使用ziplist:
- 保存的元素少于128個
- 保存的所有元素大小都小于64字節(jié)
不滿足這兩個條件則使用skiplist (注意:這兩個數(shù)值是可以通過redis.conf
的zset-max-ziplist-entries
和 zset-max-ziplist-value
選項 進(jìn)行修改。)
-
ziplist編碼
ziplist 編碼的有序集合對象使用壓縮列表作為底層實現(xiàn)委乌,每個集合元素使用兩個緊挨在一起的壓縮列表節(jié)點來保存床牧,第一個節(jié)點保存元素的成員,第二個節(jié)點保存元素的分值遭贸。并且壓縮列表內(nèi)的集合元素按分值從小到大的順序進(jìn)行排列戈咳,小的放置在靠近表頭的位置,大的放置在靠近表尾的位置壕吹。
-
skiplist編碼
skiplist 編碼的有序集合對象使用 zet 結(jié)構(gòu)作為底層實現(xiàn)著蛙,一個 zset 結(jié)構(gòu)同時包含一個字典和一個跳表:
字典的鍵保存元素的值,字典的值則保存元素的分值耳贬;跳躍表節(jié)點的 object 屬性保存元素的成員册踩,跳躍表節(jié)點的 score 屬性保存元素的分值。
這兩種數(shù)據(jù)結(jié)構(gòu)會通過指針來共享相同元素的成員和分值效拭,所以不會產(chǎn)生重復(fù)成員和分值,造成內(nèi)存的浪費胖秒。
注意:單獨使用字典缎患,時間復(fù)雜度很低(O(1)),但字典是以無序的方式保存集合元素的阎肝,需要重新進(jìn)行排序挤渔;單獨使用跳表,雖然能執(zhí)行范圍操作风题,但是查找操作從O(1)的復(fù)雜度變?yōu)榱薕(logN)判导。所以使用兩種數(shù)據(jù)結(jié)構(gòu)共同實現(xiàn)
redis過期淘汰策略
淘汰策略
定期刪除+惰性刪除
所謂定期刪除,指的是redis默認(rèn)是每隔100ms就隨機(jī)抽取一些設(shè)置了過期時間的key沛硅,檢查其是否過期眼刃,如果過期就刪除。(注意:是隨機(jī))
但是摇肌,定期刪除可能會導(dǎo)致很多過期key到了時間并沒有被刪除掉擂红,所以就得靠惰性刪除了。
惰性刪除就是在你獲取某個key的時候围小,redis會檢查一下 昵骤,這個key如果設(shè)置了過期時間那么是否過期了树碱?如果過期了此時就會刪除,不會給你返回任何東西变秦。并不是key到時間就被刪除掉成榜,而是你查詢這個key的時候,redis再懶惰的檢查一下
通過上述兩種手段結(jié)合起來蹦玫,保證過期的key一定會被淘汰
內(nèi)存淘汰機(jī)制
如果redis的內(nèi)存占用過多的時候赎婚,此時會進(jìn)行內(nèi)存淘汰,有如下一些策略:
noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時钳垮,新寫入操作會報錯(一般沒人用)
allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時惑淳,在鍵空間中,移除最近最少使用的key(這個是最常用的)
allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時饺窿,在鍵空間中歧焦,隨機(jī)移除某個key(一般沒人用)
volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中肚医,移除最近最少使用的key(這個一般不太合適)
volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時绢馍,在設(shè)置了過期時間的鍵空間中,隨機(jī)移除某個key
volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時肠套,在設(shè)置了過期時間的鍵空間中舰涌,有更早過期時間的key優(yōu)先移除
redis持久化機(jī)制?都有什么優(yōu)缺點你稚?持久化的時候還能接受請求嗎瓷耙?
RDB機(jī)制和AOF機(jī)制
RDB:
RDB其實就是把數(shù)據(jù)以快照的形式保存在磁盤上。什么是快照呢刁赖,你可以理解成把當(dāng)前時刻的數(shù)據(jù)拍成一張照片保存下來搁痛。
RDB持久化是指在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤。也是默認(rèn)的持久化方式宇弛,這種方式是就是將內(nèi)存中數(shù)據(jù)以快照的方式寫入到二進(jìn)制文件中,默認(rèn)的文件名為dump.rdb鸡典。
觸發(fā)機(jī)制
-
save觸發(fā)方式(同步)
該命令會阻塞當(dāng)前Redis服務(wù)器,執(zhí)行save命令期間枪芒,Redis不能處理其他命令彻况,直到RDB過程完成為止。執(zhí)行完成時候如果存在老的RDB文件舅踪,就把新的替代掉舊的纽甘。我們的客戶端可能都是幾萬或者是幾十萬,這種方式顯然不可取抽碌。
-
bgsave觸發(fā)方式(異步)
執(zhí)行該命令時贷腕,Redis會在后臺異步進(jìn)行快照操作,快照同時還可以響應(yīng)客戶端請求。
具體操作是Redis進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程泽裳,RDB持久化過程由子進(jìn)程負(fù)責(zé)瞒斩,完成后自動結(jié)束。阻塞只發(fā)生在fork階段涮总,一般時間很短胸囱。基本上 Redis 內(nèi)部所有的RDB操作都是采用 bgsave 命令瀑梗。
-
自動觸發(fā)
自動觸發(fā)是由我們的配置文件來完成的烹笔。
RDB 的優(yōu)勢和劣勢
①優(yōu)勢
(1)RDB文件緊湊,全量備份抛丽,非常適合用于進(jìn)行備份和災(zāi)難恢復(fù)谤职。
(2)生成RDB文件的時候,redis主進(jìn)程會fork()一個子進(jìn)程來處理所有保存工作亿鲜,主進(jìn)程不需要進(jìn)行任何磁盤IO操作允蜈。
(3)RDB 在恢復(fù)大數(shù)據(jù)集時的速度比 AOF 的恢復(fù)速度要快。
②劣勢
RDB快照是一次全量備份蒿柳,存儲的是內(nèi)存數(shù)據(jù)的二進(jìn)制序列化形式饶套,存儲上非常緊湊。當(dāng)進(jìn)行快照持久化時垒探,會開啟一個子進(jìn)程專門負(fù)責(zé)快照持久化妓蛮,子進(jìn)程會擁有父進(jìn)程的內(nèi)存數(shù)據(jù),父進(jìn)程修改內(nèi)存子進(jìn)程不會反應(yīng)出來圾叼,所以在快照持久化期間修改的數(shù)據(jù)不會被保存蛤克,可能丟失數(shù)據(jù)。
AOF:
全量備份總是耗時的夷蚊,有時候我們提供一種更加高效的方式AOF咖耘,工作機(jī)制很簡單,redis會將每一個收到的寫命令都通過write函數(shù)追加到文件中撬码。通俗的理解就是日志記錄。
AOF也有三種觸發(fā)機(jī)制
(1)每修改同步always:同步持久化 每次發(fā)生數(shù)據(jù)變更會被立即記錄到磁盤 性能較差但數(shù)據(jù)完整性比較好
(2)每秒同步everysec:異步操作版保,每秒記錄 如果一秒內(nèi)宕機(jī)呜笑,有數(shù)據(jù)丟失
(3)不同no:從不同步
AOF的優(yōu)缺點
優(yōu)點
(1)AOF可以更好的保護(hù)數(shù)據(jù)不丟失,一般AOF會每隔1秒彻犁,通過一個后臺線程執(zhí)行一次fsync操作叫胁,最多丟失1秒鐘的數(shù)據(jù)。(2)AOF日志文件沒有任何磁盤尋址的開銷汞幢,寫入性能非常高驼鹅,文件不容易破損。
(3)AOF日志文件即使過大的時候,出現(xiàn)后臺重寫操作输钩,也不會影響客戶端的讀寫豺型。
(4)AOF日志文件的命令通過非常可讀的方式進(jìn)行記錄买乃,這個特性非常適合做災(zāi)難性的誤刪除的緊急恢復(fù)姻氨。比如某人不小心用flushall命令清空了所有數(shù)據(jù),只要這個時候后臺rewrite還沒有發(fā)生剪验,那么就可以立即拷貝AOF文件肴焊,將最后一條flushall命令給刪了,然后再將該AOF文件放回去功戚,就可以通過恢復(fù)機(jī)制娶眷,自動恢復(fù)所有數(shù)據(jù)
缺點
(1)對于同一份數(shù)據(jù)來說,AOF日志文件通常比RDB數(shù)據(jù)快照文件更大
(2)AOF開啟后啸臀,支持的寫QPS會比RDB支持的寫QPS低届宠,因為AOF一般會配置成每秒fsync一次日志文件,當(dāng)然壳咕,每秒一次fsync席揽,性能也還是很高的
(3)以前AOF發(fā)生過bug,就是通過AOF記錄的日志谓厘,進(jìn)行數(shù)據(jù)恢復(fù)的時候幌羞,沒有恢復(fù)一模一樣的數(shù)據(jù)出來。
持久化的時候還能接受請求嗎竟稳?
RDB就是生成某個時間點快照属桦,有異步bgsave和同步save,同步的話肯定不能對外服務(wù)了他爸,異步是通過fork子進(jìn)程完成的聂宾,需要注意的是,在異步的時候诊笤,數(shù)據(jù)可能發(fā)生變化系谐,redis并不是直接復(fù)制一份進(jìn)行復(fù)制,redis運(yùn)用寫時復(fù)制cow思想讨跟,即一開始redis和子進(jìn)程都指向同一個數(shù)據(jù)纪他,當(dāng)某個key改變時redis主進(jìn)程指向新的,子進(jìn)程不變晾匠。
AOF也是同步不行茶袒,異步可以
redis事務(wù)
概念:
Redis 事務(wù)的本質(zhì)是一組命令的集合。事務(wù)支持一次執(zhí)行多個命令凉馆,一個事務(wù)中所有命令都會被序列化薪寓。在事務(wù)執(zhí)行過程亡资,會按照順序串行化執(zhí)行隊列中的命令,其他客戶端提交的命令請求不會插入到事務(wù)執(zhí)行命令序列中向叉。
總結(jié)說:redis事務(wù)就是一次性锥腻、順序性、排他性的執(zhí)行一個隊列中的一系列命令植康。
Redis事務(wù)沒有隔離級別的概念:
批量操作在發(fā)送 EXEC 命令前被放入隊列緩存旷太,并不會被實際執(zhí)行,也就不存在事務(wù)內(nèi)的查詢要看到事務(wù)里的更新销睁,事務(wù)外查詢不能看到供璧。
Redis事務(wù)不保證原子性:
Redis中,單條命令是原子性執(zhí)行的冻记,但事務(wù)不保證原子性睡毒,且沒有回滾。事務(wù)中任意命令執(zhí)行失敗冗栗,其余的命令仍會被執(zhí)行演顾。
Redis事務(wù)的三個階段:
開始事務(wù)
命令入隊
執(zhí)行事務(wù)
Redis事務(wù)相關(guān)命令:
watch key1 key2 ... : 監(jiān)視一或多個key,如果在事務(wù)執(zhí)行之前,被監(jiān)視的key被其他命令改動隅居,則事務(wù)被打斷 ( 類似樂觀鎖 )
multi : 標(biāo)記一個事務(wù)塊的開始( queued )
exec : 執(zhí)行所有事務(wù)塊的命令 ( 一旦執(zhí)行exec后钠至,之前加的監(jiān)控鎖都會被取消掉 )
discard : 取消事務(wù),放棄事務(wù)塊中的所有命令
unwatch : 取消watch對所有key的監(jiān)控
緩存雪崩和緩存穿透胎源,以及解決方法
-
緩存穿透
緩存穿透是指緩存和數(shù)據(jù)庫中沒有的數(shù)據(jù)棉钧,而用戶不斷發(fā)起請求,若發(fā)起 id為“-1”的數(shù)據(jù)或id為特別大而不存在的數(shù)據(jù)涕蚤,此時的用戶很可能是攻擊者宪卿,攻擊會導(dǎo)致數(shù)據(jù)庫壓力過大,而影響數(shù)據(jù)庫的性能
-
解決方案
接口層增加校驗万栅,如用戶鑒權(quán)校驗佑钾,id做基礎(chǔ)校驗,id<=0的直接攔截
從緩存取不到的數(shù)據(jù)烦粒,在數(shù)據(jù)庫中也沒有取到休溶,這時可以設(shè)置該id對應(yīng)的value為null,設(shè)置一定的有效時間扰她,可以防止攻擊用戶在一定時間內(nèi)反復(fù)使用同一id進(jìn)行暴力攻擊
-
緩存擊穿
緩存擊穿是指緩存中沒有但是數(shù)據(jù)庫中有的數(shù)據(jù)(一般是由于緩存時間到期銷毀)兽掰,這時由于并發(fā)用戶特別多,同時讀緩存沒有讀到數(shù)據(jù)义黎,又同時去數(shù)據(jù)庫中取數(shù)據(jù),使數(shù)據(jù)庫壓力瞬間增大豁跑,造成數(shù)據(jù)庫性能大幅度降低
-
解決方案
設(shè)置熱點數(shù)據(jù)永不過期
加互斥鎖
定時任務(wù)更新緩存數(shù)據(jù)
-
緩存雪崩
緩存雪崩是指緩存中數(shù)據(jù)大批量到過期時間廉涕,而查詢數(shù)量巨大泻云,引起數(shù)據(jù)庫壓力巨大甚至down機(jī)。和緩存擊穿不同的是狐蜕,緩存擊穿是指大量用戶并發(fā)查同一條數(shù)據(jù)宠纯,緩存雪崩是指大量不同數(shù)據(jù)都在同一時間過期了,大量用戶不能從緩存中得到這些數(shù)據(jù)层释,而進(jìn)入數(shù)據(jù)庫查詢
-
解決方案
緩存數(shù)據(jù)的過期時間設(shè)置為隨機(jī)婆瓜,防止大量數(shù)據(jù)在同一時間過期的現(xiàn)象出現(xiàn)
如果緩存數(shù)據(jù)庫是分布式部署,將熱點數(shù)據(jù)均勻分布在不同緩存數(shù)據(jù)庫中
設(shè)置熱點數(shù)據(jù)永不過期
如何保證緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性贡羔?
選擇淘汰緩存
原因:數(shù)據(jù)可能為簡單數(shù)據(jù)廉白,也可能為較復(fù)雜的數(shù)據(jù),復(fù)雜數(shù)據(jù)進(jìn)行緩存的更新操作乖寒,成本較高猴蹂,因此一般推薦淘汰緩存
方案:
先刪除緩存,后更新數(shù)據(jù)庫楣嘁。
更新的時候磅轻,先刪除緩存,然后再更新數(shù)據(jù)庫逐虚。
讀的時候聋溜,先讀緩存;如果沒有的話叭爱,就讀數(shù)據(jù)庫撮躁,同時將數(shù)據(jù)放入緩存,并返回響應(yīng)涤伐。
原因:因為即使后面更新數(shù)據(jù)庫失敗了馒胆,緩存是空的,讀的時候會從數(shù)據(jù)庫中重新拉凝果,雖然都是舊數(shù)據(jù)祝迂,但數(shù)據(jù)是一致的。
- 有如下場景:同時有一個請求A進(jìn)行更新操作器净,另一個請求B進(jìn)行查詢操作型雳。 (1)請求A進(jìn)行寫操作,刪除緩存 (2)請求B查詢發(fā)現(xiàn)緩存不存在 (3)請求B去數(shù)據(jù)庫查詢得到舊值 (4)請求B將舊值寫入緩存 (5)請求A將新值寫入數(shù)據(jù)庫
次數(shù)便出現(xiàn)了數(shù)據(jù)不一致問題山害。采用延時雙刪策略得以解決
- 數(shù)據(jù)庫讀寫分離的場景:
兩個請求纠俭,一個請求A進(jìn)行更新操作,另一個請求B進(jìn)行查詢操作浪慌。
(1)請求A進(jìn)行寫操作冤荆,刪除緩存 (2)請求A將數(shù)據(jù)寫入數(shù)據(jù)庫了, (3)請求B查詢緩存發(fā)現(xiàn)权纤,緩存沒有值 (4)請求B去從庫查詢钓简,這時乌妒,還沒有完成主從同步,因此查詢到的是舊值 (5)請求B將舊值寫入緩存 (6)數(shù)據(jù)庫完成主從同步外邓,從庫變?yōu)樾轮?/p>
依舊采用延時雙刪策略解決此問題
延時雙刪是將1秒內(nèi)所造成的緩存臟數(shù)據(jù)撤蚊,再次刪除。
redis是單線程還是多線程损话?為什么那么快侦啸?
Redis是單線程的
為什么快?
Redis完全基于內(nèi)存丧枪,絕大部分請求是純粹的內(nèi)存操作光涂,非常快速豪诲。數(shù)據(jù)存在內(nèi)存中顶捷,類似于HashMap,HashMap的優(yōu)勢就是查找和操作的時間復(fù)雜度都是O(1)
數(shù)據(jù)結(jié)構(gòu)簡單屎篱,對數(shù)據(jù)操作也簡單服赎,Redis中的數(shù)據(jù)結(jié)構(gòu)是專門進(jìn)行設(shè)計的;
使用多路I/O復(fù)用模型交播,非阻塞IO重虑;
采用單線程,避免了不必要的上下文切換和競爭條件秦士,也不存在多進(jìn)程或者多線程導(dǎo)致的切換而消耗 CPU缺厉,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作隧土,沒有因為可能出現(xiàn)死鎖而導(dǎo)致的性能消耗提针;
五種IO模型的區(qū)別
- 阻塞式IO
使用系統(tǒng)調(diào)用,并一直阻塞直到內(nèi)核將數(shù)據(jù)準(zhǔn)備好曹傀,之后再由內(nèi)核緩沖區(qū)復(fù)制到用戶態(tài)辐脖,在等待內(nèi)核準(zhǔn)備的這段時間什么也干不了
下圖函數(shù)調(diào)用期間,一直被阻塞皆愉,直到數(shù)據(jù)準(zhǔn)備好且從內(nèi)核復(fù)制到用戶程序才返回嗜价,這種IO模型為阻塞式IO
阻塞式IO式最流行的IO模型
- 非阻塞式IO
內(nèi)核在沒有準(zhǔn)備好數(shù)據(jù)的時候會返回錯誤碼,而調(diào)用程序不會休眠幕庐,而是不斷輪詢詢問內(nèi)核數(shù)據(jù)是否準(zhǔn)備好
下圖函數(shù)調(diào)用時久锥,如果數(shù)據(jù)沒有準(zhǔn)備好,不像阻塞式IO那樣一直被阻塞异剥,而是返回一個錯誤碼瑟由。數(shù)據(jù)準(zhǔn)備好時,函數(shù)成功返回冤寿。
應(yīng)用程序?qū)@樣一個非阻塞描述符循環(huán)調(diào)用成為輪詢歹苦。
非阻塞式IO的輪詢會耗費大量cpu绿鸣,通常在專門提供某一功能的系統(tǒng)中才會使用。通過為套接字的描述符屬性設(shè)置非阻塞式暂氯,可使用該功能
- IO多路復(fù)用
類似與非阻塞,只不過輪詢不是由用戶線程去執(zhí)行亮蛔,而是由內(nèi)核去輪詢痴施,內(nèi)核監(jiān)聽程序監(jiān)聽到數(shù)據(jù)準(zhǔn)備好后,調(diào)用內(nèi)核函數(shù)復(fù)制數(shù)據(jù)到用戶態(tài)
下圖中select這個系統(tǒng)調(diào)用究流,充當(dāng)代理類的角色辣吃,不斷輪詢注冊到它這里的所有需要IO的文件描述符芬探,有結(jié)果時,把結(jié)果告訴被代理的recvfrom函數(shù)偷仿,它本尊再親自出馬去拿數(shù)據(jù)
IO多路復(fù)用至少有兩次系統(tǒng)調(diào)用,如果只有一個代理對象酝静,性能上是不如前面的IO模型的,但是由于它可以同時監(jiān)聽很多套接字别智,所以性能比前兩者高
-
多路復(fù)用包括:
select:線性掃描所有監(jiān)聽的文件描述符,不管他們是不是活躍的薄榛。有最大數(shù)量限制(32位系統(tǒng)1024,64位系統(tǒng)2048)
poll:同select敞恋,不過數(shù)據(jù)結(jié)構(gòu)不同,需要分配一個pollfd結(jié)構(gòu)數(shù)組耳舅,維護(hù)在內(nèi)核中碌上。它沒有大小限制,不過需要很多復(fù)制操作
epoll:用于代替poll和select浦徊,沒有大小限制馏予。使用一個文件描述符管理多個文件描述符,使用紅黑樹存儲盔性。同時用事件驅(qū)動代替了輪詢霞丧。epoll_ctl中注冊的文件描述符在事件觸發(fā)的時候會通過回調(diào)機(jī)制激活該文件描述符。epoll_wait便會收到通知冕香。最后蛹尝,epoll還采用了mmap虛擬內(nèi)存映射技術(shù)減少用戶態(tài)和內(nèi)核態(tài)數(shù)據(jù)傳輸?shù)拈_銷
- 信號驅(qū)動式IO
使用信號后豫,內(nèi)核在數(shù)據(jù)準(zhǔn)備就緒時通過信號來進(jìn)行通知
首先開啟信號驅(qū)動io套接字,并使用sigaction系統(tǒng)調(diào)用來安裝信號處理程序突那,內(nèi)核直接返回挫酿,不會阻塞用戶態(tài)
數(shù)據(jù)準(zhǔn)備好時,內(nèi)核會發(fā)送SIGIO信號愕难,收到信號后開始進(jìn)行io操作
- 異步IO
異步IO依賴信號處理程序來進(jìn)行通知
不過異步IO與前面IO模型不同的是:前面的都是數(shù)據(jù)準(zhǔn)備階段的阻塞與非阻塞早龟,異步IO模型通知的是IO操作已經(jīng)完成,而不是數(shù)據(jù)準(zhǔn)備完成
異步IO才是真正的非阻塞猫缭,主進(jìn)程只負(fù)責(zé)做自己的事情葱弟,等IO操作完成(數(shù)據(jù)成功從內(nèi)核緩存區(qū)復(fù)制到應(yīng)用程序緩沖區(qū))時通過回調(diào)函數(shù)對數(shù)據(jù)進(jìn)行處理
unix中異步io函數(shù)以aio_或 lio打頭
各種IO模型對比
前面四種IO模型的主要區(qū)別在第一階段,他們第二階段是一樣的:數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到調(diào)用者緩沖區(qū)期間都被阻塞撞碌ぁ芝加!
前面四種IO都是同步IO:IO操作導(dǎo)致請求進(jìn)程阻塞,直到IO操作完成
異步IO:IO操作不導(dǎo)致請求進(jìn)程阻塞
select射窒、poll藏杖、epoll的區(qū)別?
-
支持一個線程所能打開的最大連接數(shù)
image -
FD劇增后帶來的IO效率問題
image.png
-
消息傳遞方式
image
綜上脉顿,在選擇select制市,poll,epoll時要根據(jù)具體的使用場合以及這三種方式的自身特點:
表面上看epoll的性能最好弊予,但是在連接數(shù)少并且連接都十分活躍的情況下祥楣,select和poll的性能可能比epoll好,畢竟epoll的通知機(jī)制需要很多函數(shù)回調(diào)汉柒。
select低效是因為每次它都需要輪詢误褪。但低效也是相對的兽间,視情況而定,也可通過良好的設(shè)計改善嘀略。
redis熱key問題帜羊?如何發(fā)現(xiàn)以及如何解決讼育?
熱點問題概述
熱點問題一般出現(xiàn)在讀多寫少的場景
在日常工作生活中一些突發(fā)的的事件奶段,諸如:“雙11”期間某些熱門商品的降價促銷痹籍,當(dāng)這其中的某一件商品被數(shù)萬次點擊、購買時刺洒,會形成一個較大的需求量,這種情況下就會產(chǎn)生一個單一的Key渔肩,這樣就會引起一個熱點拇惋;同理,當(dāng)被大量刊發(fā)蓉坎、瀏覽的熱點新聞蛉艾,熱點評論等也會產(chǎn)生熱點衷敌;另外缴罗,在服務(wù)端讀數(shù)據(jù)進(jìn)行訪問時面氓,往往會對數(shù)據(jù)進(jìn)行分片切分,此類過程中會在某一主機(jī)Server上對相應(yīng)的Key進(jìn)行訪問掘譬,當(dāng)訪問超過主機(jī)Server極限時屁药,就會導(dǎo)致熱點Key問題的產(chǎn)生酿箭。
當(dāng)某一熱點的Key在某一主機(jī)上超過該主機(jī)網(wǎng)卡上線時,由于流量的過度集中缔御,會導(dǎo)致服務(wù)器中其它服務(wù)無法進(jìn)行耕突。
此外评架,熱點Key的緩存過多纵诞,超過目前的緩存容量時浙芙,就會導(dǎo)致緩存分片服務(wù)被打垮現(xiàn)象的產(chǎn)生嗡呼。當(dāng)緩存服務(wù)崩潰后,此時再有請求產(chǎn)生揍很,會緩存到后臺DB上女轿,由于其本身性能較弱壕翩,在面臨大請求時很容易發(fā)生請求穿透現(xiàn)象放妈,會進(jìn)一步導(dǎo)致“雪崩”現(xiàn)象芜抒,嚴(yán)重影響設(shè)備的性能宅倒。
如何發(fā)現(xiàn)
對于db上熱點數(shù)據(jù)的發(fā)現(xiàn),首先會在一個周期內(nèi)對Key進(jìn)行請求統(tǒng)計疗绣,在達(dá)到請求量級后會對熱點Key進(jìn)行熱點定位多矮,并將所有的熱點Key放入一個小的LRU鏈表內(nèi)哈打,在通過Proxy請求進(jìn)行訪問時料仗,若Redis發(fā)現(xiàn)待訪點是一個熱點,就會進(jìn)入一個反饋階段格粪,同時對該數(shù)據(jù)進(jìn)行標(biāo)記肺孵。
如何解決
首先Client會將請求發(fā)送至Server上平窘,而Server又是一個多線程的服務(wù)瑰艘,本地就具有一個小的緩存空間紫新。當(dāng)Server本身就擁堵時芒率,Server不會將請求進(jìn)一步發(fā)送給DB而是直接返回偶芍,只有當(dāng)Server本身暢通時才會將Client請求發(fā)送至DB匪蟀,并且將該數(shù)據(jù)重新寫入到Cache中材彪。
https://blog.csdn.net/qq_35956041/article/details/81195826
redis數(shù)據(jù)分布方式段化?有什么優(yōu)點惩坑?一致性hash呢柑船?
分布方式:
-
節(jié)點取余
客戶端分片:哈希+取余
節(jié)點伸縮:數(shù)據(jù)節(jié)點關(guān)系變化,導(dǎo)致數(shù)據(jù)遷移
遷移數(shù)量和添加節(jié)點數(shù)量有關(guān):建議翻倍擴(kuò)容
-
一致性哈希
客戶端分片:哈希+順時針(優(yōu)化取余)
節(jié)點伸縮:只影響鄰近節(jié)點仔沿,但是還是有數(shù)據(jù)遷移
翻倍伸縮:保證最小遷移數(shù)據(jù)和負(fù)載均衡
-
虛擬槽分區(qū)
預(yù)設(shè)虛擬槽:每個槽映射一個數(shù)據(jù)子集封锉,一般比節(jié)點數(shù)大
良好的哈希函數(shù):例如CRC16
服務(wù)端管理節(jié)點成福、槽奴艾、數(shù)據(jù):例如Redis Cluster