Redis常見數(shù)據(jù)結(jié)構(gòu)以及使用場景分別是什么?
4、有MySQL不就夠用了嗎?為什么要用Redis這種新的數(shù)據(jù)庫?
主要是因?yàn)?Redis 具備高性能和高并發(fā)兩種特性。
高性能:假如用戶第一次訪問數(shù)據(jù)庫中的某些數(shù)據(jù)。這個過程會比較慢,因?yàn)槭菑挠脖P上讀取的。將該用戶訪問的數(shù)據(jù)存在緩存中,這樣下一次再訪問這些數(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ù)庫。
5、C++中的Map也是一種緩存型數(shù)據(jù)結(jié)構(gòu),為什么不用Map,而選擇Redis做緩存?
嚴(yán)格意義上來說緩存分為本地緩存和分布式緩存。
那以 C++ 語言為例,我們可以使用 STL 下自帶的容器 map 來實(shí)現(xiàn)緩存,但只能實(shí)現(xiàn)本地緩存,它最主要的特點(diǎn)是輕量以及快速,但是其生命周期隨著程序的銷毀而結(jié)束,并且在多實(shí)例的情況下,每個實(shí)例都需要各自保存一份緩存,緩存不具有一致性。
使用 Redis 或 Memcached 之類的稱為分布式緩存,在多實(shí)例的情況下,各實(shí)例共享一份緩存數(shù)據(jù),緩存具有一致性。這是Redis或者M(jìn)emcached的優(yōu)點(diǎn)所在,但它也有缺點(diǎn),那就是需要保持 Redis 或 Memcached服務(wù)的高可用,整個程序架構(gòu)上較為復(fù)雜。
6、使用Redis的好處有哪些?
1、訪問速度快,因?yàn)閿?shù)據(jù)存在內(nèi)存中,類似于Java中的HashMap或者C++中的Map,這兩者的優(yōu)勢就是查找和操作的時間復(fù)雜度都是O(1)
2、數(shù)據(jù)類型豐富,支持String,list,set,sorted set,hash這五種數(shù)據(jù)結(jié)構(gòu)
3、支持事務(wù),Redis中的操作都是原子性,換句話說就是對數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行,這就是原子性的定義
4、特性豐富:Redis可用于緩存,消息,按key設(shè)置過期時間,過期后將會自動刪除。
7、Memcached與Redis的區(qū)別都有哪些?
1、存儲方式
Memecache把數(shù)據(jù)全部存在內(nèi)存之中,斷電后會掛掉,沒有持久化功能,數(shù)據(jù)不能超過內(nèi)存大小。Redis有部份存在硬盤上,這樣能保證數(shù)據(jù)的持久性。
2、數(shù)據(jù)支持類型
Memcache對數(shù)據(jù)類型支持相對簡單,只有String這一種類型Redis有復(fù)雜的數(shù)據(jù)類型。Redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還提供 list,set,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲。
3、使用底層模型不同
它們之間底層實(shí)現(xiàn)方式 以及與客戶端之間通信的應(yīng)用協(xié)議不一樣。Redis直接自己構(gòu)建了VM 機(jī)制 ,因?yàn)橐话愕南到y(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費(fèi)一定的時間去移動和請求。
4、集群模式:Memcached沒有原生的集群模式,需要依靠客戶端來實(shí)現(xiàn)往集群中分片寫入數(shù)據(jù);但是 Redis 目前 是原生支持 cluster 模式的.
5、Memcached是多線程,非阻塞IO復(fù)用的網(wǎng)絡(luò)模型;Redis使用單線程的多路 IO 復(fù)用模型。
6、Value 值大小不同:Redis 最大可以達(dá)到 512MB;Memcached 只有 1MB。
8、Redis比Memcached的優(yōu)勢在哪里?
1、Memcached所有的值均是簡單字符串,Redis作為其替代者,支持更為豐富的數(shù)據(jù)類型
2、Redis 的速度比 Memcached 快很多
3、Redis可以做到持久化數(shù)據(jù)
9、緩存中常說的熱點(diǎn)數(shù)據(jù)和冷數(shù)據(jù)是什么?
其實(shí)就是名字上的意思,熱數(shù)據(jù)就是訪問次數(shù)較多的數(shù)據(jù),冷數(shù)據(jù)就是訪問很少或者從不訪問的數(shù)據(jù)。
需要注意的是只有熱點(diǎn)數(shù)據(jù),緩存才有價值對于冷數(shù)據(jù)而言,大部分?jǐn)?shù)據(jù)可能還沒有再次訪問到就已經(jīng)被擠出內(nèi)存,不僅占用內(nèi)存,而且價值不大。
數(shù)據(jù)更新前至少讀取兩次,緩存才有意義。這個是最基本的策略,如果緩存還沒有起作用就失效了,那就沒有太大價值了。
10、Redis 為什么是單線程的而不采用多線程方案?
這主要是基于一種客觀原因來考慮的。因?yàn)镽edis是基于內(nèi)存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機(jī)器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬。既然單線程容易實(shí)現(xiàn),而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了(畢竟采用多線程會有很多麻煩!)
11、單線程的Redis為什么這么快?
主要是有三個原因:1、Redis的全部操作都是純內(nèi)存的操作;2、Redis采用單線程,有效避免了頻繁的上下文切換;3,采用了非阻塞I/O多路復(fù)用機(jī)制。
12、了解Redis的線程模型嗎?可以大致說說嗎?
如果你打開看過 Redis 的源碼就會發(fā)現(xiàn)Redis 內(nèi)部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,所以 Redis 才叫做單線程的模型。它采用 IO 多路復(fù)用機(jī)制同時監(jiān)聽多個 socket,根據(jù) socket 上的事件來選擇對應(yīng)的事件處理器進(jìn)行處理。
文件事件處理器的結(jié)構(gòu)包含 4 個部分:
多個 socketIO多路復(fù)用程序文件事件分派器事件處理器(連接應(yīng)答處理器、命令請求處理器、命令回復(fù)處理器)
使用 I/O 多路復(fù)用程序來同時監(jiān)聽多個套接字, 并根據(jù)套接字目前執(zhí)行的任務(wù)來為套接字關(guān)聯(lián)不同的事件處理器。當(dāng)被監(jiān)聽的套接字準(zhǔn)備好執(zhí)行連接應(yīng)答(accept)、讀取(read)、寫入(write)、關(guān)閉(close)等操作時, 與操作相對應(yīng)的文件事件就會產(chǎn)生, 這時文件事件處理器就會調(diào)用套接字之前關(guān)聯(lián)好的事件處理器來處理這些事件。
多個 socket 可能會并發(fā)產(chǎn)生不同的操作,每個操作對應(yīng)不同的文件事件,但是 IO 多路復(fù)用程序會監(jiān)聽多個 socket,會將 socket 產(chǎn)生的事件放入隊(duì)列中排隊(duì),事件分派器每次從隊(duì)列中取出一個事件,把該事件交給對應(yīng)的事件處理器進(jìn)行處理。
一句話總結(jié)就是:“I/O 多路復(fù)用程序負(fù)責(zé)監(jiān)聽多個套接字, 并向文件事件分派器傳送那些產(chǎn)生了事件的套接字!
13、Redis設(shè)置過期時間的兩種方案是什么?
Redis中有個設(shè)置時間過期的功能,即對存儲在 Redis 數(shù)據(jù)庫中的值可以設(shè)置一個過期時間。
作為一個緩存數(shù)據(jù)庫, 這是非常實(shí)用的,比如一些 token 或者登錄信息,尤其是短信驗(yàn)證碼都是有時間限制的,按照傳統(tǒng)的數(shù)據(jù)庫處理方式,一般都是自己判斷過期,這樣無疑會嚴(yán)重影響項(xiàng)目性能。
我們 set key 的時候,都可以給一個 expire time,就是過期時間,通過過期時間我們可以指定這個 key 可以存活的時間,主要可采用定期刪除和惰性刪除兩種方案。
定期刪除:Redis默認(rèn)是每隔 100ms 就隨機(jī)抽取一些設(shè)置了過期時間的key,檢查其是否過期,如果過期就刪 除。注意這里是隨機(jī)抽取的。為什么要隨機(jī)呢?你想一想假如 Redis 存了幾十萬個 key ,每隔100ms就遍歷所 有的設(shè)置過期時間的 key 的話,就會給 CPU 帶來很大的負(fù)載!惰性刪除 :定期刪除可能會導(dǎo)致很多過期 key 到了時間并沒有被刪除掉。所以就有了惰性刪除。它是指某個鍵值過期后,此鍵值不會馬上被刪除,而是等到下次被使用的時候,才會被檢查到過期,此時才能得到刪除,惰性刪除的缺點(diǎn)很明顯是浪費(fèi)內(nèi)存。除非你的系統(tǒng)去查一下那個 key,才會被Redis給刪除掉。這就是所謂的惰性刪除!
14、定期和惰性一定能保證刪除數(shù)據(jù)嗎?如果不能,Redis會有什么應(yīng)對措施?
并不能保證一定刪除,Redsi有一個Redis 內(nèi)存淘汰機(jī)制來確保數(shù)據(jù)一定會被刪除。
首先介一下定期刪除和惰性刪除的工作流程:
1、定期刪除,Redis默認(rèn)每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,Redis不是每個100ms將所有的key檢查一次,而是隨機(jī)抽取進(jìn)行檢查(如果每隔100ms,全部key進(jìn)行檢查,Redis豈不是卡死)。因此,如果只采用定期刪除策略,會導(dǎo)致很多key到時間沒有刪除。
2、于是,惰性刪除派上用場。也就是說在你獲取某個key的時候,Redis會檢查一下,這個key如果設(shè)置了過期時間那么是否過期了?如果過期了此時就會刪除。
3、采用定期刪除+惰性刪除就沒其他問題了么?不是的,如果定期刪除沒刪除key。然后你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,Redis
4、內(nèi)存會越來越高。那么就應(yīng)該采用內(nèi)存淘汰機(jī)制。
在Redis.conf中有一行配置:maxmemory-policy volatile-lru
該配置就是配內(nèi)存淘汰策略的,主要有以下六種方案:
volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰
volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù),新寫入操作會報(bào)錯
需要注意的是,如果沒有設(shè)置 expire 的key, 不滿足先決條件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行為, 和 noeviction(不刪除) 基本上一致。
15、Redis對于大量的請求,是怎樣處理的?
1、Redis是一個單線程程序,也就說同一時刻它只能處理一個客戶端請求;2、Redis是通過IO多路復(fù)用(select,epoll,kqueue,依據(jù)不同的平臺,采取不同的實(shí)現(xiàn))來處理多個客戶端請求。
16、緩存雪崩、緩存穿透、緩存預(yù)熱、緩存更新、緩存擊穿、緩存降級全搞定!
緩存雪崩
緩存雪崩指的是緩存同一時間大面積的失效,所以,后面的請求都會落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時間內(nèi)承受大量請求而崩掉。
看不懂?那我說人話。
我們可以簡單的理解為:由于原有緩存失效,新緩存未到期間(例如:我們設(shè)置緩存時采用了相同的過期時間,在同一時刻出現(xiàn)大面積的緩存過期),所有原本應(yīng)該訪問緩存的請求都去查詢數(shù)據(jù)庫了,而對數(shù)據(jù)庫CPU和內(nèi)存造成巨大壓力,嚴(yán)重的會造成數(shù)據(jù)庫宕機(jī),從而形成一系列連鎖反應(yīng),造成整個系統(tǒng)崩潰。
解決辦法
事前:盡量保證整個 Redis 集群的高可用性,發(fā)現(xiàn)機(jī)器宕機(jī)盡快補(bǔ)上,選擇合適的內(nèi)存淘汰策略。事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL崩掉, 通過加鎖或者隊(duì)列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢數(shù)據(jù)和寫緩存,其他線程等待。事后:利用 Redis 持久化機(jī)制保存的數(shù)據(jù)盡快恢復(fù)緩存緩存穿透
一般是黑客故意去請求緩存中不存在的數(shù)據(jù),導(dǎo)致所有的請求都落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時間內(nèi)承受大量 請求而崩掉。
這也看不懂?那我再換個說法好了。
緩存穿透是指查詢一個一定不存在的數(shù)據(jù),由于緩存不命中,接著查詢數(shù)據(jù)庫也無法查詢出結(jié)果,因此也不會寫入到緩存中,這將會導(dǎo)致每個查詢都會去請求數(shù)據(jù)庫,造成緩存穿透。
解決辦法
1、布隆過濾器
這是最常見的一種解決方法了,它是將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中,一個一定不存在的數(shù)據(jù)會被 這個bitmap攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓 力。
對所有可能查詢的參數(shù)以hash形式存儲,在控制層先進(jìn)行校驗(yàn),不符合則丟棄,從而避免了對底層存儲系統(tǒng)的查詢壓力;
這里稍微科普一下布隆過濾器。
“
布隆過濾器是引入了k(k>1)k(k>1)個相互獨(dú)立的哈希函數(shù),保證在給定的空間、誤判率下,完成元素判重的過程。它的優(yōu)點(diǎn)是空間效率和查詢時間都遠(yuǎn)遠(yuǎn)超過一般的算法,缺點(diǎn)是有一定的誤識別率和刪除困難。
該算法的核心思想就是利用多個不同的Hash函數(shù)來解決“沖突”。Hash存在一個沖突(碰撞)的問題,用同一個Hash得到的兩個URL的值有可能相同。為了減少沖突,我們可以多引入幾個Hash,如果通過其中的一個Hash值我們得出某元素不在集合中,那么該元素肯定不在集合中。只有在所有的Hash函數(shù)告訴我們該元素在集合中時,才能確定該元素存在于集合中。這便是布隆過濾器的基本思想,一般用于在大數(shù)據(jù)量的集合中判定某元素是否存在。
2、緩存空對象
當(dāng)存儲層不命中后,即使返回的空對象也將其緩存起來,同時會設(shè)置一個過期時間,之后再訪問這個數(shù)據(jù)將會從緩存中獲取,保護(hù)了后端數(shù)據(jù)源;如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存 在,還是系統(tǒng)故障),我們?nèi)匀话堰@個空結(jié)果進(jìn)行緩存,但它的過期時間會很短,最長不超過五分鐘。
但是這種方法會存在兩個問題:
1、如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲更多的鍵,因?yàn)檫@當(dāng)中可能會有很多的空值的鍵;
2、即使對空值設(shè)置了過期時間,還是會存在緩存層和存儲層的數(shù)據(jù)會有一段時間窗口的不一致,這對于需要保持一致性的業(yè)務(wù)會有影響。
我們可以從適用場景和維護(hù)成本兩方面對這兩匯總方法進(jìn)行一個簡單比較:
適用場景:緩存空對象適用于1、數(shù)據(jù)命中不高 2、數(shù)據(jù)頻繁變化且實(shí)時性較高 ;而布隆過濾器適用1、數(shù)據(jù)命中不高 2、數(shù)據(jù)相對固定即實(shí)時性較低
維護(hù)成本:緩存空對象的方法適合1、代碼維護(hù)簡單 2、需要較多的緩存空間 3、數(shù)據(jù)會出現(xiàn)不一致的現(xiàn)象;布隆過濾器適合 1、代碼維護(hù)較復(fù)雜 2、緩存空間要少一些
緩存預(yù)熱
緩存預(yù)熱是指系統(tǒng)上線后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題。用戶會直接查詢事先被預(yù)熱的緩存數(shù)據(jù)!
解決思路1、直接寫個緩存刷新頁面,上線時手工操作下;2、數(shù)據(jù)量不大,可以在項(xiàng)目啟動的時候自動進(jìn)行加載;3、定時刷新緩存;
緩存更新
除了緩存服務(wù)器自帶的緩存失效策略之外(Redis默認(rèn)的有6中策略可供選擇),我們還可以根據(jù)具體的業(yè)務(wù)需求進(jìn)行自定義的緩存淘汰,常見的策略有兩種:
(1)定時去清理過期的緩存;定時刪除和惰性刪除
(2)當(dāng)有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。兩者各有優(yōu)劣,第一種的缺點(diǎn)是維護(hù)大量緩存的key是比較麻煩的,第二種的缺點(diǎn)就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復(fù)雜!具體用哪種方案,大家可以根據(jù)自己的應(yīng)用場景來權(quán)衡。
緩存擊穿
緩存擊穿,是指一個key非常熱點(diǎn),在不停的扛著大并發(fā),大并發(fā)集中對這一個點(diǎn)進(jìn)行訪問,當(dāng)這個key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請求數(shù)據(jù)庫,就像在一個屏障上鑿開了一個洞。
比如常見的電商項(xiàng)目中,某些貨物成為“爆款”了,可以對一些主打商品的緩存直接設(shè)置為永不過期。即便某些商品自己發(fā)酵成了爆款,也是直接設(shè)為永不過期就好了。mutex key互斥鎖基本上是用不上的,有個詞叫做大道至簡。
緩存降級
當(dāng)訪問量劇增、服務(wù)出現(xiàn)問題(如響應(yīng)時間慢或不響應(yīng))或非核心服務(wù)影響到核心流程的性能時,仍然需要保證服務(wù)還是可用的,即使是有損服務(wù)。系統(tǒng)可以根據(jù)一些關(guān)鍵數(shù)據(jù)進(jìn)行自動降級,也可以配置開關(guān)實(shí)現(xiàn)人工降級。降級的最終目的是保證核心服務(wù)可用,即使是有損的。而且有些服務(wù)是無法降級的(如加入購物車、結(jié)算)。以參考日志級別設(shè)置預(yù)案:
(1)一般:比如有些服務(wù)偶爾因?yàn)榫W(wǎng)絡(luò)抖動或者服務(wù)正在上線而超時,可以自動降級;
(2)警告:有些服務(wù)在一段時間內(nèi)成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發(fā)送告警;
(3)錯誤:比如可用率低于90%,或者數(shù)據(jù)庫連接池被打爆了,或者訪問量突然猛增到系統(tǒng)能承受的最大閥值,此時可以根據(jù)情況自動降級或者人工降級;
(4)嚴(yán)重錯誤:比如因?yàn)樘厥庠驍?shù)據(jù)錯誤了,此時需要緊急人工降級。服務(wù)降級的目的,是為了防止Redis服務(wù)故障,導(dǎo)致數(shù)據(jù)庫跟著一起發(fā)生雪崩問題。因此,對于不重要的緩存數(shù)據(jù),可以采取服務(wù)降級策略,例如一個比較常見的做法就是,Redis出現(xiàn)問題,不去數(shù)據(jù)庫查詢,而是直接返回默認(rèn)值給用戶。
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個字
最新活動更多
-
即日-11.13立即報(bào)名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月20日火熱報(bào)名中>> 2024 智能家居出海論壇
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會議
-
12月19日立即報(bào)名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報(bào)名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書》
推薦專題
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市