redis-cli を弄って単一の Redis クラスターを構築する
ほとんどないとは思うが*1、シングル構成のRedisクラスタが欲しくなった際に、以下のようにコマンドを実行してもエラーが発生する。
annkara@annkara:~/src/redis-5.0.5/src$ ./redis-cli --cluster create 127.0.0.1:6379 [ERR] Wrong number of arguments for specified --cluster sub command
どうやら、redis-cli コマンド内で引数のチェックをしているようなので、チェックを回避するようにして単一マスターノードのクラスタが構築できるか試してみる。
対象の Redis のバージョンは 5.0.5 を利用しており、ソースコードは公式サイトからダウンロードしてきている。
とりあえず、エラーメッセージを出力している個所を探してみる。
2050 static clusterManagerCommandProc *validateClusterManagerCommand(void) { 2051 int i, commands_count = sizeof(clusterManagerCommands) / 2052 sizeof(clusterManagerCommandDef); 2053 clusterManagerCommandProc *proc = NULL; 2054 char *cmdname = config.cluster_manager_command.name; 2055 int argc = config.cluster_manager_command.argc; 2056 for (i = 0; i < commands_count; i++) { 2057 clusterManagerCommandDef cmddef = clusterManagerCommands[i]; 2058 if (!strcmp(cmddef.name, cmdname)) { 2059 if ((cmddef.arity > 0 && argc != cmddef.arity) || 2060 (cmddef.arity < 0 && argc < (cmddef.arity * -1))) { 2061 fprintf(stderr, "[ERR] Wrong number of arguments for " 2062 "specified --cluster sub command\n"); 2063 return NULL; 2064 } 2065 proc = cmddef.proc; 2066 } 2067 } 2068 if (!proc) fprintf(stderr, "Unknown --cluster subcommand\n"); 2069 return proc; 2070 }
2059行目か2060行目のチェックに該当してエラーメッセージが出力されていそう。
チェック処理についてもう少し理解を深めるために、clusterManagerCommandDef型を見てみる。
2006 typedef struct clusterManagerCommandDef { 2007 char *name; 2008 clusterManagerCommandProc *proc; 2009 int arity; 2010 char *args; 2011 char *options; 2012 } clusterManagerCommandDef; 2013 2014 clusterManagerCommandDef clusterManagerCommands[] = { 2015 {"create", clusterManagerCommandCreate, -2, "host1:port1 ... hostN:portN", 2016 "replicas <arg>"}, 2017 {"check", clusterManagerCommandCheck, -1, "host:port", 2018 "search-multiple-owners"}, 2019 {"info", clusterManagerCommandInfo, -1, "host:port", NULL}, 2020 {"fix", clusterManagerCommandFix, -1, "host:port", 2021 "search-multiple-owners"}, 2022 {"reshard", clusterManagerCommandReshard, -1, "host:port", 2023 "from <arg>,to <arg>,slots <arg>,yes,timeout <arg>,pipeline <arg>," 2024 "replace"}, 2025 {"rebalance", clusterManagerCommandRebalance, -1, "host:port", 2026 "weight <node1=w1...nodeN=wN>,use-empty-masters," 2027 "timeout <arg>,simulate,pipeline <arg>,threshold <arg>,replace"}, 2028 {"add-node", clusterManagerCommandAddNode, 2, 2029 "new_host:new_port existing_host:existing_port", "slave,master-id <arg>"}, 2030 {"del-node", clusterManagerCommandDeleteNode, 2, "host:port node_id",NULL}, 2031 {"call", clusterManagerCommandCall, -2, 2032 "host:port command arg arg .. arg", NULL}, 2033 {"set-timeout", clusterManagerCommandSetTimeout, 2, 2034 "host:port milliseconds", NULL}, 2035 {"import", clusterManagerCommandImport, 1, "host:port", 2036 "from <arg>,copy,replace"}, 2037 {"help", clusterManagerCommandHelp, 0, NULL, NULL} 2038 };
clusterManagerCommandDef は構造体で、2014行目で定義されている clusterManagerCommands 配列を見てみると、Redis クラスタを操作するコマンド名や関数ポインタ、引数の数などを保持するための構造体であることがわかる。
arity という英単語を初めて見たのだけど、関数が受け取る引数の数の事を言うらしい。今回は create コマンドなので、-2 となっている。
改めて条件文にもどってみると、2060行目のチェック処理に該当することがわかる。
つまり、Redis クラスタを構成する際には、3台以上のノードの IP:PORT 番号が必要となる。クラスタと言っているので当たり前といえば当たり前だが。。。
## redis-cli --cluster create 127.0.0.1:6379 のコマンドを実行するとき ## cmddef.arity = -2 ## argc = 1 (create コマンドに渡される引数の数)2055行目の int argc = config.cluster_manager_command.argc の値 2059 if ((cmddef.arity > 0 && argc != cmddef.arity) || 2060 (cmddef.arity < 0 && argc < (cmddef.arity * -1))) {
なので、1ノードの設定でも通せるように修正し、もう一度コンパイルして、コマンドを実行してみる。
annkara@annkara:~/src/redis-5.0.5/src$ ./redis-cli --cluster create 127.0.0.1:6379 *** ERROR: Invalid configuration for cluster creation. *** Redis Cluster requires at least 3 master nodes. *** This is not possible with 1 nodes and 0 replicas per node. *** At least 3 nodes are required.
Redis クラスタは最低3台のマスターノードが必要だと至極まっとうなエラーが返される。
どうやら他にもチェックをしている個所があるらしい。。。
4578 /* Cluster Manager Commands */ 4579 4580 static int clusterManagerCommandCreate(int argc, char **argv) { /* 省略 */ 4628 if (masters_count < 3) { 4629 clusterManagerLogErr( 4630 "*** ERROR: Invalid configuration for cluster creation.\n" 4631 "*** Redis Cluster requires at least 3 master nodes.\n" 4632 "*** This is not possible with %d nodes and %d replicas per node.", 4633 node_len, replicas); 4634 clusterManagerLogErr("\n*** At least %d nodes are required.\n", 4635 3 * (replicas + 1)); 4636 return 0; 4637 }
clusterManagerCommandCreate関数できっちりとマスターノード台数のチェックがされているのでこれも回避する。
リトライするととりあえず成功する。
annkara@annkara:~/src/redis-5.0.5/src$ ./redis-cli --cluster create 127.0.0.1:6379 >>> Performing hash slots allocation on 1 nodes... Master[0] -> Slots 0 - 16383 M: c4ba607158e6288e4a07e19f748dc210be0cd1fc 127.0.0.1:6379 slots:[0-16383] (16384 slots) master 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:6379) M: c4ba607158e6288e4a07e19f748dc210be0cd1fc 127.0.0.1:6379 slots:[0-16383] (16384 slots) master [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
値の設定・取得くらいの簡単な確認しかしてないけど、とりあえず単一マスターのRedisクラスタを構築することができた。
結局自分の環境では3台のマスターノードを準備して、クラスタ構成を構築したので実際には運用してないけど、とりあえずのメモ書きとして残しておく。