redis入門(三)

  • 2019 年 11 月 6 日
  • 筆記

redis入門(三)

目錄

redis入門(一)
redis入門(二)
redis入門(三)

前言

在前兩章介紹了Redis的一些常用的API與功能,在本章會對一些其他功能包括事務、腳本、Redis集群搭建工具以及集群動態擴容與故障轉移方式進行講解。

事務

在關係型資料庫,我們可以通過事務(transaction)的方式執行資料庫級別的原子性操作。在Redis中也提供簡單的事務功能。
Redis通過MULTIEXECWATCH等命令來實現功能。它提供了一種將多個命令請求打包,然後一次性、按順序地執行多個命令的機制。
將一組需要一起執行的命令放到MULTIEXEC兩個命令之間。MULTI命令代表事務開始,EXEC命令代表事務結束,它們之間的命令是原子順序執行的,在MULTI執行之後,的寫命令會直接返回QUEUE,當輸入EXEC後會將所有命令一起執行。

127.0.0.1:6379> multi  OK  127.0.0.1:6379> set a 1  QUEUED  127.0.0.1:6379> set b 2  QUEUED  127.0.0.1:6379> exec  1) OK  2) OK

若不使用事務時,客戶端發送的命令會立即被服務端執行。使用事務時,當客戶端發送的命令是EXECDISCARDWATCHMULTI命令之一時,伺服器立即執行該命令,若不是上述四個命令,則會將命令加入到一個事務隊列中,然後向客戶端返回QUEUE回復。

由於開啟事務時命令不會直接被執行,而是直接入隊,因此Redis也不會立即發現運行時錯誤(比如hash的鍵使用string的命令執行)。因此當事務中某條命令執行失敗時,其他命令還是可以可以正常執行。因此使用EXECMULTI命令時Redis僅保證打包的若干條命令以原子性順序執行,而不保證事務中的命令全部執行成功。

127.0.0.1:6379> multi  OK  127.0.0.1:6379> set a 5  QUEUED  127.0.0.1:6379> hset b n 1  QUEUED  127.0.0.1:6379> set c 2  QUEUED  127.0.0.1:6379> exec  1) OK  2) (error) WRONGTYPE Operation against a key holding the wrong kind of value  3) OK

為了實現真正的事務,Redis引入了WATCH實現樂觀鎖。在MULTI命令執行之前,可以通過WATCH監控指定的鍵,若在EXEC提交事務之前,數據發生了變化,則事務執行失敗。

客戶端A

127.0.0.1:6379> WATCH a  OK  127.0.0.1:6379> multi  OK  127.0.0.1:6379> set b 1  QUEUED  127.0.0.1:6379> set a 6  QUEUED  127.0.0.1:6379> set c 3  QUEUED  127.0.0.1:6379> exec  (nil)  127.0.0.1:6379>  

客戶端B

127.0.0.1:6379>  set a 7  OK

時間點

時間序號 客戶端A 客戶端B
1 WATCH a
2 multi
3 set b 1
4 set a 6
5 set c 3 set a 7
6 exec

客戶端B在客戶端A執行WATCH之後exec命令提交前執行了一條SET命令,客戶端A提交EXEC命令則會提交失敗。

原理

  1. 每個Redis資料庫都會有一個字典用於保存被監視的鍵,而字典的的值是一個鏈表。該列表記錄了所有監視該鍵的客戶端。因此Redis伺服器就清楚的知道哪些鍵被哪些客戶端監視了。
  2. 當被監視的鍵被修改時,會觸發一個動作將被修改鍵的客戶端的該鍵的「臟數據」標誌打開,表示該鍵的事務已經被破壞。
  3. 當客戶端提交事務的時候,伺服器會判斷這個客戶端是否存在被監視的鍵打開了「臟數據」標誌。若該標識被打開,則說明客戶端所以監視的鍵已經被修改,伺服器就會拒絕事務提交。

Lua腳本

Redis從2.6版本開始引入對Lua腳本的支援。

Lua語言是在1993年由巴西一個大學研究小組發明,其設計目標是作為嵌入式程式移植到其他應用程式,它是由C語言實現的。

在redis伺服器中內嵌了一個Lua環境,在redis服務啟動之前會對該Lua環境進行一些修改,確保Lua環境滿足redis伺服器的需要。

安裝

在ubuntu可以通過以下命令下載

curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz  tar zxf lua-5.3.5.tar.gz  cd lua-5.3.5  make linux test

在我本地編譯Lua時報錯,可以參考編譯lua-5.3.5時出錯解決方法解決。

windows環境下安裝可以參考Lua在Windows下的安裝、配置、運行

由於redis中存在Lua環境,因此即使不在本地安裝Lua環境redis也是可以正常執行Lua腳本的也沒關係。

腳本命令

Redis提供了2個執行lua腳本的命令EVALEVALSHA

  1. EVAL

    命令格式為eval 腳本內容 key個數 key列表 參數列表

    127.0.0.1:6379> eval ' return KEYS[1] .. ARGV[1]' 1 hello world  "helloworld"

    redis中key下標從1開始
    lua通過..鏈接兩個字元串

    我們也可以通redis-cli --eval直接執行腳本文件
    return KEYS[1] .. ARGV[1]保存到文件中,命名為helloworld.lua
    通過--eval 腳本路徑 key列表 , 參數列表

    注意key列表和參數列表中間的,左右兩邊至少都要有一個空格,否則會報錯

    jake@Jake-PC:~/tool$ redis/src/redis-cli -p 26379 --eval lua-5.3.5/helloworld.lua hello , world  "helloworld"
  2. EVALSHA
    當腳本比較大時,每次發送腳本會佔用一定的網路頻寬。redis提供了講腳本快取的方式減少腳本傳輸的開銷。首先需要通過script load命令將lua腳本載入到redis服務端,獲得到腳本的SHA1校驗和。然後通過evalsha命令執行校驗和的腳本。

    127.0.0.1:6379> script load 'return KEYS[1] .. ARGV[1]'  "dc8235f4444d746adf3374579406c129fb1f0f0a"  127.0.0.1:6379> evalsha dc8235f4444d746adf3374579406c129fb1f0f0a 1 hello world  "helloworld"

    每個被EVAL執行成功過的lua腳本,在lua環境都會有與該腳本對應的lua函數。函數名為f_加四十位的SHA1校驗和。

    function f_dc8235f4444d746adf3374579406c129fb1f0f0a()      return KEYS[1] .. ARGV[1]  end

    我們還可以將腳本文件內容進行載入,通過evalsha獲取其SHA1校驗和。在linux環境下可以通過cat讀取文件內容,

    jake@Jake-PC:~/tool$ redis/src/redis-cli -a test1 script load "$(cat lua-5.3.5/helloworld.lua)"  "dc8235f4444d746adf3374579406c129fb1f0f0a"

    需要使用$()或“將cat lua-5.3.5/helloworld.lua包起來

    在windows環境下使用powershell可以通過Get-Content讀取文本

    PS C:UsersDm_ca> redis-cli -a test1 script load (Get-Content F:Studyhelloworld.lua)  "dc8235f4444d746adf3374579406c129fb1f0f0a"
  3. lua和redis互操作

    由於redis支援調用Lua腳本,而且Lua存在調用redis的API,這樣我們就可以將一系列Lua腳本以原子性的執行。在lua中可以通過redis.call(command,key[param1, param2…])調用redis命令。

    127.0.0.1:26379> eval 'return redis.call("set",KEYS[1],ARGV[1])' 1 "hello" , "redis"  OK

    對於redis中調用lua更多細節可以看EVAL script

  4. SCRIPT EXISTS
    通過該命令輸入SHA1校驗和可以檢查對應的腳本是否存在。

  5. SCRIPT FLUSH
    該命令用於清除伺服器中所有和lua腳本相關的資訊,並關閉當前lua環境重新創建一個新的lua環境

  6. SCRIPT KILL
    在每次執行lua腳本之前,redis伺服器都會在lua環境中設置一個超時處理鉤子,若腳本執行超過配置的lua-time-limit的時長時,可以通過該命令停止當前的lua腳本執行。

    若當前lua腳本有寫入操作,則無法在使用該腳本停止執行。只能通過SHUTDOWN nosave命令關閉。

  7. 腳本複製
    當伺服器開啟了主從複製時,寫命令的腳本也會複製到從伺服器以確保從伺服器的數據和主伺服器一致。
    但是EVALSHA命令比較特殊,因為有可能主伺服器載入了腳本,從伺服器還沒有來的及同步。所以會存在主伺服器字典中存在函數快取但是從伺服器不存在的情況。因此當Redis要求主伺服器在傳播EVALSHA命令的時候,必須確保EVALSHA命令要執行的腳本已經被所有從伺服器載入過,如果不能確保這一點的話,主伺服器會將EVALSHA命令轉換成一個等價的EVAL命令,然後通過傳播EVAL命令來代替EVALSHA命令。

集群搭建工具

redis-trib.rb

在上一節我們講解了集群搭建的原理和過程。但是一步步都採取純手工搭建會不太方便,而且也容易出錯。在redis5.0以前可以通過redis-trib.rb進行集群搭建。它是Ruby實現Redis集群管理工具。

Ruby 是一種開源的面向對象程式設計的伺服器端腳本語言,在 20 世紀 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)設計並開發。 Ruby 可運行於多種平台,如 Windows、MAC OS 和 UNIX 的各種版本。

下面我在windows平台上搭建集群。

  1. 準備ruby環境。
    在windows環境可以到RubyInstaller下載安裝。
    下載安裝完可以通過ruby -v確定是否安裝成功,以及當前ruby版本號。

    安裝完成會彈出一個框詢問安裝MSYS2,我們可以不需要。

  2. 安裝rubygem redis依賴:

    C:UsersDm_ca>gem install redis  Fetching redis-4.1.3.gem  Successfully installed redis-4.1.3  Parsing documentation for redis-4.1.3  Installing ri documentation for redis-4.1.3  Done installing documentation for redis after 2 seconds  1 gem installed
  3. 下載redis-trib.rb
    從github上下載3.2或4.0版本redis的redis-trib.rb程式碼保存到文件redis-trib.rb中。

    4.0的redis-trib.rb做了一定的優化,儘可能讓主從處於不同的主機,同時當創建集群時若主從處於同一個ip也會進行提示。
    5.0的redis-trib.rb已經不支援了,redis-cli已經集成了redis-trib.rb的功能,當使用redis-trib.rb時會提示使用redis-cli cluster執行。

  4. 創建7579~75846個埠的配置文件,啟動6個redis服務,配置可以參考上一章的集群搭建配置

     start redis-server.exe redis-7579.conf   start redis-server.exe redis-7580.conf   start redis-server.exe redis-7581.conf   start redis-server.exe redis-7582.conf   start redis-server.exe redis-7583.conf   start redis-server.exe redis-7584.conf

    為了方便暫時沒有作為windows服務啟動

  5. 通過命令ruby redis-trib.rb create --replicas <arg> host1:port1 ... hostN:portN命令創建集群,如ruby redis-trib.rb create --replicas 1 127.0.0.1:7579 127.0.0.1:7580 127.0.0.1:7581 127.0.0.1:7582 127.0.0.1:7583 127.0.0.1:7584
  6. F:Studyredisredis集群>ruby redis-trib.rb create --replicas 1 127.0.0.1:7579 127.0.0.1:7580 127.0.0.1:7581 127.0.0.1:7582 127.0.0.1:7583 127.0.0.1:7584  >>> Creating cluster  >>> Performing hash slots allocation on 6 nodes...  Using 3 masters:  127.0.0.1:7579  127.0.0.1:7580  127.0.0.1:7581  Adding replica 127.0.0.1:7583 to 127.0.0.1:7579  Adding replica 127.0.0.1:7584 to 127.0.0.1:7580  Adding replica 127.0.0.1:7582 to 127.0.0.1:7581  >>> Trying to optimize slaves allocation for anti-affinity  [WARNING] Some slaves are in the same host as their master  M: 4e4f38cce9a8dd1d7871e327e69c2a2556c90ad7 127.0.0.1:7579  slots:0-5460 (5461 slots) master  M: 426942a0f20ccbfa9d68c1b0809800c31d10c0ab 127.0.0.1:7580  slots:5461-10922 (5462 slots) master  M: 1149113de5253841923789e79c362ad745509f5c 127.0.0.1:7581  slots:10923-16383 (5461 slots) master  S: e7e172a7cba6e052d36d0a330225f48f3858fb72 127.0.0.1:7582  replicates 1149113de5253841923789e79c362ad745509f5c  S: 7fb04e281546d6f0d0e0a3a06b5f80b101eae00f 127.0.0.1:7583  replicates 4e4f38cce9a8dd1d7871e327e69c2a2556c90ad7  S: b872de59634dd245c0452b46832994bf04a6c08b 127.0.0.1:7584  replicates 426942a0f20ccbfa9d68c1b0809800c31d10c0ab  Can I set the above configuration? (type 'yes' to accept): yes  >>> Nodes configuration updated  >>> Assign a different config epoch to each node  >>> Sending CLUSTER MEET messages to join the cluster  Waiting for the cluster to join...  >>> Performing Cluster Check (using node 127.0.0.1:7579)  M: 4e4f38cce9a8dd1d7871e327e69c2a2556c90ad7 127.0.0.1:7579  slots:0-5460 (5461 slots) master  1 additional replica(s)  M: 1149113de5253841923789e79c362ad745509f5c 127.0.0.1:7581  slots:10923-16383 (5461 slots) master  1 additional replica(s)  S: 7fb04e281546d6f0d0e0a3a06b5f80b101eae00f 127.0.0.1:7583  slots: (0 slots) slave  replicates 4e4f38cce9a8dd1d7871e327e69c2a2556c90ad7  S: b872de59634dd245c0452b46832994bf04a6c08b 127.0.0.1:7584  slots: (0 slots) slave  replicates 426942a0f20ccbfa9d68c1b0809800c31d10c0ab  M: 426942a0f20ccbfa9d68c1b0809800c31d10c0ab 127.0.0.1:7580  slots:5461-10922 (5462 slots) master  1 additional replica(s)  S: e7e172a7cba6e052d36d0a330225f48f3858fb72 127.0.0.1:7582  slots: (0 slots) slave  replicates 1149113de5253841923789e79c362ad745509f5c  [OK] All nodes agree about slots configuration.  >>> Check for open slots...  >>> Check slots coverage...  [OK] All 16384 slots covered.

    由於我綁定ip沒修改,主從使用的都是127.0.0.1,因此會有警告提示[WARNING] Some slaves are in the same host as their master
    生產配置需要綁定實際的ip,同時將protected-mode設置為no,否則只允許本機訪問。
    查看集群狀態,可以看到已經存在三主三從,同時虛擬槽都自動分配了。

    F:Studyredisredis集群>redis-cli -p 7479 cluster nodes  0f6cf326c23af6399e6c3bfc374b04efbac015d3 127.0.0.1:7381@17381 master - 0 1572935809989 3 connected 10923-16383  96b98672b59fd85f8743fde5b354abdb38ee3b47 127.0.0.1:7479@17479 myself,slave 0f6cf326c23af6399e6c3bfc374b04efbac015d3 0 1572935809000 4 connected  231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 127.0.0.1:7379@17379 master - 0 1572935810997 1 connected 0-5460  e4ce1b6f872c6f72f776d534ce1dc783a0cf3655 127.0.0.1:7480@17480 slave 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 0 1572935808000 1 connected  a9a4296b46db50459c5efb00d205fff671c2bfd0 127.0.0.1:7380@17380 master - 0 1572935810000 2 connected 5461-10922  dcae00d572280d795fcbc82b899f2f1a50f1397c 127.0.0.1:7481@17481 slave a9a4296b46db50459c5efb00d205fff671c2bfd0 0 1572935809000 6 connected

redis官方集群搭建

在redis5.0開始官方集成了redis-trib.rb。可以直接通過cluster create命令創建集群。

  1. 將六個redis服務啟動

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7379.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7380.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7381.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7479.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7480.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7481.config
  2. 創建集群
    redis-cli --cluster create 127.0.0.1:7379 127.0.0.1:7380 127.0.0.1:7381 127.0.0.1:7479 127.0.0.1:7480 127.0.0.1:7481 --cluster-replicas 1
    在craete後面指定redis服務的ip和埠,最後通過--cluster-replicas表示每個主節點創建一個從節點。

    5.0的集群--cluster-replicas參數可以放到create後面也可以放到最後,但是4.0的集群--replicas需要放到create後面,不能放最後。

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster create 127.0.0.1:7379 127.0.0.1:7380 127.0.0.1:7381 127.0.0.1:7479 127.0.0.1:7480 127.0.0.1:7481 --cluster-replicas 1  >>> Performing hash slots allocation on 6 nodes...  Master[0] -> Slots 0 - 5460  Master[1] -> Slots 5461 - 10922  Master[2] -> Slots 10923 - 16383  Adding replica 127.0.0.1:7480 to 127.0.0.1:7379  Adding replica 127.0.0.1:7481 to 127.0.0.1:7380  Adding replica 127.0.0.1:7479 to 127.0.0.1:7381  >>> Trying to optimize slaves allocation for anti-affinity  [WARNING] Some slaves are in the same host as their master  M: 5591d1f47c15f919e6c492325bca0a385b581471 127.0.0.1:7379  slots:[0-5460] (5461 slots) master  M: 157bee0bd158456fc7e27eb165299ed33df769a0 127.0.0.1:7380  slots:[5461-10922] (5462 slots) master  M: eb63ce6942fd606a81113fe07622908931356057 127.0.0.1:7381  slots:[10923-16383] (5461 slots) master  S: 3eb412b810c4bd9a3c0f4ab1f4af8ee03d06d818 127.0.0.1:7479  replicates 5591d1f47c15f919e6c492325bca0a385b581471  S: 30c2792fe726a9174c07f7d2db5704f5e9ef3b66 127.0.0.1:7480  replicates 157bee0bd158456fc7e27eb165299ed33df769a0  S: 56250f10afe111ce206169588300b39a6447ed91 127.0.0.1:7481  replicates eb63ce6942fd606a81113fe07622908931356057  Can I set the above configuration? (type 'yes' to accept): yes  >>> Nodes configuration updated  >>> Assign a different config epoch to each node  >>> Sending CLUSTER MEET messages to join the cluster  Waiting for the cluster to join  .......  >>> Performing Cluster Check (using node 127.0.0.1:7379)  M: 5591d1f47c15f919e6c492325bca0a385b581471 127.0.0.1:7379  slots:[0-5460] (5461 slots) master  1 additional replica(s)  S: 30c2792fe726a9174c07f7d2db5704f5e9ef3b66 127.0.0.1:7480  slots: (0 slots) slave  replicates 157bee0bd158456fc7e27eb165299ed33df769a0  S: 56250f10afe111ce206169588300b39a6447ed91 127.0.0.1:7481  slots: (0 slots) slave  replicates eb63ce6942fd606a81113fe07622908931356057  S: 3eb412b810c4bd9a3c0f4ab1f4af8ee03d06d818 127.0.0.1:7479  slots: (0 slots) slave  replicates 5591d1f47c15f919e6c492325bca0a385b581471  M: 157bee0bd158456fc7e27eb165299ed33df769a0 127.0.0.1:7380  slots:[5461-10922] (5462 slots) master  1 additional replica(s)  M: eb63ce6942fd606a81113fe07622908931356057 127.0.0.1:7381  slots:[10923-16383] (5461 slots) master  1 additional replica(s)  [OK] All nodes agree about slots configuration.  >>> Check for open slots...  >>> Check slots coverage...  [OK] All 16384 slots covered.

    通過該命令可以自動集群握手並自動分配槽。

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli -p 7379 cluster nodes  30c2792fe726a9174c07f7d2db5704f5e9ef3b66 127.0.0.1:7480@17480 slave 157bee0bd158456fc7e27eb165299ed33df769a0 0 1572926323116 5 connected  5591d1f47c15f919e6c492325bca0a385b581471 127.0.0.1:7379@17379 myself,master - 0 1572926322000 1 connected 0-5460  56250f10afe111ce206169588300b39a6447ed91 127.0.0.1:7481@17481 slave eb63ce6942fd606a81113fe07622908931356057 0 1572926320090 6 connected  3eb412b810c4bd9a3c0f4ab1f4af8ee03d06d818 127.0.0.1:7479@17479 slave 5591d1f47c15f919e6c492325bca0a385b581471 0 1572926322107 4 connected  157bee0bd158456fc7e27eb165299ed33df769a0 127.0.0.1:7380@17380 master - 0 1572926321098 2 connected 5461-10922  eb63ce6942fd606a81113fe07622908931356057 127.0.0.1:7381@17381 master - 0 1572926320000 3 connected 10923-16383

集群橫向擴展

由於使用redis-cli --clusterredis-trib.rb命令格式大同小異,下面我都在linux下使用redis-cli --cluster執行命令。

  1. 添加兩個配置節點分別為7382和7482用於集群擴展。
  2. 啟動新的節點

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7382.config  jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-server data/redis-7482.config
  3. 添加新的主節點到集群,使用--cluster add-node 新節點地址 集群節點地址添加新的節點

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster add-node 127.0.0.1:7382 127.0.0.1:7379  >>> Adding node 127.0.0.1:7382 to cluster 127.0.0.1:7379  >>> Performing Cluster Check (using node 127.0.0.1:7379)  M: 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 127.0.0.1:7379  slots:[0-5460] (5461 slots) master  1 additional replica(s)  S: dcae00d572280d795fcbc82b899f2f1a50f1397c 127.0.0.1:7481  slots: (0 slots) slave  replicates a9a4296b46db50459c5efb00d205fff671c2bfd0  S: 96b98672b59fd85f8743fde5b354abdb38ee3b47 127.0.0.1:7479  slots: (0 slots) slave  replicates 0f6cf326c23af6399e6c3bfc374b04efbac015d3  M: 0f6cf326c23af6399e6c3bfc374b04efbac015d3 127.0.0.1:7381  slots:[10923-16383] (5461 slots) master  1 additional replica(s)  M: a9a4296b46db50459c5efb00d205fff671c2bfd0 127.0.0.1:7380  slots:[5461-10922] (5462 slots) master  1 additional replica(s)  S: e4ce1b6f872c6f72f776d534ce1dc783a0cf3655 127.0.0.1:7480  slots: (0 slots) slave  replicates 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4  [OK] All nodes agree about slots configuration.  >>> Check for open slots...  >>> Check slots coverage...  [OK] All 16384 slots covered.  >>> Send CLUSTER MEET to node 127.0.0.1:7382 to make it join the cluster.  [OK] New node added correctly.
  4. 添加新的從節點到集群,使用--cluster add-node --cluster-slave --cluster-master-id 主節點id 新的節點地址 集群節點地址添加新的節點

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster add-node --cluster-slave --cluster-master-id d683040a8654a9ce994365d988ded03c03393135 127.0.0.1:7482 127.0.0.1:7379  >>> Adding node 127.0.0.1:7482 to cluster 127.0.0.1:7379  >>> Performing Cluster Check (using node 127.0.0.1:7379)  M: 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 127.0.0.1:7379  slots:[0-5460] (5461 slots) master  1 additional replica(s)  S: dcae00d572280d795fcbc82b899f2f1a50f1397c 127.0.0.1:7481  slots: (0 slots) slave  replicates a9a4296b46db50459c5efb00d205fff671c2bfd0  S: 96b98672b59fd85f8743fde5b354abdb38ee3b47 127.0.0.1:7479  slots: (0 slots) slave  replicates 0f6cf326c23af6399e6c3bfc374b04efbac015d3  M: 0f6cf326c23af6399e6c3bfc374b04efbac015d3 127.0.0.1:7381  slots:[10923-16383] (5461 slots) master  1 additional replica(s)  M: a9a4296b46db50459c5efb00d205fff671c2bfd0 127.0.0.1:7380  slots:[5461-10922] (5462 slots) master  1 additional replica(s)  S: e4ce1b6f872c6f72f776d534ce1dc783a0cf3655 127.0.0.1:7480  slots: (0 slots) slave  replicates 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4  M: d683040a8654a9ce994365d988ded03c03393135 127.0.0.1:7382  slots: (0 slots) master  [OK] All nodes agree about slots configuration.  >>> Check for open slots...  >>> Check slots coverage...  [OK] All 16384 slots covered.  >>> Send CLUSTER MEET to node 127.0.0.1:7482 to make it join the cluster.  Waiting for the cluster to join    >>> Configure node as replica of 127.0.0.1:7382.

    現在我們新的兩個redis服務已經加入到集群中,通過cluster nodes查看當前集群節點。
    shell jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli -p 7382 cluster nodes 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 127.0.0.1:7379@17379 master - 0 1572942882135 1 connected 0-5460 4b3a42f105e56b00d5b55eec9877d759b52f17e3 127.0.0.1:7482@17482 slave d683040a8654a9ce994365d988ded03c03393135 0 1572942881000 0 connected 0f6cf326c23af6399e6c3bfc374b04efbac015d3 127.0.0.1:7381@17381 master - 0 1572942883151 3 connected 10923-16383 a9a4296b46db50459c5efb00d205fff671c2bfd0 127.0.0.1:7380@17380 master - 0 1572942879000 2 connected 5461-10922 dcae00d572280d795fcbc82b899f2f1a50f1397c 127.0.0.1:7481@17481 slave a9a4296b46db50459c5efb00d205fff671c2bfd0 0 1572942881000 2 connected d683040a8654a9ce994365d988ded03c03393135 127.0.0.1:7382@17382 myself,master - 0 1572942880000 0 connected 96b98672b59fd85f8743fde5b354abdb38ee3b47 127.0.0.1:7479@17479 slave 0f6cf326c23af6399e6c3bfc374b04efbac015d3 0 1572942881120 3 connected e4ce1b6f872c6f72f776d534ce1dc783a0cf3655 127.0.0.1:7480@17480 slave 231ee8d2ea76e1c7fe2031c127b8a055be87a3f4 0 1572942879000 1 connected

  5. 添加節點完成,此時我們需要重新分片,將虛擬槽分配給新的節點。在redis集群中可以使用2個命令進行槽分配。--cluster reshard--cluster rebalance。當我們需要集群擴容時,一般都希望槽可以平均分配,此時可以使用該命令;rebalance用於平衡集群節點虛擬槽數量,自動重新平均分配可以使用該命令。src/redis-cli --cluster rebalance 127.0.0.1:7379 --cluster-use-empty-masters,若沒有添加cluster-use-empty-masters空槽的redis服務不會加入分配,由於我們需要進行集群擴容,因此需要加上該參數。

    參數 說明
    –cluster-weight <node1=w1…nodeN=wN> 指定集群節點的權重
    –cluster-use-empty-masters 設置可以讓沒有分配slot的主節點參與,默認不允許
    –cluster-timeout 設置migrate命令的超時時間
    –cluster-pipeline 定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值為10
    –cluster-threshold 遷移的slot閾值超過threshold,執行rebalance操作
    –cluster-replace 是否直接replace到目標節點,若節點存在重複key時,不指定該參數會報錯。
    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster rebalance 127.0.0.1:7379 --cluster-use-empty-masters  >>> Performing Cluster Check (using node 127.0.0.1:7379)  [OK] All nodes agree about slots configuration.  >>> Check for open slots...  >>> Check slots coverage...  [OK] All 16384 slots covered.  >>> Rebalancing across 4 nodes. Total weight = 4.00  Moving 1366 slots from 127.0.0.1:7380 to 127.0.0.1:7382  ######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################  Moving 1365 slots from 127.0.0.1:7381 to 127.0.0.1:7382  #####################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################  Moving 1365 slots from 127.0.0.1:7379 to 127.0.0.1:7382  #####################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

關於集群詳細參數解釋可以參考redis cluster 集群搭建(增、刪、改、查)

故障轉移

當有某台redis服務不再使用或出現故障時,我們需要進行故障遷移。在集群搭建時我們需要進行集群握手,握手完成後進行虛擬槽分配。而在故障轉移的步驟也相反,我們首先需要進行虛擬槽遷移,虛擬槽遷移時會將數據進行遷移。遷移完成後將故障節點從節點中以前。這一系列故障遷移動作都是在線的,不會對redis集群的服務造成影響。
我們可以通過--cluster reshard將該節點下的所有虛擬槽遷移到新的節點上。

參數 說明
–cluster-from 需要從哪些源節點上遷移slot,可從多個源節點完成遷移,以逗號隔開,傳遞的是節點的node id,還可以直接傳遞–from all,這樣源節點就是集群的所有節點,不傳遞該參數的話,則會在遷移過程中提示用戶輸入
–cluster-to slot需要遷移的目的節點的node id,目的節點只能填寫一個,不傳遞該參數的話,則會在遷移過程中提示用戶輸入
–cluster-slots 需要遷移的slot數量,不傳遞該參數的話,則會在遷移過程中提示用戶輸入。
–cluster-yes 指定遷移時的確認輸入
–cluster-timeout 設置migrate命令的超時時間
–cluster-pipeline 定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值為10
–cluster-replace 是否直接replace到目標節點,若節點存在重複key時,不指定該參數會報錯。
  1. 準備一個新的redis服務7383(也可以將這些虛擬槽遷移到其他的主上)。
  2. 啟動服務src/redis-server data/redis-7383.config
  3. 執行src/redis-cli --cluster add-node 127.0.0.1:7383 127.0.0.1:7379,將7382設置為主庫加入到集群。
  4. 開始槽遷移,src/redis-cli --cluster reshard 127.0.0.1:7379 --cluster-from 0a81b56b44e7974112534a596c9e2ef3ed8b4603 --cluster-to 756eb55a943453f87b49191f35c88271c650fb91

     jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster reshard 127.0.0.1:7379 --cluster-from 0a81b56b44e7974112534a596c9e2ef3ed8b4603 --cluster-to 756eb55a943453f87b49191f35c88271c650fb91   >>> Performing Cluster Check (using node 127.0.0.1:7379)   M: 9bc411a648c4a0dc1ff8644973ded10c21857109 127.0.0.1:7379   slots:[1365-5460] (4096 slots) master   1 additional replica(s)   S: d14a7d117eff2798e3ca5aa8a9afc88a0dbbdab1 127.0.0.1:7482   slots: (0 slots) slave   replicates 0a81b56b44e7974112534a596c9e2ef3ed8b4603   M: 3d0c5deba0cd2b441d04cf7abe9dbd7af36b1af3 127.0.0.1:7380   slots:[6827-10922] (4096 slots) master   1 additional replica(s)   M: 0a81b56b44e7974112534a596c9e2ef3ed8b4603 127.0.0.1:7382   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master   1 additional replica(s)   S: 7d2ab32bff9437b4fdd65ffe4011715569a45362 127.0.0.1:7481   slots: (0 slots) slave   replicates 3d0c5deba0cd2b441d04cf7abe9dbd7af36b1af3   M: e5fb7a9da406787dffd80f847102e4405eaf013d 127.0.0.1:7381   slots:[12288-16383] (4096 slots) master   1 additional replica(s)   M: 756eb55a943453f87b49191f35c88271c650fb91 127.0.0.1:7383   slots: (0 slots) master   S: 06c1040b46e733cda47265ec64d56fec86459237 127.0.0.1:7480   slots: (0 slots) slave   replicates 9bc411a648c4a0dc1ff8644973ded10c21857109   S: da488721d9d3271b557b1dcbf1e1dba48df7a856 127.0.0.1:7479   slots: (0 slots) slave   replicates e5fb7a9da406787dffd80f847102e4405eaf013d   [OK] All nodes agree about slots configuration.   >>> Check for open slots...   >>> Check slots coverage...   [OK] All 16384 slots covered.   How many slots do you want to move (from 1 to 16384)? 4097     Ready to move 4097 slots.   Source nodes:       M: 0a81b56b44e7974112534a596c9e2ef3ed8b4603 127.0.0.1:7382       slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master       1 additional replica(s)   Destination node:       M: 756eb55a943453f87b49191f35c88271c650fb91 127.0.0.1:7383       slots: (0 slots) master   Resharding plan:       Moving slot 0 from 0a81b56b44e7974112534a596c9e2ef3ed8b4603       Moving slot 1 from 0a81b56b44e7974112534a596c9e2ef3ed8b4603       ...       Moving slot 12286 from 127.0.0.1:7382 to 127.0.0.1:7383:       Moving slot 12287 from 127.0.0.1:7382 to 127.0.0.1:7383:

    當沒有輸入槽的數量,會提示需要遷移的槽數量。

  5. 執行src/redis-cli -p 7482 cluster REPLICATE 756eb55a943453f87b49191f35c88271c650fb91,將7382的從庫7482設置為7383的從。
  6. 現在就可以將7382的庫去除了。集群會移除該節點,同時該節點也會關閉。

    jake@Jake-PC:~/tool/demo/redis-cluster/redis$ src/redis-cli --cluster del-node 127.0.0.1:7379 0a81b56b44e7974112534a596c9e2ef3ed8b4603   >>> Removing node 0a81b56b44e7974112534a596c9e2ef3ed8b4603 from cluster 127.0.0.1:7379   >>> Sending CLUSTER FORGET messages to the cluster...   >>> SHUTDOWN the node.

redis管理

目前我們可以使用redis自帶的客戶端對集群進行動態橫向擴展與故障遷移。當redis服務較少時可以使用這種方式,但是當redis服務較多時,通過手動橫向擴展與故障遷移的方式的工作量就非常大了,同時我們可能還需要多大量的redis服務進行監控與預警,這時候我們可以寫一些腳本來方便運維,甚至可以使用專業的redis管理平台提高生產力。對於redis管理平台暫時沒有研究,知名的有redislivecachecolud等。有興趣的同學可以自己看一下。

參考文檔

  1. redis
  2. redis開發與運維
  3. 編譯lua-5.3.5時出錯解決方法
  4. redis-5.0.0基於Redis官方工具的集群搭建(排坑指南,從安裝Redis開始)
  5. Windows下 搭建redis集群
  6. redis cluster 集群搭建(增、刪、改、查)
  7. Linux—shell中((( ))、)( )、“與${ }的區別
  8. Redis Cluster & HDFS & ClustrixDB Reshard/Rebalance
  9. Redis實用監控工具一覽

出處:https://www.cnblogs.com/Jack-Blog/p/11804743.html
作者:傑哥很忙
本文使用「CC BY 4.0」創作共享協議。歡迎轉載,請在明顯位置給出出處及鏈接。