GA

2014/11/27

MySQL 5.7.5-labsのQuery Rewrite Plugin

Query Rewrite pluginの一番ベーシックな使い方はこちら。
The Query Rewrite Plugins | MySQL Server Blog

MySQL 5.7.5-labsに$basedir/lib/plugin/install_rewriter_plugin.sqlを食わせてやれば取り敢えず有効になる。MySQL 5.7.5-m15にはこのプラグインは存在しないので注意。

$ mysql57 < install_rewriter_plugin.sql

mysql57> SELECT @@version;
+------------------------+
| @@version              |
+------------------------+
| 5.7.5-labs-preview-log |
+------------------------+
1 row in set (0.00 sec)

mysql57> show plugins;
+----------------------------+--------+--------------------------+-------------+---------+
| Name                       | Status | Type                     | Library     | License |
+----------------------------+--------+--------------------------+-------------+---------+
..
| Rewriter                   | ACTIVE | QUERY REWRITE POST PARSE | rewriter.so | GPL     |
+----------------------------+--------+--------------------------+-------------+---------+
43 rows in set (0.00 sec)

mysql57> show databases like 'query_rewrite';
+--------------------------+
| Database (query_rewrite) |
+--------------------------+
| query_rewrite            |
+--------------------------+
1 row in set (0.00 sec)

mysql57> show tables;
+-------------------------+
| Tables_in_query_rewrite |
+-------------------------+
| rewrite_rules           |
+-------------------------+
1 row in set (0.00 sec)


このquery_rewrite.rewrite_rulesにクエリー書き換えのルールを記述していく感じ。
記述したら、query_rewrite.flush_rewrite_rulesを呼んで更新してやる(FLUSH PRIVILEGESみたいな感じだ)

mysql57> INSERT INTO query_rewrite.rewrite_rules (pattern, replacement) VALUES ('INSERT INTO t1 VALUES (?)', 'INSERT INTO t2 VALUES (? + 1)');
Query OK, 1 row affected (0.01 sec)

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+---------------------------+------------------+-------------------------------+---------+---------+
| pattern                   | pattern_database | replacement                   | enabled | message |
+---------------------------+------------------+-------------------------------+---------+---------+
| INSERT INTO t1 VALUES (?) | NULL             | INSERT INTO t2 VALUES (? + 1) | Y       | NULL    |
+---------------------------+------------------+-------------------------------+---------+---------+
1 row in set (0.00 sec)

mysql57> CALL query_rewrite.flush_rewrite_rules();
Query OK, 1 row affected (0.01 sec)

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
| pattern                   | pattern_database | replacement                   | enabled | message                                          |
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
| INSERT INTO t1 VALUES (?) | NULL             | INSERT INTO t2 VALUES (? + 1) | N       | Parse error in pattern: >>No database selected<< |
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
1 row in set (0.00 sec)


あれ、なんか怒られた。 "No database selected" なので、pattern_databaseがNULLなのがいけないのか…ってテーブル名を指定しない時はNULLでも大丈夫ぽい流れが冒頭のブログには書いてあった(´・ω・`)

mysql57> UPDATE query_rewrite.rewrite_rules SET pattern_database= 'd1', enabled= 'Y';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
| pattern                   | pattern_database | replacement                   | enabled | message                                          |
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
| INSERT INTO t1 VALUES (?) | d1               | INSERT INTO t2 VALUES (? + 1) | Y       | Parse error in pattern: >>No database selected<< |
+---------------------------+------------------+-------------------------------+---------+--------------------------------------------------+
1 row in set (0.00 sec)


enabledは自分で'Y'に戻さないと、次にflush_rewrite_rulesを呼んでもそもそもFLUSHしようとしてくれなくなる(はまった)

mysql57> CALL query_rewrite.flush_rewrite_rules();
Query OK, 1 row affected (0.00 sec)

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+---------------------------+------------------+-------------------------------+---------+---------------------------------+
| pattern                   | pattern_database | replacement                   | enabled | message                         |
+---------------------------+------------------+-------------------------------+---------+---------------------------------+
| INSERT INTO t1 VALUES (?) | d1               | INSERT INTO t2 VALUES (? + 1) | N       | Pattern not a select statement. |
+---------------------------+------------------+-------------------------------+---------+---------------------------------+
1 row in set (0.00 sec)


(´・ω・`) SELECTステートメントしか食ってくれないようなことを言っている。かなしい。

mysql57> DELETE FROM query_rewrite.rewrite_rules;
Query OK, 1 row affected (0.00 sec)

mysql57> INSERT INTO query_rewrite.rewrite_rules (pattern, pattern_database, replacement) VALUES ('SELECT * FROM t1', 'd1', 'SELECT * FROM t1 LIMIT 1');
Query OK, 1 row affected (0.00 sec)

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+------------------+------------------+--------------------------+---------+---------+
| pattern          | pattern_database | replacement              | enabled | message |
+------------------+------------------+--------------------------+---------+---------+
| SELECT * FROM t1 | d1               | SELECT * FROM t1 LIMIT 1 | Y       | NULL    |
+------------------+------------------+--------------------------+---------+---------+
1 row in set (0.00 sec)

mysql57> CALL query_rewrite.flush_rewrite_rules();
Query OK, 1 row affected (0.01 sec)

mysql57> SELECT * FROM query_rewrite.rewrite_rules;
+------------------+------------------+--------------------------+---------+---------+
| pattern          | pattern_database | replacement              | enabled | message |
+------------------+------------------+--------------------------+---------+---------+
| SELECT * FROM t1 | d1               | SELECT * FROM t1 LIMIT 1 | Y       | NULL    |
+------------------+------------------+--------------------------+---------+---------+
1 row in set (0.00 sec)


という訳で、d1.t1のテーブルを単純SELECTした時に"LIMIT 1"を押し込むようなやつを作って(まともに読み込まれたときは、messageはNULLのままで見た目変化がないっぽい)

mysql57> SELECT * FROM t1;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set, 1 warning (0.00 sec)

mysql57> SHOW WARNINGS;
+-------+------+---------------------------------------------------------------------------------------+
| Level | Code | Message                                                                               |
+-------+------+---------------------------------------------------------------------------------------+
| Note  | 1105 | Query 'SELECT * FROM t1' rewritten to 'SELECT * FROM t1 LIMIT 1' by plugin: Rewriter. |
+-------+------+---------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

おお、書き換えてくれたぽい。 クエリーキャッシュぽく、クエリーの文字列で判定しているだけぽいけど


mysql57> select * FROM t1;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set, 1 warning (0.00 sec)

mysql57> SELECT /* dummy */  * FROM t1;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set, 1 warning (0.00 sec)

mysql57> SELECT *
    -> FROM t1;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set, 1 warning (0.00 sec)

mysql57> SELECT sql_cache * FROM t1;
+------+
| num  |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
+------+
5 rows in set (0.00 sec)


大文字小文字の吸収と、コメント, スペースや改行文字くらいは無視してくれるっぽい。SQL構文として有効なsql_cacheとか入るとさすがにダメ。簡単なプレースホルダー(?文字)は使えるけど、テーブル名の書き換えとかはできない。

SELECT以外の何かをゴニョゴニョしたかったり、テーブル名の書き換えをやりたかったら、Rewrite Pluginを自作することになるっぽい。
Write Yourself a Query Rewrite Plugin: Part 1 | MySQL Server Blog

取り敢えずrewrite_example(クエリーを全て小文字に書き換える)というのが付属しているので、

mysql57> INSTALL PLUGIN rewrite_example SONAME 'rewrite_example.so';
Query OK, 0 rows affected (0.01 sec)

mysql57> use d1
Database changed, 1 warning

mysql57> INSERT INTO t1 VALUES (100);
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql57> SHOW WARNINGS;
+-------+------+------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                    |
+-------+------+------------------------------------------------------------------------------------------------------------+
| Note  | 1105 | Query 'INSERT INTO t1 VALUES (100)' rewritten to 'insert into t1 values (100)' by plugin: rewrite_example. |
| Note  | 1105 | Query 'SHOW WARNINGS' rewritten to 'show warnings' by plugin: rewrite_example.                             |
+-------+------+------------------------------------------------------------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

うむ、INSERTもSHOWも軒並み全部イケる。こっちはC++で文字列を書き換えてるだけだから結構融通が利く感じ。

Enjoy :)

2014/11/26

MySQL Sandboxで./use_allをrootでやりたい

いっつも忘れるのだ!
前に使ってても忘れるのだ!
http://yoku0825.blogspot.jp/2014/11/mysql-fabric_29.html

こたえ: MYCLIENT_OPTIONS

$ ./use_all "select current_user"
# server: 1:
current_user
msandbox@localhost
# server: 2:
current_user
msandbox@localhost
# server: 3:
current_user
msandbox@localhost
# server: 4:
current_user
msandbox@localhost

$ export MYCLIENT_OPTIONS="-uroot"

$ ./use_all "select current_user"
# server: 1:
current_user
root@localhost
# server: 2:
current_user
root@localhost
# server: 3:
current_user
root@localhost
# server: 4:
current_user
root@localhost

2014/11/25

MySQL Fabricつらい(FABRIC_OPT_MODE = roでスレーブだけを見に行かせる方法が見つかったと思ったのに失敗した)

FABRIC_OPT_MODE = roはスレーブだけを見に行くわけじゃない の時にはweightにしたがってコネクションがラウンドロビンされるから、スレーブのweightを大きくして誤魔化す的なことをしていたけど、なんかそれっぽいものを見つけた。


$ mysqlfabric group lookup_servers my_first_fabric
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0



このmodeの値、"READ_WRITE", "READ_ONLY"が入ってるところの取りうるバリエーションを知りたい。
マニュアルにはread_only, read_write, offlineっぽいのが書いてはあるものの、 正直信用ならないので


$ grep -r READ_WRITE /usr/lib/python2.6/site-packages/mysql/fabric/
/usr/lib/python2.6/site-packages/mysql/fabric/server.py:    :type mode: OFFLINE, READ_ONLY, READ_WRITE.
/usr/lib/python2.6/site-packages/mysql/fabric/server.py:    READ_WRITE = "READ_WRITE"
/usr/lib/python2.6/site-packages/mysql/fabric/server.py:    SERVER_MODE = [OFFLINE, READ_ONLY, WRITE_ONLY, READ_WRITE]
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/server.pyo matches
/usr/lib/python2.6/site-packages/mysql/fabric/services/highavailability.py:    master.mode = _server.MySQLServer.READ_WRITE
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/services/highavailability.pyc matches
/usr/lib/python2.6/site-packages/mysql/fabric/services/server.py:        (_server.MySQLServer.WRITE_ONLY, _server.MySQLServer.READ_WRITE)
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/services/highavailability.pyo matches
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/services/server.pyo matches
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/services/server.pyc matches
Binary file /usr/lib/python2.6/site-packages/mysql/fabric/server.pyc matches

ああ、あるね、マニュアルに載ってないのあるね。Fabricクオリティだもんね。


$ mysqlfabric server set_mode 47cf54df-63fc-11e4-942e-fa163e020fd0 WRITE_ONLY
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
0389370b-8f9e-4b68-ab2a-75e2940701cb        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41689e+09 Triggered by <mysql .fabric.events.event="" 0x217fc90="" at="" object="">.
    4       2   1.41689e+09                          Executing action (_set_server_mode).
    5       2   1.41689e+09                           Executed action (_set_server_mode).


$ mysqlfabric group lookup_servers my_first_fabric
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY WRITE_ONLY    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0



セットできた。。


$ less test.cc
    mysql_options(&mysql, FABRIC_OPT_GROUP, "my_first_fabric");
    mysql_options(&mysql, FABRIC_OPT_DEFAULT_MODE, "ro");
    mysql_options4(&mysql, FABRIC_OPT_GROUP_CREDENTIALS, "msandbox", "msandbox");

    for (n= 0; n < 1000; n++)
    {
      //mysql_options(&mysql, FABRIC_OPT_MODE, "ro");
      mysql_query(&mysql, "SELECT @@port, @@read_only");
      res= mysql_store_result(&mysql);
      row = mysql_fetch_row(res);
      std::cout << "port: " << row[0] << ", read_only: " << row[1] << std::endl;
      mysql_free_result(res);
      mysql_query(&mysql, "COMMIT");
    }

$ gcc -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysqlclient -g test.cc

$ ./a.out | sort | uniq -c
    506 port: 20886, read_only: 0
    494 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection

だが有効にならないFabricクオリティ!
とはいえ。


$ gdb a.out
gdb> b Fabric_context::pick_connection
gdb> r
gdb> p *m_grp
..
  m_iter = {
    m_grp = 0x6221a0,
    m_srv_list = std::vector of length 2, capacity 2 = {{
        m_host = "127.0.0.1",
        m_port = 20886,
        m_mode = fabric::Server::WRITE_ONLY,
        m_status = fabric::Server::PRIMARY,
        m_weight = 1,
        m_uuid = {
          uuid = "G\317T\337c\374\021\344\224.\372\026>\002\017", 
        },
        m_parent_group = 0x6221a0,
        m_tainted = false
      }, {
        m_host = "127.0.0.1",
        m_port = 20887,
        m_mode = fabric::Server::READ_ONLY,
        m_status = fabric::Server::SECONDARY,
        m_weight = 1,
        m_uuid = {
          uuid = "Kp6\251c\374\021\344\224.\372\026>\002\017", 
        },
        m_parent_group = 0x6221a0,
        m_tainted = false
      }},
..

クライアント側にWRITE_ONLYは渡されてるから、Connector/Cがまだ対応してないってことなのかしら。labsとはいえ同じ会社が作ってるConnector/Cでこれだというのに、PHPのMySQL Fabric対応実装の mysqlnd とか本当に大丈夫かしら。。愛想尽かされない程度にやってくださいね。。

2014/11/18

MySQL Fabricつらい(Fabricサーバー上のMySQLプロトコルの口でFabricのAPIが呼べる編)

もともとは、mysqlコマンドラインクライアントにHA切り替え機能を実装する編 でいじってたクライアントにもう少しパラメーターを突っ込もうとか Fabricサーバー上でstatusコマンド叩くとmysqlコマンドラインクライアントがクラッシュする件 を直したいとかそんなことを考えてソースを読んでいたときのこと。

mysql-utilities-1.5.3/mysql/fabric/protocols/mysqlrpc.py のMySQLRPCRequestHandler.handleあたりの中で
 925             # Handle CALL
 926             if CHECK_CALL.match(data):
 927                 call_match = PARSE_CALL.match(data)
 928                 if call_match:
 929                     self._handle_call(call_match)
 930                 else:
 931                     self.send_syntax_error()
 932                 continue
 933
 934             # Handle SHOW CREATE PROCEDURE
 935             if CHECK_SHOW_CREATE_PROC.match(data):
 936                 showproc_match = PARSE_SHOW_CREATE_PROC.match(data)
 937                 if showproc_match:
 938                     self._handle_show_create_procedure(showproc_match)
 939                 else:
 940                     self.send_syntax_error()
 941                 continue
 942
 943             # Handle INFORMATION_SCHEMA.ROUTINES
 944             is_routines_match = PARSE_IS_ROUTINES.match(data)
 945             if is_routines_match:
 946                 self._handle_information_schema_routines(is_routines_match)
 947                 continue
 948
 949             # Handle SET
 950             set_match = PARSE_SET.match(data)
 951             if set_match and set_match.group(1).lower() in ('format',):
 952                 format = dequote(set_match.group(2).strip()).strip().lower()
 953                 if format not in ('json',):
 954                     self.send_error(
 955                         errorcode.ER_LOCAL_VARIABLE,
 956                         "Format '{0}' is not supported".format(format),
 957                         "42000"
 958                     )
 959                 else:
 960                     _LOGGER.debug("Format set to %s", format)
 961                     self._format = format
 962
 963             # We accept anything else without doing anything
 964             self.send_packet(self.ok_packet())


なんか特定の文字列が来た時だけ別ハンドルにしているように見える。
さかのぼってこのPARSE_*の中身を覗いてみると、
  57 # Regular expression getting group, command and the arguments as a string
  58 CHECK_CALL = re.compile(
  59     r"""^CALL\s*""", re.IGNORECASE
  60 )
  61 PARSE_CALL = re.compile(
  62     r"""CALL\s+(\w+)\.(\w+)\s*\((.*)\)"""
  63     r"""(?=(?:[^"']*["'][^"']*["'])*[^"']*$)""", re.IGNORECASE
  64 )
  65 PARSE_CALL_ARGS = re.compile(
  66     r""",(?=(?:[^"']*["'][^"']*["'])*[^"']*$)"""
  67 )
  68 PARSE_CALL_KWARG = re.compile(
  69     r"""=(?=(?:[^"']*["'][^"']*["'])*[^"']*$)"""
  70 )
  71
  72 # Regular expression for SHOW CREATE PROCEDURE
  73 CHECK_SHOW_CREATE_PROC = re.compile(
  74     r"""^SHOW\s+CREATE\s+PROCEDURE\s*""", re.IGNORECASE
  75 )
  76 PARSE_SHOW_CREATE_PROC = re.compile(
  77     r"""SHOW\s+CREATE\s+PROCEDURE\s+(\w+).(\w+)$""", re.IGNORECASE
  78 )
  79
  80 # Regular expression for INFORMATION_SCHEMA.ROUTINES
  81 PARSE_IS_ROUTINES = re.compile(
  82     r"""SELECT\s+(.*)\s+FROM\s+INFORMATION_SCHEMA.ROUTINES\s*(.*)""",
  83     re.IGNORECASE
  84 )
  85
  86 # Regular expression getting SET statements
  87 PARSE_SET = re.compile(
  88     r"""SET\s+(\w+)\s*=(.*)""", re.IGNORECASE
  89 )

このあたりのクエリーは無視せずに返してくれるらしい。

$ client/mysql -P 32275 -u admin -p --protocol=tcp
mysql> SELECT * FROM information_schema.routines;
+----------------------------+-----------------+----------------+----------------------+----------------+
| SPECIFIC_NAME              | ROUTINE_CATALOG | ROUTINE_SCHEMA | ROUTINE_NAME         | ROUTINE_TYPE   |
+----------------------------+-----------------+----------------+----------------------+----------------+
| statistics.node            | fabric          | statistics     | node                 | FABRIC_COMMAND |
| statistics.group           | fabric          | statistics     | group                | FABRIC_COMMAND |
| statistics.procedure       | fabric          | statistics     | procedure            | FABRIC_COMMAND |
| group.activate             | fabric          | group          | activate             | FABRIC_COMMAND |
| group.description          | fabric          | group          | description          | FABRIC_COMMAND |
| group.deactivate           | fabric          | group          | deactivate           | FABRIC_COMMAND |
| group.create               | fabric          | group          | create               | FABRIC_COMMAND |
| group.remove               | fabric          | group          | remove               | FABRIC_COMMAND |
| group.add                  | fabric          | group          | add                  | FABRIC_COMMAND |
| group.health               | fabric          | group          | health               | FABRIC_COMMAND |
| group.lookup_servers       | fabric          | group          | lookup_servers       | FABRIC_COMMAND |
| group.destroy              | fabric          | group          | destroy              | FABRIC_COMMAND |
| group.demote               | fabric          | group          | demote               | FABRIC_COMMAND |
| group.promote              | fabric          | group          | promote              | FABRIC_COMMAND |
| group.lookup_groups        | fabric          | group          | lookup_groups        | FABRIC_COMMAND |
| dump.fabric_nodes          | fabric          | dump           | fabric_nodes         | FABRIC_COMMAND |
| dump.shard_index           | fabric          | dump           | shard_index          | FABRIC_COMMAND |
| dump.sharding_information  | fabric          | dump           | sharding_information | FABRIC_COMMAND |
| dump.servers               | fabric          | dump           | servers              | FABRIC_COMMAND |
| dump.shard_tables          | fabric          | dump           | shard_tables         | FABRIC_COMMAND |
| dump.shard_maps            | fabric          | dump           | shard_maps           | FABRIC_COMMAND |
| manage.teardown            | fabric          | manage         | teardown             | FABRIC_COMMAND |
| manage.stop                | fabric          | manage         | stop                 | FABRIC_COMMAND |
| manage.setup               | fabric          | manage         | setup                | FABRIC_COMMAND |
| manage.ping                | fabric          | manage         | ping                 | FABRIC_COMMAND |
| manage.start               | fabric          | manage         | start                | FABRIC_COMMAND |
| manage.logging_level       | fabric          | manage         | logging_level        | FABRIC_COMMAND |
| server.set_mode            | fabric          | server         | set_mode             | FABRIC_COMMAND |
| server.clone               | fabric          | server         | clone                | FABRIC_COMMAND |
| server.list                | fabric          | server         | list                 | FABRIC_COMMAND |
| server.set_weight          | fabric          | server         | set_weight           | FABRIC_COMMAND |
| server.lookup_uuid         | fabric          | server         | lookup_uuid          | FABRIC_COMMAND |
| server.set_status          | fabric          | server         | set_status           | FABRIC_COMMAND |
| server.destroy             | fabric          | server         | destroy              | FABRIC_COMMAND |
| server.create              | fabric          | server         | create               | FABRIC_COMMAND |
| role.list                  | fabric          | role           | list                 | FABRIC_COMMAND |
| user.roles                 | fabric          | user           | roles                | FABRIC_COMMAND |
| user.usercommand           | fabric          | user           | usercommand          | FABRIC_COMMAND |
| user.list                  | fabric          | user           | list                 | FABRIC_COMMAND |
| user.add                   | fabric          | user           | add                  | FABRIC_COMMAND |
| user.password              | fabric          | user           | password             | FABRIC_COMMAND |
| user.delete                | fabric          | user           | delete               | FABRIC_COMMAND |
| threat.report_error        | fabric          | threat         | report_error         | FABRIC_COMMAND |
| threat.report_failure      | fabric          | threat         | report_failure       | FABRIC_COMMAND |
| provider.unregister        | fabric          | provider       | unregister           | FABRIC_COMMAND |
| provider.register          | fabric          | provider       | register             | FABRIC_COMMAND |
| provider.list              | fabric          | provider       | list                 | FABRIC_COMMAND |
| sharding.list_definitions  | fabric          | sharding       | list_definitions     | FABRIC_COMMAND |
| sharding.remove_definition | fabric          | sharding       | remove_definition    | FABRIC_COMMAND |
| sharding.move_shard        | fabric          | sharding       | move_shard           | FABRIC_COMMAND |
| sharding.disable_shard     | fabric          | sharding       | disable_shard        | FABRIC_COMMAND |
| sharding.remove_table      | fabric          | sharding       | remove_table         | FABRIC_COMMAND |
| sharding.split_shard       | fabric          | sharding       | split_shard          | FABRIC_COMMAND |
| sharding.create_definition | fabric          | sharding       | create_definition    | FABRIC_COMMAND |
| sharding.add_shard         | fabric          | sharding       | add_shard            | FABRIC_COMMAND |
| sharding.add_table         | fabric          | sharding       | add_table            | FABRIC_COMMAND |
| sharding.lookup_table      | fabric          | sharding       | lookup_table         | FABRIC_COMMAND |
| sharding.enable_shard      | fabric          | sharding       | enable_shard         | FABRIC_COMMAND |
| sharding.remove_shard      | fabric          | sharding       | remove_shard         | FABRIC_COMMAND |
| sharding.list_tables       | fabric          | sharding       | list_tables          | FABRIC_COMMAND |
| sharding.prune_shard       | fabric          | sharding       | prune_shard          | FABRIC_COMMAND |
| sharding.lookup_servers    | fabric          | sharding       | lookup_servers       | FABRIC_COMMAND |
| snapshot.destroy           | fabric          | snapshot       | destroy              | FABRIC_COMMAND |
| snapshot.create            | fabric          | snapshot       | create               | FABRIC_COMMAND |
| event.trigger              | fabric          | event          | trigger              | FABRIC_COMMAND |
| event.wait_for_procedures  | fabric          | event          | wait_for_procedures  | FABRIC_COMMAND |
+----------------------------+-----------------+----------------+----------------------+----------------+
66 rows in set (0.00 sec)


おお、ホントだ。
これ、バッキングストアやファームのMySQLサーバーの上ではなくFabricサーバーの上なので、たとえば他のテーブルとかは存在しない。というかたぶんクエリーを握りつぶしてる。

mysql> SELECT * FROM information_schema.tables;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW DATABASES;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW GLOBAL VARIABLES;
Query OK, 0 rows affected (0.00 sec)


SHOW CREATE PROCEDUREでプロシージャを見ると、

mysql> SHOW CREATE PROCEDURE group.health\G
*************************** 1. row ***************************
fabric_help: group health group_id

Check if any server within a group has failed and report health
information.

It returns a dictionary where keys are the servers' uuids and the
values are dictionaries which have the following keys:

* is_alive - whether it is possible to access the server or not.     *
status - PRIMARY, SECONDARY, SPARE or FAULTY.     * threads -
Information on the replication threads.
1 row in set (0.00 sec)


簡単なusageが表示される。

mysql> CALL group.health();
+--------------------------------------+-----+-----------------------------------------------+
| fabric_uuid                          | ttl | message                                       |
+--------------------------------------+-----+-----------------------------------------------+
| 5ca1ab1e-a007-feed-f00d-cab3fe13249e |   1 | execute() takes exactly 2 arguments (1 given) |
+--------------------------------------+-----+-----------------------------------------------+
1 row in set (0.01 sec)


ありゃ、引数の数が足りないらしい。や、それこそusageのSHOW CREATE PROCEDUREに書けよ。
取り敢えずたぶんFabric Groupが足りないんだと思うので渡してみようか。

mysql> CALL group.health('my_first_fabric');
+--------------------------------------+-----+---------+
| fabric_uuid                          | ttl | message |
+--------------------------------------+-----+---------+
| 5ca1ab1e-a007-feed-f00d-cab3fe13249e |   1 | NULL    |
+--------------------------------------+-----+---------+
1 row in set (0.14 sec)

+--------------------------------------+----------+-----------+----------------+-------------------+----------------+-----------------+----------+-----------+
| uuid                                 | is_alive | status    | is_not_running | is_not_configured | io_not_running | sql_not_running | io_error | sql_error |
+--------------------------------------+----------+-----------+----------------+-------------------+----------------+-----------------+----------+-----------+
| 47cf54df-63fc-11e4-942e-fa163e020fd0 |        1 | PRIMARY   |              0 |                 0 |              0 |               0 | False    | False     |
| 4b7036a9-63fc-11e4-942e-fa163e020fd0 |        1 | SECONDARY |              0 |                 0 |              0 |               0 | False    | False     |
+--------------------------------------+----------+-----------+----------------+-------------------+----------------+-----------------+----------+-----------+
2 rows in set (0.14 sec)

Empty set (0.14 sec)


うむ。
こんなこともできるんだ、ってことは認識したんだが、

ドキュメントはよ

MySQL Fabricつらい(AWS連携を試したかったけど挫折した編)

MySQL Utilities 1.5.3からMySQL FabricからAWSが叩けるよ! という噂があったので、1週間半くらいがんばっていたメモ。結論先に言うと、1.5.3では使えない気がする。
http://dev.mysql.com/doc/relnotes/mysql-utilities/en/wb-utils-news-1-5-3.html

この記事は2014/11/18現在の情報を元に書かれているので、「ちゃんと情報書いてあるんじゃん」という未来が来るかも知れません。というか来てくれないと困る。ドキュメントちゃんと書いてくれマジで。

まず、"MySQL Fabric AWS"や"MySQL Fabric EC2"でググっても何も出てこない。これがFabricクオリティ。
かろうじてOracle Open World 2014の "Elastic Scalability in MySQL Fabric with OpenStack" の資料に(教えてもらって)辿り着くものの、

Experiments with Amazon AWS
mysqlfabric provider register my_amazon
   AKIAIOSFODNN7EXAMPLE wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
   eu­west­1 ­­provider_type=AMAZON
mysqlfabric machine create my_amazon
   ­­image image­id=ami­892fe1fe
   ­­flavor name=t2.micro

Note!
Not in MySQL Fabric 1.5
Will be on MySQL Lab
ノートの部分がリリースノートと矛盾しててなんかどうなのかって感じがするけれど、providerサブコマンドを使うらしい。

$ mysqlfabric help provider

Commands available in group 'provider' are:
    provider unregister provider_id  [--synchronous]
    provider register provider_id username password url  [--tenant=NONE] [--provider_type=OPENSTACK] [--default_image=NONE] [--default_flavor=NONE] [--extra=NONE] [--synchronous]
    provider list  [--provider_id=NONE]


うん、構文だけ教えてもらっても、肝心な「何を指定すればいいのか」が全くわからない。
そんな時はマニュアル嫁ですよねわかりますん。

http://dev.mysql.com/doc/mysql-utilities/1.5/en/fabric-util.html

(  д ) ゚  ゚ 載ってねええええええ! そもそもproviderコマンドが載ってねええええええ!

さすがのFabricクオリティなので手探りでproviderコマンドを叩いてみる。

$ mysqlfabric provider list
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

provider_id type username url tenant default_image default_flavor extra
----------- ---- -------- --- ------ ------------- -------------- -----


$ mysqlfabric provider register my_amazon AKIAIOSFODNN7EXAMPLE wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY eu-west-1 --provider_type=AMAZON
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

ProviderError: Provider type (AMAZON) is not supported yet.




あ、ああ、うん、まだサポートされてないのね。うん。さすがFabricクオリティ。リリースノートなんて知ったこっちゃねぇぜ。

( ゚д゚) えっ

しかし更に待ち構える驚きのFabricクオリティ。
じゃあOPENSTACK(暗黙のデフォルト)ならサポートしてるのかっていうと

$ mysqlfabric provider register my_provider provider_user_name provider_passsword provider_url
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

ProviderError: Provider type (OPENSTACK) is not supported yet.



ちょwwwwwおまwwwwwデフォルトくらいサポートしろwwwww

なお、同じスライドの別のコマンドをコピペすると

$ mysqlfabric provider register my_stack mats xyzzy http://example.net:5000/v2.0/ my_project --provider_type=OPENSTACK
Password for admin:
Usage:  provider register provider_id username password url  [--tenant=NONE] [--provider_type=OPENSTACK] [--default_image=NONE] [--default_flavor=NONE] [--extra=NONE] [--synchronous]

mysqlfabric: error: Wrong number of parameters were provided for command 'provider register'.

ちょwwwww引数の数がおかしいってwwwww
まあほらこのスライド、Oracle Open World 2014のセッションのやつですからねー。。アテになんなくても仕方ないかしらFabricクオリティだし。

( ゚д゚) えっ

取り敢えず db tech showcase 2014 東京 に来ていた 日本一MySQL Fabricに詳しそうな人 を捕まえてみたところ、開発チームに問い合わせてくれました。

返ってきた返答は
You need to install the OpenStack libraries;
- python-novaclient for Compute node
- python-neutronclient for Network node
だそうで、


$ sudo pip install python-novaclient python-neutronclient
$ mysqlfabric manage stop
$ mysqlfabric manage start --daemonize

$ mysqlfabric provider register my_provider provider_user_name provider_passsword provider_url
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
dae961a0-4ec2-4e40-b554-88cb284a5a02        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41628e+09 Triggered by <mysql.fabric.events.Event object at 0x260ebd0>.
    4       2   1.41628e+09                        Executing action (_register_provider).
    5       2   1.41628e+09                         Executed action (_register_provider).


$ mysqlfabric provider list
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

provider_id      type           username          url tenant default_image default_flavor extra
----------- --------- ------------------ ------------ ------ ------------- -------------- -----
my_provider OPENSTACK provider_user_name provider_url   None          None           None  None




取り敢えず、not supported yetだけは回避できた模様。

:(;゙゚'ω゚'): なんかドキュメント書けよ。。せめてエラーに出せよ。。

ここまでで1週間半。

しかしなんかどうも、

$ ll /usr/lib/python2.6/site-packages/mysql/fabric/providers
total 96
-rw-r--r-- 1 root root 10088 Oct 21 20:13 __init__.py
-rw-r--r-- 2 root root 12202 Oct 22 01:32 __init__.pyc
-rw-r--r-- 2 root root 12202 Oct 22 01:32 __init__.pyo
-rw-r--r-- 1 root root  2951 Oct 21 20:13 null.py
-rw-r--r-- 2 root root  3873 Oct 22 01:32 null.pyc
-rw-r--r-- 2 root root  3873 Oct 22 01:32 null.pyo
-rw-r--r-- 1 root root 14317 Oct 21 20:13 openstack.py
-rw-r--r-- 2 root root 13481 Oct 22 01:32 openstack.pyc
-rw-r--r-- 2 root root 13481 Oct 22 01:32 openstack.pyo


ここを見てる限り、OpenStack以外はまだ実装されてないんじゃないかなぁって気がする。。また今度。

2014/11/17

topライクにperformance_schemaを眺めるらしいpstopとやら

pstop – a top-like program for MySQL (based on performance_schema) を見て試してみたメモ。

$ git clone https://github.com/sjmudd/pstop.git
$ cd pstop
$ ll
total 52
-rw-rw-r-- 1 ec2-user ec2-user  710 Nov 17 10:03 BUGS
-rw-rw-r-- 1 ec2-user ec2-user  738 Nov 17 10:03 keys.txt
drwxrwxr-x 2 ec2-user ec2-user 4096 Nov 17 10:03 lib
-rw-rw-r-- 1 ec2-user ec2-user 1315 Nov 17 10:03 LICENSE
-rw-rw-r-- 1 ec2-user ec2-user 3905 Nov 17 10:03 main.go
-rw-rw-r-- 1 ec2-user ec2-user 1986 Nov 17 10:03 NEW_FEATURES
drwxrwxr-x 6 ec2-user ec2-user 4096 Nov 17 10:03 performance_schema
-rw-rw-r-- 1 ec2-user ec2-user 1041 Nov 17 10:03 README.md
drwxrwxr-x 2 ec2-user ec2-user 4096 Nov 17 10:03 screen
-rw-rw-r-- 1 ec2-user ec2-user 5551 Nov 17 10:03 screen_samples.txt
drwxrwxr-x 2 ec2-user ec2-user 4096 Nov 17 10:03 state
drwxrwxr-x 2 ec2-user ec2-user 4096 Nov 17 10:03 version

おい、こいつgoだぞ…:(;゙゚'ω゚'): go弱な俺には起動の仕方すらわからない。。


$ go build
main.go:15:2: cannot find package "github.com/go-sql-driver/mysql" in any of:
        /usr/lib/golang/src/pkg/github.com/go-sql-driver/mysql (from $GOROOT)
        ($GOPATH not set)
main.go:16:2: cannot find package "github.com/nsf/termbox-go" in any of:
        /usr/lib/golang/src/pkg/github.com/nsf/termbox-go (from $GOROOT)
        ($GOPATH not set)
main.go:18:2: cannot find package "github.com/sjmudd/mysql_defaults_file" in any of:
        /usr/lib/golang/src/pkg/github.com/sjmudd/mysql_defaults_file (from $GOROOT)
        ($GOPATH not set)
main.go:19:2: cannot find package "github.com/sjmudd/pstop/lib" in any of:
        /usr/lib/golang/src/pkg/github.com/sjmudd/pstop/lib (from $GOROOT)
        ($GOPATH not set)
main.go:20:2: cannot find package "github.com/sjmudd/pstop/state" in any of:
        /usr/lib/golang/src/pkg/github.com/sjmudd/pstop/state (from $GOROOT)
        ($GOPATH not set)
main.go:21:2: cannot find package "github.com/sjmudd/pstop/version" in any of:
        /usr/lib/golang/src/pkg/github.com/sjmudd/pstop/version (from $GOROOT)
        ($GOPATH not set)

むーん。


$ export GOPATH=~/gopath
$ go get
go install: no install location for directory /home/ec2-user/pstop outside GOPATH
$ go build

よくわかってないけどこれでビルドできた。


$ ./pstop
2014/11/17 10:06:11 Could not load ini fileopen /home/ec2-user/.my.cnf: no such file or directory

どうも~/.my.cnfを読み込んで接続情報を取るらしい。


$ cat ~/.my.cnf
[client]
user= msandbox
password= msandbox
port= 5621
host= 127.0.0.1

$ ./pstop

起動できた。
TABキーを叩くとtable_io_waits_summary_by_table, table_io_waits_summary_by_table, file_summary_by_instance, table_lock_waits_summary_by_tableのタブを順繰りに表示してくれる。
"t"でp_sが収集し始めてからの累計と、最後に統計情報をリセット(たぶん、pstopの中で。いちども"z"を叩いてなければ、pstopが起動したときから)の累計切り替え。
"+", "-"で表示間隔の調整。"h"でヘルプだけど、ヘルプから戻るのはもう一度"h"。罠い。

今のところは荒削りにこれで機能が全てっぽい。innotopばりに発展していってくれるととてもうれしい。

Mroonga + MySQL 5.6とMariaDB 10.0だとスピードが結構違う?

あんま真面目に調べてないんですがメモ。


mysql> SELECT COUNT(*) FROM t1 WHERE MATCH(text_column) AGAINST('*D+ xxx' IN BOOLEAN MODE);
+----------+
| COUNT(*) |
+----------+
|    45402 |
+----------+
1 row in set (0.03 sec)

MariaDB [d1]> SELECT COUNT(*) FROM t1 WHERE MATCH(text_column) AGAINST('*D+ xxx' IN BOOLEAN MODE);
+----------+
| COUNT(*) |
+----------+
|    45402 |
+----------+
1 row in set (0.06 sec)

なんか倍くらい違う。


MariaDB [d1]> SHOW PROFILE cpu for query 1;
+-------------------------+----------+----------+------------+
| Status                  | Duration | CPU_user | CPU_system |
+-------------------------+----------+----------+------------+
| starting                | 0.000109 | 0.000000 |   0.000000 |
| checking permissions    | 0.000009 | 0.000000 |   0.000000 |
| Opening tables          | 0.000032 | 0.000000 |   0.000000 |
| After opening tables    | 0.000010 | 0.000000 |   0.000000 |
| System lock             | 0.000008 | 0.000000 |   0.000000 |
| Table lock              | 0.000008 | 0.000000 |   0.001000 |
| After table lock        | 0.000019 | 0.000000 |   0.000000 |
| init                    | 0.000045 | 0.000000 |   0.000000 |
| optimizing              | 0.000347 | 0.000000 |   0.000000 |
| statistics              | 0.000200 | 0.000000 |   0.000000 |
| preparing               | 0.000028 | 0.000000 |   0.000000 |
| FULLTEXT initialization | 0.040459 | 0.027995 |   0.014998 |
| executing               | 0.000024 | 0.000000 |   0.000000 |
| Sending data            | 0.020768 | 0.019997 |   0.000000 |
| end                     | 0.000011 | 0.000000 |   0.000000 |
| query end               | 0.000006 | 0.000000 |   0.000000 |
| closing tables          | 0.000839 | 0.000000 |   0.001000 |
| freeing items           | 0.000012 | 0.000000 |   0.000000 |
| updating status         | 0.000025 | 0.000000 |   0.000000 |
| cleaning up             | 0.000008 | 0.000000 |   0.000000 |
+-------------------------+----------+----------+------------+
20 rows in set (0.00 sec)

mysql> SHOW PROFILE cpu for query 2;
+----------------------+----------+----------+------------+
| Status               | Duration | CPU_user | CPU_system |
+----------------------+----------+----------+------------+
| starting             | 0.000057 | 0.000000 |   0.000000 |
| checking permissions | 0.000009 | 0.000000 |   0.000000 |
| Opening tables       | 0.000016 | 0.000000 |   0.000000 |
| init                 | 0.000018 | 0.000000 |   0.000000 |
| System lock          | 0.000007 | 0.000000 |   0.000000 |
| optimizing           | 0.031675 | 0.094985 |   0.011998 |
| executing            | 0.000027 | 0.000000 |   0.000000 |
| end                  | 0.000007 | 0.000000 |   0.000000 |
| query end            | 0.000005 | 0.000000 |   0.000000 |
| closing tables       | 0.000255 | 0.000000 |   0.000000 |
| freeing items        | 0.000344 | 0.002000 |   0.001000 |
| cleaning up          | 0.000005 | 0.000000 |   0.000000 |
+----------------------+----------+----------+------------+
12 rows in set, 1 warning (0.00 sec)

MariaDB 10.0はMySQL 5.5の時と同じような感じで、FULLTEXT initializationとSending Dataがほとんどの時間を占めてる。MySQL 5.6はoptimizingだけに集中している。これは、計上するステージが変わったからなのかなで済むけど、CPU_userを見るとMariaDBでは全て実時間以下のCPU使用時間に対し、MySQL 5.6のoptimizingステージは実時間の3倍くらいのCPU使用時間になっている。

MySQL 5.6、このへんなんかチューニングしてる? それともPROFILINGでやってるから取れてない(MySQL 5.6ではPROFILING非推奨でp_s使えってことになってるから)だけ?


【2014/11/17 16:10】
お客様の中に詳しい方がいらっしゃいました :)




mysql> SET SESSION mroonga_enable_optimization= OFF;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT COUNT(*) FROM t1 WHERE MATCH(text_column) AGAINST('*D+ xxx' IN BOOLEAN MODE);
+----------+
| COUNT(*) |
+----------+
|    45402 |
+----------+
1 row in set (0.04 sec)

確かにMySQL 5.6ではenable_optimization切ってもそんなに変わらない(= Mroongaのoptimizationでなく、MySQLのFTのレイヤーでごにょごにょしてMroongaのAPIを叩いてる?)


MariaDB [d1]> SET SESSION mroonga_enable_optimization= OFF;
Query OK, 0 rows affected (0.00 sec)

MariaDB [d1]> SELECT COUNT(*) FROM t1 WHERE MATCH(search_text) AGAINST('*D+ xxx' IN BOOLEAN MODE);
+----------+
| COUNT(*) |
+----------+
|    45402 |
+----------+
1 row in set (0.22 sec)

MariaDB 10.0はごりっと落ちる。


【2015/05/27 17:25】
全く別の本番データでPercona Server 5.6 + Mroonga (本当はスレッドプールの影響を計りたかったのでスレッドプール有/無) vs. MariaDB 10.0.19 + Mroonga (面倒なのでスレッドプールなしだけ)を計ってみたけど、やっぱりMariaDBの方が結構遅い。

なんなんだろう。。



MySQL Fabricつらい(FABRIC_OPT_MODE = roはスレーブだけを見に行くわけじゃない)

mysqlコマンドラインクライアントにHA切り替え機能を実装する編 でいじったコマンドラインクライアントでちょこちょこいじってたらなんか不思議な挙動に辿り着く。


mysql> \F ro
Current FABRIC_OPT_DEFAULT_MODE is ro

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

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

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

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

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


マスターとスレーブの間で分散してる。

mysql_options(&mysql, FABRIC_OPT_DEFAULT_MODE, "ro")を設定して10回mysql_queryを叩くプログラムで試してみると

$ ./a.out
Using Fabric for MYSQL connection
port: 20887, read_only: 1
port: 20886, read_only: 0
port: 20887, read_only: 1
port: 20887, read_only: 1
port: 20887, read_only: 1
port: 20887, read_only: 1
port: 20886, read_only: 0
port: 20887, read_only: 1
port: 20887, read_only: 1
port: 20887, read_only: 1


やっぱり分散してる。

$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0




Fabric内部のweightとやらは1:1になっているのでそうなのか(にしては、スレーブに偏りすぎてる気がするんだけど 母数が足りなかっただけで、1000回に増やしたらまあこんなもんだろうって感じだった)

$ ./a.out | sort | uniq -c
    528 port: 20886, read_only: 0
    472 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection

$ ./a.out | sort | uniq -c
    505 port: 20886, read_only: 0
    495 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection

$ ./a.out | sort | uniq -c
    499 port: 20886, read_only: 0
    501 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection


スレーブ側のweightを10000まで上げてみる。

$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ mysqlfabric server set_weight 4b7036a9-63fc-11e4-942e-fa163e020fd0 10000
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
4ca2ef7d-3770-4beb-b557-55ea025b18bf        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41619e+09 Triggered by <mysql.fabric.events.Event object at 0x1102610>.
    4       2   1.41619e+09                        Executing action (_set_server_weight).
    5       2   1.41619e+09                         Executed action (_set_server_weight).


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode  weight
------------------------------------ --------------- --------- ---------- -------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE     1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY 10000.0


$ ./a.out | sort | uniq -c
   1000 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection

$ ./a.out | sort | uniq -c
   1000 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection

$ ./a.out | sort | uniq -c
      1 port: 20886, read_only: 0
    999 port: 20887, read_only: 1
      1 Using Fabric for MYSQL connection


うん、よさげ。スレーブのweightを1のままでマスターのweight 0の方がいいのかしらんと思ったけど、weightを0にするのはダメみたい。

$ mysqlfabric server set_weight 47cf54df-63fc-11e4-942e-fa163e020fd0 0
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

ServerError: Cannot set the server's weight (0.0) to a value lower than or equal to 0.0


当たり前ながら、どれだけスレーブ側にweightを寄せてもFABRIC_OPT_MODE = rwなら必ずマスターを見に行く。

$ ./a.out | sort | uniq -c
   1000 port: 20886, read_only: 0
      1 Using Fabric for MYSQL connection


まだまだ検証要りそうだねぇ。。

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

2014/11/10

MySQL Fabricつらい(Connector/CでマスタースレーブHA打ち分け編)

わたしのC力は低いので、サンプルプログラムはへちょいです。

MySQL Fabric対応のコネクターというともろもろありますが、俺が使えるコネクター(つまりDBD::mysqlのことだ!)がないので、Connector/Cにしました。labsです。

参考にしたサイトはこちら。
Using Connector/C with Fabric (MySQL Connectors C)
Oracle公式のConnector/C(チーム)のブログなんてあったんだね! というかこの1記事しかn<censored>

まずは labs からConnector/C 6.2.0 を取ってきてmake。なんかlabsからダウンロードする時にちょくちょく接続がリセットされるんだけどこれ俺だけ?


$ wget http://downloads.mysql.com/snapshots/pb/mysql-connector-c-6.2.0-labs/mysql-connector-c-6.2.0-labs-src.tar.gz
$ tar xzf mysql-connector-c-6.2.0-labs-src.tar.gz
$ cd mysql-connector-c-6.2.0-labs-src
$ cmake -DCMAKE_INSTALL_PREFIX=/home/mysql/connector .
$ make
$ make install

インストール場所だけ他とぶつからないように変えました。


$ vim test.cc
  1 #include <iostream>
  2 #include "mysql.h"
  3
  4
  5 int main()
  6 {
  7   MYSQL mysql;
  8
  9   mysql_init(&mysql);
 10   mysql_options(&mysql, MYSQL_OPT_USE_FABRIC, NULL);
 11
 12   if (!(mysql_real_connect(&mysql, "127.0.0.1", "admin", "xxxx", NULL,
 13                            32275, NULL, 0)))
 14     std::cout << mysql_error(&mysql) << std::endl;
 15   else
 16   {
 17     mysql_options(&mysql, FABRIC_OPT_GROUP, "my_first_fabric");
 18     mysql_options4(&mysql, FABRIC_OPT_GROUP_CREDENTIALS, "msandbox", "msandbox");
 19     mysql_options(&mysql, FABRIC_OPT_MODE, "ro");
 20     mysql_query(&mysql, "SELECT @@port");
 21     MYSQL_RES *res_from_ro= mysql_store_result(&mysql);
 22     MYSQL_ROW row_from_ro = mysql_fetch_row(res_from_ro);
 23     std::cout << "Fabric ro port: " << row_from_ro[0] << std::endl;
 24
 25     mysql_options(&mysql, FABRIC_OPT_MODE, "rw");
 26     mysql_query(&mysql, "SELECT @@port");
 27     MYSQL_RES *res_from_rw= mysql_store_result(&mysql);
 28     MYSQL_ROW row_from_rw = mysql_fetch_row(res_from_rw);
 29     std::cout << "Fabric rw port: " << row_from_rw[0] << std::endl;
 30   }
 31
 32 }


Fabricサーバーに接続して、roプロパティとrwプロパティでそれぞれポート番号を調べるだけのヤーツ(mysql_free_resultすらしない手抜きっぷり)

$ export LD_LIBRARY_PATH=/home/mysql/connector/lib
$ gcc -I/home/mysql/connector/include -L/home/mysql/connector/lib -lmysqlclient -g test.cc
/usr/bin/ld: cannot find -lmysqlclient
collect2: ld returned 1 exit status

$ ll /home/mysql/connector/lib
total 28256
-rw-r--r-- 1 mysql mysql 19390738 Nov 10 19:27 libmysqlconc62.a
lrwxrwxrwx 1 mysql mysql       24 Nov 10 19:27 libmysqlconc62.so -> libmysqlconc62.so.19.0.0
-rw-r--r-- 1 mysql mysql  9537551 Nov 10 19:27 libmysqlconc62.so.19.0.0
lrwxrwxrwx 1 mysql mysql       16 Nov 10 19:27 libmysqlconc.a -> libmysqlconc62.a
lrwxrwxrwx 1 mysql mysql       17 Nov 10 19:27 libmysqlconc.so -> libmysqlconc62.so
lrwxrwxrwx 1 mysql mysql       24 Nov 10 19:27 libmysqlconc.so.19 -> libmysqlconc62.so.19.0.0

$ gcc -I/home/mysql/connector/include -L/home/mysql/connector/lib -lmysqlconc -g test.cc

$ ldd a.out
        linux-vdso.so.1 =>  (0x00007fff415ff000)
        libmysqlconc.so.19 => /home/mysql/connector/lib/libmysqlconc.so.19 (0x00007f05dcc37000)
        libc.so.6 => /lib64/libc.so.6 (0x00000039a8000000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000321aa00000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00000039a8400000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00000039a7c00000)
        librt.so.1 => /lib64/librt.so.1 (0x00000039a9000000)
        libm.so.6 => /lib64/libm.so.6 (0x00000039a8c00000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000321a600000)
        /lib64/ld-linux-x86-64.so.2 (0x00000039a7800000)


むむ、なんかlibmysqlclientからlibmysqlconcに名前が変わってた。

$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ ./a.out
Using Fabric for MYSQL connection
Fabric ro port: 20887
Fabric rw port: 20886
ちゃんとmysql_optionsで"ro"を指定したのはSECONDARYに、"rw"を指定したのはPRIMARYに行ってる。
$ ./sandboxes/rsandbox_5_6_21/master/stop

$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address  status       mode weight
------------------------------------ --------------- ------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886  FAULTY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 PRIMARY READ_WRITE    1.0


$ ./a.out
Using Fabric for MYSQL connection
Fabric ro port: 20887
Fabric rw port: 20887


マスターを停止して(MySQL Fabric上での)切り替わりが起こると、roもrwも両方新しいPRIMARYの方に向いた。
$ ./sandboxes/rsandbox_5_6_21/master/start
. sandbox server started

$ mysqlfabric server set_status 47cf54df-63fc-11e4-942e-fa163e020fd0 SPARE
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
79142ce2-bc61-4be9-8837-3b6d782344c0        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41562e+09 Triggered by <mysql .fabric.events.event="" 0x22ae450="" at="" object="">.
    4       2   1.41562e+09                        Executing action (_set_server_status).
    5       2   1.41562e+09                         Executed action (_set_server_status).

$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address  status       mode weight
------------------------------------ --------------- ------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   SPARE    OFFLINE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 PRIMARY READ_WRITE    1.0


$ ./a.out
Using Fabric for MYSQL connection
Fabric ro port: 20887
Fabric rw port: 20887


起動してSPARE状態に戻してやると、mode: OFFLINEになってた。相変わらずConnector/Cからは両方PRIMARYを向いている。
$ mysqlfabric server set_status 47cf54df-63fc-11e4-942e-fa163e020fd0 SECONDARY
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
b946e459-f80e-4a9f-8f99-a43174de4832        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41562e+09 Triggered by <mysql .fabric.events.event="" 0x22ae450="" at="" object="">.
    4       2   1.41562e+09                        Executing action (_set_server_status).
    5       2   1.41562e+09                         Executed action (_set_server_status).


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886 SECONDARY  READ_ONLY    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887   PRIMARY READ_WRITE    1.0


$ ./a.out
Using Fabric for MYSQL connection
Fabric ro port: 20887
Fabric rw port: 20887

んん、status: SECONDARYに戻してもConnector/Cは戻ってない。コネクター側でキャッシュを持つとか聞いてるやつだろうか。
とはいえ、3分くらい待ってみても、Fabricサーバーを再起動しても、test.ccをコンパイルしなおしてもずっと20887に寄ったままだった。なんじゃこれ。

ちなみに、DBD::mysqlなんかはlibmysqlclientをそのまま使ってるのでDBI->connectのところでFabricのオプションを突っ込むことになるだろうし(それがmysql_optionsにマッピングされているはず), Connector/JやConnector/PythonはそもそもMySQLプロトコルじゃなくてXML-RPCでしゃべっているのでこれとは違ったアレになるはず。ちょっと微妙かな。。

MySQL Fabricつらい(XML-RPCでつついてみる編)

MySQL Fabricの基本概念としては、
* Fabricサーバーはファームに関する情報だけを提供して、
* 実際の接続のハンドルはFabric対応コネクターが提供する

Fabricサーバーがしゃべるプロトコルは2種類。XML-RPCとMySQLプロトコルで、問い合わせ結果はコネクター側にキャッシュされて、TTLによって破棄される(実際にはコネクターの実装に依存するんだろうけど)

現在MySQL Fabricに対応しているコネクターは
* Connector/Python (○racleさん謹製)
* Connector/J (○racleさん謹製)
* mysqlnd (PHPによるクライアント実装で、シャード機能のみ実験的にサポート(HA機能は(まだ?)サポートしない))
* Connector/C (○racleさん謹製だけどlabsリリース)

そして、Connector/Cが現在唯一FabricサーバーとMySQLプロトコルでしゃべる。
…ってか、

MYSQL mysql;
mysql_init(&mysql);
mysql_option(&mysql, MYSQL_OPT_USE_FABRIC, NULL);
mysql_real_connect(&mysql, "127.0.0.1", "user", "password",
NULL, 32275, NULL, 0);
https://blogs.oracle.com/mysqlconnectors-C/entry/using_fabric_with_connector_c

( д ) ゚ ゚ え、mysql_real_connectで直接叩くの!? プロキシも直接兼ねる感じになるの!? (調べてない)

DBD::mysqlはlibmysqlclientを使ってるので、方式的にはこっちになるはず。他にlibmysqlclient使ってるのってなんかあったっけ。Rubyにも何かあった気がする(RubyのMySQLライブラリは名前がややこしすぎて憶えられない。。)


まあいいや。取り敢えず、コネクターのつもりになってXML-RPCでつついてみようという企画。

$ mysqlfabric group lookup_servers my_first_fabric
Password for admin:
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ perl -MRPC::XML::Client -MData::Dumper -e '$client= RPC::XML::Client->new("http://localhost:32274/RPC2"); $request= RPC::XML::request->new("group.lookup_servers", RPC::XML::string->new("my_first_fabric")); print Dumper $client->send_request($request);'
$VAR1 = 'RPC::XML::Client::send_request: HTTP server error: Unauthorized';

ありゃ、怒られた。そりゃそうか。認証があった。


$ perl -MRPC::XML::Client -MData::Dumper -e '$client= RPC::XML::Client->new("http://localhost:32274/RPC2"); $client->credentials("MySQL Fabric", "admin", "xxxx"); $request= RPC::XML::request->new("group.lookup_servers", RPC::XML::string->new("my_first_fabric")); print Dumper $client->send_request($request);'
$VAR1 = 'RPC::XML::Client::send_request: HTTP server error: Bad Request';

Bad Request言われた(´・ω・`)
あんまり時間もかけたくないし、取り敢えずXML-RPC経由では認証要らない設定にして再起動。


$ mysqlfabric manage stop

$ vim /etc/mysql/fabric.cfg
..
[protocol.xmlrpc]
disable_authentication = yes
..

$ mysqlfabric manage start --daemonize

止める前に設定を変えてしまうと、クライアントとしてのmysqlfabric manage stopがそれを読んで認証をかっ飛ばそうとするので、まだ認証が有効なFabricサーバーがそれを蹴る。ので間にはさむ。
これでどうかというと


$ perl -MRPC::XML::Client -MData::Dumper -e '$client= RPC::XML::Client->new("http://localhost:32274/RP
C2"); $client->credentials("MySQL Fabric", "admin", "xml"); $request= RPC::XML::request->new("group.lookup_servers", RPC::XML:
:string->new("my_first_fabric")); print Dumper $client->send_request($request);'
$VAR1 = bless( [
                 bless( do{\(my $o = '1')}, 'RPC::XML::int' ),
                 bless( do{\(my $o = '5ca1ab1e-a007-feed-f00d-cab3fe13249e')}, 'RPC::XML::string' ),
                 bless( do{\(my $o = '1')}, 'RPC::XML::int' ),
                 bless( do{\(my $o = '')}, 'RPC::XML::string' ),
                 bless( [
                          bless( {
                                   'info' => bless( {
                                                    'names' => bless( [
                                                                      bless( do{\(my $o = 'server_uuid')}, 'RPC::XML::string'
),
                                                                      bless( do{\(my $o = 'address')}, 'RPC::XML::string' ),
                                                                      bless( do{\(my $o = 'status')}, 'RPC::XML::string' ),
                                                                      bless( do{\(my $o = 'mode')}, 'RPC::XML::string' ),
                                                                      bless( do{\(my $o = 'weight')}, 'RPC::XML::string' )
                                                                    ], 'RPC::XML::array' )
                                                  }, 'RPC::XML::struct' ),
                                   'rows' => bless( [
                                                    bless( [
                                                             bless( do{\(my $o = '47cf54df-63fc-11e4-942e-fa163e020fd0')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = '127.0.0.1:20886')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = 'PRIMARY')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = 'READ_WRITE')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = '1.0')}, 'RPC::XML::double' )
                                                           ], 'RPC::XML::array' ),
                                                    bless( [
                                                             bless( do{\(my $o = '4b7036a9-63fc-11e4-942e-fa163e020fd0')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = '127.0.0.1:20887')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = 'SECONDARY')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = 'READ_ONLY')}, 'RPC::XML::string' ),
                                                             bless( do{\(my $o = '1.0')}, 'RPC::XML::double' )
                                                           ], 'RPC::XML::array' )
                                                  ], 'RPC::XML::array' )
                                 }, 'RPC::XML::struct' )
                        ], 'RPC::XML::array' )
               ], 'RPC::XML::array' );

よっしゃよっしゃ。
これでFabric非対応のコネクターからでもほげほげふがふができそう(認証さえ何とかすれば)

…やー、Fabricサーバー以外の追加コンポーネントがなしでできるからMySQL Fabricいいなーと思ってるのに、ゴニョゴニョするとか正直やりたくないけど。。

2014/11/06

MySQL Fabricつらい(障害ノードの戻しとか)

マスター昇格編 でマスターをkillしても、スレーブがちゃんとマスターに昇格してくれるところまでは良かったんですが、


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address  status       mode weight
------------------------------------ --------------- ------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886  FAULTY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 PRIMARY READ_WRITE    1.0



(旧)マスターを起動したあとでも、待てど暮らせどファームには勝手に戻ってこない。


$ ./m
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.21-log Source distribution

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.

master [localhost] {msandbox} ((none)) > show slave status\G
Empty set (0.00 sec)


$ mysqlfabric group promote my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

GroupError: There is no valid candidate that can be automatically chosen in group (my_first_fabric). Please, choose one manual
ly.

killしてもう一度起動したマスターには、当然今のマスターの情報はない。生きてる間にpromoteならFabricサーバーがログインしてゴニョゴニョしてくれるんだろうけど、そもそも接続できなかったんだから当たり前。スレーブがいないんだからもちろんpromoteもできない。


$ mysqlfabric group demote my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
dec31088-00b1-4a33-bf36-622a9e1f302a        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26c38d0="" at="" object="">.
    4       2   1.41526e+09                       Executing action (_block_write_demote).
    5       2   1.41526e+09                        Executed action (_block_write_demote).
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26c39d0="" at="" object="">.
    4       2   1.41526e+09                       Executing action (_wait_slaves_demote).
    5       2   1.41526e+09                        Executed action (_wait_slaves_demote).


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive    status is_not_running is_not_configured io_not_running sql_not_running io_err
or sql_error
------------------------------------ -------- --------- -------------- ----------------- -------------- --------------- ------
-- ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        1    FAULTY              0                 1              0               0    Fal
se     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1 SECONDARY              0                 1              0               0    Fal
se     False

issue
-----


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886    FAULTY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ mysqlfabric group promote my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
01a40c48-347d-4fa8-887c-2cde33a353ad        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x2552e50="" at="" object="">.
    4       2   1.41526e+09                      Executing action (_define_ha_operation).
    5       2   1.41526e+09                       Executed action (_define_ha_operation).
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26bc7d0="" at="" object="">.
    4       2   1.41526e+09                      Executing action (_find_candidate_fail).
    5       2   1.41526e+09                       Executed action (_find_candidate_fail).
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26bc710="" at="" object="">.
    4       2   1.41526e+09                     Executing action (_check_candidate_fail).
    5       2   1.41526e+09                      Executed action (_check_candidate_fail).
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26bc750="" at="" object="">.
    4       2   1.41526e+09                          Executing action (_wait_slave_fail).
    5       2   1.41526e+09                           Executed action (_wait_slave_fail).
    3       2   1.41526e+09 Triggered by <mysql .fabric.events.event="" 0x26c3890="" at="" object="">.
    4       2   1.41526e+09                      Executing action (_change_to_candidate).
    5       2   1.41526e+09                       Executed action (_change_to_candidate).


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive  status is_not_running is_not_configured io_not_running sql_not_running io_error
 sql_error
------------------------------------ -------- ------- -------------- ----------------- -------------- --------------- --------
 ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        1  FAULTY              0                 1              0               0    False
     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1 PRIMARY              0                 0              0               0    False
     False

issue
-----



demote/promoteしてみたけどコレジャナイ
じゃあ、remove/addで登録しなおすか。


$ mysqlfabric group remove my_first_fabric 47cf54df-63fc-11e4-942e-fa163e020fd0
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
51509e3b-d1a7-4876-a52d-e25364c46d8d        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41526e+09 Triggered by .
    4       2   1.41526e+09                            Executing action (_remove_server).
    5       2   1.41526e+09                             Executed action (_remove_server).


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address  status       mode weight
------------------------------------ --------------- ------- ---------- ------
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 PRIMARY READ_WRITE    1.0


$ mysqlfabric group add my_first_fabric 127.0.0.1:20886
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
f50a682b-dab6-4094-9f54-72c72569e71a        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41526e+09 Triggered by .
    4       2   1.41526e+09                               Executing action (_add_server).
    5       2   1.41526e+09                                Executed action (_add_server).


$ mysqlfabric group lookup_servers my_first_fabric                            [896/2897]
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886 SECONDARY  READ_ONLY    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887   PRIMARY READ_WRITE    1.0


$ ./check_slaves.a
master
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 1548
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 1548
slave # 1
             File: mysql-bin.000003
         Position: 1548

あ、ちゃんとスレーブとしてファームに組み込まれた。


$ make_multiple_sandbox 5.6.21
installing node 1
installing node 2
installing node 3
group directory installed in $HOME/sandboxes/multi_msb_5_6_21

$ ./use_all "select @@port"
# server: 1:
@@port
14722
# server: 2:
@@port
14723
# server: 3:
@@port
14724

$ vim node?/my.sandbox.cnf
..
log-slave-updates
gtid-mode= ON
enforce-gtid-consistency

$ export MYCLIENT_OPTIONS="-uroot"
$ ./use_all "grant all on *.* to fabric@localhost identified by 'fabric_password'"
$ ./restart_all

$ mysqlfabric group add my_first_fabric 127.0.0.1:14722
$ mysqlfabric group add my_first_fabric 127.0.0.1:14723
$ mysqlfabric group add my_first_fabric 127.0.0.1:14724

$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive    status is_not_running is_not_configured io_not_running sql_not_running io_err
or sql_error
------------------------------------ -------- --------- -------------- ----------------- -------------- --------------- ------
-- ---------
01250ed8-6584-11e4-9e28-fa163e020fd0        1 SECONDARY              0                 0              0               0    Fal
se     False
47cf54df-63fc-11e4-942e-fa163e020fd0        1 SECONDARY              0                 0              0               0    Fal
se     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1   PRIMARY              0                 0              0               0    Fal
se     False
f9fe3cee-6583-11e4-9e28-fa163e020fd0        1 SECONDARY              0                 0              0               0    Fal
se     False
fd8c1c45-6583-11e4-9e28-fa163e020fd0        1 SECONDARY              0                 0              0               0    Fal
se     False

issue
-----


$ ./n1
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 28
Server version: 5.6.21-log Source distribution

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.

node1 [localhost] {root} ((none)) > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| d1                 |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

おおー。GTIDだから、マスターにバイナリーログさえ残ってればmysqlfabric group addするより前のバイナリーログもちゃんと適用される。
ジェネラルログを覗くと、


76 Connect   fabric@localhost on
                   76 Query     SET NAMES 'utf8' COLLATE 'utf8_general_ci'
                   76 Query     SET @@session.autocommit = ON
                   76 Query     SELECT @@GLOBAL.SERVER_UUID as SERVER_UUID
                   76 Query     SELECT @@GLOBAL.SERVER_ID as SERVER_ID
                   76 Query     SELECT @@GLOBAL.VERSION as VERSION
                   76 Query     SELECT @@GLOBAL.GTID_MODE as GTID_MODE
                   76 Query     SELECT @@GLOBAL.LOG_BIN as LOG_BIN
                   76 Query     SELECT @@GLOBAL.READ_ONLY as READ_ONLY
                   76 Query     SHOW GRANTS
                   76 Query     STOP SLAVE
                   76 Query     SHOW SLAVE STATUS
                   76 Query     SHOW SLAVE STATUS
                   76 Query     CHANGE MASTER TO MASTER_HOST = '127.0.0.1' MASTER_USER = 'fabric' MASTER_PASSWORD =  MASTER_PORT = 20887
                   76 Query     SET @@GLOBAL.READ_ONLY = ON
                   76 Query     SELECT @@GLOBAL.READ_ONLY as READ_ONLY
                   76 Query     START SLAVE
                   76 Query     SHOW SLAVE STATUS
                   76 Query     SHOW SLAVE STATUS

うむ。シャードをゴニョゴニョするときはmysqldumpを使う(/etc/mysql/fabric.cfgにmysqldumpのパスを書くパラメーターがある)けど、単に追加するだけの時はFabricサーバーは特に面倒を見ないと。とはいえGTID前提だから、XtraBackupでサクッと作ってサクッとmysqlfabric group addでおしまいと。

( ´-`).oO(や、便利なんだけどその前提条件がな。。


【2014/11/06 18:16】
途中からだいぶ脱線していた気がするけれど、もともとの目的だった"status: FAULTYからstatus: SECONDARYに戻す"は、




$ mysqlfabric server set_status 4b7036a9-63fc-11e4-942e-fa163e020fd0 SPARE
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
aa09ecf8-2f55-4c11-bc25-53b0ae19b3b0        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41527e+09 Triggered by .
    4       2   1.41527e+09                        Executing action (_set_server_status).
    5       2   1.41527e+09                         Executed action (_set_server_status).


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive  status is_not_running is_not_configured io_not_running sql_not_running io_error sql_error
------------------------------------ -------- ------- -------------- ----------------- -------------- --------------- -------- ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        1 PRIMARY              0                 0              0               0    False     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1   SPARE              0                 0              0               0    False     False

issue
-----


$ mysqlfabric server set_status 4b7036a9-63fc-11e4-942e-fa163e020fd0 SECONDARY
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
1e8eb7c0-2233-4087-86cb-bedc9e331f1e        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41527e+09 Triggered by .
    4       2   1.41527e+09                        Executing action (_set_server_status).
    5       2   1.41527e+09                         Executed action (_set_server_status).


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive    status is_not_running is_not_configured io_not_running sql_not_running io_error sql_error
------------------------------------ -------- --------- -------------- ----------------- -------------- --------------- -------- ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        1   PRIMARY              0                 0              0               0    False     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1 SECONDARY              0                 0              0               0    False     False

issue
-----



Σ(゚д゚lll) できたーっ!

MySQL Fabricつらい(マスター昇格編)

一昨日インストールして 、 昨日HA構成だけ設定してみた MySQL Fabric。
さすがに手動での切り替えくらいは簡単だった。

* ファームに登録しているのはMySQL::Sandboxで作ったマスター/スレーブ1台ずつ構成です。


$ ./use_all "select @@read_only"
# master
@@read_only
0
# server: 1:
@@read_only
1

$ ./check_slaves
master
             File: mysql-bin.000004
         Position: 191
slave # 1
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 191
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 191

こんな状態から


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ mysqlfabric group promote my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
03c27976-809f-48f1-a385-e3dc6caf9ae6        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                      Executing action (_define_ha_operation).
    5       2   1.41525e+09                       Executed action (_define_ha_operation).
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                    Executing action (_find_candidate_switch).
    5       2   1.41525e+09                     Executed action (_find_candidate_switch).
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                   Executing action (_check_candidate_switch).
    5       2   1.41525e+09                    Executed action (_check_candidate_switch).
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                       Executing action (_block_write_switch).
    5       2   1.41525e+09                        Executed action (_block_write_switch).
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                       Executing action (_wait_slaves_switch).
    5       2   1.41525e+09                        Executed action (_wait_slaves_switch).
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                      Executing action (_change_to_candidate).
    5       2   1.41525e+09                       Executed action (_change_to_candidate).


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886 SECONDARY  READ_ONLY    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887   PRIMARY READ_WRITE    1.0



単にmysqlfabric group promoteでグループ名だけ指定してやればよくて


$ ./use_all "select @@read_only"
# master
@@read_only
1
# server: 1:
@@read_only
0

$ ./check_slaves.a
master
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 1548
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 1548
slave # 1
             File: mysql-bin.000003
         Position: 1548

こんな状態に入れ替わる。
(そのままじゃ動かないので、./check_slavesはマスターとスレーブでSHOW MASTER STATUSとSHOW SLAVE STATUSを逆にしてある)

* 出力結果のmaster, slave #1というのはMySQL::Sandboxから見た(最初の構成の)マスターとスレーブ。


マスターをもとに戻してから、今度はkill。


$ kill -9 15569 15853

$ ./check_slaves
master
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql_sandbox20886.sock' (111)
slave # 1
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 191
             Slave_IO_Running: Connecting
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 191

マスターが死んだぞ。さあどうする。


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive    status is_not_running is_not_configured io_not_running sql_not_running                                                                           io_error sql_error
------------------------------------ -------- --------- -------------- ----------------- -------------- --------------- ---------------------------------------------------------------------------------- ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        0    FAULTY              0                 0              0               0                                                                              False     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1 SECONDARY              0                 0              1               0 error reconnecting to master 'fabric@127.0.0.1:20886' - retry-time: 60  retries: 3     False

issue
-----


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886   PRIMARY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 SECONDARY  READ_ONLY    1.0


$ ./check_slaves
master
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql_sandbox20886.sock' (111)
slave # 1
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 191
             Slave_IO_Running: Connecting
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 191

変わんねぇ(´・ω・`)

と思ったら、答えはなんと日本語のスライドの中に見つけた。 doublemarketさん++。




mysqlfabric group activateだと…:(;゙゚'ω゚'):


$ mysqlfabric group activate my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
91e8f2cc-43fa-4855-a6c9-44a4deedc9bf        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.41525e+09 Triggered by .
    4       2   1.41525e+09                           Executing action (_activate_group).
    5       2   1.41525e+09                            Executed action (_activate_group).


$ mysqlfabric group health my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid is_alive  status is_not_running is_not_configured io_not_running sql_not_running io_error
 sql_error
------------------------------------ -------- ------- -------------- ----------------- -------------- --------------- --------
 ---------
47cf54df-63fc-11e4-942e-fa163e020fd0        0  FAULTY              0                 0              0               0    False
     False
4b7036a9-63fc-11e4-942e-fa163e020fd0        1 PRIMARY              0                 0              0               0    False
     False

issue
-----


$ mysqlfabric group lookup_servers my_first_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address  status       mode weight
------------------------------------ --------------- ------- ---------- ------
47cf54df-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20886  FAULTY READ_WRITE    1.0
4b7036a9-63fc-11e4-942e-fa163e020fd0 127.0.0.1:20887 PRIMARY READ_WRITE    1.0


$ ./check_slaves.a
master
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql_sandbox20886.sock' (111)
slave # 1
             File: mysql-bin.000003
         Position: 1548


$ ./use_all "select @@read_only"
# master
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql_sandbox20886.sock' (111)
# server: 1:
@@read_only
0

おおおお切り替わった!!

参考にしていたブログ公式スタートガイドもうちょっと大きな字で書いてくれていいんですよactivate。というかデフォルトそれじゃダメですかバッキングストアのテーブルにDEFAULT句つけるくらいで済むと思うんですがどうなんですかあとで見てみよう。

Fabric対応コネクターであれば、このstatus: PRIMARYとかを見て接続先を判断することになるので、VIPとかそういう仕組みなしでMySQL Fabricだけで完結するのが利点だと思う。余計な仕組み考えなくて良いけどGTID必須。新規には(コネクター使うかどうかは別として)配備だけでもしておいていいかも知れない。ヘルスチェックできるし。

今のところの感想は引き続きこれ。