Redis學習與總結

Redis將按照以下的的順序進行總結

  • Redis
  • Redis的常用命令
  • Redis的安裝過程
  • Redis主從複製原理
  • Redis持久化原理
  • Redis的哨兵Sentinel機制
  • Redis的API使用

Redis

Redis是一個開源、支持網絡、基於內存、鍵值對的NoSQL數據庫

Redis常用命令


Redis 支持string list hash set sortset 五種數據類型

http://8d9901d5.wiz01.com/share/s/2dCg7l3-1kCv2lEZIt2_gYod0iaUd42pBATf28cVd41LwKTl


Redis安裝過程

安裝環境:Linux centos
安裝版本:redis-3.0.7
安裝過程:
  • 下載 redis-3.0.7.tar.gz 並解壓
  • 進入解壓目錄並make,然後可以看到src目錄下的可執行命令
  • redis安裝採用主從模式,使用redis的兩種持久化方法:快照(RDB文件)與追加式文件(AOF文件);同時採用redis自帶哨兵機制以完成主從切換。
  • 大部分的配置默認即可,下面爲改動或者添加的部分
  •  下面是redis.conf中對應改動的部分
  1. #默認採用daemon的方式
  2. daemonize yes
  3. #改變默認的6379端口,防止人爲攻擊
  4. port 16379
  5. #指定redis的日誌文件位置
  6. logfile /home/stat/redis-3.0.7/logs/redis.log
  7. #指定持久化文件的日誌文件
  8. dir /home/stat/redis-3.0.7/data
  9. #這個只在slave側的redis.conf中進行設置
  10. slaveof 10.186.150.201 16379
  11. #開啓aof持久化方式
  12. appendonly yes
  •     下面是sentinel.conf中對應改動的部分
  1. #指定sentinel的工作目錄
  2. dir "/home/stat/redis-3.0.7/data"
  3. #指定sentinel監控的master節點及端口
  4. sentinel monitor mymaster 10.186.150.201 16379 2
  • redis啓動:./redis-server ../redis.conf
  • redis停止:./redis-cli -p 16379 shutdown
  • 其他的查詢命令:
    • ./redis-cli -h host_ip -p 16379 (redis服務端口);INFO命令查看當前主機是slave還是master及其他狀態
    • ./redis-cli -h host_ip -p 26379(redis sentinel服務端口);INFO  sentinel 查看sentinel哨兵信息;sentinel masters 查看master 節點信息;sentinel slaves mymaster(sentinel.conf制定的名字) 查看slave信息

Redis主從複製原理

  1. 配置好slave後,slave與master建立連接,然後發送sync命令. 
  2. 無論是第一次連接還是重新連接,master都會啓動一個後臺進程,將數據庫快照保存到文件中,同時master主進程會開始收集新的寫命令並緩存. 
  3. 後臺進程完成寫文件後,master就發送文件給slave,slave將文件保存到硬盤上,再加載到內存中, 
  4. 接着master就會把緩存的命令轉發給slave,後續master將收到的寫命令發送給slave. 
  5. 如果master同時收到多個slave發來的同步連接命令,master只會啓動一個進程來寫數據庫鏡像, 然後發送給所有的slave

Redis持久化原理

Redis有兩種持久化的方式:快照(RDB文件)和追加式文件(AOF文件):

  • RDB持久化方式會在一個特定的間隔保存那個時間點的一個數據快照。
  • AOF持久化方式則會記錄每一個服務器收到的寫操作。在服務啓動時,這些記錄的操作會逐條執行從而重建出原來的數據。寫操作命令記錄的格式跟Redis協議一致,以追加的方式進行保存。
  • Redis的持久化是可以禁用的,就是說你可以讓數據的生命週期只存在於服務器的運行時間裏。
  • 兩種方式的持久化是可以同時存在的,但是當Redis重啓時,AOF文件會被優先用於重建數據。
RDB

工作原理
  • Redis調用fork(),產生一個子進程。
  • 子進程把數據寫到一個臨時的RDB文件。
  • 當子進程寫完新的RDB文件後,把舊的RDB文件替換掉。
優點
  • RDB文件是一個很簡潔的單文件,它保存了某個時間點的Redis數據,很適合用於做備份。你可以設定一個時間點對RDB文件進行歸檔,這樣就能在需要的時候很輕易的把數據恢復到不同的版本。
  • 基於上面所描述的特性,RDB很適合用於災備。單文件很方便就能傳輸到遠程的服務器上。
  • RDB的性能很好,需要進行持久化時,主進程會fork一個子進程出來,然後把持久化的工作交給子進程,自己不會有相關的I/O操作。
  • 比起AOF,在數據量比較大的情況下,RDB的啓動速度更快。
缺點
  • RDB容易造成數據的丟失。假設每5分鐘保存一次快照,如果Redis因爲某些原因不能正常工作,那麼從上次產生快照到Redis出現問題這段時間的數據就會丟失了。
  • RDB使用fork()產生子進程進行數據的持久化,如果數據比較大的話可能就會花費點時間,造成Redis停止服務幾毫秒。如果數據量很大且CPU性能不是很好的時候,停止服務的時間甚至會到1秒。
保存點(RDB的啓用和禁用)

你可以配置保存點,使Redis如果在每N秒後數據發生了M次改變就保存快照文件。例如下面這個保存點配置表示每60秒,如果數據發生了1000次以上的變動,Redis就會自動保存快照文件:

save 60 1000

保存點可以設置多個,Redis的配置文件就默認設置了3個保存點:

# 格式爲:save <seconds> <changes># 可以設置多個。
save 900 1 #900秒後至少1個key有變動
save 300 10 #300秒後至少10個key有變動
save 60 10000 #60秒後至少10000個key有變動

如果想禁用快照保存的功能,可以通過註釋掉所有"save"配置達到,或者在最後一條"save"配置後添加如下的配置:

save ""

錯誤處理

默認情況下,如果Redis在後臺生成快照的時候失敗,那麼就會停止接收數據,目的是讓用戶能知道數據沒有持久化成功。但是如果你有其他的方式可以監控到Redis及其持久化的狀態,那麼可以把這個功能禁止掉。

stop-writes-on-bgsave-error yes

數據壓縮

默認Redis會採用LZF對數據進行壓縮。如果你想節省點CPU的性能,你可以把壓縮功能禁用掉,但是數據集就會比沒壓縮的時候要打。

rdbcompression yes

數據校驗

從版本5的RDB的開始,一個CRC64的校驗碼會放在文件的末尾。這樣更能保證文件的完整性,但是在保存或者加載文件時會損失一定的性能(大概10%)。如果想追求更高的性能,可以把它禁用掉,這樣文件在寫入校驗碼時會用0替代,加載的時候看到0就會直接跳過校驗。

rdbchecksum yes

手動生成快照

Redis提供了兩個命令用於手動生成快照。

SAVE

SAVE命令會使用同步的方式生成RDB快照文件,這意味着在這個過程中會阻塞所有其他客戶端的請求。因此不建議在生產環境使用這個命令,除非因爲某種原因需要去阻止Redis使用子進程進行後臺生成快照(例如調用fork(2)出錯)。

BGSAVE

BGSAVE命令使用後臺的方式保存RDB文件,調用此命令後,會立刻返回OK返回碼。Redis會產生一個子進程進行處理並立刻恢復對客戶端的服務。在客戶端我們可以使用LASTSAVE命令查看操作是否成功。

127.0.0.1:6379> BGSAVEBackground saving started
127.0.0.1:6379> LASTSAVE
(integer) 1433936394

配置文件裏禁用了快照生成功能不影響SAVEBGSAVE命令的效果。

AOF

快照並不是很可靠。如果你的電腦突然宕機了,或者電源斷了,又或者不小心殺掉了進程,那麼最新的數據就會丟失。而AOF文件則提供了一種更爲可靠的持久化方式。每當Redis接受到會修改數據集的命令時,就會把命令追加到AOF文件裏,當你重啓Redis時,AOF裏的命令會被重新執行一次,重建數據。

優點

  • 比RDB可靠。你可以制定不同的fsync策略:不進行fsync、每秒fsync一次和每次查詢進行fsync。默認是每秒fsync一次。這意味着你最多丟失一秒鐘的數據。
  • AOF日誌文件是一個純追加的文件。就算是遇到突然停電的情況,也不會出現日誌的定位或者損壞問題。甚至如果因爲某些原因(例如磁盤滿了)命令只寫了一半到日誌文件裏,我們也可以用redis-check-aof這個工具很簡單的進行修復。
  • 當AOF文件太大時,Redis會自動在後臺進行重寫。重寫很安全,因爲重寫是在一個新的文件上進行,同時Redis會繼續往舊的文件追加數據。新文件上會寫入能重建當前數據集的最小操作命令的集合。當新文件重寫完,Redis會把新舊文件進行切換,然後開始把數據寫到新文件上。
  • AOF把操作命令以簡單易懂的格式一條接一條的保存在文件裏,很容易導出來用於恢復數據。例如我們不小心FLUSHALL命令把所有數據刷掉了,只要文件沒有被重寫,我們可以把服務停掉,把最後那條命令刪掉,然後重啓服務,這樣就能把被刷掉的數據恢復回來。

缺點

  • 在相同的數據集下,AOF文件的大小一般會比RDB文件大。
  • 在某些fsync策略下,AOF的速度會比RDB慢。通常fsync設置爲每秒一次就能獲得比較高的性能,而在禁止fsync的情況下速度可以達到RDB的水平。
  • 在過去曾經發現一些很罕見的BUG導致使用AOF重建的數據跟原數據不一致的問題。

啓用AOF

把配置項appendonly設爲yes

appendonly yes

文件路徑和名稱

# 文件存放目錄,與RDB共用。默認爲當前工作目錄。dir ./

# 默認文件名爲appendonly.aof
appendfilename "appendonly.aof"

可靠性

你可以配置Redis調用fsync的頻率,有三個選項:

  • 每當有新命令追加到AOF的時候調用fsync。速度最慢,但是最安全。
  • 每秒fsync一次。速度快(2.4版本跟快照方式速度差不多),安全性不錯(最多丟失1秒的數據)。
  • 從不fsync,交由系統去處理。這個方式速度最快,但是安全性一般。

推薦使用每秒fsync一次的方式(默認的方式),因爲它速度快,安全性也不錯。相關配置如下:

# appendfsync alwaysappendfsync everysec
# appendfsync no

日誌重寫(Rewrite機制)

隨着寫操作的不斷增加,AOF文件會越來越大。例如你遞增一個計數器100次,那麼最終結果就是數據集裏的計數器的值爲最終的遞增結果,但是AOF文件裏卻會把這100次操作完整的記錄下來。而事實上要恢復這個記錄,只需要1個命令就行了,也就是說AOF文件裏那100條命令其實可以精簡爲1條。所以Redis支持這樣一個功能:在不中斷服務的情況下在後臺重建AOF文件。

工作原理如下:

  • Redis調用fork(),產生一個子進程。
  • 子進程把新的AOF寫到一個臨時文件裏。
  • 主進程持續把新的變動寫到內存裏的buffer,同時也會把這些新的變動寫到舊的AOF裏,這樣即使重寫失敗也能保證數據的安全。
  • 當子進程完成文件的重寫後,主進程會獲得一個信號,然後把內存裏的buffer追加到子進程生成的那個新AOF裏。
  • Redis

我們可以通過配置設置日誌重寫的條件:

# Redis會記住自從上一次重寫後AOF文件的大小(如果自Redis啓動後還沒重寫過,則記住啓動時使用的AOF文件的大小)。# 如果當前的文件大小比起記住的那個大小超過指定的百分比,則會觸發重寫。# 同時需要設置一個文件大小最小值,只有大於這個值文件纔會重寫,以防文件很小,但是已經達到百分比的情況。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

要禁用自動的日誌重寫功能,我們可以把百分比設置爲0:

auto-aof-rewrite-percentage 0

Redis 2.4以上纔可以自動進行日誌重寫,之前的版本需要手動運行BGREWRITEAOF這個命令。

Redis數據恢復順序


當redis服務器掛掉時,重啓時將按以下優先級恢復數據到內存種:

1. 如果只配置了AOF,重啓時加載AOF文件恢復數據.

2. 如果同時配置了RBD和AOF,啓動時只加載AOF文件恢復數據.

3. 如果只配置了㻾DB,啓動時將加載dump文件恢復數據.

數據損壞修復

如果因爲某些原因(例如服務器崩潰)AOF文件損壞了,導致Redis加載不了,可以通過以下方式進行修復:

  • 備份AOF文件。
  • 使用redis-check-aof命令修復原始的AOF文件:

    $ redis-check-aof --fix
  • 可以使用diff -u命令看下兩個文件的差異。
  • 使用修復過的文件重啓Redis服務。

從RDB切換到AOF

這裏只說Redis >= 2.2版本的方式:

  • 備份一個最新的dump.rdb的文件,並把備份文件放在一個安全的地方。
  • 運行以下兩條命令:

    $ redis-cli config set appendonly yes
    $ redis-cli config set save ""
  • 確保數據跟切換前一致。

  • 確保數據正確的寫到AOF文件裏。

第二條命令是用來禁用RDB的持久化方式,但是這不是必須的,因爲你可以同時啓用兩種持久化方式。

記得對配置文件redis.conf進行編輯啓用AOF,因爲命令行方式修改配置在重啓Redis後就會失效。

備份

建議的備份方法

  • 創建一個定時任務,每小時和每天創建一個快照,保存在不同的文件夾裏。
  • 定時任務運行時,把太舊的文件進行刪除。例如只保留48小時的按小時創建的快照和一到兩個月的按天創建的快照。
  • 每天確保一次把快照文件傳輸到數據中心外的地方進行保存,至少不能保存在Redis服務所在的服務器
Redis哨兵機制

Sentinel(哨兵)是用於監控redis集羣中Master狀態的工具


Sentinel作用


  1. Master狀態檢測
  2. 如果Master異常,則會進行Master-Slave切換,將其中一個Slave作爲Master,將之前的Master作爲Slave
  3. Master-Slave切換後,master_redis.conf、slave_redis.conf和sentinel.conf的內容都會發生改變,即master_redis.conf中會多一行slaveof的配置,sentinel.conf的監控目標會隨之調換

Sentinel工作方式


  1. 每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 實例發送一個 PING 命令
  2. 如果一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記爲主觀下線
  3. 如果一個Master被標記爲主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態
  4. 當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記爲客觀下線
  5. 在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有Master,Slave發送 INFO 命令
  6. 當Master被 Sentinel 標記爲客觀下線時,Sentinel 向下線的 Master 的所有 Slave 發送 INFO 命令的頻率會從 10 秒一次改爲每秒一次
  7. 若沒有足夠數量的 Sentinel 同意 Master 已經下線, Master 的主觀下線狀態就會被移除
  8. 若 Master 重新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除


備註

主觀下線:Subjectively Down,簡稱 SDOWN,指的是當前 Sentinel 實例對某個redis服務器做出的下線判斷

客觀下線:Objectively Down, 簡稱 ODOWN,指的是多個 Sentinel 實例在對Master Server做出 SDOWN 判斷,並且通過 SENTINEL is-master-down-by-addr 命令互相交流之後,得出的Master Server下線判斷,然後開啓failover.

SDOWN適合於Master和Slave,只要一個 Sentinel 發現Master進入了ODOWN, 這個 Sentinel 就可能會被其他 Sentinel 推選出, 並對下線的主服務器執行自動故障遷移操作。

ODOWN只適用於Master,對於Slave的 Redis 實例,Sentinel 在將它們判斷爲下線前不需要進行協商, 所以Slave的 Sentinel 永遠不會達到ODOWN。

注意點

  1. 首次啓動時,必須先啓動Master
  2. Sentinel 只在 server 端做主從切換,app端要自己開發(例如Jedis庫的SentinelJedis,能夠監控Sentinel的狀態)
  3. 若Master已經被判定爲下線,Sentinel已經選擇了新的Master,也已經將old Master改成Slave,但是還沒有將其改成new Master。若此時重啓old Master,則Redis集羣將處於無Master狀態,此時只能手動修改配置文件,然後重新啓動集羣

Redis API使用

Redis的使用需要用到API,maven依賴如下
  1. <dependency>
  2. <groupId>redis.clients</groupId>
  3. <artifactId>jedis</artifactId>
  4. <version>2.7.3</version>
  5. </dependency>
Redis的使用主要以下三種:
  • 直接使用Redis的接口Jedis
  • 使用Redis資源池的接口JedisPool
    • 資源池維護一個資源連接池,jedis實例可以動態的從中獲取連接資源
  • 使用Redis 集羣的接口JedisCluster
    • JedisCluster是jedis封裝的關於redis cluster操作的class;
    • JedisCluster裏主要有兩個成員變量:maxRedirections和connectionHandler
    • JedisCluster會從connectionHandler基於key找出對應的SLOTS和NODES,並找出對應的JedisPool對象
    • 從JedisPool對象中找出可用的Jedis實例,執行Jedis的對應操作

JedisPool的使用
JedisPool的配置
  1. JedisPoolConfig config = new JedisPoolConfig();
  2. String host = Config.getM_strRedisIp();
  3. int port = Config.getM_nRedisPort();
  4. config.setMaxTotal(MAX_ACTIVE);
  5. config.setMaxIdle(MAX_IDLE);
  6. config.setMaxWaitMillis(MAX_WAIT);
  7. config.setTestOnBorrow(TEST_ON_BORROW);
  8. jedisPool = new JedisPool(config, host, port, TIMEOUT);
JedisPool之Jedis實例調用
  1. Jedis jedis = jedisPool.getResource();

JedisCluster的使用
  1. #設置集羣的節點
  2. Set<HostAndPort> nodes = new HashSet<HostAndPort>();
  3. String redisCluster = Config.getM_strRedisCluster();
  4. String[] ipPorts = redisCluster.split(",");
  5. for (String ipPort : ipPorts)
  6. {
  7. String ip = ipPort.split(":")[0];
  8. String port = ipPort.split(":")[1];
  9. nodes.add(new HostAndPort(ip, Integer.parseInt(port)));
  10. }
  11. #配置config
  12. JedisPoolConfig poolConfig = new JedisPoolConfig();
  13. poolConfig.setMaxIdle(5);
  14. poolConfig.setMaxTotal(20);
  15. // 在borrow一個jedis實例時,是否提前進行validate操作;如果爲true,則得到的jedis實例均是可用的;
  16. poolConfig.setTestOnBorrow(true);
  17. #設置超時時間
  18. int timeout = 5000;
  19. #創建jedisCluster
  20. JedisCluster jedisCluster = new JedisCluster(nodes, timeout, poolConfig);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章