2015年1月26日月曜日

MySQL 5.7で暗黙のデフォルトが変わりそうなはなし

Morgan Tocker というMySQLの中の人(MySQL Community Teamのひと)が 自身のブログ で、MySQL 5.7のデフォルト値の変更に関する意見を募集していたりする。







ので、ちょっと解説してみます。わたしが勝手に思っていることを述べているだけなので、詳しくは原文をあたってください。


まずはこっち。 Proposal to change additional defaults in MySQL 5.7 | Master MySQL

* transaction_isolation
  * REPEATABLE-READ から READ-COMMITTED に

実際READ-COMMITTEDで十分だし、いくつかのサービスはREAD-COMMITTEDで速くなってるし、今後波及させていくつもりだったし、個人的にはいいんじゃない感。
クセのあるREPEATABLE-READがデフォルトじゃなくなるのは少し寂しい気がしなくもないのと、REPEATABLE-READを前提にした情報がWEBには溢れているので、それが淘汰されるまで時間がかかりそうだなぁと思うくらい。


* binlog_format
  * STATEMENT から ROW に

トランザクション分離レベルがREAD-COMMITTEDになるとSBRは使えないから当然こうなる。RBRはSBRに比べてサイズがでかいとはいえ、1クエリーで100万レコード書き換えるようなクエリーはそうそう(ユーザートラフィック上では)ないのでそこまで悲観してない。ところで一時期は暗黙のデフォルトまで上り詰めたMIXEDはどこいった。


* innodb_autoinc_lock_mode
  * 1から2に

1よりも2の方が並列性能高いんだけど、SBRで2にするとデータがズレることがあるよ! ということで1になっていたのが、RBRになるので安心して2にできるということか。


( ´-`).oO(新しいデフォルトでbinlog_formatをROW以外の何かに変える時は残りの2つも変えないとヤバい、と。憶えてられるかな。


次はこっち。 Proposal to change Replication and InnoDB Settings in MySQL 5.7 | Master MySQL


* binlog_error_action
  * 5.7.5ではbinlogging_impossible_modeと呼ばれていたアレ。
  * IGNORE_ERROR から ABORT_SERVER へ

バイナリーログの書き出しに失敗した時の動作を指定できるオプション。バイナリーログに書き出しができなければmysqldがまるっと落ちるようなデフォルトに。InnoDBログファイルとかもともとそうだし、InnoDBのクラッシュリカバリーにバイナリーログを使ったりする昨今では妥当な変更。


* innodb_checksum_algorithm
  * 昔innodb_checksumと呼ばれていたアレの発展バージョン。5.6からこの名前。
  * innodb (ソフトウェア計算) から crc32 (ハードウェア支援が受けられればそれを使える) に

ベンチとってみたくなります。


* innodb_page_cleaners, innodb_purge_threads
  * 1 から 4 へ

* innodb_strict_mode
  * OFF から ON へ

もともとONで使ってるからそんなに気にならない。


* innodb_log_file_size
  * 48M から 128M へ

今までが少なすぎたので、いいことかと(いや、自分で指定するけど)
昔はクラッシュリカバリーに時間がかかったーというけど5.5以降ならギガバイト単位でもそんなに困らないし、ストレージも大きくなったしってことで。


* innodb_buffer_pool_dump_at_shutdown, innodb_buffer_pool_load_at_startup
  * 0 から 1 へ

MySQL 5.6で入ったInnoDBバッファプール暖機のアレ。デフォルトで有効に。


* innodb_buffer_pool_dump_pct
  * 100 から 25 に

InnoDBバッファプールダンプ(↑InnoDBバッファプール暖気のやつ)のとき、バッファプール全体の何%をib_buffer_poolに書き出すかというオプションらしい。そもそも5.7での新顔。


* innodb_file_format
  * Antelope から Barracuda

ついにデフォルトになるときがきたのだー


* innodb_large_prefix
  * OFF から ON に

かみぽさんの悲願がついにかなう。


* binlog_gtid_recovery_simplified
  * OFF から ON に

オプション名も変わっているみたいだけど、そもそも初めて知ったオプション。
このへんと関係ある? Relay Log Recovery when SQL Thread’s Position is Unavailable | MySQL Server Blog


* sync_binlog
  * 0 から 1 へ

ACIDのDに使うようになっちゃってますからね。


* slave_net_timeout
  * 3600 から 60 へ

これも長すぎる長すぎる言われてたのが、ついに。


* [mysql]セクションのpropmt
  * "mysql> " から "\u@\h [\d] > " に

ユーザー名@ホスト名 [スキーマ名]、これはもともとやってる人多かったんじゃなかろうか。


* sql_mode
  * 今までのに加えて NO_AUTO_CREATE_USER

GRANTステートメント前にCREATE USERステートメント必須。


どっちもプロポーザルってことになっているので、興味があればコメントしてみたりするといいと思います :)

2014年12月25日木曜日

MySQL Fabricつらい(クライアントとしてのmysqlfabricとサーバーとしてのmysqlfabricのオプションの扱いが一緒)

/etc/mysql/fabric.cfg はイケてない。
何がどうイケてないかというと、クライアントとしてのmysqlfabricとサーバーとしてのmysqlfabricを全く区別していないところ。

最初に(そしてこれは随分前から)気が付いたのは、[protocol.xmlrpc]セクションと[protocol.mysql]セクションのdisable_authentication。

[protocol.xmlrpc]
disable_authentication = no


デフォルトはnoだが、認証を無効化したいと思うとyesにする。
だがしかしこれ、サーバーとして起動されたときとクライアントとして起動されたときで同じパラメーターを使っているため、MySQL Fabricサーバーが起動している最中に書き換えたりすると(サーバーは再起動するまでその内容が有効にならないので)、結構アレってなる。

それはいい。それは全然いい。困らない。


だがこれはつらい。


$ less /etc/mysql/fabric.cfg
..
[protocol.xmlrpc]
..
address = localhost:32274
..

$ mysqlfabric manage start
[INFO] 1419482563.650106 - MainThread - Initializing persister: user (backingstore), server (localhost:3306), database (fabric).
[WARNING] 1419482563.670879 - MainThread - Provider error: No module named novaclient.
[INFO] 1419482563.671135 - MainThread - Loading Services.
[WARNING] 1419482563.686219 - MainThread - Authentication disabled
[INFO] 1419482563.686369 - MainThread - MySQL-RPC protocol server started, listening on localhost:32275
[WARNING] 1419482563.686489 - MainThread - Authentication disabled
[INFO] 1419482563.695672 - MainThread - Fabric node starting.
[INFO] 1419482563.698753 - MainThread - Starting Executor.
[INFO] 1419482563.698855 - MainThread - Setting 5 executor(s).
[INFO] 1419482563.699274 - Executor-0 - Started.
[INFO] 1419482563.701372 - Executor-1 - Started.
[INFO] 1419482563.702225 - Executor-2 - Started.
[INFO] 1419482563.703481 - Executor-3 - Started.
[INFO] 1419482563.705299 - Executor-4 - Started.
[INFO] 1419482563.705777 - MainThread - Executor started.
[INFO] 1419482563.710501 - MainThread - Starting failure detector.
[INFO] 1419482563.711543 - XML-RPC-Server - XML-RPC protocol server ('127.0.0.1', 32274) started.
[INFO] 1419482563.712189 - XML-RPC-Server - Setting 1 XML-RPC session(s).
[INFO] 1419482563.712714 - XML-RPC-Session-0 - Started XML-RPC-Session.

$ ss -ltp
State      Recv-Q Send-Q                             Local Address:Port                                 Peer Address:Port
LISTEN     0      0                                      127.0.0.1:32274                                           *:*        users:(("mysqlfabric",675,4))
LISTEN     0      0                                      127.0.0.1:32275                                           *:*        users:(("mysqlfabric",675,6))
LISTEN     0      0                                             :::mysql                                          :::*

[protocol.xmlrpc]セクションのaddressはmysqldでいうところの--bind-addressと--portをあわせたような用途で使われる。つまりが、address=localhost:32274で起動していると、127.0.0.1:32274で起動してしまうので、他のホストから叩けなくなる。しょんぼり。

なので当然、address=0.0.0.0:32274とかやるわけだ。


[INFO] 1419482742.772749 - MainThread - Initializing persister: user (backingstore), server (localhost:3306), database (fabric).
[WARNING] 1419482742.792821 - MainThread - Provider error: No module named novaclient.
[INFO] 1419482742.793089 - MainThread - Loading Services.
[WARNING] 1419482742.805074 - MainThread - Authentication disabled
[INFO] 1419482742.805208 - MainThread - MySQL-RPC protocol server started, listening on 0.0.0.0:32275
[WARNING] 1419482742.805334 - MainThread - Authentication disabled
[INFO] 1419482742.814918 - MainThread - Fabric node starting.
[INFO] 1419482742.818677 - MainThread - Starting Executor.
[INFO] 1419482742.818770 - MainThread - Setting 5 executor(s).
[INFO] 1419482742.819158 - Executor-0 - Started.
[INFO] 1419482742.819843 - Executor-1 - Started.
[INFO] 1419482742.821553 - Executor-2 - Started.
[INFO] 1419482742.822262 - Executor-3 - Started.
[INFO] 1419482742.825073 - Executor-4 - Started.
[INFO] 1419482742.825355 - MainThread - Executor started.
[INFO] 1419482742.829459 - MainThread - Starting failure detector.
[INFO] 1419482742.830409 - XML-RPC-Server - XML-RPC protocol server ('0.0.0.0', 32274) started.
[INFO] 1419482742.830877 - XML-RPC-Server - Setting 1 XML-RPC session(s).
[INFO] 1419482742.831168 - XML-RPC-Session-0 - Started XML-RPC-Session.

State      Recv-Q Send-Q                             Local Address:Port                                 Peer Address:Port
LISTEN     0      0                                              *:32274                                           *:*        users:(("mysqlfabric",702,4))
LISTEN     0      0                                              *:32275                                           *:*        users:(("mysqlfabric",702,6))
LISTEN     0      0                                             :::mysql                                          :::*

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

                  group_id description failure_detector master_uuid
-------------------------- ----------- ---------------- -----------
fabric_server_in_container        None                0        None


ここまではいい。
さて、じゃあ隣のノードからこのmysqlfabricサーバーを叩くにはどうしたらいいか?

そう、 *クライアント側のfabric.cfgの[protocol.xmlrpc]のaddressをここに指定する*


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

                  group_id description failure_detector master_uuid
-------------------------- ----------- ---------------- -----------
fabric_server_in_baremetal        None                0        None

$ vim /etc/mysql/fabric.cfg
..
[protocol.xmlrpc]
..
#address = localhost:32274
address = 172.17.0.144:32274
..

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

                  group_id description failure_detector master_uuid
-------------------------- ----------- ---------------- -----------
fabric_server_in_container        None                0        None




--paramオプションを使えば特定のオプションだけ上書きできるはずだから、わざわざ書き換えなくてもいいはずなんだけど、エラーメッセージも謎いし、受け取っても気に食わない形だとエラーも何もせずに読み飛ばしやがるので、全然わからない。

フンス。


【2014/12/25 14:04】
もともとは MySQL FabricのファームになれるようなDockerイメージを作ったやつ のついでに、だったらMySQL FabricサーバーそのものもDockerイメージにすればいいんじゃん? と思ってハマったのがこの記事だったり。

yoku0825/mysql_fabric_server ってイメージもつくりました。バッキングストアとMySQL Fabricサーバーがそのまま起動できるヤーツ。

【2015/01/02 16:43】↑リポジトリとリンク張り替えた

2014年12月19日金曜日

DockerでMySQL Fabricをさっくり試すための整備をしたつもり

みんな、僕と地雷友達になってよ!

【2014/12/25 14:03】 リンク間違ってんじゃん。。
https://github.com/yoku0825/my_script/blob/master/make_centos_baseimage_for_docker.sh
https://github.com/yoku0825/my_script/blob/master/make_mysqlfabric_sandbox.sh


MySQL Fabricのファームにすぐに突っ込めるようなDockerイメージ を使ってもろもろ整理した結果、こんなんなりました。

確認した環境は、 どっかのVPS の テンプレートイメージ"CentOS 6.5(64bit)"、epel-releaseは予め入ってました。


# rpm -i http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
# yum install -y mysql-server mysql-utilities docker-io

DockerホストをそのままMySQL Fabricサーバー(バッキングストア相乗り)にするので、そのへんをゴニョゴニョ。
あとそういう趣旨なのでDockerも入れないと。


# vim /etc/mysql/fabric.cfg
..
# diff -C 0 /etc/mysql/fabric.cfg.orig /etc/mysql/fabric.cfg
*** /etc/mysql/fabric.cfg.orig  2014-12-19 17:57:22.512670132 +0900
--- /etc/mysql/fabric.cfg       2014-12-19 17:56:43.957666364 +0900
***************
*** 16 ****
! user = fabric
--- 16 ----
! user = backingstore
***************
*** 20 ****
! password =
--- 20 ----
! password = backingstore
***************
*** 34 ****
! password =
--- 34 ----
! password = fabric_password
***************
*** 45 ****
! disable_authentication = no
--- 45 ----
! disable_authentication = yes
***************
*** 64 ****
! disable_authentication = no
--- 64 ----
! disable_authentication = yes

色々面倒なのでXML経由もMySQLプロトコル経由もdisable_authentication=yesにしてしまう。
バッキングストアのユーザー名を変えてるのは単なる気まぐれ。
Dockerイメージには予めFabric管理用の特権ユーザーとしてfabricユーザーがいるので、なんとなくかぶせたくなかっただけ。


# /etc/init.d/mysqld start
# mysql
mysql> GRANT ALL ON fabric.* TO backingstore@127.0.0.1 IDENTIFIED BY 'backingstore';
Query OK, 0 rows affected (0.02 sec)

# /etc/init.d/docker start
# git clone https://github.com/yoku0825/my_script
# my_script/make_mysqlfabric_sandbox.sh start global shard1 shard2
..
Finishing initial setup
=======================
Password for admin user is not yet set.
Password for admin/xmlrpc:
Repeat Password:
Password set.
Password set.
No result returned
..
# my_script/mysqlfabric_tree.sh
global
        3d2f0764-8760-11e4-baf4-0242ac110002 172.17.0.2 PRIMARY READ_WRITE    1.0
shard1
        4395a789-8760-11e4-baf4-0242ac110003 172.17.0.3 PRIMARY READ_WRITE    1.0
shard2
        4b23890a-8760-11e4-baf4-0242ac110004 172.17.0.4 PRIMARY READ_WRITE    1.0

途中、mysqlfabricを初期化してるところでパスワードは聞かれる(そして空にできない)ので取り敢えず入力するけど、disable_authentication=yesなので実際にコマンドラインクライアントから叩くときには使われない。これだけで1グループ1台構成のシャーディングの準備ができる。そのうち、1グループに2台以上追加する何かも考えようかどうしようか。

大事なことなのでもう一度いいます。
僕と地雷友達になってください :)

さて、やっとここまで来られたので次はシャードの検証しましょうかね。。

MySQL Fabricつらい(複数グループの視認性が悪いのでスクリプト書いた…けど実は既にあった)

MySQL Fabricの何が面倒って、複数グループあっても登録してるサーバーを全部一覧したいときにそのコマンドがない(ような気がする)ところ。

取り敢えずシェルスクリプト書いた。
https://github.com/yoku0825/my_script/blob/master/mysqlfabric_tree.sh


$ ./mysqlfabric_tree.sh
global
        105087a3-8752-11e4-ba97-4277c372408b 172.17.0.80 SECONDARY READ_ONLY    1.0
shard1
        134469a1-8752-11e4-ba98-1a32de75db4e 172.17.0.81 SECONDARY READ_ONLY    1.0
shard2
        16937ac5-8752-11e4-ba98-d60c364380fa 172.17.0.82 SECONDARY READ_ONLY    1.0
shard3
        19ea7137-8752-11e4-ba98-32bfdacb274f 172.17.0.83 SECONDARY READ_ONLY    1.0

よしOK。
というかmysqlfabricコマンド側に入れてくれないかねこういうの。


【2014/12/19 17:21】
と思ったらあった。

$ mysqlfabric dump servers
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid group_id        host port mode status weight
------------------------------------ -------- ----------- ---- ---- ------ ------
105087a3-8752-11e4-ba97-4277c372408b   global 172.17.0.80 3306    1      2    1.0
134469a1-8752-11e4-ba98-1a32de75db4e   shard1 172.17.0.81 3306    1      2    1.0
16937ac5-8752-11e4-ba98-d60c364380fa   shard2 172.17.0.82 3306    1      2    1.0
19ea7137-8752-11e4-ba98-32bfdacb274f   shard3 172.17.0.83 3306    1      2    1.0



マニュアルに負けたなんて。。ダメダメだ。。
http://dev.mysql.com/doc/mysql-utilities/1.5/en/fabric-util-store-commands.html

( ´-`).oO(modeとstatusが数値じゃなくて人間に読めるほうの値で出してくれればいいのに。。

2014年12月18日木曜日

MySQL Fabricのファームにすぐに突っ込めるようなDockerイメージを作ってみた

今までずっと MySQL::Sandbox で試してきたけど、ふと思いついたのでDockerイメージにしてみた。
Dockerが面白くて肝心のMySQL Fabricを全然触ってなかった気がするけど、いいの。

取り合えずMySQL Fabricに必要な要素としては、
* gtid-mode= ON
* server-idはカブらないように
* Fabricノードからファームのサーバーへはフルアクセスのユーザーが必要
くらいでしょうか。

何台追加で作ってもserver-idがカブらないようにするために、server-idはIPアドレスの下2バイトから自動生成するようにmysqld_safeにパッチをしてあります(--server-id=autoで、server_id= 3バイト目 * 256 + 4バイト目に自動設定する)

( ´-`).oO(これ、今まで誰もFRとか上げなかったのかな。。

Dockerfile見るのが一番判りやすいんですが、

# cat Dockerfile
FROM yoku0825/cent66:init
MAINTAINER yoku0825
RUN yum install -y perl libaio
RUN rpm -i http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-server-5.6.22-1.linux_glibc2.5.x86_64.rpm
RUN rpm -i http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-client-5.6.22-1.linux_glibc2.5.x86_64.rpm
ADD ./mysqld_safe.patch /root/mysqld_safe.patch
RUN patch /usr/bin/mysqld_safe /root/mysqld_safe.patch
ADD ./my.cnf /etc/my.cnf
ADD ./init_mysql.sh /root/init_mysql.sh
RUN bash /root/init_mysql.sh
EXPOSE 3306
CMD /etc/init.d/mysql start && tail -f /dev/null

クライアント(MySQL Fabric用のユーザー作ったりするのに使う)とサーバーだけrpmで突っ込んで、mysqld_safeにパッチ当てて、MySQLのユーザー作成はシェルスクリプトで押し込んで、というのがこれだけで書けました。楽チン。



# docker run -d -h fabric1 --name fabric1 fabric_aware_5622
da51ddad4e26f228435b60e2b2ec6c1dc465438b640575f232691b07affaeb4d

# docker run -d -h fabric2 --name fabric2 fabric_aware_5622
fd84f396f8fbcf688db6ca689b10f1d8bccb6dcc12fac3eb0c82a2639a23168f

# docker run -d -h fabric3 --name fabric3 fabric_aware_5622
8f5bc6199cb699048194bd1aff92d6ed0e8caad406e1a222f4e908fe8478509c

# docker inspect -f "{{.Name}}, {{.Config.Hostname}}, {{.NetworkSettings.IPAddress}}" $(docker ps | grep -v "^CONTAINER" | awk '{print $1}')
/fabric3, fabric3, 172.17.0.54
/fabric2, fabric2, 172.17.0.53
/fabric1, fabric1, 172.17.0.52

docker runでドカドカ上げて、


$ mysqlfabric group create my_docker_fabric
$ mysqlfabric group add my_docker_fabric 172.17.0.52
$ mysqlfabric group add my_docker_fabric 172.17.0.53
$ mysqlfabric group add my_docker_fabric 172.17.0.54
$ mysqlfabric group promote my_docker_fabric

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

                         server_uuid     address    status       mode weight
------------------------------------ ----------- --------- ---------- ------
b9d7c753-86a3-11e4-b627-aa6edb94a664 172.17.0.52 SECONDARY  READ_ONLY    1.0
bd269d22-86a3-11e4-b627-e6e3a6deb92c 172.17.0.53 SECONDARY  READ_ONLY    1.0
bff11b23-86a3-11e4-b627-a6df24859725 172.17.0.54   PRIMARY READ_WRITE    1.0

これだけで簡単に誰でもMySQL Fabricを試せるようになりました。。と、いいな。
ホストネームとIPアドレスの紐付けをDockerのホスト側になんか持たせようかしら(mysqlfabricとバッキングストアはDockerのホストにいる想定)

これでtcpdumpが見やすくなる!


DockerfileはGithubに。

Docker Hubだとここ。
【2014/01/02 16:41】リポジトリ変えた
https://registry.hub.docker.com/u/yoku0825/mysql_fabric_aware/

yoku0825/cent66:fabric_aware_5622っていうタグのがそうです。

Have fun!


【2014/12/19 18:40】
このあたりのmysqlfabric group create/add を自動でやるようなスクリプトも書いた。
http://yoku0825.blogspot.jp/2014/12/dockermysql-fabric.html

2014年12月12日金曜日

Mroongaの全文検索が上手くいかない気がするときの初動メモ

この記事は Groonga Advent Calendar 2014 の12日目の記事です。

最初は「Mroonga with MySQL Fabric(仮)」というタイトルを考えていたんですが、MySQL FabricはフツーのMySQLサーバーの上でマスター昇格とかよしなにやってくれるためのミドル(?)ウェアなので、Mroongaも動いて当たり前だと思ってやめました。

じゃあ別のMySQLのHA実装のXtraDB Clusterでもやろうかなと思いましたが、よく考えたらそれはもう1年半前にやっていて ( mroongaをXtraDB Clusterで冗長化できそうなメモ ) 当時はまだ"m"が小文字だったんだなーとか感慨深いですね。
PXCも5.6になりましたしwsrepもバージョン上がってますが、今でもできるのかどうかは知りません。誰か試してください。

MySQL Cluster with Mroongaは仕組み上不可能だし (ラッパーモード使っても、SQLノード上に転置索引が作成されるのでダメ) もうHAやめて、フツーに普段やっていることをメモしておこうと思います。

長かったな前置き。


基本的にMySQLしか触ったことなかった人がMroongaで全文検索…なのを想定しています。そう、俺だ。
さて、何はともあれテーブルの定義を確認したりします。


mysql56> use d1
Database changed

mysql56> CREATE TABLE t1 (num serial, val varchar(32), FULLTEXT KEY(val)) Engine= Mroonga Comment= 'Engine "InnoDB"';
Query OK, 0 rows affected (0.06 sec)

mysql56> SELECT mroonga_command('table_list')\G
*************************** 1. row ***************************
mroonga_command('table_list'): [[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[259,"t1","d1.mrn.0000103","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null],[260,"t1-val","d1.mrn.0000104","TABLE_PAT_KEY|PERSISTENT","ShortText",null,"TokenBigram","NormalizerMySQLGeneralCI"]]
1 row in set (0.00 sec)

mysql56>
mysql56> SELECT mroonga_command('table_list --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('table_list --output_type tsv'): "id"   "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigram"
"NormalizerMySQLGeneralCI"
1 row in set (0.02 sec)

特に何もこだわりがないときは--output_type tsvを指定しておくと、改行が多くなって見やすいのでわたしは好きです。

groongaコマンドラインクライアントから叩くときは、余計なものが何もついていない"データベース名".mrnファイルを指定します。


$ /usr/groonga/4.0.6/bin/groonga d1.mrn
> table_list --output_type tsv
0       1418374830.69561        0.00125479698181152
"id"    "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigram"
"NormalizerMySQLGeneralCI"
END

何が書いてあるのか詳しくは判りませんが、転置索引はt1-val("テーブル名"-"インデックス名")というオブジェクトに入っているようです。
トークナイザーはTokenBigram, ノーマライザーはNormalizerMySQLGeneralCIですね。トークナイザーやノーマライザーをTypoするとここが想定しているのと違う値になったりしますね_| ̄|○


mysql56> SELECT * FROM t1;
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
|   2 | yoku0826 |
+-----+----------+
2 rows in set (0.00 sec)

mysql56> SELECT mroonga_command('select t1-val --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('select t1-val --output_type tsv'): 3
[       "_id"   "UInt32"        ]       [       "_key"  "ShortText"     ]       [       "index" "t1"    ]
2       "0825"  1
3       "0826"  1
1       "YOKU"  4
1 row in set (0.02 sec)

実際にトークナイズされた結果が見られます。本番でこれをやると結構大変なので、CREATE TABLE .. LIKE, INSERT INTO .. SELECTでズレてる気がする行だけを抽出して読みます。


mysql56> ALTER TABLE t1 DROP KEY val;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql56> ALTER TABLE t1 ADD FULLTEXT KEY (val) Comment 'parser "TokenBigramIgnoreBlankSplitSymbolAlphaDigit"';
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql56> SELECT mroonga_command('table_list --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('table_list --output_type tsv'): "id"   "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigramIgnoreBlankSplitSymbolAlphaDigit"
"NormalizerMySQLGeneralCI"
1 row in set (0.02 sec)

mysql56> SELECT mroonga_command('select t1-val --limit -1 --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('select t1-val --limit -1 --output_type tsv'): 10
[       "_id"   "UInt32"        ]       [       "_key"  "ShortText"     ]       [       "index" "t1"    ]
5       "08"    8
7       "25"    1
9       "26"    1
8       "5"     1
10      "6"     1
6       "82"    9
3       "KU"    6
2       "OK"    5
4       "U0"    7
1       "YO"    4
1 row in set (0.02 sec)

たとえばトークナイザーを変えるとどうなるんだとかいうのはこのように調べています。(Groongaの)selectコマンドは暗黙に--limit 10を押し込んでくれるので、トークンが10個以上に分かれる(たぶん、フツーは分かれる、だろう)場合は--limit -1で無制限に出力させられます。

こんな感じで調べて、なんかどうも全角の記号より後ろに詰められた文字がちゃんとトークナイズされてなくね? とかいうのに気付いたり気付かなかったりします。
http://sourceforge.jp/projects/groonga/lists/archive/dev/2014-February/002110.html


ちなみにTritonn時代にもsennaコマンドラインクライアント(たぶんgroongaコマンドラインクライアントと同じような機能を持っていたんだろうけれど)があったんですが、こっちはコマンドのドキュメントがどこにも存在しなかったので挫折しました。。(TritonnからMroongaへの移行の時に、同じようなのが見られたら少し便利だっただろうなぁ、と思いつつ)

とはいえ、「検索結果がおかしい」ことに気付くのって難しいですよね。。

2014年12月10日水曜日

MariaDB 10.0のCONNECTストレージエンジンからOracle DBに接続してみる

この記事は JPOUG Advent Calendar 2014 の10日目の記事です。

MariaDB 10.0には CONNECTストレージエンジン という MS Accessでいうところのリンクテーブルなストレージエンジンが搭載されていて、リンクの方法にCSVとかXMLとかODBCとか色々あるようです。MySQLに昔から入っているFEDERATEDストレージエンジンはMySQLプロトコルしかしゃべれないのでリンク先は必ずMySQLサーバーでないといけないという制約がありますが、ODBCなら色々できるわけですよね。

というわけでさっくり試してみました。
unixODBC-develと OracleのInstant Client (とりあえず、basic, odbc, develの3つをrpmで突っ込みました)は予めインストールしてあります。

$ wget "https://downloads.mariadb.org/f/mariadb-10.0.15/source/mariadb-10.0.15.tar.gz/from/http%3A/ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb?serve" -O mariadb-10.0.15.tar.gz
$ tar xzf mariadb-10.0.15.tar.gz
$ cmake -DWITH_CONNECT_STORAGE_ENGINE=ON .
$ make
$ make install


ODBCドライバーの設定をしておきます。

$ sudo vim /etc/odbcinst.ini
..
[Oracle 12c ODBC driver]
Description     = Oracle ODBC driver for Oracle 12c
Driver          = /usr/lib/oracle/12.1/client64/lib/libsqora.so.12.1

$ vim ~/.odbc.ini
[JPOUG]
Driver       = Oracle 12c ODBC driver
ServerName   = xxx.xxx.xxx.xxx:1521/HOGE
DSN          = JPOUG


ではCONNECTテーブルの作成。

mysql> CREATE TABLE connect_test Engine= Connect TABLE_TYPE=ODBC tabname='TABLE_1' CONNECTION='DSN=JPOUG;UID=xxxx;PWD=xxxx';
ERROR 1105 (HY000): [unixODBC][Driver Manager]Can't open lib '/usr/lib/oracle/12.1/client64/lib/libsqora.so.12.1' : file not found

( ゚д゚) ファッ
ライブラリーパスが通ってなさそうなパスに入れたんですね○racleさん。。


$ export LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib
$ bin/mysqladmin shutdown
$ bin/mysqld_safe &

取りあえずLD_LIBRARY_PATHに突っ込んでmysqldを再起動。


mysql> CREATE TABLE connect_test Engine= Connect TABLE_TYPE=ODBC tabname='TABLE_1' CONNECTION='DSN=JPOUG;UID=xxxx;PWD=xxxx';
Query OK, 0 rows affected (2.21 sec)

通ったー。


mysql> SELECT * FROM connect_test LIMIT 3;
+---------+-----------+--------+-----------+--------------+------------+---------------------+---------------+--------+
| USER_ID | ACTION_ID | SERIAL | REMOTE_IP | HTTP_REFERER | USER_AGENT | START_TIME          | COMPLETE_TIME | STATUS |
+---------+-----------+--------+-----------+--------------+------------+---------------------+---------------+--------+
|  277385 |       159 |      1 | NULL      | NULL         | NULL       | 2014-10-29 04:43:40 | NULL          |      1 |
+---------+-----------+--------+-----------+--------------+------------+---------------------+---------------+--------+
1 row in set (0.11 sec)


xxxx@test-db03>SELECT * FROM TABLE_1;

   USER_ID  ACTION_ID     SERIAL REMOTE_IP
---------- ---------- ---------- ---------------
HTTP_REFERER
--------------------------------------------------------------------------------
USER_AGENT
--------------------------------------------------------------------------------
START_TI COMPLETE     STATUS
-------- -------- ----------
    277385        159          1


14-10-29                   1

取り合えずテスト用のDBを間借りしただけなので何のデータも入ってないけど、同じデータが引けてはいるぽい。

こんなことして何が嬉しいかというと、MariaDBをオペレーター用(Not アプリケーション用)のプロキシとして使うことで
* Oracle側で設定するよりも柔軟にアクセス制限が出来る(かも知れない)
  * MySQL(MariaDB)はカラム単位までアクセス制限ができる
  * 接続元IPアドレスが違えば別ユーザーとして扱える
  * MariaDBならPAM Auditプラグインが入っているので、既存のLDAPと連携できるかも
* Oracle側でやる気にならなさそうな全件クエリーログとかできる
  * アプリケーション用のクエリーは別の方法を模索するとして、内部アクセスの証左にするぶんならgeneral_logとPAM Auditを使えば結構イケるんじゃね?
なあたりのユースケースが無いかなぁと思っている所存。