Redis總結

定義

Redis是C語言開發的一個開源的(聽從BSD協議)高性能鍵值對(key-value)的內存數據庫,能夠用做數據庫、緩存、消息中間件等。它是一種NoSQL的內存數據庫。web

特性

  • 性能優秀,數據在內存中,讀寫速度很是快,單機支持併發10W QPS
  • 單進程單線程,是線程安全的,採用IO多路複用機制
  • 豐富的數據類型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等
  • 支持數據持久化。能夠將內存中數據保存在磁盤中,重啓時加載
  • 主從複製,哨兵,高可用
  • 能夠用做分佈式鎖
  • 能夠做爲消息中間件使用,支持發佈訂閱

數據類型

  • 歸納:使用一個redisObject對象來表示全部的key和value。redisObject有type(數據類型)encoding(存儲方式)、數據指針、虛擬內存等
  • String:基本的類型,string類型是二進制安全的,string類型能夠包含任何數據,值最大能存儲512M
  • Hash是一個鍵值(key-value)的集合。redis的hash是一個string的key和value的映射表,Hash特別適合存儲對象。經常使用命令:hget,hset,hgetall等。應用場景:存儲、讀取、修改用戶屬性
  • list列表是簡單的字符串列表,按照插入順序排序。經常使用命令:lpush、rpush、lpop、rpop、lrange。應用場景:關注列表,粉絲列表,最新消息排行;消息隊列
  • set是string類型的無序集合。無序無重複。經常使用命令:sdd、spop、smembers、sunion。應用場景:共同好友,統計訪問網站的全部Ip
  • zset和set同樣是string類型元素的集合,有序且不容許重複的元素。經常使用命令:zadd、zrange、zrem、zcard。內部使用HashMap和跳躍表(skipList)來保證數據的存儲和有序,HashMap裏放的是成員到score的映射,而跳躍表裏存放的是全部的成員,排序依據是HashMap裏存的score,使用跳躍表的結構能夠得到比較高的查找效率。場景:排行榜;帶權重的消息隊列

數據結構

  • int
  • embstr
  • raw
  • LinkedList
  • QuickList
  • ZipList
  • Intset
  • Dict
  • SkipList

使用方式

  • RedisTemplate

緩存問題

  • 緩存和數據庫數據一致性問題
    1. 沒法保證二者間的強一致性
    2. 只能採起合適的策略來下降緩存和數據庫間數據不一致的機率
    3. 更新數據庫後及時更新緩存、緩存失敗時增長重試機制
  • 緩存雪崩
    1. 描述:多個緩存key同時失效,請求所有落在數據庫上,致使數據庫被打掛。 解決:把每一個Key的失效時間都加個隨機值,保證key數據不會在同一時間大面積失效。
  • 緩存穿透
    1. 描述:用戶發起一個緩存和數據庫都不存在的id進行請求,透過緩存不對不斷攻擊數據庫,致使數據庫壓力很大,嚴重會擊垮數據庫。
    2. 解決:
      • 進行用戶鑑權,不合法的用戶請求直接return
      • 利用布隆過濾器,就是利用高效的數據結構和算法快速判斷出你這個Key是否在數據庫中存在,不存在你return就行了,存在你就去查DB刷新KV再return
  • 緩存擊穿
    1. 描述:指一個很是熱點的key不斷的承受着大量的請求,當這個Key在失效的瞬間,持續的大併發直接落到了數據庫上,形成了緩存擊穿。
    2. Redis爲什麼這麼快解決:設置熱點數據永不過時,或者加上互斥鎖就搞定了

Redis爲什麼這麼快

  • 官方提供的數據能夠達到100000+的QPS(每秒內的查詢次數),這個數據不比Memcached差!
  • Redis確實是單進程單線程的模型,由於Redis徹底是基於內存的操做,CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存的大小或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落的採用單線程的方案了(畢竟採用多線程會有不少麻煩)
  • 第一:Redis徹底基於內存,絕大部分請求是純粹的內存操做,很是迅速,數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度是O(1)。
  • 第二:數據結構簡單,對數據操做也簡單。
  • 第三:採用單線程,避免了沒必要要的上下文切換和競爭條件,不存在多線程致使的CPU切換,不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有死鎖問題致使的性能消耗。
  • 第四:使用多路複用IO模型,非阻塞IO。

Redis和Memcached的區別

  • 存儲方式上:memcache會把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小。redis有部分數據存在硬盤上,這樣能保證數據的持久性。
  • 數據支持類型上:memcache對數據類型的支持簡單,只支持簡單的key-value,,而redis支持五種數據類型。
  • 使用底層模型不一樣:它們之間底層實現方式以及與客戶端之間通訊的應用協議不同。redis直接本身構建了VM機制,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
  • value的大小:redis能夠達到1GB,而memcache只有1MB。

key過時策略

  • 定時刪除
  • 惰性刪除

淘汰策略

  • volatile-lru:從已設置過時時間的KV集中優先對最近最少使用(less recently used)的數據淘汰
  • volitile-ttl:從已設置過時時間的KV集中優先對剩餘時間短(time to live)的數據淘汰
  • volitile-random:從已設置過時時間的KV集中隨機選擇數據淘汰
  • allkeys-lru:從全部KV集中優先對最近最少使用(less recently used)的數據淘汰
  • allKeys-random:從全部KV集中隨機選擇數據淘汰
  • noeviction:不淘汰策略,若超過最大內存,返回錯誤信息

持久化

  • RDB(默認):快照形式是直接把內存中的數據保存到一個dump的文件中,定時保存,保存策略。
    1. save
    2. bgsave
    3. fork()
  • AOF:把全部的對Redis的服務器進行修改的命令都存到一個文件裏,命令的集合。
    1. fsync
    2. always
    3. no
    4. everysec
    5. Rewrite
  • 當Redis重啓的時候,它會優先使用AOF文件來還原數據集,由於AOF文件保存的數據集一般比RDB文件所保存的數據集更完整。

事務

  • 開啓事務--命令入隊--執行/放棄
  • multi
  • queued
  • exec/discard
  • watch
  • unwatch

分佈式鎖

  • 利用setnx命令的原子性來保證分佈式系統中只有一個節點中的一個線程能夠得到鎖。
  • 設置過時時間
  • 續期
  • 防止釋放別人的鎖
  • 經常使用redisson框架實現

主從複製

  • 主從配置結合哨兵模式能解決單點故障問題,提升redis可用性。從節點僅提供讀操做,主節點提供寫操做。對於讀多寫少的情況,可給主節點配置多個從節點,從而提升響應效率。
  • 主從複製過程
    1. 從節點執行slaveof,保存主節點信息
    2. 從節點中的定時任務發現主節點信息,創建和主節點的socket鏈接
    3. 從節點發送Ping信號,主節點返回Pong,兩邊能互相通訊
    4. 鏈接創建後,主節點將全部數據發送給從節點(數據同步)
    5. 主節點把當前的數據同步給從節點後,便完成了複製的創建過程。接下來,主節點就會持續的把寫命令發送給從節點,保證主從數據一致性。
  • 數據同步的過程
    1. edis2.8以前使用sync [runId] [ offset]同步命令,redis2.8以後使用psync [runId] [offset]命令。
      • sync命令僅支持全量複製過程,psync支持全量和部分複製。
      • runId:每一個redis節點啓動都會生成惟一的uuid,每次redis重啓後,runId都會發生變化。
      • offset:主節點和從節點都各自維護本身的主從複製偏移量
    2. (1)主節點發送數據給從節點過程當中,主節點還會進行一些寫操做,這時候的數據存儲在複製緩衝區中。從節點同步主節點數據完成後,主節點將緩衝區的數據繼續發送給從節點,用於部分複製。
    3. (2)主節點響應寫命令時,不但會把命名發送給從節點,還會寫入複製積壓緩衝區,用於複製命令丟失的數據補救。
    4. 從節點發送psync [runId] [offset]命令,主節點有三種響應:
      1. FULLRESYNC:第一次鏈接,進行全量複製
      2. CONTINUE:進行部分複製
      3. ERR:不支持psync命令,進行全量複製
  • 全量複製的流程
    1. 從節點發送psync ? -1命令(由於第一次發送,不知道主節點的runId,因此爲?,由於是第一次複製,因此offset=-1)。
    2. 主節點發現從節點是第一次複製,返回FULLRESYNC {runId} {offset},runId是主節點的runId,offset是主節點目前的offset。
    3. 從節點接收主節點信息後,保存到info中。
    4. 四、主節點在發送FULLRESYNC後,啓動bgsave命令,生成RDB文件(數據持久化)。
    5. 五、主節點發送RDB文件給從節點。到從節點加載數據完成這段期間主節點的寫命令放入緩衝區。
    6. 六、從節點清理本身的數據庫數據。
    7. 七、從節點加載RDB文件,將數據保存到本身的數據庫中。
    8. 八、若是從節點開啓了AOF,從節點會異步重寫AOF文件。
  • 部分複製的流程
    1. 部分複製主要是Redis針對全量複製的太高開銷作出的一種優化措施,使用psync[runId][offset]命令實現。當從節點正在複製主節點時,若是出現網絡閃斷或者命令丟失等異常狀況時,從節點會向主節點要求補發丟失的命令數據,主節點的複製積壓緩衝區將這部分數據直接發送給從節點,這樣就能夠保持主從節點複製的一致性。補發的這部分數據通常遠遠小於全量數據。
    2. 主從鏈接中斷期間主節點依然響應命令,但因複製鏈接中斷命令沒法發送給從節點,不過主節點內的複製積壓緩衝區依然能夠保存最近一段時間的寫命令數據。
    3. 當主從鏈接恢復後,因爲從節點以前保存了自身已複製的偏移量和主節點的運行ID。所以會把它們當作psync參數發送給主節點,要求進行部分複製。
    4. 主節點接收到psync命令後首先覈對參數runId是否與自身一致,若是一致,說明以前複製的是當前主節點;以後根據參數offset在複製積壓緩衝區中查找,若是offset以後的數據存在,則對從節點發送+COUTINUE命令,表示能夠進行部分複製。由於緩衝區大小固定,若發生緩衝溢出,則進行全量複製。
    5. 主節點根據偏移量把複製積壓緩衝區裏的數據發送給從節點,保證主從複製進入正常狀態。

哨兵

  • 主從複製會存在哪些問題
    1. 一旦主節點宕機,從節點晉升爲主節點,同時須要修改應用方的主節點地址,還須要命令全部從節點去複製新的主節點,整個過程須要人工干預。
    2. 主節點的寫能力受到單機的限制。
    3. 主節點的存儲能力受到單機的限制。
    4. 原生複製的弊端在早期的版本中也會比較突出,好比:redis複製中斷後,從節點會發起psync。此時若是同步不成功,則會進行全量同步,主庫執行全量備份的同時,可能會形成毫秒或秒級的卡頓。
  • 哨兵功能 主要功能包括主節點存活檢測、主從運行狀況檢測、自動故障轉移、主從切換。
    1. 監控:不斷檢查主服務器和從服務器是否正常運行。
    2. 通知:當被監控的某個redis服務器出現問題,Sentinel經過API腳本向管理員或者其餘應用程序發出通知。
    3. 自動故障轉移:當主節點不能正常工做時,Sentinel會開始一次自動的故障轉移操做,它會將與失效主節點是主從關係的其中一個從節點升級爲新的主節點,而且將其餘的從節點指向新的主節點,這樣人工干預就能夠免了。
    4. 配置提供者:在Redis Sentinel模式下,客戶端應用在初始化時鏈接的是Sentinel節點集合,從中獲取主節點的信息。
  • 工做原理
    1. 每一個Sentinel節點都須要按期執行如下任務:每一個Sentinel以每秒一次的頻率,向它所知的主服務器、從服務器以及其餘的Sentinel實例發送一個PING命令。
    2. 若是一個實例距離最後一次有效回覆PING命令的時間超過down-after-milliseconds所指定的值,那麼這個實例會被Sentinel標記爲主觀下線。
    3. 若是一個主服務器被標記爲主觀下線,那麼正在監視這個服務器的全部Sentinel節點,要以每秒一次的頻率確認主服務器的確進入了主觀下線狀態。
    4. 若是一個主服務器被標記爲主觀下線,而且有足夠數量的Sentinel(至少要達到配置文件指定的數量)在指定的時間範圍內贊成這一判斷,那麼這個主服務器被標記爲客觀下線。
    5. 通常狀況下,每一個Sentinel會以每10秒一次的頻率向它已知的全部主服務器和從服務器發送INFO命令,當一個主服務器被標記爲客觀下線時,Sentinel向下線主服務器的全部從服務器發送INFO命令的頻率,會從10秒一次改成每秒一次。
    6. Sentinel和其餘Sentinel協商客觀下線的主節點的狀態,若是處於SDOWN狀態,則投票自動選出新的主節點,將剩餘從節點指向新的主節點進行數據複製。
    7. 當沒有足夠數量的Sentinel贊成主服務器下線時,主服務器的客觀下線狀態就會被移除。當主服務器從新向Sentinel的PING命令返回有效回覆時,主服務器的主觀下線狀態就會被移除。
相關文章
相關標籤/搜索