1. 程式人生 > >Redis 3.0叢集搭建測試(二)

Redis 3.0叢集搭建測試(二)

四、客戶端叢集命令

叢集
cluster info 列印叢集的資訊
cluster nodes 列出叢集當前已知的所有節點(node),以及這些節點的相關資訊。
節點
cluster meet <ip> <port> 將ip和port所指定的節點新增到叢集當中,讓它成為叢集的一份子。
cluster forget <node_id> 從叢集中移除 node_id 指定的節點。
cluster replicate <node_id> 將當前節點設定為node_id指定的節點的從節點。
cluster saveconfig 將節點的配置檔案儲存到硬盤裡面。
槽(slot)
cluster addslots <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。
cluster delslots <slot> [slot ...] 移除一個或多個槽對當前節點的指派。
cluster flushslots 移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。
cluster setslot <slot> node <node_id> 將槽 slot 指派給 node_id 指定的節點,如果槽已經指派給另一個節點,那麼先讓另一個節點刪除該槽>,然後再進行指派。
cluster setslot <slot> migrating <node_id> 將本節點的槽 slot 遷移到 node_id 指定的節點中。
cluster setslot <slot> importing <node_id> 從 node_id 指定的節點中匯入槽 slot 到本節點。
cluster setslot <slot> stable 取消對槽 slot 的匯入(import)或者遷移(migrate)。
鍵
cluster keyslot <key> 計算鍵 key 應該被放置在哪個槽上。
cluster countkeysinslot <slot> 返回槽 slot 目前包含的鍵值對數量。
cluster getkeysinslot <slot> <count> 返回 count 個 slot 槽中的鍵。
五、redis-trib.rb操作叢集

每臺機器增加埠6383 redis例項節點,並啟動例項。

1.新增新master節點
1)add-node  將一個節點新增到叢集裡面, 第一個是新節點ip:port, 第二個是任意一個已存在節點ip:port
./bin/redis-trib.rb add-node 192.168.36.54:6383 192.168.36.54:6380

>>> Adding node 192.168.36.54:6383 to cluster 192.168.36.54:6380
Connecting to node 192.168.36.54:6380: OK
Connecting to node 192.168.36.189:6380: OK
Connecting to node 192.168.36.189:6382: OK
Connecting to node 192.168.36.54:6382: OK
Connecting to node 192.168.36.54:6381: OK
Connecting to node 192.168.36.189:6381: OK
>>> Performing Cluster Check (using node 192.168.36.54:6380)
M: f6285c8a7506b224840d7b26b2b5d1671320c21f 192.168.36.54:6380
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: b1a15a3cd14ea65671a7134850e17b8919a17da5 192.168.36.189:6380
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: de4302f43ff89843675446396552fd19f741246a 192.168.36.189:6382
   slots: (0 slots) slave
   replicates 26ce71d626175f88e0416e3f45b2bfb29304c7b3
S: 83fc65283bbbb71b4c089337df05594d67f4cab6 192.168.36.54:6382
   slots: (0 slots) slave
   replicates b1a15a3cd14ea65671a7134850e17b8919a17da5
M: 26ce71d626175f88e0416e3f45b2bfb29304c7b3 192.168.36.54:6381
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 1080e423a55a2c24dae649dac03ffa09ed26d3e8 192.168.36.189:6381
   slots: (0 slots) slave
   replicates f6285c8a7506b224840d7b26b2b5d1671320c21f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
Connecting to node 192.168.36.54:6383: OK
>>> Send CLUSTER MEET to node 192.168.36.54:6383 to make it join the cluster.
[OK] New node added correctly.
新節點沒有包含任何資料, 因為它沒有包含任何slot。新加入的加點是一個主節點, 當叢集需要將某個從節點升級為新的主節點時, 這個新節點不會被選中。

2)為新節點分配slot

你只需要指定叢集中其中一個節點的地址, redis-trib 就會自動找到叢集中的其他節點。目前 redis-trib 只能在管理員的協助下完成重新分片的工作, 要讓 redis-trib 自動將雜湊槽從一個節點移動到另一個節點, 目前來說還做不到 (不過實現這個功能並不難)。
./bin/redis-trib.rb reshard 192.168.36.54:6383
設定你打算移動的雜湊槽slots的數量(這裡槽數量設定為1000)
How many slots do you want to move (from 1 to 16384)? 1000
除了移動的雜湊槽數量之外, redis-trib 還需要知道重新分片的目標(target node), 也即是, 負責接收這 1000 個雜湊槽的節點。指定目標需要使用節點的 ID , 而不是 IP 地址和埠。 比如說, 我們打算使用叢集的第一個主節點來作為目標, 它的 IP 地址和埠是 192.168.36.54:6383 , 而節點 ID 則是50cd88737109d0398e35b19747cc02832f05d125 , 那麼我們應該向 redis-trib 提供節點的 ID :
What is the receiving node ID?50cd88737109d0398e35b19747cc02832f05d125
redis-trib 會打印出叢集中所有節點的 ID , 並且我們也可以通過執行以下命令來獲得節點的執行 ID :
./bin/redis-cli -h 192.168.36.54 -p 6380 cluster nodes |grep 192.168.36.54:6383
接著, redis-trib 會向你詢問重新分片的源節點(source node), 也即是, 要從哪個節點中取出 1000 個雜湊槽,並將這些槽移動到目標節點上面。如果我們不打算從特定的節點上取出指定數量的雜湊槽, 那麼可以向 redis-trib 輸入 all , 這樣的話, 叢集中的所有主節點都會成為源節點, redis-trib 將從各個源節點中各取出一部分雜湊槽, 湊夠 1000 個, 然後移動到目標節點上面:
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 就會正式開始執行重新分片操作, 將指定的雜湊槽從源節點一個個地移動到目標節點上面。
在重新分片操作執行完畢之後, 可以使用以下命令來檢查叢集是否正常:
./bin/redis-trib.rb check 192.168.36.54:6380
根據檢查結果顯示, 叢集運作正常。

2.新增新的slave節點

1)新增節點

./bin/redis-trib.rb add-node 192.168.36.189:6383 192.168.36.54:6380

2)redis-cli連線上新節點shell,輸入命令:cluster replicate 對應master的node-id
./bin/redis-cli -c -h 192.168.36.189 -p 6383
>cluster replicate 50cd88737109d0398e35b19747cc02832f05d125
線上新增slave 時,需要dump整個master程序,並傳遞到slave,再由 slave載入rdb檔案到記憶體,rdb傳輸過程中Master可能無法提供服務,整個過程消耗大量io,小心操作.
檢視執行結果:
./bin/redis-cli -h 192.168.36.189 -p 6383 cluster nodes | grep slave | grep 50cd88737109d0398e35b19747cc02832f05d125
5178d6342a6470f928cfa6d43d98640b9303ad38 192.168.36.189:6383 myself,slave 50cd88737109d0398e35b19747cc02832f05d125 0 0 0 connected

3)線上reshard 資料
對於負載/資料不均勻的情況,可以線上reshard slot來解決,方法與新增新master的reshard一樣,只是需要reshard的master節點是老節點。
4)刪除一個slave節點
./bin/redis-trib.rb del-node 192.168.36.54:6380 5178d6342a6470f928cfa6d43d98640b9303ad38
5)刪除一個master節點
刪除master節點之前首先要使用reshard移除master的全部slot,然後再刪除當前節點(目前只能把被刪除master的slot遷移到一個節點上),操作和分配slot類似,指定具體的Source node即可。
然後在使用4步驟中的命令刪除節點

六、叢集測試

1.資料測試

使用redis客戶端redis-cli進行新增資料操作。

./bin/redis-cli -c -h 192.168.36.189 -p 6380
192.168.36.189:6380> set abc 123
OK
192.168.36.189:6380> set xxx 123
-> Redirected to slot [4038] located at 192.168.36.54:6380
OK
192.168.36.54:6380> set ttt aaa
-> Redirected to slot [15942] located at 192.168.36.54:6381
OK
redis-cli 對叢集的支援是非常基本的, 所以它總是依靠 Redis 叢集節點來將它轉向(redirect)至正確的節點。

2.故障轉移測試

要觸發一次故障轉移, 最簡單的辦法就是令叢集中的某個主節點進入下線狀態。
首先用以下命令列出叢集中的所有主節點:

 ./bin/redis-cli -h 192.168.36.189 -p 6383 cluster nodes |grep master
50cd88737109d0398e35b19747cc02832f05d125 192.168.36.54:6383 master - 0 1428823692383 7 connected 0-332 5461-5794 10923-11255
26ce71d626175f88e0416e3f45b2bfb29304c7b3 192.168.36.54:6381 master - 0 1428823692893 2 connected 11256-16383
f6285c8a7506b224840d7b26b2b5d1671320c21f 192.168.36.54:6380 master - 0 1428823693918 1 connected 333-5460
b1a15a3cd14ea65671a7134850e17b8919a17da5 192.168.36.189:6380 master - 0 1428823692893 4 connected 5795-10922
通過命令輸出, 我們知道埠號為 192.168.36.54:6380、 192.168.36.54:6381、192.168.36.54:6383 和 192.168.36.189:6380的節點都是主節點, 然後我們可以通過向埠號為192.168.36.54:6380的主節點發送 DEBUG SEGFAULT 命令, 讓這個主節點崩潰:
./bin/redis-cli -h 192.168.36.54 -p 6380  debug segfault
Error: Server closed the connection
我們使用 cluster nodes 命令, 檢視叢集在執行故障轉移操作之後, 主從節點的佈局情況:
./bin/redis-cli -h 192.168.36.189 -p 6383 cluster nodes
50cd88737109d0398e35b19747cc02832f05d125 192.168.36.54:6383 master - 0 1428823969555 7 connected 0-332 5461-5794 10923-11255
1080e423a55a2c24dae649dac03ffa09ed26d3e8 192.168.36.189:6381 master - 0 1428823968475 8 connected 333-5460
de4302f43ff89843675446396552fd19f741246a 192.168.36.189:6382 slave 26ce71d626175f88e0416e3f45b2bfb29304c7b3 0 1428823968886 2 connected
26ce71d626175f88e0416e3f45b2bfb29304c7b3 192.168.36.54:6381 master - 0 1428823967861 2 connected 11256-16383
83fc65283bbbb71b4c089337df05594d67f4cab6 192.168.36.54:6382 slave b1a15a3cd14ea65671a7134850e17b8919a17da5 0 1428823969555 4 connected
f6285c8a7506b224840d7b26b2b5d1671320c21f 192.168.36.54:6380 master,fail? - 1428823891006 1428823888448 1 disconnected
b1a15a3cd14ea65671a7134850e17b8919a17da5 192.168.36.189:6380 master - 0 1428823970008 4 connected 5795-10922
5178d6342a6470f928cfa6d43d98640b9303ad38 192.168.36.189:6383 myself,slave 50cd88737109d0398e35b19747cc02832f05d125 0 0 0 connected
重啟了之前下線的節點192.168.36.54:6380, 該節點已經從原來的主節點變成了從節點。
 ./bin/redis-cli -h 192.168.36.189 -p 6383 cluster nodes
50cd88737109d0398e35b19747cc02832f05d125 192.168.36.54:6383 master - 0 1428824165896 7 connected 0-332 5461-5794 10923-11255
1080e423a55a2c24dae649dac03ffa09ed26d3e8 192.168.36.189:6381 master - 0 1428824166406 8 connected 333-5460
de4302f43ff89843675446396552fd19f741246a 192.168.36.189:6382 slave 26ce71d626175f88e0416e3f45b2bfb29304c7b3 0 1428824165382 2 connected
26ce71d626175f88e0416e3f45b2bfb29304c7b3 192.168.36.54:6381 master - 0 1428824165896 2 connected 11256-16383
83fc65283bbbb71b4c089337df05594d67f4cab6 192.168.36.54:6382 slave b1a15a3cd14ea65671a7134850e17b8919a17da5 0 1428824164870 4 connected
f6285c8a7506b224840d7b26b2b5d1671320c21f 192.168.36.54:6380 slave 1080e423a55a2c24dae649dac03ffa09ed26d3e8 0 1428824166920 8 connected
b1a15a3cd14ea65671a7134850e17b8919a17da5 192.168.36.189:6380 master - 0 1428824166407 4 connected 5795-10922
5178d6342a6470f928cfa6d43d98640b9303ad38 192.168.36.189:6383 myself,slave 50cd88737109d0398e35b19747cc02832f05d125 0 0 0 connected
注:cluster nodes 命令的輸出有點兒複雜, 它的每一行都是由以下資訊組成的:
節點 ID :例如 3fc783611028b1707fd65345e763befb36454d73 。
ip:port :節點的 IP 地址和埠號, 例如 127.0.0.1:7000 , 其中 :0 表示的是客戶端當前連線的 IP 地址和埠號。
flags :節點的角色(例如 master 、 slave 、 myself )以及狀態(例如 fail ,等等)。
如果節點是一個從節點的話, 那麼跟在 flags 之後的將是主節點的節點 ID : 例如 127.0.0.1:7002 的主節點的節點 ID 就是 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 。
叢集最近一次向節點發送 PING 命令之後, 過去了多長時間還沒接到回覆。
節點最近一次返回 PONG 回覆的時間。
節點的配置紀元(configuration epoch):詳細資訊請參考 Redis 叢集規範 。
本節點的網路連線情況:例如 connected 。
節點目前包含的槽:例如192.168.36.189:6380 目前包含號碼為5795-10922的雜湊槽。
七、叢集下java客戶端使用

如下以jedis為例:

package cn.slimsmart.redis.demo.cluster;

import java.util.HashSet;
import java.util.Set;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

public class RedisClusterTest {

	public static void main(String[] args) {
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(100);
		config.setMaxIdle(100);
		config.setMinIdle(100);
		config.setMaxWaitMillis(6 * 1000);
		config.setTestOnBorrow(true);

		Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
		jedisClusterNodes.add(new HostAndPort("192.168.36.54", 6380));
		jedisClusterNodes.add(new HostAndPort("192.168.36.54", 6381));
		jedisClusterNodes.add(new HostAndPort("192.168.36.54", 6382));
		jedisClusterNodes.add(new HostAndPort("192.168.36.54", 6383));

		jedisClusterNodes.add(new HostAndPort("192.168.36.189", 6380));
		jedisClusterNodes.add(new HostAndPort("192.168.36.189", 6381));
		jedisClusterNodes.add(new HostAndPort("192.168.36.189", 6382));
		jedisClusterNodes.add(new HostAndPort("192.168.36.189", 6383));

		JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes, 2000, 2, config);
		try {
			for (int i = 0; i < 1000; i++) {
				long t1 = System.currentTimeMillis();
				jedisCluster.set("" + i, "" + i);
				long t2 = System.currentTimeMillis();
				String value = jedisCluster.get("" + i);
				long t3 = System.currentTimeMillis();
				System.out.println("" + value);
				System.out.println((t2 - t1) + "mills");
				System.out.println((t3 - t2) + "mills");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			jedisCluster.close();
		}
	}
}
jedis客戶端不足之處
1.cluster環境下redis的slave不接受任何讀寫操作
2.client端不支援keys批量操作,不支援select dbNum操作,只有一個db:select 0
3.JedisCluster 的info()等單機函式無法呼叫,返回(No way to dispatch this command to Redis Cluster)錯誤
4.JedisCluster 沒有針對byte[]的API,需要自己擴充套件