2014年11月14日金曜日

MySQL Fabricつらい(mysqlコマンドラインクライアントにHA切り替え機能を実装する編)

Connector/CでマスタースレーブHA打ち分け編 の応用で、mysqlコマンドラインクライアントにHA打ち分け機能を追加してみました。

パッチはこんな感じ。MySQL 5.7.5-m15のmysqlコマンドラインクライアントベースだけど、labs版のConnector/Cが5.6をベースにしてるっぽい気配がして、おとなしく5.6のコマンドラインクライアントベースにすればよかったかも。。


*** client/mysql.cc.orig 2014-09-18 22:36:41.000000000 +0900
--- client/mysql.cc 2014-11-14 16:28:49.499593984 +0900
***************
*** 76,82 ****
  using std::min;
  using std::max;
  
! const char *VER= "14.14";
  
  /* Don't try to make a nice table if the data is too big */
  #define MAX_COLUMN_LENGTH      1024
--- 76,82 ----
  using std::min;
  using std::max;
  
! const char *VER= "14.14-fabric";
  
  /* Don't try to make a nice table if the data is too big */
  #define MAX_COLUMN_LENGTH      1024
***************
*** 188,193 ****
--- 188,195 ----
  static char delimiter[16]= DEFAULT_DELIMITER;
  static size_t delimiter_length= 1;
  unsigned short terminal_width= 80;
+ static char *opt_fabric_group= 0, *opt_fabric_user= 0;
+ static char *opt_fabric_password= 0;
  
  #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
  static char *shared_memory_base_name=0;
***************
*** 255,261 ****
             com_notee(String *str, char*), com_charset(String *str,char*),
             com_prompt(String *str, char*), com_delimiter(String *str, char*),
       com_warnings(String *str, char*), com_nowarnings(String *str, char*),
!      com_resetconnection(String *str, char*);
  
  #ifdef USE_POPEN
  static int com_nopager(String *str, char*), com_pager(String *str, char*),
--- 257,264 ----
             com_notee(String *str, char*), com_charset(String *str,char*),
             com_prompt(String *str, char*), com_delimiter(String *str, char*),
       com_warnings(String *str, char*), com_nowarnings(String *str, char*),
!      com_resetconnection(String *str, char*),
!      com_fabric(String *str, char*);
  
  #ifdef USE_POPEN
  static int com_nopager(String *str, char*), com_pager(String *str, char*),
***************
*** 322,327 ****
--- 325,332 ----
  #ifdef USE_POPEN
    { "edit",   'e', com_edit,   0, "Edit command with $EDITOR."},
  #endif
+   // Added by yoku0825.
+   { "fabric", 'F', com_fabric, 1, "Choose fabric opt group." },
    { "ego",    'G', com_ego,    0,
      "Send command to mysql server, display result vertically."},
    { "exit",   'q', com_quit,   0, "Exit mysql. Same as quit."},
***************
*** 1833,1838 ****
--- 1838,1855 ----
     "password sandbox mode.",
     &opt_connect_expired_password, &opt_connect_expired_password, 0, GET_BOOL,
     NO_ARG, 0, 0, 0, 0, 0, 0},
+   // Added by yoku0825.
+   {"fabric-group", 0,
+    "fabric group", &opt_fabric_group, &opt_fabric_group, 0,
+    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+   {"fabric-user", 0,
+    "Real user name which is used to connect through MySQL Fabric",
+    &opt_fabric_user, &opt_fabric_user, 0,
+    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+   {"fabric-password", 0,
+    "Real password which is used to connect through MySQL Fabric",
+    &opt_fabric_password, &opt_fabric_password, 0,
+    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
    { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
  };
  
***************
*** 4883,4888 ****
--- 4900,4909 ----
    }
  #endif
  
+   // Added by yoku0825.
+   if (opt_fabric_group)
+     mysql_options(&mysql, MYSQL_OPT_USE_FABRIC, NULL);
+ 
    if (!mysql_real_connect(&mysql, host, user, password,
                            database, opt_mysql_port, opt_mysql_unix_port,
                            connect_flag | CLIENT_MULTI_STATEMENTS))
***************
*** 4898,4903 ****
--- 4919,4932 ----
      return -1;     // Retryable
    }
  
+   // Added by yoku0825.
+   if (opt_fabric_group)
+   {
+     mysql_options(&mysql, FABRIC_OPT_GROUP, opt_fabric_group);
+     mysql_options4(&mysql, FABRIC_OPT_GROUP_CREDENTIALS, opt_fabric_user, opt_fabric_password);
+     mysql_options(&mysql, FABRIC_OPT_DEFAULT_MODE, "rw");
+   }
+ 
  #ifdef _WIN32
    /* Convert --execute buffer from UTF8MB4 to connection character set */
    if (!execute_buffer_conversion_done++ &&
***************
*** 5763,5765 ****
--- 5792,5812 ----
    }
    return error;
  }
+ 
+ // Added by yoku0825.
+ static int com_fabric(String *buffer __attribute__((unused)),
+                       char *line __attribute__((unused)))
+ {
+   char *ptr=strchr(line, ' ');
+   char *new_fabric_opt_mode= my_strdup(PSI_NOT_INSTRUMENTED,
+                                         ptr ? ptr + 1 : 0, MYF(MY_WME));
+ 
+   if (strcmp(new_fabric_opt_mode, "ro") || strcmp(new_fabric_opt_mode, "rw"))
+   {
+     mysql_options(&mysql, FABRIC_OPT_DEFAULT_MODE, new_fabric_opt_mode);
+     tee_fprintf(stdout, "Current FABRIC_OPT_DEFAULT_MODE is %s\n", new_fabric_opt_mode);
+   }
+   else
+     tee_fprintf(stdout, "Failed to change FABRIC_OPT_DEFAULT_MODE. Only 'ro' and 'rw' are permitted.\n", new_fabric_opt_mode);
+   return 0;
+ }

取り敢えずConnector/CからMySQL Fabricでマスタースレーブの打ち分けをするのに必要なパラメーターはグループ名, 本物のノードに接続するユーザー名とパスワードくらいなので、オプション(--fabric-group, --fabric-user, --fabric-password)で受け取るようにする。

あとはmysql_real_connectを読んでいるsql_real_connectの中で、--fabric-groupが渡されてたらMYSQL_OPT_USE_FABRICを押し込んで、接続後にFABRIC_OPT_GROUP, FABRIC_OPT_GROUP_CREDENTIALS, FABRIC_OPT_DEFAULT_MODEを押し込むという感じ。コンソールの中でrwとroを切り替えるためにcom_fabricも追加。

実際こんな感じ。


$ client/mysql -P32275 -h127.0.0.1 -uadmin -pxxxx --protocol=tcp ## FabricサーバーのMySQLプロトコルの口に、FABRICモードでなく接続
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 53
Server version: 1.5.3-fabric -- Fabricサーバーのバージョンが出てくる

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT @@port; -- Fabricサーバーにつながってるだけなので何も出てこない
Query OK, 0 rows affected (0.00 sec)


$ client/mysql -P32275 -h127.0.0.1 -uadmin -pxxxx --protocol=tcp --fabric-group=my_first_fabric --fabric-user=msandbox --fabric-password=msandbox
mysql: [Warning] Using a password on the command line interface can be insecure.
Using Fabric for MYSQL connection -- FABRIC経由でつながると(今のところ必ず)これが出る。
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 167034
Server version: 5.6.21-log Source distribution -- MySQLサーバーのバージョン

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT @@port; -- デフォルトはrw側
+--------+
| @@port |
+--------+
|  20886 |
+--------+
1 row in set (0.00 sec)

mysql> fabric ro -- "fabric {ro|rw}"で切り替えられるようにした
Current FABRIC_OPT_DEFAULT_MODE is ro

mysql> SELECT @@port; -- こっちがro側
+--------+
| @@port |
+--------+
|  20887 |
+--------+
1 row in set (0.00 sec)

mysql> \F rw -- "\Fはfabricのシノニム"
Current FABRIC_OPT_DEFAULT_MODE is rw

mysql> SELECT @@port;
+--------+
| @@port |
+--------+
|  20886 |
+--------+
1 row in set (0.00 sec)

前回 使ってたFABRIC_OPT_MODEの方は、mysql_optionsしたすぐ次のクエリー(ただし、トランザクションの途中であれば考慮してくれる)でしか有効でないらしいので、FABRIC_OPT_DEFAULT_modeを使うようにしてみた。

ちなみに、Fabricサーバー(mysqlfabric)のMySQLプロトコルの口にログインしただけの状態でstatusとか叩くとコマンドラインクライアントが落ちる。

MySQL Bugs: #74340: Crash on status query when connected to fabric

--fabric-groupや--fabric-user, --fabric-passwordが間違ってて上手くバックエンドにつなぎにいけない場合も(クライアントがコア吐いて)これまた落ちるんだけど、取り敢えず仕様ということで。。

こんな感じで誰か DBD::mysql にMySQL Fabricをポートしてくだしあ。


【2014/11/17 11:33】
FABRIC_OPT_MODEの動きについてこっちに追記。
http://yoku0825.blogspot.jp/2014/11/mysql-fabricfabricoptmode-ro.html


【2014/12/02 18:56】
Githubに上げたのを忘れてたので一応張っておく。
https://github.com/yoku0825/fabric_mysql_client

0 件のコメント :

コメントを投稿