Redis分片:
為什么要分片:隨着Redis存儲的數據越來越龐大,會導致Redis的性能越來越差!
目前分片的方法:
1、客戶端分片
在應用層面分片,程序里指定什么數據存放在那個Redis 優勢:比較靈活 缺點:加個節點擴容就很費勁
2、代理Proxy分片 第三方的Twemproxy 使用代理的缺點,你代理什么性能,那么你整個Redis的性能就是什么樣的!
3、redis cluster
4、codis (豌豆莢)開源
Redis cluster:
這里摘錄:http://redisdoc.com/topic/cluster-tutorial.html#id2
集群分片:
Redis 集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384 個哈希槽(hash slot),
Redis 集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384 個哈希槽(hash slot),
數據庫中的每個鍵都屬於這 16384 個哈希槽的其中一個, 集群使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽,
其中 CRC16(key) 語句用於計算鍵 key 的 CRC16 校驗和 。
集群中的每個節點負責處理一部分哈希槽。 舉個例子, 一個集群可以有三個哈希槽, 其中:
* 節點 A 負責處理 0 號至 5500 號哈希槽。
* 節點 B 負責處理 5501 號至 11000 號哈希槽。
* 節點 C 負責處理 11001 號至 16384 號哈希槽。
這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。 比如說:
* 如果用戶將新節點 D 添加到集群中, 那么集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
* 與此類似, 如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然后再移除空白(不包含任何哈希槽)的節點 A 就可以了。
因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。
* 節點 A 負責處理 0 號至 5500 號哈希槽。
* 節點 B 負責處理 5501 號至 11000 號哈希槽。
* 節點 C 負責處理 11001 號至 16384 號哈希槽。
這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。 比如說:
* 如果用戶將新節點 D 添加到集群中, 那么集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
* 與此類似, 如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然后再移除空白(不包含任何哈希槽)的節點 A 就可以了。
因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。
Redis 集群中的主從復制
為了使得集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作,
Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。
在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那么集群將無法正常運行, 因為集群找不到節點來處理 5501 號至 11000 號的哈希槽。
另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那么當主節點 B 下線的時候, 集群就會將 B1 設置為新的主節點,
在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那么集群將無法正常運行, 因為集群找不到節點來處理 5501 號至 11000 號的哈希槽。
另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那么當主節點 B 下線的時候, 集群就會將 B1 設置為新的主節點,
並讓它代替下線的主節點 B , 繼續處理 5501 號至 11000 號的哈希槽, 這樣集群就不會因為主節點 B 的下線而無法正常運作了。
不過如果節點 B 和 B1 都下線的話, Redis 集群還是會停止運作。
Redis 集群的一致性保證(guarantee)
Redis 集群不保證數據的強一致性(strong consistency): 在特定條件下, Redis 集群可能會丟失已經被執行過的寫命令。
使用異步復制(asynchronous replication)是 Redis 集群可能會丟失寫命令的其中一個原因。 考慮以下這個寫命令的例子:
* 客戶端向主節點 B 發送一條寫命令。
* 主節點 B 執行寫命令,並向客戶端返回命令回復。
* 主節點 B 將剛剛執行的寫命令復制給它的從節點 B1 、 B2 和 B3 。
如你所見, 主節點對命令的復制工作發生在返回命令回復之后, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那么主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。
如果真的有必要的話, Redis 集群可能會在將來提供同步地(synchronou)執行寫命令的方法。
Redis 集群另外一種可能會丟失命令的情況是, 集群出現網絡分裂(network partition), 並且一個客戶端與至少包括一個主節點在內的少數(minority)實例被孤立。
舉個例子, 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, 而 A1 、B1 、C1 分別為三個主節點的從節點, 另外還有一個客戶端 Z1 。
假設集群中發生網絡分裂, 那么集群可能會分裂為兩方, 大多數(majority)的一方包含節點 A 、C 、A1 、B1 和 C1 , 而少數(minority)的一方則包含節點 B 和客戶端 Z1 。
在網絡分裂期間, 主節點 B 仍然會接受 Z1 發送的寫命令:
* 如果網絡分裂出現的時間很短, 那么集群會繼續正常運行;
* 但是, 如果網絡分裂出現的時間足夠長, 使得大多數一方將從節點 B1 設置為新的主節點, 並使用 B1 來代替原來的主節點 B , 那么 Z1 發送給主節點 B 的寫命令將丟失。
注意, 在網絡分裂出現期間, 客戶端 Z1 可以向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱為節點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
* 對於大多數一方來說, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么集群會將這個主節點視為下線, 並使用從節點來代替這個主節點繼續工作。
* 對於少數一方, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么它將停止處理寫命令, 並向客戶端報告錯誤。
不過如果節點 B 和 B1 都下線的話, Redis 集群還是會停止運作。
Redis 集群的一致性保證(guarantee)
Redis 集群不保證數據的強一致性(strong consistency): 在特定條件下, Redis 集群可能會丟失已經被執行過的寫命令。
使用異步復制(asynchronous replication)是 Redis 集群可能會丟失寫命令的其中一個原因。 考慮以下這個寫命令的例子:
* 客戶端向主節點 B 發送一條寫命令。
* 主節點 B 執行寫命令,並向客戶端返回命令回復。
* 主節點 B 將剛剛執行的寫命令復制給它的從節點 B1 、 B2 和 B3 。
如你所見, 主節點對命令的復制工作發生在返回命令回復之后, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那么主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。
如果真的有必要的話, Redis 集群可能會在將來提供同步地(synchronou)執行寫命令的方法。
Redis 集群另外一種可能會丟失命令的情況是, 集群出現網絡分裂(network partition), 並且一個客戶端與至少包括一個主節點在內的少數(minority)實例被孤立。
舉個例子, 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, 而 A1 、B1 、C1 分別為三個主節點的從節點, 另外還有一個客戶端 Z1 。
假設集群中發生網絡分裂, 那么集群可能會分裂為兩方, 大多數(majority)的一方包含節點 A 、C 、A1 、B1 和 C1 , 而少數(minority)的一方則包含節點 B 和客戶端 Z1 。
在網絡分裂期間, 主節點 B 仍然會接受 Z1 發送的寫命令:
* 如果網絡分裂出現的時間很短, 那么集群會繼續正常運行;
* 但是, 如果網絡分裂出現的時間足夠長, 使得大多數一方將從節點 B1 設置為新的主節點, 並使用 B1 來代替原來的主節點 B , 那么 Z1 發送給主節點 B 的寫命令將丟失。
注意, 在網絡分裂出現期間, 客戶端 Z1 可以向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱為節點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
* 對於大多數一方來說, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么集群會將這個主節點視為下線, 並使用從節點來代替這個主節點繼續工作。
* 對於少數一方, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么它將停止處理寫命令, 並向客戶端報告錯誤。
Redis Cluster安裝:
1、安裝環境:首先確保安裝了Redis
cd /opt/ mkdir `seq 7001 7008` cp /etc/redis/6379.conf ./ 配置文件里: 新增這三行即可 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 並且報:AOF是開啟的 appendonly yes 把相關的信息都統一修改為:6379 (端口、日志文件、存儲dir持久化) sed 's/6379/7001/g' 6379.conf > 7001/redis.conf sed 's/6379/7002/g' 6379.conf > 7002/redis.conf sed 's/6379/7003/g' 6379.conf > 7003/redis.conf sed 's/6379/7004/g' 6379.conf > 7004/redis.conf sed 's/6379/7005/g' 6379.conf > 7005/redis.conf sed 's/6379/7006/g' 6379.conf > 7006/redis.conf sed 's/6379/7007/g' 6379.conf > 7007/redis.conf sed 's/6379/7008/g' 6379.conf > 7008/redis.conf for i in `seq 7001 7009`;do cd /opt/$i && /usr/local/bin/redis-server redis.conf ; done
2、安裝管理工具,源碼自帶了一個管理Cluster集群的工具是用ruby寫的所以需要安裝ruby
yum -y install ruby rubygems 安裝ruby的管理工具redis gem install redis
3、復制管理工具
cp /opt/redis-3.0.4/src/redis-trib.rb /usr/local/bin/redis-trib 查看redis-trib幫助 redis-trib help
4、創建集群 7001-7006 6個redis為集群node 7007-7008 “2個redis為back node”
[root@server.tianshuai.com]$ redis-trib create --replicas 1 192.168.0.201:7001 192.168.0.201:7002 192.168.0.201:7003 192.168.0.201:7004 192.168.0.201:7005 192.168.0.201:7006 >>> Creating cluster Connecting to node 192.168.0.201:7001: OK Connecting to node 192.168.0.201:7002: OK Connecting to node 192.168.0.201:7003: OK Connecting to node 192.168.0.201:7004: OK Connecting to node 192.168.0.201:7005: OK Connecting to node 192.168.0.201:7006: OK >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 192.168.0.201:7001 192.168.0.201:7002 192.168.0.201:7003 Adding replica 192.168.0.201:7004 to 192.168.0.201:7001 Adding replica 192.168.0.201:7005 to 192.168.0.201:7002 Adding replica 192.168.0.201:7006 to 192.168.0.201:7003 M: 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 slots:0-5460 (5461 slots) master M: 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 slots:5461-10922 (5462 slots) master M: f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 slots:10923-16383 (5461 slots) master S: d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 replicates 699f318027f87f3c49d48e44116820e673bd306a S: d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 replicates 96892fd3f51292e922383ddb6e8018e2f772deed S: a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 replicates f702fd03c1e3643db7e385915842533ba5aab98d 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 192.168.0.201:7001) M: 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 slots:0-5460 (5461 slots) master M: 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 slots:5461-10922 (5462 slots) master M: f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 slots:10923-16383 (5461 slots) master M: d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 slots: (0 slots) master replicates 699f318027f87f3c49d48e44116820e673bd306a M: d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 slots: (0 slots) master replicates 96892fd3f51292e922383ddb6e8018e2f772deed M: a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 slots: (0 slots) master replicates f702fd03c1e3643db7e385915842533ba5aab98d [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. #create --replicas 1 這里--replicas 1 是指定復制幾份,相當於每個master有幾個從 #redis cluaster最低要求有3個master #master的定義 host1:port host2:port host3:port如果--replicas 1 那么: #host1:port == master host2:port 是:host1:port從 #如果--replicas 2 那么: #host1:port == master host2:port & host3:port 是host1:port 的從 M: 這個是cluaster 自動生成的ID 集群在通信的時候是使用這個ID來區分的
4、連接cluster,(連接任意的Cluster集群中的服務器即可)
redis-cli -c -h 192.168.0.201 -p 7001 的需要加-c的參數 可以連接集群的任意節點! 192.168.0.201:7001> cluster nodes 查看cluster節點 f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 master - 0 1444813870405 3 connected 10923-16383 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 myself,master - 0 0 1 connected 0-5460 d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 slave 699f318027f87f3c49d48e44116820e673bd306a 0 1444813870105 4 connected a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 slave f702fd03c1e3643db7e385915842533ba5aab98d 0 1444813868605 6 connected 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 master - 0 1444813869405 2 connected 5461-10922 d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 slave 96892fd3f51292e922383ddb6e8018e2f772deed 0 1444813869105 5 connected 192.168.0.201:7001> cluster info 查看cluster信息 cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_sent:1809 cluster_stats_messages_received:1809
5、集群擴容
redis-trib add-node 192.168.0.201:7007 192.168.0.201:7001 命令解釋: redis-trib add-node 要加的節點和端口 現有任意節點和端口 加完之后查看結果: 192.168.0.201:7001> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:7 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_sent:2503 cluster_stats_messages_received:2503 192.168.0.201:7001> cluster nodes f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 master - 0 1444814061587 3 connected 10923-16383 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 myself,master - 0 0 1 connected 0-5460 d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 slave 699f318027f87f3c49d48e44116820e673bd306a 0 1444814062087 4 connected a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 slave f702fd03c1e3643db7e385915842533ba5aab98d 0 1444814061087 6 connected a1301a9e1fd24099cd8dc49c47f2263e3124e4d6 192.168.0.201:7007 master - 0 1444814063089 0 connected 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 master - 0 1444814062589 2 connected 5461-10922 d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 slave 96892fd3f51292e922383ddb6e8018e2f772deed 0 1444814061587 5 connected 192.168.0.201:7001>
6、新加上來沒有數據-及沒有槽位,我們可以用命令讓他重新分片(分片)
redis-trib reshard 192.168.0.201:7007
7、在添加一個服務器做從
在添加一個7008 讓他做7008的從 [root@server.tianshuai.com]$ redis-trib add-node 192.168.0.201:7008 192.168.0.201:7001 加進來之后默認就是mater但是他沒有任何的槽位 192.168.0.201:7001> cluster nodes f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 master - 0 1444814915795 3 connected 11089-16383 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 myself,master - 0 0 1 connected 166-5460 d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 slave 699f318027f87f3c49d48e44116820e673bd306a 0 1444814917298 4 connected a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 slave f702fd03c1e3643db7e385915842533ba5aab98d 0 1444814916297 6 connected a02a66e0286ee2f0a9b5380f7584b9b20dc032ff 192.168.0.201:7008 master - 0 1444814915796 0 connected a1301a9e1fd24099cd8dc49c47f2263e3124e4d6 192.168.0.201:7007 master - 0 1444814915295 7 connected 0-165 5461-5627 10923-11088 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 master - 0 1444814916898 2 connected 5628-10922 d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 slave 96892fd3f51292e922383ddb6e8018e2f772deed 0 1444814916798 5 connected 然后連接到7008的這個redis實例上,然后復制7007的ID 192.168.0.201:7008> cluster replicate a1301a9e1fd24099cd8dc49c47f2263e3124e4d6 OK 然后看下: 192.168.0.201:7008> cluster nodes 699f318027f87f3c49d48e44116820e673bd306a 192.168.0.201:7001 master - 0 1444815074072 1 connected 166-5460 a1301a9e1fd24099cd8dc49c47f2263e3124e4d6 192.168.0.201:7007 master - 0 1444815073071 7 connected 0-165 5461-5627 10923-11088 96892fd3f51292e922383ddb6e8018e2f772deed 192.168.0.201:7002 master - 0 1444815073671 2 connected 5628-10922 a77b16c4f140c0f5c17c907ce7ee5e42ee2a7b02 192.168.0.201:7006 slave f702fd03c1e3643db7e385915842533ba5aab98d 0 1444815073571 3 connected f702fd03c1e3643db7e385915842533ba5aab98d 192.168.0.201:7003 master - 0 1444815072571 3 connected 11089-16383 d0994ce7ef68c0834030334afcd60013773f2e77 192.168.0.201:7004 slave 699f318027f87f3c49d48e44116820e673bd306a 0 1444815073071 1 connected d880581504caff4a002242b2b259d5242b8569fc 192.168.0.201:7005 slave 96892fd3f51292e922383ddb6e8018e2f772deed 0 1444815073871 2 connected a02a66e0286ee2f0a9b5380f7584b9b20dc032ff 192.168.0.201:7008 myself,slave a1301a9e1fd24099cd8dc49c47f2263e3124e4d6 0 0 0 connected 192.168.0.201:7008>
8、Cluster的主從復制這個操作也是向master發送請求,然后master做個BGSAVE然后拿過來之后重載一下!如果master特別大的所以要起個多個redis實例,每個里面存一部分。
也需要注意,涉及到多key的操作!是不行的因為你不同的key存在不同的地方!
192.168.7.107:7002> set key101 shuaige -> Redirected to slot [1601] located at 192.168.7.107:7001 OK 192.168.7.107:7001> set key102 shuaige -> Redirected to slot [13858] located at 192.168.7.107:7003 OK 192.168.7.107:7003> set key103 shuaige -> Redirected to slot [9731] located at 192.168.7.107:7002 OK 192.168.7.107:7002> set key104 shuaige -> Redirected to slot [5860] located at 192.168.7.107:7007 OK 192.168.7.107:7007> set key105 shuaige -> Redirected to slot [1733] located at 192.168.7.107:7001 OK 192.168.7.107:7001>