Redis學習完結篇經典面試題+重點知識

      網友投稿 854 2022-05-30

      Redis介紹

      Redis,英文全稱是Remote Dictionary Server(遠程字典服務),是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。

      與MySQL數據庫不同的是,Redis的數據是存在內存中的。它的讀寫速度非常快,每秒可以處理超過10萬次讀寫操作。因此redis被廣泛應用于緩存,另外,Redis也經常用來做分布式鎖。除此之外,Redis支持事務、持久化、LUA 腳本、LRU 驅動事件、多種集群方案。

      Redis基本數據類型結構Redis

      有以下這五種基本類型:

      String(字符串)應用場景:共享session、分布式鎖,計數器、限流

      Hash(哈希)應用場景:緩存用戶信息

      List(列表)應用場景:消息隊列,文章列表

      Set(集合)應用場景:用戶標簽、生成隨機數抽獎、社交需求

      Redis學習完結篇:經典面試題+重點知識

      zset(有序集合)應用場景:排行榜,社交需求

      它還有三種特殊的數據結構類型

      Geospatial 專門用來做地圖坐標

      Hyperloglog 做基數統計

      Bitmap 用一個比特位反應某個元素的狀態

      String

      簡介:String是Redis最基礎的數據結構類型,它是二進制安全的,可以存儲圖片或者序列化的對象,值最大存儲為512M

      簡單使用舉例: set key value、get key等

      應用場景:共享session、分布式鎖,計數器、限流。

      內部編碼有3種,int(8字節長整型)/embstr(小于等于39字節字符串)/raw(大于39個字節字符串)

      C語言的字符串是char[]實現的,而Redis使用SDS(simple dynamic string) 封裝,sds源碼如下:

      struct sdshdr{ unsigned int len; // 標記buf的長度 unsigned int free; //標記buf中未使用的元素個數 char buf[]; // 存放元素的坑 }

      舉例其中一點,SDS中,O(1)時間復雜度,就可以獲取字符串長度;

      而C 字符串,需要遍歷整個字符串,時間復雜度為O(n).

      hash

      簡介:在Redis中,哈希類型是指v(值)本身又是一個鍵值對(k-v)結構

      簡單使用舉例:hset key field value 、hget key field

      內部編碼:ziplist(壓縮列表) 、hashtable(哈希表)

      應用場景:緩存用戶信息等。

      注意點:如果開發使用hgetall,哈希元素比較多的話,可能導致Redis阻塞,可以使用hscan。而如果只是獲取部分field,建議使用hmget。

      list列表

      簡介:列表(list)類型是用來存儲多個有序的字符串,一個列表最多可以存儲2^32-1個元素。

      簡單實用舉例:lpush key value [value …] 、lrange key start end

      內部編碼:ziplist(壓縮列表)、linkedlist(鏈表)

      應用場景:消息隊列,文章列表,

      list應用場景參考以下:

      lpush+lpop=Stack(棧)

      lpush+rpop=Queue(隊列)

      lpsh+ltrim=Capped Collection(有限集合)

      lpush+brpop=Message Queue(消息隊列)

      Set集合

      簡介:集合(set)類型也是用來保存多個的字符串元素,但是不允許重復元素

      簡單使用舉例:sadd key element [element …]、smembers key

      內部編碼:intset(整數集合)、hashtable(哈希表)

      注意點:smembers和lrange、hgetall都屬于比較重的命令,如果元素過多存在阻塞Redis的可能性,可以使用sscan來完成。

      應用場景:用戶標簽,生成隨機數抽獎、社交需求。

      zset 有序集合

      簡介:已排序的字符串集合,同時元素不能重復

      簡單格式舉例:zadd key score member [score member …],zrank key member

      底層內部編碼:ziplist(壓縮列表)、skiplist(跳躍表)

      應用場景:排行榜,社交需求(如用戶)。

      Redis為什么這么快

      基于內存實現

      內存讀寫是比在磁盤快很多的,Redis基于內存存儲實現的數據庫,相對于數據存在磁盤的MySQL數據庫,省去磁盤I/O的消耗。

      高效的數據結構

      Mysql索引為了提高效率,選擇了B+樹的數據結構。其實合理的數據結構,就是可以讓你的應用/程序更快。先看下Redis的數據結構&內部編碼圖:

      SDS簡單動態字符串

      字符串長度處理:Redis獲取字符串長度,時間復雜度為O(1),而C語言中,需要從頭開始遍歷,復雜度為O(n);

      空間預分配:字符串修改越頻繁的話,內存分配越頻繁,就會消耗性能,而SDS修改和空間擴充,會額外分配未使用的空間,減少性能損耗。

      惰性空間釋放:SDS 縮短時,不是回收多余的內存空間,而是free記錄下多余的空間,后續有變更,直接使用free中記錄的空間,減少分配。

      二進制安全:Redis可以存儲一些二進制數據,在C語言中字符串遇到’\0’會結束,而 SDS中標志字符串結束的是len屬性。

      字典

      Redis 作為 K-V 型內存數據庫,所有的鍵值就是用字典來存儲。字典就是哈希表,比如HashMap,通過key就可以直接獲取到對應的value。而哈希表的特性,在O(1)時間復雜度就可以獲得對應的值。

      跳躍表

      跳躍表是Redis特有的數據結構,就是在鏈表的基礎上,增加多級索引提升查找效率。

      跳躍表支持平均 O(logN),最壞 O(N)復雜度的節點查找,還可以通過順序性操作批量處理節點。

      合理的數據編碼

      Redis 支持多種數據數據類型,每種基本類型,可能對多種數據結構。什么時候,使用什么樣數據結構,使用什么樣編碼,是redis設計者總結優化的結果。

      合理的線程模型

      IO多路復用

      多路I/O復用技術可以讓單個線程高效的處理多個連接請求,而Redis使用用epoll作為I/O多路復用技術的實現。并且,Redis自身的事件處理模型將epoll中的連接、讀寫、關閉都轉換為事件,不在網絡I/O上浪費過多的時間。

      什么是I/O多路復用?

      I/O :網絡 I/O

      多路 :多個網絡連接

      復用:復用同一個線程。

      IO多路復用其實就是一種同步IO模型,它實現了一個線程可以監視多個文件句柄;一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作;而沒有文件句柄就緒時,就會阻塞應用程序,交出cpu。

      單線程模型

      Redis是單線程模型的,而單線程避免了CPU不必要的上下文切換和競爭鎖的消耗。也正因為是單線程,如果某個命令執行過長(如hgetall命令),會造成阻塞。Redis是面向快速執行場景的數據庫。所以要慎用如smembers和lrange、hgetall等命令。

      Redis 6.0 引入了多線程提速,它的執行命令操作內存的仍然是個單線程。

      虛擬內存機制

      Redis直接自己構建了VM機制 ,不會像一般的系統會調用系統函數處理,會浪費一定的時間去移動和請求。

      虛擬內存機制就是暫時把不經常訪問的數據(冷數據)從內存交換到磁盤中,從而騰出寶貴的內存空間用于其它需要訪問的數據(熱數據)。通過VM功能可以實現冷熱數據分離,使熱數據仍在內存中、冷數據保存到磁盤。這樣就可以避免因為內存不足而造成訪問速度下降的問題。

      Redis的常用應用場景

      緩存

      排行榜

      計數器應用

      共享Session

      分布式鎖

      社交網絡

      消息隊列

      位操作

      緩存

      我們一提到redis,自然而然就想到緩存,國內外中大型的網站都離不開緩存。合理的利用緩存,比如緩存熱點數據,不僅可以提升網站的訪問速度,還可以降低數據庫DB的壓力。并且,Redis相比于memcached,還提供了豐富的數據結構,并且提供RDB和AOF等持久化機制,強的一批。

      排行榜

      當今互聯網應用,有各種各樣的排行榜,如電商網站的月度銷量排行榜、社交APP的禮物排行榜、小程序的投票排行榜等等。Redis提供的zset數據類型能夠實現這些復雜的排行榜。

      計數器

      各大網站、APP應用經常需要計數器的功能,如短視頻的播放數、電商網站的瀏覽數。這些播放數、瀏覽數一般要求實時的,每一次播放和瀏覽都要做加1的操作,如果并發量很大對于傳統關系型數據的性能是一種挑戰。Redis天然支持計數功能而且計數的性能也非常好,可以說是計數器系統的重要選擇。

      共享Session

      如果一個分布式Web服務將用戶的Session信息保存在各自服務器,用戶刷新一次可能就需要重新登錄了,這樣顯然有問題。實際上,可以使用Redis將用戶的Session進行集中管理,每次用戶更新或者查詢登錄信息都直接從Redis中集中獲取。

      分布式鎖

      幾乎每個互聯網公司中都使用了分布式部署,分布式服務下,就會遇到對同一個資源的并發訪問的技術難題,如秒殺、下單減庫存等場景。

      用synchronize或者reentrantlock本地鎖肯定是不行的。

      如果是并發量不大話,使用數據庫的悲觀鎖、樂觀鎖來實現沒啥問題。

      但是在并發量高的場合中,利用數據庫鎖來控制資源的并發訪問,會影響數據庫的性能。

      實際上,可以用Redis的setnx來實現分布式的鎖。

      社交網絡推送

      贊/踩、粉絲、共同好友/喜好、推送、下拉刷新等是社交網站的必備功能,由于社交網站訪問量通常比較大,而且傳統的關系型數據不太適保存 這種類型的數據,Redis提供的數據結構即求交并集和隨機數據等可以相對比較容易地實現這些功能。

      消息隊列

      消息隊列是大型網站必用中間件,如ActiveMQ、RabbitMQ、Kafka等流行的消息隊列中間件,主要用于業務解耦、流量削峰及異步處理實時性低的業務。Redis提供了發布/訂閱及阻塞隊列功能,能實現一個簡單的消息隊列系統。另外,這個不能和專業的消息中間件相比。

      位操作

      用于數據量上億的場景下,例如幾億用戶系統的簽到,去重登錄次數統計,某用戶是否在線狀態等等。騰訊10億用戶,要幾個毫秒內查詢到某個用戶是否在線,能怎么做?千萬別說給每個用戶建立一個key,然后挨個記(你可以算一下需要的內存會很恐怖,而且這種類似的需求很多。這里要用到位操作——使用setbit、getbit、bitcount命令。原理是:redis內構建一個足夠長的數組,每個數組元素只能是0和1兩個值,然后這個數組的下標index用來表示用戶id(必須是數字哈),那么很顯然,這個幾億長的大數組就能通過下標和元素值(0和1)來構建一個記憶系統。

      怎么實現Redis的高可用

      我們在項目中使用Redis,肯定不會是單點部署Redis服務的。因為,單點部署一旦宕機,就不可用了。為了實現高可用,通常的做法是,將數據庫復制多個副本以部署在不同的服務器上,其中一臺掛了也可以繼續提供服務。Redis 實現高可用有三種部署模式:主從模式,哨兵模式,集群模式。

      Redis底層用的什么協議

      RESP,英文全稱是Redis Serialization Protocol,它是專門為redis設計的一套序列化協議. 這個協議其實在redis的1.2版本時就已經出現了,但是到了redis2.0才最終成為redis通訊協議的標準。

      RESP主要有實現簡單、解析速度快、可讀性好等優點。

      Redis的事務機制

      為什么Redis6.0改用多線程

      Redis6.0之前,Redis在處理客戶端的請求時,包括讀socket、解析、執行、寫socket等都由一個順序串行的主線程處理,這就是所謂的“單線程”。

      Redis6.0之前為什么一直不使用多線程?使用Redis時,幾乎不存在CPU成為瓶頸的情況, Redis主要受限于內存和網絡。例如在一個普通的Linux系統上,Redis通過使用pipelining每秒可以處理100萬個請求,所以如果應用程序主要使用O(N)或O(log(N))的命令,它幾乎不會占用太多CPU。

      redis使用多線程并非是完全摒棄單線程,redis還是使用單線程模型

      來處理客戶端的請求,只是使用多線程來處理數據的讀寫和協議解析,執行命令還是使用單線程。

      這樣做的目的是因為redis的性能瓶頸在于網絡IO而非CPU,使用多線程能提升IO讀寫的效率,從而整體提高redis的性能。

      Redis與mysql如何保持雙寫一致性

      1、緩存延時雙刪

      2、刪除緩存重試機制

      3、讀取biglog異步刪除緩存

      緩存延時雙刪

      先刪除緩存

      再更新數據庫

      休眠一會(比如1秒),再次刪除緩存。

      這個休眠一會,一般多久呢?都是1秒?

      這個休眠時間 = 讀業務邏輯數據的耗時 + 幾百毫秒。為了確保讀請求結束,寫請求可以刪除讀請求可能帶來的緩存臟數據。

      這種方案還算可以,只有休眠那一會(比如就那1秒),可能有臟數據,一般業務也會接受的。但是如果第二次刪除緩存失敗呢?緩存和數據庫的數據還是可能不一致,對吧?給Key設置一個自然的expire過期時間,讓它自動過期怎樣?那業務要接受過期時間內,數據的不一致咯?還是有其他更佳方案呢?

      刪除緩存重試機制

      因為延時雙刪可能會存在第二步的刪除緩存失敗,導致的數據不一致問題。可以使用這個方案優化:刪除失敗就多刪除幾次呀,保證刪除緩存成功就可以了呀~ 所以可以引入刪除緩存重試機制。

      寫請求更新數據庫

      緩存因為某些原因,刪除失敗

      把刪除失敗的key放到消息隊列

      消費消息隊列的消息,獲取要刪除的key

      重試刪除緩存操作

      讀取biglog異步刪除緩存

      重試刪除緩存機制還可以吧,就是會造成好多業務代碼入侵。其實,還可以這樣優化:通過數據庫的binlog來異步淘汰key。

      以mysql為例吧

      可以使用阿里的canal將binlog日志采集發送到MQ隊列里面

      然后通過ACK機制確認處理這條更新消息,刪除緩存,保證數據緩存一致性

      分布式鎖的應用,需要注意哪些。搶紅包、秒殺

      分布式鎖,是控制分布式系統不同進程共同訪問共享資源的一種鎖的實現。秒殺下單、搶紅包等等業務場景,都需要用到分布式鎖,我們項目中經常使用Redis作為分布式鎖。

      選了Redis分布式鎖的幾種實現方法,大家來討論下,看有沒有啥問題哈。

      命令setnx + expire分開寫

      setnx + value值是過期時間

      set的擴展命令(set ex px nx)

      set ex px nx + 校驗唯一隨機值,再刪除

      Redis 數據結構

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:圖書推廣銷售方案
      下一篇:云脈移動辦公電子政務解決方案
      相關文章
      久久亚洲精品国产亚洲老地址 | 亚洲精品国产免费| 国产亚洲精品线观看动态图| 亚洲AV无码一区二区三区鸳鸯影院| 亚洲视频无码高清在线| 亚洲黄色激情视频| 亚洲国产美女视频| 亚洲成年人电影在线观看| 91亚洲精品自在在线观看| 亚洲制服丝袜在线播放| 亚洲一卡2卡4卡5卡6卡在线99| 亚洲国产av一区二区三区丶| 亚洲sss综合天堂久久久| 亚洲sss综合天堂久久久| 亚洲AV无码乱码在线观看代蜜桃 | 亚洲av无码成人黄网站在线观看| 国产gv天堂亚洲国产gv刚刚碰| 国产偷国产偷亚洲清高动态图 | 亚洲国产超清无码专区| 亚洲国产av美女网站| 亚洲人成网站色在线观看| 亚洲精品又粗又大又爽A片| 亚洲另类无码专区丝袜| 亚洲中文字幕乱码熟女在线| 亚洲av成人片在线观看| 亚洲欧洲久久av| 亚洲国产精品一区二区成人片国内| 亚洲卡一卡2卡三卡4卡无卡三| 亚洲毛片无码专区亚洲乱| 亚洲人成人网毛片在线播放| 亚洲国产精品成人午夜在线观看| 亚洲Av无码国产情品久久| 国产AV无码专区亚洲AWWW| 亚洲精品无码不卡| 亚洲区视频在线观看| 亚洲丶国产丶欧美一区二区三区| 亚洲XX00视频| 国产亚洲精品a在线无码| 亚洲视频在线一区二区三区| 99亚偷拍自图区亚洲| www.亚洲一区|