ラベル MySQL の投稿を表示しています。 すべての投稿を表示
ラベル MySQL の投稿を表示しています。 すべての投稿を表示

2014年3月28日金曜日

WebScaleSQLとは何か(まとめと想像)

WebScaleSQLが公開されました。 これはFacebook, Google, LinkedInそしてTwitterのMySQLエンジニアが、大規模環境で使用する際に必要な変更点をまとめて、違う名前をつけてリリースしたものです。

MySQLとの違い

FAQにまとまってるものと、GitHubのcommitsを見ればなんとなくわかります。

  • 変更点それぞれについて全部のテストを自動で走らせるようなフレームワークを追加
  • ストレステストと自動化された性能テストを追加
  • テストを整理して、安全な変更が余計なテストを壊さないようにした
  • NUMA interleave、innodb バッファプールフラッシュの最適化、いくつかのクエリに対する最適化など性能改善
  • super_read_onlyと、1秒以下の精度でタイムアウトを指定するといった、web scaleで必要な変更

super_read_only とは、SUPER な権限を持った人でも read only にしてしまう機能のようです。

なぜ独立のブランチなのか

WebScaleSQLと新しく名前がついた割にはそこまで大きな変更点はなく、なぜリリースされたのかと疑問に思いました。私の想像ですが次のような感じなのかなぁと思っています。根拠なしなので間違ってたらごめんなさい。

  • お互いにエンジニア同士が交流する中、「それウチも困ってる!」というのが増えた
  • Oracle にパッチを投げるには少し面倒な手続きが必要
  • もう少し身軽に、様々な機能を取り込んで速いペースで試せる共通基盤がほしい
  • そうだ、名前をつけて公開してしまえば開発も加速できるしライセンスもはっきり

もう一度書きますが根拠レスです。あとはテストが彼らの求める水準としてはcommunity版には含まれていなくて、そういうのをもうちょっと気軽にメンテしておきたいんじゃないかとも思いました。

今後の見通し

しばらくはMySQLの最新プロダクションリリースに対するパッチセットのような感じで、"fork"と言わず"branch"と名乗って開発を続けるようです。コミットを見ていると1年以上前のコミットも多くて、とりあえずまとめてみました、ここからスタートですという感じに受け止めました。

最近また新しい機能の追加がぽつぽつ行われているようなので、しばらくするともう少し変わったものになるのかもしれません。

蛇足

きちんとかっこいいWebを作って、プレスリリースも出して、ニュースにもなってというのはすごいなぁと思いました。

2013年12月16日月曜日

MySQLにMHA を導入してハマったところ

この記事はMySQL Casual Advent Calendar 2013の16日目の記事です。

MySQLのマスタ冗長化のいち手段としてMHAというものがあります。マスタが落ちた時に自動的にスレーブに切り替えてくれます。詳しいアーキテクチャは公式ページやそこから辿れるスライドに詳しいのでそちらを参照していただくとして、ここではカジュアルに導入の時に詰まった店を挙げます。

幾つかはバグらしきものも含まれているので、後ほど公式にレポートしようと思います。

MySQLのパスワードに記号が入っているとうまくいかない

MySQLのパスワードに一部の記号が入っていると認証が通りませんでした。コードを見るとエスケープして戻して、MySQL向けのエスケープしたりシェル向けのエスケープをしたりと入り組んでいたので、どこかで対応が崩れているのかと思いましたが他にもこの種の問題はありそうなのでとりあえず記号を使わないパスワードに変更して乗り切りました。

shebangがenv perlになっている

MHAのスクリプトはすべてshebangが "#!/usr/bin/env perl" になっています。make installしても変わりません。ところで、#!/usr/bin/envはイマイチという噂もありますが、これperlbrewと相性が極端に悪くって、システムperlのパッケージを入れてもperlbrewのほうが実行されてライブラリが見つからなかったり逆にperlbrewに入れたのにシステムperlのほうが実行されたりして危ないのです。今回はすべてperlbrewの方に統一することにしました。

たぶんmake installする際に書き換えるのが正解だと思います。

relay_log_info=TABLEだとうまく動かない

MySQL 5.6の新機能でmaster-infoやrelay-log-infoがテーブルに入れれるようになりましたが、これがMHAではうまく動きませんでした。コードを見ると一見サポートしてそうに見えるのですが、マスタはrelay-log-infoが無いのにrelay-log-infoをSELECTして、見つからないのでエラーで止まります。ファイルの場合はちゃんと動くのですけどね。というわけで今回はファイルで使うことにしました。

パスワードを平文で書かないといけない

これはMySQLに常に付きまとう問題ですしもはや仕様なのですが、例えばpurge_relay_logsを動かそうとするとオプション引数にパスワードを平分で書く必要があります。crontabをちゃんと一定のユーザーに設定すれば見られる危険は少ないですが、気持ち悪いですね。

SSHのオプションがおかしい

failoverするときに使うサンプルスクリプトが付属していますが、これから参照されているSSHのオプション定数がちょっとおかしいです。

our $SSH_OPT_CHECK =
"-o StrictHostKeyChecking=no -o PasswordAuthentication=no -o BatchMode=yes -o ConnectTimeout=VAR_CONNECT_TIMEOUT";

VAR_CONNECT_TIMEOUT って謎の定数らしきものが使われていて、sshがinvalid time valueと言って死にます。ちょっとハマりました。

新しいレプリカセットを作って切り替えするときには同時に入らない

MHAはthree tier以上のレプリケーションも限定的にサポートしているのですが、これは一番上のマスタを登録する必要があります。新しいマスタスレーブのペアを既存のマスタにぶら下げて切り替えるという時に、既存のマスタへ新しいマスタからレプリケーションが走っていると、MHAがその既存のマスタに飛んでいって「Master %s:%d from which slave %s replicates is not defined in the configuration file!」というエラーメッセージとともに死にます。ので、新しいセットにMHAを入れてから切り替えようということはできません。

切り替えてからMHAを起動すればいいだけなのですが、どうしようか少し悩みました。

何回もテストすると失敗する

MHAは最近failoverした時刻を .failover.complete というファイルで管理していて、最近failoverしたばっかりでもう一度failoverしようとすると、「Current time is too early to do failover again.」というエラーで止まります。毎回手動でファイルを削除する必要があって少し面倒でした。

おわりに

問題点ばかり列挙しましたが、MHAは実績のある限られたマスタ冗長化ツールです。一度導入してしまえば安眠できると思います。これからパッチやバグレポートを書きます...

明日はYuya Takeyamaさんです。

2013年11月29日金曜日

allocatorを変えてMySQLをベンチしてみた

MySQL Performance Blogにtcmalloc/jemallocを使うとパフォーマンスが良くなるという記事があるので、気になって手元の環境でも計測してみました。

環境

CPUIntel Xeon CPU E5-2620 x 2
OSCentOS 6.4 64bit
MySQLMySQL 5.6.14
sysbenchSysbench 0.4.12
jemallocjemalloc 3.4.1
tcmallocgperftools 2.1

MySQLのmax_connectionsは2048に設定しました。innodb_file_formatはBarracudaで、Buffer poolは56GBを確保し、buffer pool instanceは32に設定しました。

測定内容

sysbench の OLTP テストを下記のようなコマンドで走らせました。

for t in 16 32 64 128 256 512 1024; do sysbench --test=oltp --oltp-table-size=1000000 --mysql-user=benchuser --mysql-password=benchuser --db-driver=mysql --num-threads=$t --max-requests=200000 --oltp-read-only run; done
for t in 16 32 64 128 256 512 1024; do sysbench --test=oltp --oltp-table-size=1000000 --mysql-user=benchuser --mysql-password=benchuser --db-driver=mysql --num-threads=$t --max-requests=200000 run; done

jemalloc の nodirty というのは "MALLOC_CONF=lg_dirty_mult:-1" という環境変数をセットしたものです。これは3.2以降性能がベンチマークによっては劣化することがあるというので気になって測りました。

tcmalloc + large page は、my.cnf に large-page を付けてMySQLを起動したものです。read/writeは取り忘れたのでreadのみです。

なお試行回数は1回で、ベンチマークを2回走らせた2回目の値です(平均とか取ってません)。測定のたびにmysqlを再起動し、cleanup/prepareを実施しました。

allocatorの差し替えは/etc/init.d/mysqlにexport LD_PRELOAD=...を記述する方法を取りました。ロードされていることは/proc/{pid}/mapsを見て確認しました。

測定結果

read/writeに関しては、測定のばらつきが大きく、実行するたびに2割程度は差が出る結果になりましたのであまり信頼の高い結果ではありません。jemallocはスレッド数が1024の場合にのみ、glibc mallocより22%程度高速という結果になりました。tcmallocは16-32スレッドの場合は最大2割遅く、64スレッド以上では1割程度高速でした。

readは比較的安定した結果が出ました。jemallocはglibc mallocと比較し5%程度遅くなりました。tcmallocはglibc mallocと同等または高速で、最大3%程度の差が出ました。

tcmallocでlarge-pageを有効にしても有意な差は見られませんでした。これは今回のデータサイズが小さく、TLBサイズが変わってもヒット率が変わらなかった可能性があります。

考察、まとめ

MySQL Performance blogに掲載されていたような、256スレッド以上ではglibcが遅くなるという現象は見られませんでした。また、jemallocがtcmalloc/glibc mallocとくらべて低速であるという結果になりました。これは設定によるのか、ベンチマークの種類によるのかはわかりませんが、必ずしもjemallocやtcmallocに差し替えることによってMySQLの性能が向上するとは言えない結果になりました。ただしtcmallocはglibc mallocより遅いことはなかったので、差し替えることによってデメリットはメモリの消費量が増える以外は生じないので、メモリに余裕があるのであれば検討してもよいかと思いました。

元のblogでは64スレッドを超えると1万transactions/secを超えているのに対し、こちらではたかだか5000スレッドしか出てません。向こうは32スレッドあるのでこちらより性能が良いのですが、それでも少し性能が低い気がします。ですので、何か設定がまずいのか、それともallocatorが実は差し替わっていない可能性も残っています。

transactions/secだけではなく、CPU使用率やレイテンシにも着目するべきですが、それは今後の課題とします。

2013年10月10日木曜日

MariaDB / MySQL コミュニティイベント in Tokyoに参加しました

10月9日に秋葉原で開催されたMariaDB / MySQL コミュニティイベント in Tokyoに参加してきました。最近話題の MariaDB、いったいどんな感じだろう?という情報収集に出かけました。

MySQL と MariaDB の歴史

  • MySQL は1995年生まれ。MySQL=会社=ソフト
  • 2007年、10億米ドルで Sun が買収
  • 2009年、MariaDB が fork
  • 2009年、Oracle が Sun を買収
  • 2010年、Oracleからコンサルと営業部隊が抜けてSkySQLを創業
  • 2013年、SkySQLとMariaDB Services(エンジニア部隊)が経営統合

SkySQL ABについて

SkySQLはMySQLとMariaDBのサポートを提供している会社。MariaDBの開発にもコミットしているが、MariaDBの運営自体は MariaDB Foundation によって行われている。これはまた買収されることを防ぐため。

ドメインは

  • mariadb.com: Enteprise サービス
  • mariadb.org: MariaDB コミュニティ、Foundation管理

となっている。

顧客満足度は高いと考えている。93%のサブスクリプション更新率を誇る。

MariaDB について

MariaDBの誕生から44ヶ月で、もうすぐ10.0がリリースされる予定。特徴は

  • MySQL との互換性を確保
  • バイナリを置き換えるだけで移行できること
  • 100% GPLv2

バージョン 10.0 は MySQL 5.5 ベース。これは Oracle MySQL 5.6 がリリースされた時に Oracle が過去のコミット履歴をリファクタリングして一部消してしまったため。機能は独自実装を含め、5.6 のスーパーセットを目指している。

私が個人的にいいなと思った機能は

  • Multi-source replication: 一つのスレーブに複数のマスタからレプリケーションする
  • Optimizer がかなり良くなってる(特にJOINやサブクエリ)
  • スレッドプール(Oracle版では有償)
  • SHOW EXPLAIN を使って実行中のクエリに対して EXPLAIN が発行できる
  • group commit によってfsyncを呼ぶ頻度が減った
  • FusionIO DirectFS をサポートし、atomic write できるようになってる
  • GTIDを有効にするときに、全部を一度に切り替えず、徐々にノードを入れ替えられる

あたりです。MySQL でも使えるのかは調べてないので、MySQLでもサポートしていたらご指摘ください...

クライアントライブラリはLGPL版が用意されている。ただしプロトコルは現在のところ互換性があるので、LGPLでなくても良いのであれば無理に移行する必要はないとのこと。

その他、MariaDB Galera Cluster や TokuDB のサポートという言葉が飛んでいて、このあたり知らないので今度調べてみようと思います。

サポートはリリース後5年間提供していて、これは各distributionがMariaDBに移行した理由の一つだと考えている。

MariaDB Manager について

MariaDB をモニタリング、設定、プロビジョンするためのツール群で、シェルスクリプトとPHP、Javaを組み合わせて実装されている。オープンソースで提供される。現在はまだ開発中。

GUIを使っても良いし、RESTful APIを使って既存のツールと組み合わせて利用することも可能。

興味深いと思ったのはスレーブの追加やバックアップもAPIからできるようになっていると言っていたところです。Xtra Backupと組み合わせて使ったりするのか、それとも似たような機能が独自で実装されるのか、そのあたり気になりました。

MaxScale について

MySQL Proxy のような、クライアントとサーバーの間に挟むプロキシを開発中。C言語で、Event-basedで開発しているので高い性能を出せる。従来のプロキシより高機能なものを目指している様子。

  • master-slave、マルチマスタ構成をサポート
  • Sharding のサポート(将来的にはMariaDBの改良とセットでSQLをフルサポート)
  • 各ノードにslaveとして接続し、binlogの進み具合を見て一貫性を保証する仕組み
  • PAM, LDAP, Keystone などの認証をサポート
  • 将来的にはMariaDBのパーザーを載せ、サーバーとの通信をバイナリプロトコルにすることも検討

開発はまだ初期段階で、10月22日にgithubで公開予定なので、フィードバックをくださいとのこと。

全体を通した感想

OracleがMySQLのプロプライエタリライセンスを持っている以上、すべてをGPLで提供するしかないのでどの程度ビジネスが上手くいってるのかなぁと気になって、「いいことばっかりのように思うけど、フリーランチは無いはずで、何を利用者に求めてるの?」と聞いてみました。そしたら「まずはOSSとして開発が進み、フィードバックやパッチがもらえること。もちろんサブスクリプションを買ってもらえるとうれしい」とのことでした。今日聞いただけの話ですが、開発自体はかなりオープンに進めているようで好印象でした。商用版を使っているかどうかで、Oracle MySQLとMariaDBを比較した時の印象は大きく変わるんじゃないかなぁと思います。

テストケースをつけてリリースしていることも強調していました。Oracle MySQL 5.6.14 にはテストケースがひとつも追加されずリリースされたことを引き合いに、オープンソースとしてはMariaDBのほうが参画しやすいのではないか、また、バグトラッカーも一本化していると言っていました。なるほど、普通のオープンソースの開発にかなり近いようです。また、Perconaとは密な協力関係でやっていると言っていました。

今のところRDBMSといえばMySQLという感じですが、PostgreSQLもかなり進化しているし、MariaDBも評価され始めているようなので、一度フラットにいろいろ調べてみるのが良いのかなぁ、と思いました。

「今MySQL 5.6を使ってるんですけど」という話をしたら「MariaDB 10.0が来春に出る予定なので、それまで評価を進めてもらって、その時に移行するかどうか検討するのが良いのではないか」とのことでした。

MaxScale や MariaDB Manager はまだ開発の初期段階で実用は難しそうですが、便利そうではあるのでこの先どういうふうに開発が進むのかなぁと興味を持ちました。

2013年9月8日日曜日

MySQL 5.6 の GTID のしくみ

MySQL 5.6 で GTID (Global Transaction ID)が導入されました。どうも使うと便利そうだ、というものの実際どんなものかイマイチ分からなかったので、調べてみました。

サーバーがUUIDを持つ

私は調べるまで誤解していたのですが、UUIDを持つのはサーバーであって、トランザクションではありません。それぞれのサーバーにUUIDが割り当てられ、トランザクションは連番が振られます。
例えば、4台のMySQLインスタンスで1台をマスターにした場合は以下のようににUUIDが振られます。
そして、トランザクションは次のようにIDが振られます。
UUID:トランザクション番号
例えば"40bbcf9b-e556-45b0-bdb3-e528f0041652"で実行された123番目のトランザクションは
40bbcf9b-e556-45b0-bdb3-e528f0041652:123
という感じになります。
そして、それぞれのサーバーで実行されたトランザクションは "GTID_Executed" に "uuid:最初-最後" というように記録されます。
この図の場合では、右端のスレーブのみ最後のトランザクションが実行されず、遅れていることがわかります。
ちなみに、途中のトランザクションだけ抜けた場合は、
40bbcf9b-e556-45b0-bdb3-e528f0041652:1-20:22-1021
という感じで、 : でつなげて記録されます。

マスターを切り替える

ではマスターが落ちた場合の動作を見てみましょう。
マスターが落ちました。右端のスレーブが遅れているので除外し、今回は左端のスレーブをマスターに昇格させます。
この場合、左側のスレーブは新マスターに追いついているので、新マスターの最新のログポジションに合わせれば良いことがわかります。右側のスレーブはひとつ遅れているので、新マスターの該当のログポジションに合わせます。これらが自動計算され CHANGE MASTER TO に MASTER_AUTO_POSITION=1 を指定するだけで良いのが GTID の売りです。

新マスターでのトランザクション

新マスターでトランザクションが実行された場合は、新マスターのUUID:1 から新しくトランザクションが数えられます。
GTID_Executed にはこれまで実行されたトランザクションがすべて記録されます。マスターが変更された場合は複数行記録されます。

新しくスレーブを追加

旧マスターに対するスナップショットから新しくスレーブを追加することもできます
右端に新しくスレーブを追加しました。旧マスターのトランザクションのみ実行され、新マスターのトランザクションが実行されていないことが GTID_Executed からわかりますので、新マスターに接続した時にポジションを新マスターの場所に自動的に設定します。

バイナリログの中身

GTIDを有効にした状態では、バイナリログに
SET @@SESSION.GTID_NEXT= 'a8679745-1864-11e3-a1ec-28924a2bea1c:14'
という行が現れます。これは、次に実行するトランザクションのIDを指定しています。
GTID_NEXT は通常であれば "AUTOMATIC" に設定されていて、その状態では "自分のuuid:次の番号" のIDを次のトランザクションに設定しますが、設定し直すと任意のIDのトランザクションを作成することができます。
# at 2621
#130908 21:05:04 server id 10  end_log_pos 2669 CRC32 0x20b2bc89        GTID [commit=yes]
SET @@SESSION.GTID_NEXT= 'a8679745-1864-11e3-a1ec-28924a2bea1c:14'/*!*/;
# at 2669
#130908 21:05:04 server id 10  end_log_pos 2737 CRC32 0x5e5fa3bb        Query   thread_id=10    exec_time=0     error_code=0
SET TIMESTAMP=1378641904/*!*/;
BEGIN
/*!*/;
# at 2737
#130908 21:05:04 server id 10  end_log_pos 2785 CRC32 0x757ca2c9        Table_map: `yuryu`.`test` mapped to number 70
# at 2785
#130908 21:05:04 server id 10  end_log_pos 2829 CRC32 0x4e043fe7        Write_rows: table id 70 flags: STMT_END_F

BINLOG '
8GcsUhMKAAAAMAAAAOEKAAAAAEYAAAAAAAEABXl1cnl1AAR0ZXN0AAEIAADJonx1
8GcsUh4KAAAALAAAAA0LAAAAAEYAAAAAAAEAAgAB//4RAAAAAAAAAOc/BE4=
'/*!*/;
# at 2829
#130908 21:05:04 server id 10  end_log_pos 2860 CRC32 0x3fbac367        Xid = 226
COMMIT/*!*/;
つまり、バイナリログがスレーブに転送されて実行されるのは
  1. GTID_NEXT を次に実行されるトランザクションID(マスターと同じもの)にセット
  2. BEGIN ~ COMMIT でトランザクションを実行
ということになります。

まとめ

  • サーバーごとにUUIDを付与
  • トランザクションIDは サーバーUUID:番号 として連番で生成
  • スレーブで実行するときは GTID_NEXT を指定して同じトランザクションを再生
  • 実行したトランザクションは GTID_EXECUTED に記録される
以上のような仕組みで GTID は自分がどこまでのトランザクションを実行したのか追跡しています。

参考資料

PerconaのMySQL 5.6 GTID in a nutshellというスライドが大変参考になりました。

2013年9月4日水曜日

MySQL 5.6.11でGTIDを有効にしFLUSH LOGSするとレプリケーションが止まる

タイトルのとおりです。 MySQL 5.6.11 (5.6.10までと5.6.12以降は大丈夫) において GTID を有効にした状態で、マスターで FLUSH LOGS すると、レプリケーションが停止します。

スレーブで SHOW SLAVE STATUS すると下記のようなエラーが出ています。

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Found a Gtid_log_event or Previous_gtids_log_event when @@GLOBAL.GTID_MODE = OFF.; the first event 'mysql-bin.000013' at 404, the last event read from './mysql-bin.000013' at 452, the last byte read from './mysql-bin.000013' at 452.'
Last_SQL_Errno: 1778
Last_SQL_Error: Error 'Cannot execute statements with implicit commit inside a transaction when @@SESSION.GTID_NEXT != AUTOMATIC or @@SESSION.GTID_NEXT_LIST != NULL.' on query. Default database: ''. Query: 'FLUSH ERROR LOGS'

FLUSH ERROR LOGS でレプリケーションが止まってしまいます。これは logrotate するときに発行されていて、1日経つと(深夜に)レプリケーションが止まるという、とても困った状態になりました。

調べたところこれは 5.6.11 固有のバグでした。公式に MySQL Bugs: #69045: replication was broken while executing flush tables としてレポートされています。

gtid_next が automatic ではないときに、暗黙にトランザクションを発生させてコミットするようなステートメントを禁止した副作用で、FLUSH LOGSなどのステートメントがうまく動かなくなってしまったらしいのです。

5.6.12 以降ではこのパッチは差し戻されて、正常に戻っています。