訂閱
糾錯
加入自媒體

Redis常見數(shù)據(jù)結(jié)構(gòu)以及使用場景分別是什么?

4、有MySQL不就夠用了嗎?為什么要用Redis這種新的數(shù)據(jù)庫?

主要是因為 Redis 具備高性能和高并發(fā)兩種特性。

高性能:假如用戶第一次訪問數(shù)據(jù)庫中的某些數(shù)據(jù)。這個過程會比較慢,因為是從硬盤上讀取的。將該用戶訪問的數(shù)據(jù)存在緩存中,這樣下一次再訪問這些數(shù)據(jù)的時候就可以直接從緩存中獲取了。操作緩存就是直接操作內(nèi)存,所以速度相當(dāng)快。如果數(shù)據(jù)庫中的對應(yīng)數(shù)據(jù)改變的之后,同步改變緩存中相應(yīng)的數(shù)據(jù)即可!高并發(fā):直接操作緩存能夠承受的請求是遠遠大于直接訪問數(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 來實現(xiàn)緩存,但只能實現(xiàn)本地緩存,它最主要的特點是輕量以及快速,但是其生命周期隨著程序的銷毀而結(jié)束,并且在多實例的情況下,每個實例都需要各自保存一份緩存,緩存不具有一致性。

使用 Redis 或 Memcached 之類的稱為分布式緩存,在多實例的情況下,各實例共享一份緩存數(shù)據(jù),緩存具有一致性。這是Redis或者Memcached的優(yōu)點所在,但它也有缺點,那就是需要保持 Redis 或 Memcached服務(wù)的高可用,整個程序架構(gòu)上較為復(fù)雜。

6、使用Redis的好處有哪些?

1、訪問速度快,因為數(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、使用底層模型不同

它們之間底層實現(xiàn)方式 以及與客戶端之間通信的應(yīng)用協(xié)議不一樣。Redis直接自己構(gòu)建了VM 機制 ,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費一定的時間去移動和請求。

4、集群模式:Memcached沒有原生的集群模式,需要依靠客戶端來實現(xiàn)往集群中分片寫入數(shù)據(jù);但是 Redis 目前 是原生支持 cluster 模式的.

5、Memcached是多線程,非阻塞IO復(fù)用的網(wǎng)絡(luò)模型;Redis使用單線程的多路 IO 復(fù)用模型。

6、Value 值大小不同:Redis 最大可以達到 512MB;Memcached 只有 1MB。

8、Redis比Memcached的優(yōu)勢在哪里?

1、Memcached所有的值均是簡單字符串,Redis作為其替代者,支持更為豐富的數(shù)據(jù)類型

2、Redis 的速度比 Memcached 快很多

3、Redis可以做到持久化數(shù)據(jù)

9、緩存中常說的熱點數(shù)據(jù)和冷數(shù)據(jù)是什么?

其實就是名字上的意思,熱數(shù)據(jù)就是訪問次數(shù)較多的數(shù)據(jù),冷數(shù)據(jù)就是訪問很少或者從不訪問的數(shù)據(jù)。

需要注意的是只有熱點數(shù)據(jù),緩存才有價值對于冷數(shù)據(jù)而言,大部分?jǐn)?shù)據(jù)可能還沒有再次訪問到就已經(jīng)被擠出內(nèi)存,不僅占用內(nèi)存,而且價值不大。

數(shù)據(jù)更新前至少讀取兩次,緩存才有意義。這個是最基本的策略,如果緩存還沒有起作用就失效了,那就沒有太大價值了。

10、Redis 為什么是單線程的而不采用多線程方案?

這主要是基于一種客觀原因來考慮的。因為Redis是基于內(nèi)存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬。既然單線程容易實現(xiàn),而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了(畢竟采用多線程會有很多麻煩!)

11、單線程的Redis為什么這么快?

主要是有三個原因:1、Redis的全部操作都是純內(nèi)存的操作;2、Redis采用單線程,有效避免了頻繁的上下文切換;3,采用了非阻塞I/O多路復(fù)用機制。

12、了解Redis的線程模型嗎?可以大致說說嗎?

如果你打開看過 Redis 的源碼就會發(fā)現(xiàn)Redis 內(nèi)部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,所以 Redis 才叫做單線程的模型。它采用 IO 多路復(fù)用機制同時監(jiān)聽多個 socket,根據(jù) socket 上的事件來選擇對應(yīng)的事件處理器進行處理。

文件事件處理器的結(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)生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應(yīng)的事件處理器進行處理。

一句話總結(jié)就是:“I/O 多路復(fù)用程序負責(zé)監(jiān)聽多個套接字, 并向文件事件分派器傳送那些產(chǎn)生了事件的套接字!

13、Redis設(shè)置過期時間的兩種方案是什么?

Redis中有個設(shè)置時間過期的功能,即對存儲在 Redis 數(shù)據(jù)庫中的值可以設(shè)置一個過期時間。

作為一個緩存數(shù)據(jù)庫, 這是非常實用的,比如一些 token 或者登錄信息,尤其是短信驗證碼都是有時間限制的,按照傳統(tǒng)的數(shù)據(jù)庫處理方式,一般都是自己判斷過期,這樣無疑會嚴(yán)重影響項目性能。

我們 set key 的時候,都可以給一個 expire time,就是過期時間,通過過期時間我們可以指定這個 key 可以存活的時間,主要可采用定期刪除和惰性刪除兩種方案。

定期刪除:Redis默認(rèn)是每隔 100ms 就隨機抽取一些設(shè)置了過期時間的key,檢查其是否過期,如果過期就刪 除。注意這里是隨機抽取的。為什么要隨機呢?你想一想假如 Redis 存了幾十萬個 key ,每隔100ms就遍歷所 有的設(shè)置過期時間的 key 的話,就會給 CPU 帶來很大的負載!惰性刪除 :定期刪除可能會導(dǎo)致很多過期 key 到了時間并沒有被刪除掉。所以就有了惰性刪除。它是指某個鍵值過期后,此鍵值不會馬上被刪除,而是等到下次被使用的時候,才會被檢查到過期,此時才能得到刪除,惰性刪除的缺點很明顯是浪費內(nèi)存。除非你的系統(tǒng)去查一下那個 key,才會被Redis給刪除掉。這就是所謂的惰性刪除!

14、定期和惰性一定能保證刪除數(shù)據(jù)嗎?如果不能,Redis會有什么應(yīng)對措施?

并不能保證一定刪除,Redsi有一個Redis 內(nèi)存淘汰機制來確保數(shù)據(jù)一定會被刪除。

首先介一下定期刪除和惰性刪除的工作流程:

1、定期刪除,Redis默認(rèn)每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,Redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,Redis豈不是卡死)。因此,如果只采用定期刪除策略,會導(dǎo)致很多key到時間沒有刪除。

2、于是,惰性刪除派上用場。也就是說在你獲取某個key的時候,Redis會檢查一下,這個key如果設(shè)置了過期時間那么是否過期了?如果過期了此時就會刪除。

3、采用定期刪除+惰性刪除就沒其他問題了么?不是的,如果定期刪除沒刪除key。然后你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,Redis

4、內(nèi)存會越來越高。那么就應(yīng)該采用內(nèi)存淘汰機制。

在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ù),新寫入操作會報錯

需要注意的是,如果沒有設(shè)置 expire 的key, 不滿足先決條件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行為, 和 noeviction(不刪除) 基本上一致。

15、Redis對于大量的請求,是怎樣處理的?

1、Redis是一個單線程程序,也就說同一時刻它只能處理一個客戶端請求;2、Redis是通過IO多路復(fù)用(select,epoll,kqueue,依據(jù)不同的平臺,采取不同的實現(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ù)庫宕機,從而形成一系列連鎖反應(yīng),造成整個系統(tǒng)崩潰。

解決辦法

事前:盡量保證整個 Redis 集群的高可用性,發(fā)現(xiàn)機器宕機盡快補上,選擇合適的內(nèi)存淘汰策略。事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL崩掉, 通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個key只允許一個線程查詢數(shù)據(jù)和寫緩存,其他線程等待。事后:利用 Redis 持久化機制保存的數(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形式存儲,在控制層先進行校驗,不符合則丟棄,從而避免了對底層存儲系統(tǒng)的查詢壓力;

這里稍微科普一下布隆過濾器。

布隆過濾器是引入了k(k>1)k(k>1)個相互獨立的哈希函數(shù),保證在給定的空間、誤判率下,完成元素判重的過程。它的優(yōu)點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。

該算法的核心思想就是利用多個不同的Hash函數(shù)來解決“沖突”。Hash存在一個沖突(碰撞)的問題,用同一個Hash得到的兩個URL的值有可能相同。為了減少沖突,我們可以多引入幾個Hash,如果通過其中的一個Hash值我們得出某元素不在集合中,那么該元素肯定不在集合中。只有在所有的Hash函數(shù)告訴我們該元素在集合中時,才能確定該元素存在于集合中。這便是布隆過濾器的基本思想,一般用于在大數(shù)據(jù)量的集合中判定某元素是否存在。

2、緩存空對象

當(dāng)存儲層不命中后,即使返回的空對象也將其緩存起來,同時會設(shè)置一個過期時間,之后再訪問這個數(shù)據(jù)將會從緩存中獲取,保護了后端數(shù)據(jù)源;如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存 在,還是系統(tǒng)故障),我們?nèi)匀话堰@個空結(jié)果進行緩存,但它的過期時間會很短,最長不超過五分鐘。

但是這種方法會存在兩個問題:

1、如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲更多的鍵,因為這當(dāng)中可能會有很多的空值的鍵;

2、即使對空值設(shè)置了過期時間,還是會存在緩存層和存儲層的數(shù)據(jù)會有一段時間窗口的不一致,這對于需要保持一致性的業(yè)務(wù)會有影響。

我們可以從適用場景和維護成本兩方面對這兩匯總方法進行一個簡單比較:

適用場景:緩存空對象適用于1、數(shù)據(jù)命中不高 2、數(shù)據(jù)頻繁變化且實時性較高 ;而布隆過濾器適用1、數(shù)據(jù)命中不高 2、數(shù)據(jù)相對固定即實時性較低

維護成本:緩存空對象的方法適合1、代碼維護簡單 2、需要較多的緩存空間 3、數(shù)據(jù)會出現(xiàn)不一致的現(xiàn)象;布隆過濾器適合 1、代碼維護較復(fù)雜 2、緩存空間要少一些

緩存預(yù)熱

緩存預(yù)熱是指系統(tǒng)上線后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題。用戶會直接查詢事先被預(yù)熱的緩存數(shù)據(jù)!

解決思路1、直接寫個緩存刷新頁面,上線時手工操作下;2、數(shù)據(jù)量不大,可以在項目啟動的時候自動進行加載;3、定時刷新緩存;

緩存更新

除了緩存服務(wù)器自帶的緩存失效策略之外(Redis默認(rèn)的有6中策略可供選擇),我們還可以根據(jù)具體的業(yè)務(wù)需求進行自定義的緩存淘汰,常見的策略有兩種:

(1)定時去清理過期的緩存;定時刪除和惰性刪除

(2)當(dāng)有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復(fù)雜!具體用哪種方案,大家可以根據(jù)自己的應(yīng)用場景來權(quán)衡。

緩存擊穿

緩存擊穿,是指一個key非常熱點,在不停的扛著大并發(fā),大并發(fā)集中對這一個點進行訪問,當(dāng)這個key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請求數(shù)據(jù)庫,就像在一個屏障上鑿開了一個洞。

比如常見的電商項目中,某些貨物成為“爆款”了,可以對一些主打商品的緩存直接設(shè)置為永不過期。即便某些商品自己發(fā)酵成了爆款,也是直接設(shè)為永不過期就好了。mutex key互斥鎖基本上是用不上的,有個詞叫做大道至簡。

緩存降級

當(dāng)訪問量劇增、服務(wù)出現(xiàn)問題(如響應(yīng)時間慢或不響應(yīng))或非核心服務(wù)影響到核心流程的性能時,仍然需要保證服務(wù)還是可用的,即使是有損服務(wù)。系統(tǒng)可以根據(jù)一些關(guān)鍵數(shù)據(jù)進行自動降級,也可以配置開關(guān)實現(xiàn)人工降級。降級的最終目的是保證核心服務(wù)可用,即使是有損的。而且有些服務(wù)是無法降級的(如加入購物車、結(jié)算)。以參考日志級別設(shè)置預(yù)案:

(1)一般:比如有些服務(wù)偶爾因為網(wǎng)絡(luò)抖動或者服務(wù)正在上線而超時,可以自動降級;

(2)警告:有些服務(wù)在一段時間內(nèi)成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發(fā)送告警;

(3)錯誤:比如可用率低于90%,或者數(shù)據(jù)庫連接池被打爆了,或者訪問量突然猛增到系統(tǒng)能承受的最大閥值,此時可以根據(jù)情況自動降級或者人工降級;

(4)嚴(yán)重錯誤:比如因為特殊原因數(shù)據(jù)錯誤了,此時需要緊急人工降級。服務(wù)降級的目的,是為了防止Redis服務(wù)故障,導(dǎo)致數(shù)據(jù)庫跟著一起發(fā)生雪崩問題。因此,對于不重要的緩存數(shù)據(jù),可以采取服務(wù)降級策略,例如一個比較常見的做法就是,Redis出現(xiàn)問題,不去數(shù)據(jù)庫查詢,而是直接返回默認(rèn)值給用戶。


<上一頁  1  2  3  
聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗證碼繼續(xù)

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯
x
*文字標(biāo)題:
*糾錯內(nèi)容:
聯(lián)系郵箱:
*驗 證 碼:

粵公網(wǎng)安備 44030502002758號