Redis高可靠,高可用,高性能原理分析

從幾個問題來探索思考redis的原理

  1. redis的數據都是在內存中的,那麼redis如何去實現數據的持久化呢?
  2. 服務器的內存是有限的,當數據量即將達到內存大小時,如何進行回收呢?
  3. 對於單線程的redis,如何作處處理請求仍是如此的快呢?

由上述三個問題,看看redis如何解決這三大難題:node

redis的持久化

Redis支持兩種方式的持久化,一種是RDB方式、另外一種是AOF(append-only-file)方式。前者會根據指定的規則「定時」將內存中的數據存儲在硬盤上,然後者每次會將事務操做記錄下來。兩種持久化方式能夠單獨使用其中一種,也能夠將這兩種方式結合使用。mysql

從對比中看看RDB和AOF的持久化的方式:redis

RDB方式 後臺建立(fork)一個子進程去持久化數據,能夠理解成磁盤和內存直接的一個讀寫IO,這個過程咱們會考慮三個問題:算法

  1. 什麼時候觸發一次讀寫快照
  2. IO過程當中數據發生變化,會出現時間點和數據會有細微的差別
  3. 快照以後數據寫入了,下次快照以前宕機了,數據會丟失 rdb快照以後會存儲一個rdb.dump文件,這個是數據文件。 redis默認配置了三個規則能夠觸發快照: save 900 1 save 300 10 save 60 10000 每條快照規則佔一行,每條規則之間是「或」的關係。 在900秒(15分)內有一個以上的鍵被更改則進行快照。 手動觸發快照的方法: save,bgsave,FLUSHALL這三個命令能夠觸發快照。
    1. save命令 當執行save命令時,Redis同步作快照操做,在快照執行過程當中會阻塞全部來自客戶端的請求使用save命令能夠上述問題2,其實至關於加分佈式鎖。當redis內存中的數據較多時,經過該命令將致使Redis較長時間的不響應。因此不建議在生產環境上使用這個命令,而是推薦使用bgsave命令
    2. bgsave命令 bgsave命令能夠在後臺異步地進行快照操做,快照的同時服務器還能夠繼續響應來自客戶端的請求。執行BGSAVE後,Redis會當即返回ok表示開始執行快照操做。經過LASTSAVE命令能夠獲取最近一次成功執行快照的時間; (自動快照採用的是異步快照操做)
    3. FLUSHALL命令 會清除redis在內存中的全部數據。執行該命令後,只要redis中配置的快照規則不爲空,也就是save的規則存在。redis就會執行一次快照操做。無論規則是什麼樣的都會執行。若是沒有定義快照規則,就不會執行快照操做 對於問題3也是RDB持久化方式的最大缺點,自己存在的缺陷,因此出現了AOF持久化方式。

AOF方式 默認狀況下Redis沒有開啓AOF(append only file)方式的持久化,能夠經過appendonly參數啓用,在redis.conf中找到 appendonly yes.開啓AOF持久化後每執行一條會更改Redis中的數據的命令後,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是經過dir參數設置的,默認的文件名是apendonly.aof. 能夠在redis.conf中的屬性 appendfilename appendonlyh.aof修改.sql

AOF過程當中咱們已經明白的一點是:他的持久化並不是儲存的是數據,而是記錄,有點相似於mysql的binlog.因此AOF就算宕機也是不可能發生數據丟失的。那對於日誌文件愈來愈大,AOF該如何處理?緩存

set foo 1 set foo 2 set foo 3 get 對於AOF的這份日誌,其實最終只須要一個set foo 3.因此對於redis的aof文件能夠配置重寫策略,這個條件的配置爲 auto-aof-rewritepercentage 100 auto-aof-rewrite-min-size 64mb服務器

auto-aof-rewrite-percentage 表示的是當目前的AOF文件大小超過上一次重寫時的AOF文件大小的百分之多少時會再次進行重寫,若是以前沒有重寫過,則以啓動時AOF文件大小爲依據網絡

auto-aof-rewrite-min-size 表示限制了容許重寫的最小AOF文件大小,一般在AOF文件很小的狀況下即便其中有不少冗餘的命令咱們也並不太關心。併發

AOF重寫原理:app

aof的重寫原理能夠解決不阻塞的狀況下保證數據的完整性。 重寫的流程是這樣,主進程會fork一個子進程出來進行AOF重寫,這個重寫過程並非基於原有的aof文件來作的,而是有點相似於快照的方式,全量遍歷內存中的數據,而後逐個序列到aof文件中。在fork子進程這個過程當中,服務端仍然能夠對外提供服務,那這個時候重寫的aof文件的數據和redis內存數據不一致了怎麼辦?不用擔憂,這個過程當中,主進程的數據更新操做,會緩存到aof_rewrite_buf中,也就是單獨開闢一塊緩存來存儲重寫期間收到的命令,當子進程重寫完之後再把緩存中的數據追加到新的aof文件。當全部的數據所有追加到新的aof文件中後,把新的aof文件重命名爲,此後全部的操做都會被寫入新的aof文件。

Redis的內存回收策略

Redis中提供了多種內存回收策略,當內存容量不足時,爲了保證程序的運行,這時就不得不淘汰內存中的一些對象,釋放這些對象佔用的空間,那麼選擇淘汰哪些對象呢?

  1. 默認的策略爲noeviction策略,當內存使用達到閾值的時候,全部引發申請內存的命令會報錯
  2. allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰(熱點數據)
  3. allkeys-random:隨機移除某個key。
  4. volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰。
  5. volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰。
  6. volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰

redis設置過時key如何去清除?

過時時間設置

在Redis中提供了Expire命令設置一個鍵的過時時間,到期之後Redis會自動刪除它。這個在咱們實際使用過程當中用得很是多。 EXPIRE命令的使用方法爲 EXPIRE key seconds 其中seconds 參數表示鍵的過時時間,單位爲秒。其中可使用TTL key 查看時間剩餘。

過時key自動刪除的原理:

redis有兩種方式去刪除key:

消極方法(passive way) 在key被訪問時若是發現它已經失效,那麼就刪除它.

積極方法(active way) 週期性地從設置了失效時間的主鍵中選擇一部分失效的key刪除 對於那些從未被查詢的key,即使它們已通過期,被動方式也沒法清除。所以Redis會週期性地隨機測試一些key,已過時的key將會被刪掉。Redis每秒會進行10次操做,具體的流程:

  1. 隨機測試 20 個帶有timeout信息的key;
  2. 刪除其中已通過期的key;
  3. 若是超過25%的key被刪除,則重複執行步驟1;這是一個簡單的機率算法(trivial probabilistic algorithm),基於假設咱們隨機抽取的key表明了所有的key空間。

Redis是單進程單線程?性能爲何這麼快

官方的解釋是,CPU並非Redis的瓶頸所在,Redis的瓶頸主要在機器的內存和網絡的帶寬。那麼Redis能不能處理高併發請求呢?固然是能夠的,至於怎麼實現的,目前只說一個名詞:多路複用,至於什麼事多路複用,在後續的netty框架博客中會詳細介紹。

redis的高可用配置和原理解析:

1. 主從複製

配置:
配置步驟很簡單,例如如今有3臺機器(master,node1,node2)

只須要在node1,node2的redis.conf 文件下加上一個slaveof  master  port。

錯誤排查:如何未成功,先檢驗node1和node2是否能夠鏈接master的服務。
 redis-cli    -h  master的iP      -p   端口port
觀察redis服務端狀態的命令:127.0.0.1:6379> INFO replication
能夠用來查看主從是否配置成功。

主從複製的特色:
master機器能夠讀寫,slave機器默認狀況下不能夠寫操做

主從複製,數據同步過程和原理:
slave 剛啓動成爲master的從庫:
觀察輸出日誌:
[2603] 18 Jan 10:32:41.106 * Slave asks for synchronization
[2603] 18 Jan 10:32:41.106 * Full resync requested by slave.
[2603] 18 Jan 10:32:41.106 * Starting BGSAVE for SYNC
[2603] 18 Jan 10:32:41.210 * Background saving started by pid 2618
[2618] 18 Jan 10:32:41.232 * DB saved on disk
[2618] 18 Jan 10:32:41.232 * RDB: 6 MB of memory used by copy-on-write
[2603] 18 Jan 10:32:41.333 * Background saving terminated with success
[2603] 18 Jan 10:32:41.333 * Synchronization with slave succeeded   
複製代碼

從日誌能夠看出,redis會觸發bgsave去生成一個快照,而後發送給slave。從庫load快照文件,成功而後通知主庫。接下來會進行,增量複製從redis2.8開始,就支持主從複製的斷點續傳,若是主從複製過程當中,網絡鏈接斷掉了,那麼能夠接着上次複製的地方,繼續複製下去,而不是從頭開始複製一份masternode會在內存中建立一個backlog,master和slave都會保存一個replica offset還有一個masterid,offset就是保存在backlog中的。若是master和slave網絡鏈接斷掉了,slave會讓master從上次的replicat offset開始繼續複製可是若是沒有找到對應的offset,那麼就會執行一次全量同步。

另外一種複製方式就是無磁盤複製: Redis複製的工做原理基於RDB方式的持久化實現的,也就是master在後臺保存RDB快照,slave接收到rdb文件並載入,可是這種方式會存在一些問題

  • 當master禁用RDB時,若是執行了複製初始化操做,Redis依然會生成RDB快照,當master下次啓動時執行該RDB文件的恢復,可是由於複製發生的時間點不肯定,因此恢復的數據多是任什麼時候間點的。就會形成數據出現問題
  • 當硬盤性能比較慢的狀況下(網絡硬盤),那初始化複製過程會對性能產生影響 所以2.8.18之後的版本,Redis引入了無硬盤複製選項,能夠不須要經過RDB文件去同步,直接發送數據。

經過如下配置來開啓該功能 repl-diskless-sync yes master在內存中直接建立rdb,而後發送給slave,不會在本身本地落地磁盤了。

  1. 哨兵機制

    哨兵的做用就是監控和選舉,監控master 和 slave 是否正常,master宕機以後,從新選舉

    配置過程:

    哨兵模式的配置也很是簡單,只須要啓動一個哨兵的sentinel服務便可。配置信息中有一個須要注意的: sentinel monitor mymaster 192.168.2.7 6379 1 其中192.168.2.7是master的ip 6379是端口,1表明是幾個哨兵經過。通常看哨兵服務有多少個。配置通常是n/2 +1 (半數以上)

    接下看看master宕機以後:首先會從slave中選取一個做爲master。選舉完成後會發生以下變化,redis.conf中的,slaveof ip port會變化,sentinel.conf 文件也會發生變化。master的ip 和端口會發生變化。

總而言之,redis的主從複製和哨兵模式服務能夠保證redis服務的高可用。

redis-cluster

redis的分片存儲,單臺redis的內存是有限的,若是對於特別大的數據量,就必須使用redis的分片存儲了。目前本人並何嘗試這種開發,在redis3.0版本以後。redis支持集羣的功能,能夠解決路由規則(hash算法的均勻分佈) 和 動態擴容。能簡單的水平擴容,增長節點機器,分片存儲。客戶端操做面向的是集羣。

Redis的應用場景:

客戶端選擇:jedis ,Redisson(相似zk的curator,更上層的封裝) Jedis客戶端鏈接有三種方式: 單個redis鏈接池,哨兵模式下鏈接池,集羣鏈接池。在不一樣的框架中如jedis對於三種鏈接定義不一樣的封裝類。 對於後續的redis的分佈式鎖以及布隆過濾器解決緩存擊穿等問題,請持續關注博客更新。

91Code-就要編碼,關注公衆號獲取更多內容!

在這裏插入圖片描述
相關文章
相關標籤/搜索