所謂的分片其實就是大的數據分紅幾個小的部分,分別放置存儲,對於數據而言無外乎就是讀寫,讀寫的基礎就是數據的定位,redis利用集羣的方式+槽位完成,分片的數據的定位和管理維護。node
Redis 集羣是一個能夠在多個 Redis 節點之間進行數據共享的設施(installation)。redis
Redis 集羣使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集羣包含 16384 個哈希槽(hash slot), 數據庫中的每一個鍵都屬於這 16384 個哈希槽的其中一個, 集羣使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪一個槽, 其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。數據庫
1. 槽位分配異步
集羣中的每一個節點負責處理一部分哈希槽。 舉個例子, 一個集羣能夠有三個哈希槽, 其中:async
這種將哈希槽分佈到不一樣節點的作法使得用戶能夠很容易地向集羣中添加或者刪除節點。 好比說:工具
由於將一個哈希槽從一個節點移動到另外一個節點不會形成節點阻塞, 因此不管是添加新節點仍是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會形成集羣下線。性能
2.高可用性命令行
爲了使得集羣在一部分節點下線或者沒法與集羣的大多數(majority)節點進行通信的狀況下, 仍然能夠正常運做, Redis 集羣對節點使用了主從複製功能: 集羣中的每一個節點都有 1 個至 N 個複製品(replica), 其中一個複製品爲主節點(master), 而其他的 N-1 個複製品爲從節點(slave)。orm
在以前列舉的節點 A 、B 、C 的例子中, 若是節點 B 下線了, 那麼集羣將沒法正常運行, 由於集羣找不到節點來處理 5501 號至 11000號的哈希槽。server
另外一方面, 假如在建立集羣的時候(或者至少在節點 B 下線以前), 咱們爲主節點 B 添加了從節點 B1 , 那麼當主節點 B 下線的時候, 集羣就會將 B1 設置爲新的主節點, 並讓它代替下線的主節點 B , 繼續處理 5501 號至 11000 號的哈希槽, 這樣集羣就不會由於主節點 B 的下線而沒法正常運做了。
不過若是節點 B 和 B1 都下線的話, Redis 集羣仍是會中止運做
3.一致性保證(非強一致性)
Redis 集羣不保證數據的強一致性(strong consistency): 在特定條件下, Redis 集羣可能會丟失已經被執行過的寫命令。
使用異步複製(asynchronous replication)是 Redis 集羣可能會丟失寫命令的其中一個緣由。 考慮如下這個寫命令的例子:
如你所見, 主節點對命令的複製工做發生在返回命令回覆以後, 由於若是每次處理命令請求都須要等待複製操做完成的話, 那麼主節點處理命令請求的速度將極大地下降 —— 咱們必須在性能和一致性之間作出權衡。
4.建立集羣(不詳說啦,參照個人另外一篇博客)
如今咱們已經有了六個正在運行中的 Redis 實例, 接下來咱們須要使用這些實例來建立集羣, 併爲每一個節點編寫配置文件。
經過使用 Redis 集羣命令行工具 redis-trib , 編寫節點配置文件的工做能夠很是容易地完成: redis-trib 位於 Redis 源碼的 src 文件夾中, 它是一個 Ruby 程序, 這個程序經過向實例發送特殊命令來完成建立新集羣, 檢查集羣, 或者對集羣進行從新分片(reshared)等工做。
咱們須要執行如下命令來建立集羣:
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
命令的意義以下:
簡單來講, 以上命令的意思就是讓 redis-trib 程序建立一個包含三個主節點和三個從節點的集羣。
接着, redis-trib 會打印出一份預想中的配置給你看, 若是你以爲沒問題的話, 就能夠輸入 yes , redis-trib 就會將這份配置應用到集羣當中:
>>> Creating cluster Connecting to node 127.0.0.1:7000: OK Connecting to node 127.0.0.1:7001: OK Connecting to node 127.0.0.1:7002: OK Connecting to node 127.0.0.1:7003: OK Connecting to node 127.0.0.1:7004: OK Connecting to node 127.0.0.1:7005: OK >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7000 replica #1 is 127.0.0.1:7003 127.0.0.1:7001 replica #1 is 127.0.0.1:7004 127.0.0.1:7002 replica #1 is 127.0.0.1:7005 M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001 slots:5461-10921 (5461 slots) master M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002 slots:10922-16383 (5462 slots) master S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003 S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004 S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005 Can I set the above configuration? (type 'yes' to accept): yes
輸入 yes 並按下回車確認以後, 集羣就會將配置應用到各個節點, 並鏈接起(join)各個節點 —— 也便是, 讓各個節點開始互相通信:
>>> Nodes configuration updated >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join... >>> Performing Cluster Check (using node 127.0.0.1:7000) M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001 slots:5461-10921 (5461 slots) master M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002 slots:10922-16383 (5462 slots) master M: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003 slots: (0 slots) master M: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004 slots: (0 slots) master M: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005 slots: (0 slots) master [OK] All nodes agree about slots configuration.
若是一切正常的話, redis-trib 將輸出如下信息:
>>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
這表示集羣中的 16384 個槽都有至少一個主節點在處理, 集羣運做正常。
5.從新分區
如今, 讓咱們來試試對集羣進行從新分片操做。
在執行從新分片的過程當中, 請讓你的 example.rb 程序處於運行狀態, 這樣你就會看到, 從新分片並不會對正在運行的集羣程序產生任何影響, 你也能夠考慮將 example.rb 中的 sleep 調用刪掉, 從而讓從新分片操做在近乎真實的寫負載下執行。
從新分片操做基本上就是將某些節點上的哈希槽移動到另一些節點上面, 和建立集羣同樣, 從新分片也可使用 redis-trib 程序來執行。
執行如下命令能夠開始一次從新分片操做:
$ ./redis-trib.rb reshard 127.0.0.1:7000
你只須要指定集羣中其中一個節點的地址, redis-trib 就會自動找到集羣中的其餘節點。
目前 redis-trib 只能在管理員的協助下完成從新分片的工做, 要讓 redis-trib 自動將哈希槽從一個節點移動到另外一個節點, 目前來講還作不到 (不過實現這個功能並不難)。
執行 redis-trib 的第一步就是設定你打算移動的哈希槽的數量:
$ ./redis-trib.rb reshard 127.0.0.1:7000 Connecting to node 127.0.0.1:7000: OK Connecting to node 127.0.0.1:7002: OK Connecting to node 127.0.0.1:7005: OK Connecting to node 127.0.0.1:7001: OK Connecting to node 127.0.0.1:7003: OK Connecting to node 127.0.0.1:7004: OK >>> Performing Cluster Check (using node 127.0.0.1:7000) M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002 slots:10922-16383 (5462 slots) master S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005 slots: (0 slots) slave M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001 slots:5461-10921 (5461 slots) master S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003 slots: (0 slots) slave S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004 slots: (0 slots) slave [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)? 1000
咱們將打算移動的槽數量設置爲 1000 個, 若是 example.rb 程序一直運行着的話, 如今 1000 個槽裏面應該有很多鍵了。
除了移動的哈希槽數量以外, redis-trib 還須要知道從新分片的目標(target node), 也便是, 負責接收這 1000 個哈希槽的節點。
指定目標須要使用節點的 ID , 而不是 IP 地址和端口。 好比說, 咱們打算使用集羣的第一個主節點來做爲目標, 它的 IP 地址和端口是 127.0.0.1:7000 , 而節點 ID 則是 9991306f0e50640a5684f1958fd754b38fa034c9 , 那麼咱們應該向 redis-trib 提供節點的 ID :
$ ./redis-trib.rb reshard 127.0.0.1:7000 ... What is the receiving node ID? 9991306f0e50640a5684f1958fd754b38fa034c9
redis-trib 會打印出集羣中全部節點的 ID , 而且咱們也能夠經過執行如下命令來得到節點的運行 ID :
$ ./redis-cli -p 7000 cluster nodes | grep myself 9991306f0e50640a5684f1958fd754b38fa034c9 :0 myself,master - 0 0 0 connected 0-5460
接着, redis-trib 會向你詢問從新分片的源節點(source node), 也便是, 要從哪一個節點中取出 1000 個哈希槽, 並將這些槽移動到目標節點上面。
若是咱們不打算從特定的節點上取出指定數量的哈希槽, 那麼能夠向 redis-trib 輸入 all , 這樣的話, 集羣中的全部主節點都會成爲源節點, redis-trib 將從各個源節點中各取出一部分哈希槽, 湊夠 1000 個, 而後移動到目標節點上面:
$ ./redis-trib.rb reshard 127.0.0.1:7000 ... Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1:all
輸入 all 並按下回車以後, redis-trib 將打印出哈希槽的移動計劃, 若是你以爲沒問題的話, 就能夠輸入 yes 並再次按下回車:
$ ./redis-trib.rb reshard 127.0.0.1:7000 ... Moving slot 11421 from 393c6df5eb4b4cec323f0e4ca961c8b256e3460a Moving slot 11422 from 393c6df5eb4b4cec323f0e4ca961c8b256e3460a Moving slot 5461 from e68e52cee0550f558b03b342f2f0354d2b8a083b Moving slot 5469 from e68e52cee0550f558b03b342f2f0354d2b8a083b ... Moving slot 5959 from e68e52cee0550f558b03b342f2f0354d2b8a083b Do you want to proceed with the proposed reshard plan (yes/no)? yes
輸入 yes 並使用按下回車以後, redis-trib 就會正式開始執行從新分片操做, 將指定的哈希槽從源節點一個個地移動到目標節點上面:
$ ./redis-trib.rb reshard 127.0.0.1:7000 ... Moving slot 5934 from 127.0.0.1:7001 to 127.0.0.1:7000: Moving slot 5935 from 127.0.0.1:7001 to 127.0.0.1:7000: Moving slot 5936 from 127.0.0.1:7001 to 127.0.0.1:7000: Moving slot 5937 from 127.0.0.1:7001 to 127.0.0.1:7000: ... Moving slot 5959 from 127.0.0.1:7001 to 127.0.0.1:7000:
在從新分片的過程當中, example.rb 應該能夠繼續正常運行, 不會出現任何問題。
在從新分片操做執行完畢以後, 可使用如下命令來檢查集羣是否正常:
$ ./redis-trib.rb check 127.0.0.1:7000 Connecting to node 127.0.0.1:7000: OK Connecting to node 127.0.0.1:7002: OK Connecting to node 127.0.0.1:7005: OK Connecting to node 127.0.0.1:7001: OK Connecting to node 127.0.0.1:7003: OK Connecting to node 127.0.0.1:7004: OK >>> Performing Cluster Check (using node 127.0.0.1:7000) M: 9991306f0e50640a5684f1958fd754b38fa034c9 127.0.0.1:7000 slots:0-5959,10922-11422 (6461 slots) master M: 393c6df5eb4b4cec323f0e4ca961c8b256e3460a 127.0.0.1:7002 slots:11423-16383 (4961 slots) master S: 3375be2ccc321932e8853234ffa87ee9fde973ff 127.0.0.1:7005 slots: (0 slots) slave M: e68e52cee0550f558b03b342f2f0354d2b8a083b 127.0.0.1:7001 slots:5960-10921 (4962 slots) master S: 48b728dbcedff6bf056231eb44990b7d1c35c3e0 127.0.0.1:7003 slots: (0 slots) slave S: 345ede084ac784a5c030a0387f8aaa9edfc59af3 127.0.0.1:7004 slots: (0 slots) slave [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
根據檢查結果顯示, 集羣運做正常。
須要注意的就是, 在三個主節點中, 節點 127.0.0.1:7000 包含了 6461 個哈希槽, 而節點 127.0.0.1:7001 和節點 127.0.0.1:7002 都只包含了 4961 個哈希槽, 由於後二者都將本身的 500 個哈希槽移動到了節點 127.0.0.1:7000 。
6.添加新的節點(特意放在5以後)
根據新添加節點的種類, 咱們須要用兩種方法來將新節點添加到集羣裏面:
本節將對以上兩種狀況進行介紹, 首先介紹主節點的添加方法, 而後再介紹從節點的添加方法。
不管添加的是那種節點, 第一步要作的老是添加一個空節點。
咱們能夠繼續使用以前啓動 127.0.0.1:7000 、 127.0.0.1:7001 等節點的方法, 建立一個端口號爲 7006 的新節點, 使用的配置文件也和以前同樣, 只是記得要將配置中的端口號改成 7000 。
如下是啓動端口號爲 7006 的新節點的詳細步驟:
若是一切正常, 那麼節點應該會正確地啓動。
接下來, 執行如下命令, 將這個新節點添加到集羣裏面:
./redis-trib.rb addnode 127.0.0.1:7006 127.0.0.1:7000
命令中的 addnode 表示咱們要讓 redis-trib 將一個節點添加到集羣裏面, addnode 以後跟着的是新節點的 IP 地址和端口號, 再以後跟着的是集羣中任意一個已存在節點的 IP 地址和端口號, 這裏咱們使用的是 127.0.0.1:7000 。
經過 cluster nodes 命令, 咱們能夠確認新節點 127.0.0.1:7006 已經被添加到集羣裏面了:
redis 127.0.0.1:7006> cluster nodes 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385543178575 0 connected 5960-10921 3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected 2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected 97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:7000 master - 0 1385543179080 0 connected 0-5959 10922-11422 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385543177568 3 connected 11423-16383
新節點如今已經鏈接上了集羣, 成爲集羣的一份子, 而且能夠對客戶端的命令請求進行轉向了, 可是和其餘主節點相比, 新節點還有兩點區別:
接下來, 只要使用 redis-trib 程序, 將集羣中的某些哈希桶移動到新節點裏面, 新節點就會成爲真正的主節點了。
由於使用 redis-trib 移動哈希桶的方法在前面已經介紹過, 因此這裏就再也不重複介紹了。
如今, 讓咱們來看看, 將一個新節點轉變爲某個主節點的複製品(也便是從節點)的方法。
舉個例子, 若是咱們打算讓新節點成爲 127.0.0.1:7005 的從節點, 那麼咱們只要用客戶端鏈接上新節點, 而後執行如下命令就能夠了:
redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
其中命令提供的 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 就是主節點 127.0.0.1:7005 的節點 ID 。
執行 cluster replicate 命令以後, 咱們可使用如下命令來確認 127.0.0.1:7006 已經成爲了 ID 爲 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 的節點的從節點:
$ redis-cli -p 7000 cluster nodes | grep slave | grep 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e f093c80dde814da99c5cf72a7dd01590792b783b 127.0.0.1:7006 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617702 3 connected 2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617198 3 connected
3c3a0c... 如今有兩個從節點, 一個從節點的端口號爲 7002 , 而另外一個從節點的端口號爲 7006 。