ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

よりよいプログラマになりたいから「ベタープログラマ」読んだ

はじめに

読んだ。

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

この手のポエム、読むの好きなんですよね。でも社会人になってはじめて読んだ時と感じることは違うわけで、いろんな名著がありますし、これからも発売されていくでしょう。

原著は2014年発売のよう。

shop.oreilly.com

この本の最後でも語られていますが、何より大事なのはエンジニアの態度なんですね。

ひどいプログラマと優れたプログラマを区別しているものは、態度です。それが、単なる適当なプログラマと並外れたプログラマを区別するものです。態度は、技術スキルに勝ります。プログラミング言語の複雑な知識は、保守可能なコードを保証しません。プログラミングモデルを多く理解したからといって、必ずしも優れた設計を生み出すとは限りません。あなたのコードが優れているかどうかと、あなたと一緒に働くのが楽しいのかどうかを決めるのは、あなたの態度なのです。(p346 結び より)

この手の本は何か1つでも心にひっかかるものがあれば儲けだと思うのです。ぼくは「情熱プログラマー」の"1番の下手くそであれ"を今でも毎日思って仕事をしています。

情熱プログラマー ソフトウェア開発者の幸せな生き方

情熱プログラマー ソフトウェア開発者の幸せな生き方

では内容を章ごとに振り返っていきましょう。

第1部 you.write(code)

1部ではコードを書くための心構えが主に書かれています。この手の考え方は何度読んでも読みすぎることはないですね。他にも著名な以下のような本があります。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

Clean Coder プロフェッショナルプログラマへの道

Clean Coder プロフェッショナルプログラマへの道

ここではとりわけ個別のものを取り上げませんが、単純にコオードをきれいに保つこと、シンプルに保つこと、無駄なものは生まないこと、という以前から言われていることに加えて自動ビルド、テスト、バグへの取り組み方など少しモダンな内容までカバーできています。

目次だけおいておきますね。

  • 2章 見かけの良い状態を維持する
  • 3章 少ないコードを書く
  • 4章 取り除くことでコードを改善する
  • 5章 コードベースの過去の幽霊
  • 6章 航路を航行する
  • 7章 汚物の中で転げ回る
  • 8章 そのエラーを無視するな!
  • 9章 予期せぬことを予期する
  • 10章 バグ狩り
  • 11章 テストの時代
  • 12章 複雑さに対処する
  • 13章 二つのシステムの物語

第2部 練習することで完璧になる

この章ではコーディングというところから一歩下がって、ソフトウェア開発、(多くの場合にチームで行われる、大規模な開発)に対する態度を示しています。

ここで1番好きなのは「変わらないものはない」ですね。ソフトウェアとしての性質はもちろんなんですが、もっと、人生観というレベルで、まさに変わらないものなんて、ないんだよなぁ、と思うところで深く共感しました。ソフトウェア開発、あるいはチーム開発であればなおさら、変わらないものがないことはみなさん身をもって知っているでしょう。

僕は変化しないことを恐れています。それは自分自身もそうですし、コードもそうです。変化しないコードは恐ろしいし、変化しない自分自身もまた、恐ろしい。

ここも章タイトルを置いておきます。

  • 14章 ソフトウェア開発とは
  • 15章 規則に従って競技する
  • 16章 単純に保つ
  • 17章 頭を使いなさい
  • 18章 変わらないものはない
  • 19章 コードを再利用するケース
  • 20章 効果的なバージョンコントロール
  • 21章 ゴールポストを抜ける
  • 22章 凍結されたコードの数奇な人生
  • 23章 プリーズ・リリース・ミー

第3部 個人的なこと

ここからがすごく面白くなってきます。(個人的には)

(思いの外アツくなってきたのでここからが個人的なポエムが急に入ります)

というのも、僕は勉強コンプレックスを持っているからです。原体験的には、大学の第一志望に落ちたことなような気もしますが、僕は勉強に取り組むし、時間は費やすものの、それに見合う結果を出せていない、というある種の思い込みを持っています。コンプレックスとも言うでしょう。

だからこそ、入社して、自分が1番同期でもできない。社内、部内でもできないのだから、誰よりも勉強しないとダメだ、という、お前、そういうとこだぞ、的な考えてやっぱりガムシャラに勉強をしてきました。

丸3年がすぎて、そのやりかたは間違ってなかった、少なからず、それをしなければ僕は今の何分の1の技術・知識しかなかったと思う。今でももちろん足りないけれど、それでも自分が得意なこと、自分がまわりよりできることは見えてきた。

何より、僕が今、成長できていると、あるいは強みになっているなと思う点は、メンタリティ、本書でいうところの"態度"がもたらす点が大きいと思った。

僕はまわりの同僚より技術力はない、だけど。。。 * 何でも試してみることはできる * 勉強会を主催して、すごいひとに喋ってもらうこともできる * 新しいものを試して、使ってみて、感想とともに広めてみることはできる

自分が学んだことを、こんな風にブログに書いて伝えることもできるし、 メールで部内に情報発信することもできる。

仕事の態度で言えば、属人化を何よりも嫌い、すべての情報をgitlabに置くスタイルにした。 メンバー内のレビューはすべてgitlabのMRで行うようチームへ啓蒙したし config変更の手作業を行わない、行っても気づけるよう技術を導入して推進した。

本当はすごいみなさんを巻き込んで、ほんとうはすごいみなさんが、忙しすぎてできないことを吸い上げて、僕が実現できた。

たぶんね、そこが自分が1番したいことで、1番得意なところなんだろうなあ、

でもそれをするためにはすごくならなきゃ、だから、技術を、学びを、絶対にやめちゃダメだ。続けるんだ。


(ここまでアツいポエム)

というわけで、"学びを愛して生きる" "学ぶことを学ぶ"というのは自分にとって一大テーマなわけです。

そしてもう1つ、前の章でも話しましたが、変化しないことを僕はもっとも恐れています。それは停滞でしかありません。

あぁ、このままでも、多分やっていけるんだろうな、楽だなあと思ってしまえば、それは停滞で、それは死です。

それだけは、常に変わり続けること、常に変化を求めること、常に新しいものに手を伸ばすことだけは、失わないようにします。

章タイトルです。

  • 24章 学びを愛して生きる
  • 25章 試験に基づく開発者
  • 26章 チャレンジを楽しむ
  • 27章 停滞を避ける
  • 28章 倫理的なプログラマ
  • 29章 言語への愛
  • 30章 プログラマの姿勢

第4部 成し遂げる

まさに僕は一生懸命になるしか脳がないのですが、それでも賢くあろうという視点は失ってはいけない。本当にそれはやる必要があるのか、やる必要があることだけやるようにしたい。

そして、何をもって物事を完了させるかということはとても重要だと思う。どこがゴールなの?この問いは絶対やめちゃいけない。終わらせることはとても重要だ。いつまでに、どこまでやるのか。

  • 31章 一生懸命ではなく、賢く
  • 32章 完了したときが完了
  • 33章 今度こそ分かった

第5部 人々の営み

意図を持って、優れたプログラマと一緒に働いてください

これは冒頭で述べた"1番の下手くそであれ"と近いんだよなぁ。今の職場にも優れたプログラマはたくさんいます、いや、全員が僕より優れたプログラマです。恵まれた環境です。

その中で、周囲の優れたプログラマ1人1人の、このひとのこの点がいいよねと、常に考えています。いいとこ探しは得意なんです。いつかそう思われる側になるぞ!

  • 34章 人々の力
  • 35章 原因は思考
  • 36章 遠慮なく話
  • 37章 多くのマニフェスト
  • 38章 コードへの叙情歌

おわりに

何と訳者の柴田芳樹氏は大学の(遠い)先輩でした。著者紹介であったけど私的な時間に技術書の翻訳してるってすごいなあ。。。

ついでにいうと著者のPete Goodliffは音楽家でもあるんだ、すごい。。。

途中エモい話はさみましたが、ソフトウェアエンジニアは態度が大事、技術を示すにはコードが大事。あるべき態度で、コードを書いて、コードで語ろう。そんなエンジニアになります。

「実践ハイパフォーマンスMySQL」を読んだ

はじめに

正確には全部読んでない。MySQLのパフォーマンス問題に悩まされたことがあったので買った。

実践ハイパフォーマンスMySQL 第3版

実践ハイパフォーマンスMySQL 第3版

全部は読んでないが、内容の復讐に書き留めておく。

1章 MySQLアーキテクチャと歴史

この章はその名の通り基本的なことなので読むべきだろう。

MySQLの論理的なアーキテクチャはよくみる図だ。

また、トランザクションに関して、ACID特性、ロック、分離レベルの説明もある。RDBMSを扱う上で重要な概念なので何度学んでもよい。

マルチバージョン並行性制御、MVCCについて。ストレージエンジンによって実装は異なるが、行ロック+ひとひねりとのこと。

InnoDBでは行ごとに、行が作成されたタイミングと、期限切れ(削除された)タイミングを記録し、このイベントが発生したときのシステムバージョン番号を格納する。すなわち、上記2つのイベントが起きるごとにバージョンはインクリメントされることになる。

このバージョンを使って、分離レベルを実現する。

InnoDBストレージエンジンについては、よほどの理由がない限りない限りInnoDBを使うべきだし、他のストレージエンジンを調べるよりInnoDBを詳しく調べたほうがよいと言っている。

MySQLマニュアルの「InnoDBトランザクションモデルとロック」セクションをぜひ読んでおこう、とのこと。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.2.2 InnoDB のトランザクションモデルおよびロック

2章 MySQLベンチマーク

本書で語るパフォーマンスを図る上で最も重要なベンチマークベンチマークの方法、考え方が記載されているので必読。

なぜベンチマークをするのか?ハードウェアの変化のため、アプリケーションの変化のため、成長を予測するため。いろいろあるが、いかなるときでもベンチマークをとるようにしておかないと、いざ変化が起きた時に計測できない。

ベンチマーク指標には以下のものがある

まぁもっともわかりやすく使われるのはスループットだろう。

また、誤ったベンチマークの例として、

  • データセット・サイズが実アプリケーションと合っていない
  • マルチユーザーのアプリケーションに対してシングルユーザでのテスト
  • ループを使って同じクエリを実行する
  • リブート直後等で、ウォームアップが加味されていない
  • ベンチマーク時間が短い

などなど、なるべく実際の使用用途に近い形にしてあげないといけない。これはなかなか難しいだろう。

パフォーマンスを定期取得することになるが、必ず自動化しよう。何度も実行されるからだね。

データベースそのものをテストする、単一コンポーネントツールの紹介がされている。

  • mysqlslap
  • MySQL Benchmark Suite(sql-bench)
  • Super Smack
  • Database Test Suite
  • PerconaのTPCC-MySQL
  • SysBench

いろいろあるが私はSysBenchを選択した。mysqlslapは付属してて楽なんだけど、client側が落ちることが多く。。。

本書がSysBenchを推していたこともある。

3章 サーバのパフォーマンスのプロファイリング

この章な流し読みしたが、サーバ・アプリケーション・SQLクエリそれぞれのプロファイリングの方法であり、実際にパフォーマンスが劣化している、うまく性能が出ていないときにとる手段である。

そのような場面になったとき必ず読み返したい章。

4章 スキーマとデータ型の最適化

今回、業務ではクエリを変えることはできないので、この章は読み飛ばした。実際スキーマからアプリケーションを設計するときには一読したい。

5章 インデックスによるパフォーマンスの向上

残念ながらインデックスをどう作るか、まで込み入った世界に入っていないのでこの章も飛ばし。インデックスについてかなり詳しく載っている。

6章 クエリのパフォーマンスの最適化

4章と同じく、クエリは変えられなかったので飛ばし。

7章 MySQLの高度な機能

飛ばし!あることだけ知っておこう!

8章 サーバ設定の最適化

my.cnfで設定できるパラメタの説明および効果についての章で、この章は読みました。

学ぶべきは「最適な設定が見つかるまで設定変更を繰り返すことでサーバを「チューニング」することが期待されている、あるいは期待されていると思っているかもしれない。通常、私たちはほとんどのユーザにそうした方法を勧めない。調査と作業に追われるわりには、期待できる見返りはほんのわずかで、時間を無駄にする可能性がある」

そのあとでの述べているが「チューニング」をしてはならないと言っている。言葉も使うべきではないとも。「設定」「最適化」「調整」がよい。あてずっぽうで値を変化して試してみる、という行為は無意味で効果が薄いし、インターネット上の情報を鵜呑みにしてもいけない。

内部論理と設定の意味を理解したものが、特定の目的に対して変更をすべきだ、というごもっともな内容が語られています。デフォルトでいい感じにしてくれてるから下手にいじるなってことですね。

MySQLがこれほど細かく設定できるようになっていることはかえって弱点である。というのも、実際にはほとんどの設定にデフォルト値が適しており、たいていは設定せずに忘れてしまったほうがよいにもかかわらず、設定に時間をかけるべきであるかのように思えてしまうからだ。

実際に本書が必要と掲げるパラメタは20数個。基本的なものもあるので、「チューニングパラメタ」っぽいものは10もない。このぐらいで十分なんだなーと思う。

  • innodb_buffer_pool_size
  • innodb_log_file_size
  • innodb_file_per_table
  • innodb_flush_method
  • key_buffer_size
  • tmp_table_size
  • max_heap_table_size
  • query_cache_type
  • query_cache_size
  • max_connections
  • thread_cache_size
  • table_cache_size
  • open_files_limit

こんなもんだ。

中でもメモリをどう扱うかが重要だ。

その他安全性、健全性のための設定もある。目を通しておくといい。

とはいえやはり重要なのは

の2つでたいていの問題は解決するし、してはならないことは

  • サーバを「チューニング」してはならない
  • 比率、公式、または「チューニングスクリプト」を設定オプションの基準値として使用してはならない
  • インターネットで見知らぬ人のアドバイスを信用しない
  • SHOW STATUSんカウンタで悪く見える値を探さない

この4つのならないはとても重要で、いいこと書いてると思います。

9章 オペレーティングシステムとハードウェアの最適化

重要ですが、今回OSやハードレイヤを変更するわけではないので飛ばしました。近年はSSDもあるから、そのへん書かれてますね。あとはRAIDとかSANとかNASとか。ストレージを含むハードから選定することになったらこの章を読むべきですね。

10章 レプリケーション

MySQLレプリケーションを使ってないので飛ばしました。

どんなレプリケーション方法があってどんな風にやるかがかなり詳細に書かれています。

11章 MySQLのスケーリング

規模拡大のしやすさ、スケーラビリティについて。シャーディング、スケールアップ、スケールアウト。負荷分散手法について。ここも飛ばしました。

12章 高可用性

ダウンタイムを最小限にする方法について。SPOFの回避、バックアップ、リストア時間の計測。

同期(双方向)レプリケーションが安心ですね。(MySQL Cluster、Percona XtraDB Cluster)

13章 クラウドでのMySQL

この本が出たのは第3版で2013年、その後ずいぶんクラウドMySQLも進化してるので、本書執筆当時と状況は代わってきてるでしょうね。

どちらかというと若干クラウドには懐疑的な論調で進んでいる。まぁ、クラウドがなんでも解決してくれるんだ!最強だ!ってのは幻想ですから、そりゃそうだろうけども、

クラウド、特にDBaaSではCPU、メモリ、ディスクが十分でなく、パフォーマンスが十分でない可能性があるのでしっかりベンチをとること。

それに引き換えメンテナンスをしなくてもいいし、自動でスケールアウトすることを考えると十分選択肢に入ると思う。

aws.amazon.com

aws.amazon.com

14章 アプリケーションレベルの最適化

アプリを触れないので飛ばした。アプリ側で見直せることがあるのではないか。キャッシュ。

15章 バックアップとリカバリ

パフォーマンスに閉じない、一般的だけど重要なバックアップとリカバリについて。

面白いのが

バックアップの都市伝説その1:レプリカはバックアップである

間違いも伝搬してしまうのでバックアップじゃないですよね。

論理/物理バックアップ、オンライン/オフラインバックアップについて。

あとはInnoDBのクラッシュリカバリについても。

MySQLのバックアップとリストアをしないひとはいないと思うので全員必読の上で自身のバックアップポリシーの再確認をしたほうがいいですね。

16章 MySQLユーザーのためのツール

MySQL WorkBench便利そうだなーいれてみようかな。

監視ツールがいろいろ紹介されているのも助かる。

  • 監視し、異常を検知
  • メトリクスを計測

の2種類必要だ。

  • Nagios
  • Zabbix
  • Zenoss
  • Hyperic HQ
  • OpenNMS
  • Groundwork Open source

可視化観点だと

おわりに

分厚い本書、今後MySQLで壁にぶつかったときに何らかの形で役に立ってくれるはずである。どのセクションも非常に詳しく記載されていて、心強い。中でも8章の考え方は肝に銘じておこう。ちなみに付録も驚きの充実度。良い本です。職場の本棚に置いておきます。

「MariaDB&MySQL全機能バイブル」を読んでMySQLの基本をおさらい

はじめに

読みました。

MariaDB&MySQL全機能バイブル

MariaDB&MySQL全機能バイブル

日本語でMariaDBが書籍になってるのはこれぐらいじゃないでしょうか。

仕事でMariaDBに関する案件を担当しています。それまでもmysql -uでログインしてSELECT叩くぐらいはしてきたのですが、そもそもこういうオープンソースのRDMSの仕組みをまったく知らないので、語彙がありません。

まずどういう仕組みでデータベースが成り立っているのか、そしてMySQLからフォークしたMariaDBとの違い、その他の機能について、おおまかな把握と語彙獲得のために読みました。

本書のchapter06のSQL文と、Chapter07のデータ型、演算子と関数はリファレンス的に使おうと思って読んでいません。(語彙を増やすためならさらっとでも目を通したほうがいいのですが、今回はスルー。)

Chapter1 イントロダクション

MySQLMariaDBの歴史について記載されています。MySQLの生みの親、Michael "Monty" Widenius氏がSUNを退職し、Monty Program AB社を設立、MariaDBの開発をはじめたとのこと。

MariaDBSQLレベルでほぼ完全な互換性を持っているので、MySQLからMariaDBへの切り替えに特別な作業は不要。

どうでもいいですがwikipedia mariadbで検索するとwikipediaのDBがmariadbであることがわかりました。(笑)

news.mynavi.jp

機能

主要機能について復習。

Thread PoolがMariaDBはあり、MySQLは商用のみってのが目立った違いか。

ストレージエンジン

たくさんサポートしていますが、InnoDBMyISAMだけ覚えておけばよさそう。なおMariaDBのデフォルトストレージエンジンはInnoDBです。(5.5まではXtraDBだったが、10.0からはInnoDB)

MariaDBMySQLの違い

SQLはほぼ互換あり、微妙に差異があるものもあるが、今回はスルー。

プロトコルも共通なので、特に問題なくお互いを変更することができそうだ。

機能面は先ほどあげたThread Pool。あとはバイナリログのバージョン、MariaDBはv1のみ、MySQLはv1とv2。

Chapter2 MariaDB/MySQLの内部構造

mysqldサーバの本体はmysqldというデーモンプロセスです。mysqlクライアントから接続要求を受けると内部にスレッドを生成し、そのスレッドがクライアントのSQL文を処理します。

さてこのスレッド生成ですが、スレッドキャッシュというキャッシュが用意されており、キャッシュ内にスレッドがあればここから使い、なければ新規生成することになります。

特殊なスレッド

clientからの接続ごとに生成されるスレッド以外に、ある処理を専門に行う特殊なスレッドがあります。

I/Oスレッド

InnoDBのため、複数のI/Oスレッド、加えてinnodb_thread_currencyで指定した数のスレッドが起動。その名の通りDBへの書き込みを行うスレッド。

Purgeスレッド

UNDOログを削除するスレッド。

Pager_cleanerスレッド

buffer poolのdirty pageを書き出すスレッド。

メモリ構造

実際のデータベースファイルに書き込む前に、様々なメモリ領域に事前に書き込む。

問い合わせ処理のときのバッファ

  • key_buffer: MyISAMテーブルの場合、インデックスデータを読み込んでスキャンするためのバッファ。
  • read_buffer: インデックスが参照しているテーブルデータを読み込んでスキャンするためのバッファ
  • sort_buffer: ORDER_BY処理など、結果の並べ替えに使うバッファ
  • join_buffer: テーブルの完全結合を行うバッファ

キャッシュ

  • テーブルキャッシュ
  • ネットバッファ: クライアントから受信するSQL文やクライアントに送信するデータの一時保存場所
  • クエリキャッシュ: 実行されたSELECT文の結果を保存しておく
  • スレッドキャッシュ: クライアントから接続されるためのスレッドのキャッシュ

InnoDBのデータ構造

実際のデータファイルであるibdata1の中には、 * データディクショナリ... メタデータ * ダブルライトバッファ... データ頑強性のため * ロールバックセグメント...トランザクションロールバックのため * UNDOログ...トランザクションロールバックのため * インデックス...インデックス * テーブルデータ...テーブルデー

が含まれています。

また、トランザクションログ(REDOログ)はib_logfile0とib_logfile1です。

InnoDBのWAL戦略

データの変更はトランザクションログ(REDOログ、すなわちib_logfile1/2)に書き込み、て0ブルデータファイルを直接操作することは極力避ける

書き込む順は

  1. log_buffer(メモリ)
  2. buffer_pool(メモリ)
  3. ib_logfile(ファイル)
  4. ibdata(ファイル)

ログバッファの中身をトランザクションログに書き込むタイミングは、innodb_flash_log_at_trx_commit変数の値によって3パターンにわかれる。

そしてbuffer poolをibdataに書き込むタイミングはチェックポイントごと。一定周期で一気に書き込むらしい。

chapter3 インストール

省略!

chapter4 MariaDB/MySQLサーバ管理

システム変数全部見ていくわけにもいかないのと、レプリケーション、ログ、ダンプ/リストア、文字コードなど内容盛りだくさんで、詳しいです。

chapter5 対話型インタフェースmysqlの使い方

対話型インターフェイスの基本的な使い方。多くの方は習得してるでしょう。

chapter6 SQL

今回の仕事ではクエリをいじるわけでないので読み飛ばし。

chapter7 データ型、演算子と関数

同じく読み飛ばし

おわりに

内容はかなり詳しいですし、リファレンスとして使えるだけでなく、深い構造の理解も可能になっています。何か困った時関連の章をしっかり読み込み復習する、という使い方もできそうです。

とはいえ、これをMySQL/MariaDBの最初の1冊として読むのは結構厳しいと思います。(そうして後悔。。。)

せめてデータベース一般の用語を押さえてからですね。(WALとか、レプリケーションとか。)

とはいえ、MariaDB唯一の書籍なんだよなぁ。10系で本でないかなー。10.2とか10.3サポートで。

Galera Cluster Documentを読む Configuration編(6) AUTO EVICTION

はじめに

全部読んでちゃ時間がいくらあっても足りないことにようやく気づいたので、要所だけ読んでパラメタの詳細については使うときにまたじっくり読むという風にしようと思いました今回はAUTO EVICTIONです。新しい概念ですね。

Auto Eviction — Galera Cluster Documentation

AUTO EVICTION

(訳注:evictionは追い立て、立ち退き。)

Galera Clusterはノードが不思議な振る舞いをした場合、(例えば、異常にレスポンスが遅いとか、) クラスタから永久的にノードを取り除くプロセスを行います。このプロセスをAuto Evictionと呼びます。

(訳注:なるほど、まさに立ち退きさせるわけですね。変な住民を。)

CONFIGURING AUTO EVICTION

各ノードはgroup communicationのレスポンスタイムを使ってクラスタを監視しています。クラスタを登録したとき、ノードからのレスポンスが遅い場合はまず遅延リストにノードを追加します。

遅延したノードはいくつかの固定秒間レスポンスを繰り返すと、遅延リストから除かれます。ノードが十分な時間遅延し、大多数の遅延ノードに見つかった場合、遅延したノードは永続的にクラスタから追放されます。

追放されたノードは再起動するまでクラスタに再加入できません。

パラメタに関しては省略。

CHECKING EVICTION STATUS

ノードが遅延したっぽいと疑われた時にはこのパラメタをみたらいいよとのこと。省略。

UPGRADING FROM PREVIOUS VERSIONS

evs(追放)を行うためのプロトコルのようなので省略。

おわりに

接続が切れた場合は自動で除外するけど、それとは違うのだろうか?確かログにevsと出ていた気がするのであとで確認しよう。

Galera Cluster Documentを読む Configuration編(5) MANAGING FLOW CONTROL

はじめに

configuration編第5弾。Galera Clusterではそれぞれのノードでtransactionが発生し、それを全ノードへ書き込み可能か確認してから書き込みます。この書き込み制御のことをFlow Controlと言うのでした。

take-she12.hatenablog.com

今回はこのFlow Controlの管理についてです。

Managing Flow Control — Galera Cluster Documentation

MANAGING FLOW CONTROL

クラスタは変更をグローバルな順番で同期しますが、各ノードでの変更は非同期に行われます。クラスタから離れているノードの適用失敗を防ぐために、Galera ClusterはFlow Controlと呼ばれるフィードバックメカニズムを実装しています。

ノードはグローバルな順に並べられたwrite-setをキューにいれて、データベースにコミットします。大きいキューを受け取った場合、ノードはFlow Controlを初期化します。ノードはキューを受け取っている間レプリケーションを停止します。管理できる量までキューが減ったら、レプリケーションを再開します。

MONITORING FLOW CONTROL

Galera ClusterはFlow Controlの監視にグローバル変数を使います。Flow Controlを数えるステータスは、pauseイベントとpauseの効果を計測するものにわけられます。

SHOW STATUS LIKE 'wsrep_flow_control_%';

これらのステータス変数はノードの現在の状況だけを返却します。結果をグラフ化して活用したいのであれば一定間隔でみていくといいでしょう。例えば、myq_gadgetsを使います。

$ mysql -u monitor -p -e 'FLUSH TABLES WITH READ LOCK;' \
   example_database
$ myq_status wsrep

Wsrep    Cluster        Node           Queue  Ops      Bytes   Flow         Conflct
time     name     P cnf  # name  cmt  sta  Up  Dn  Up  Dn   Up   Dn pau snt dst lcf bfa
09:22:17 cluster1 P   3  3 node3 Sync T/T   0   0   0   9    0  13K 0.0   0 101   0   0
09:22:18 cluster1 P   3  3 node3 Sync T/T   0   0   0  18    0  28K 0.0   0 108   0   0
09:22:19 cluster1 P   3  3 node3 Sync T/T   0   4   0   3    0 4.3K 0.0   0 109   0   0
09:22:20 cluster1 P   3  3 node3 Sync T/T   0  18   0   0    0    0 0.0   0 109   0   0
09:22:21 cluster1 P   3  3 node3 Sync T/T   0  27   0   0    0    0 0.0   0 109   0   0
09:22:22 cluster1 P   3  3 node3 Sync T/T   0  29   0   0    0    0 0.9   1 109   0   0
09:22:23 cluster1 P   3  3 node3 Sync T/T   0  29   0   0    0    0 1.0 

Queue Dn列の下にslave queueを、FC pauはFlow Control pausesを意味することがわかるだろう。slave queueがある点まで上昇すると、Flow Controlはpauseの値を1に変更する。ノードはslave queueが管理できる値に下がるまでこの値を維持する。

Monitoring for Flow Control Pauses

Flow Conrtrolが動いているとき、FC_Pauseイベントを使ってレプリケーションを停止していることをクラスタに知らせる。Galera Clusterは2つのstatus変数でこれらのイベントを監視する。

  • wsrep_flow_control_sent: ローカルノードが最後にstatusを変更してから送信したFlow Control イベントの数
  • wsrep_flow_control_recv: ローカルノードによって最後にstatusを変更してから他のノードでpause eventが発生した数(?)

Measuring the Flow Control Pauses

Flow Controlのpauseを追跡することに加えて、Galera Clusterは最後のFLUSH STATUSからreplicationが停止するまでの総量も計測できる。

  • wsrep_flow_control_paused: replicationが停止した時間の総量。
  • wsrep_flow_control_paused_ns: 上記ナノ秒単位。

CONFIGURING FLOW CONTROL

Galera ClusterはFlowControlとレプリケーションレートを扱うための2つのパラメタを提供する。1つめはwrite-set cache、2つめはFlow Controlを停止または開始するポイントである。

Managing the Replication Rate

レプリケーションレートを変更するための3つのパラメタがある。これらは各ノードでwrite-set cacheを管理する。

  • gcs.recv_q_hard_limit: これはwrite-set cache sizeの最大値である。パフォーマンスが発揮できる範囲のRAM、swapサイズのの合計に依存する。

デフォルトは、32bitシステムではSSIZE_MAXから2 GBを引いた値である。64bitシステムでは制限はない。

nodeがこの制限を超えて、gcs.max_throttleが0でない場合、nodeはout-of-memoryエラーでダウンする。gcs.mx_throttleが0にセットしてあれば、クラスタレプリケーションは停止する。

デフォルト値は0.25である。

デフォルト値は0.25である。

write-set cacheはstate transferが完了するために、gcs.recv_q_soft_limitと時間経過とともに大きくなる。

Managing Flow Control

ノードがFlow Controlをトリガーとして決定されるパラメタである。Flow Controlとレプリケーションの再開が動くべきでないときに決定される。

  • gcs.fc_limit: このパラメタはFlow Controlが作動する点を決定する。slave queueがこの制限を超えた場合、ノードはレプリケーションを停止する。

マルチマスタ設定ではこの制限を低くすることが重要である。証明が衝突する確率はslave queueの長さに比例する。マスタースレーブ設定では、Flow Controlが間に入ることを減らせるようにできるだけ高い値を使うことができる。

デフォルトは1.6。

  • gcs.fc_factor: このパラメタはノードがFlow Controlを停止するときに決められる値。slave queueがgcs.fc_limitより低いと、fcs.fc_factorのレプリケーションが再開する。(?)

デフォルトは0.5。

マルチマスタの場合、できるだけslave queueは小さく保つことが重要である一方で、マスタ-スレーブの場合はそこまで気にする必要はない。アプリケーションやハードウェアに依存しするが、ノードは瞬間的に1kものwrite-setを適用することができる。slave queueの長さはmaster-slaveのフェールオーバーには影響しない。

注意:警告:クラスタはそれぞれが日同期にトランザクションを行います。ノードはどのぐらいの量のレプリケーションデータがあるか予期することができません。このため、Flow Controlは常に反応するのです。これは、ノードが各種制限を超えた場合のみ動作します。これらの制限を超えることを妨げることはできませんし、こえた場合に、どれほど超えるかを保証することもできません。ノードに以下の設定をするとしましょう。

gcs.recv_q_hard_limit=100Mb

このノードは1Gbのwrite-setによって制限を超えてしまいます。

おわりに

Flow Controlは書き込み量が多すぎたときに、slave-queueにたまったwrite-setの書き込みに集中させ、同期を中止するなど、書き込み流量をコントロールする仕組みでした。

Galera Cluster Documentを読む Configuration編(4) RESETTING THE QUORUM

はじめに

Configuration編第4弾。quorumの再計算について。

Resetting the Quorum — Galera Cluster Documentation

RESETTING THE QUORUM

時々、Primary Componentの一部でなくなったノードが見られることもあるでしょう。例えば、ネットワーク障害や、クラスタの半分異常が故障した場合、あるいはsplit-brainが起きた時。これらのケースでは、ノードは接続されていない他のノードがPrimary Componentであると考えます。

これが起きた時、全てのノードは全てのqueryにUnknown command errorを返却します。wsrep_cluster_status変数を見ることでこの状況が発生しているかどうか確認できます。以下のクエリを各ノードで実行しましょう。

SHOW GLOBAL STATUS LIKE 'wsrep_cluster_status';

+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| wsrep_cluster_status | Primary |
+----------------------+---------+

Primaryという値が返却された場合、そのノードがPrimary Componentであることを示します。queryが他の値を返却したとき、ノードが操作不能であることを示します。Primaryと返すノードが存在しない場合、それはquorumのリセットが必要であることを意味します。

注意:Primary Componentを示すノードが存在しないケースが非常にまれであることに注意してください。あるノードがPrimaryを返す場合は、quorumのリセットは必要なく、ネットワークの問題です。接続の問題をトラブルシュートしましょう。ノードのネットワークが再接続されると、Primary Componentと自動的に再同期されます。

FINDING THE MOST ADVANCED NODE

quorumをリセットする前に、クラスタ内でもっとも進んでるノードを特定する必要があります。これは、最後のトランザクションがコミットされたデータベースを探すということです。quorumをリセットする方法にかかわらず、このノードは新しいPrimary Componentとしてスタートします。

クラスタ内でもっとも進んでいるノードを特定することには、もっともシーケンスナンバーが進んでいるノードを探す必要があります。wsrep_last_commitedステータス変数を使いましょう。

各ノードで、以下のクエリを実行します。

SHOW STATUS LIKE 'wsrep_last_committed';

+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| wsrep_last_committed | 409745 |
+----------------------+--------+

ここで返却された値は、各ノードでの最後のtransactionのシーケンスナンバーです。クラスタ内でこの番号がもっとも高いノードがもっとも進んでいるノードです。新しいPrimary Componentとしてbootstrapするときはこのポイントを使います。

RESETTING THE QUORUM

quprumをリセットするときに行うことは、使用可能なノードのうちもっとも進んでいるノードでPrimary Componentを起動することです。このノードは新しいPrimary Componentとして機能するもので、クラスタの残りのノードはその状態に合わせます。

このプロセスでは、automaticとmanualの2つの方法があります。

注意:quorumのリセットで好ましい方法はautomaticメソッドです。manualメソッドと違って、automatic bootstrapsはwrite-set cache(すなわちGCache)を各ノードで保持します。これが意味することはあらたなPrimary Componentが起動したとき、joiningノードのいくつか、またはすべてはISTメソッドを使うことになります。

Automatic Bootstrap

quprumをリセットすると、最も進んでいるノード上でPrimary Componentをbootstrapします。これによってautomatic methodではデータベースクライアントを通じて、wsrep_provider_optionsの下のpc.bootstrapを動的に有効にすることで行われます。

自動的にbootstrapを行うために、最も進んでいるデータベースクライアントで、以下のコマンドを実行します。

SET GLOBAL wsrep_provider_options='pc.bootstrap=YES';

ノードは新しいPrimary Componentとして起動します。操作できないcomponentのノードは可能な限りISTでのネットワーク再接続を試み、もしできなければSSTを行います。

Manual Bootstrap

quorumをリセットすると、最も進んでいるノードでPrimary Componentをbootstrapします。manualメソッドでは、クラスタをシャットダウンし、もっとも進んでいるノードで再起動します。

  1. 全てのクラスタノードをシャットダウンします。initを使ってる場合は、以下のコマンドを実行します。
# service mysql stop
  1. もっとも進んでいるノードで、--wsrep-new-clusterオプションをつけて起動します。
# service mysql start --wsrep-new-cluster
  1. クラスタ内の他のノードを全て起動します。
# service mysql start

最初のノードで--wsrep-new-clusterオプションをつけて起動した時、以前のクラスタでもっとも進んでいるノードのデータを使って初期化します。他のノードはこのノードに接続し、データベースを更新するためにstate snapshot transferをリクエストします。

おわりに

この章ではシンプルに、全ノードが落ちてしまったとき、例えばデータセンターのダウンや、split-brainによって分断してnon-primary(閉塞)に陥った時、どのノードがもっとも進んでいるかを特定し、そこからの復旧の仕方が書かれていました。

これまでは適当にノードを選んで、manual methodでやっていましたね。。。最悪起動しなくてもSSTで加入させるという。

しかしpc.bootstrapをYESにした瞬間に立ち上がるんですかね?ちょっと試してみたいです。

Galera Parameters — Galera Cluster Documentation

これをいれるとNon-PrimaryからPrimaryになるようです。

Galera Cluster Documentを読む Configuration編(3) RECOVERING THE PRIMARY COMPONENT

はじめに

configuration編第3弾はRECOVERING THE PRIMARY COMPONENT。ノードがこけたときどうやってPRIMARY COMPONENTと同じになるまで修復するか、ですかね。クラスタ状態を記録するgvwstate.datの読み方が載ってるので期待。

Recovering the Primary Component — Galera Cluster Documentation

RECOVERING THE PRIMARY COMPONENT

クラスタノードはdisk上にPrimary Componentの状態を保存します。ノードはPrimary Componentの状態とUUIDを記録します。ノードが停止する場合、すべてのノードは最後に接続したノードの状態を保存するとクラスタはPrimary Componentを修復します。(?)

ノード間で異なるwrite-setポジションを持つ時、リカバリプロセスはstate snapshot transferを必要とします。

(訳注:pc.recoveryパラメタをみろと言っている。これをTRUEにすると、grastate.datにPrimary Componentの情報を記録するようになる。クラスタ全体が壊れたとき、最後に接続したノードと再接続することで自動的に復旧するとか)

UNDERSTANDING THE PRIMARY COMPONENT STATE

Primary Componentの状態がディスクに保存されるとき、それはgrastate.datファイルに保存されます。ノードはPrimary Componentの状態が変わるたびにこのファイルを更新または作成します。これはノードの最新のPrimary Componentの情報を保証します。ノードが接続を失った場合、このファイルを参照します。ノードが正常にシャットダウンした場合、このファイルを削除します。

gvwstate.datファイルは2つの部分にわけられます。

  • Node Information: my_uuidフィールドに、ノードのUUIDを記載します
  • View Information: #vwdevと"vwendの間に、Primary Componentから見ることのできる情報を記載します。
    • view_idは3つのパートから特定されます
      • view_typeはprimaryの場合常に3を示します
      • view_uuidとview_seqはともにユニークに特定できる値です
    • bootstrapはノードばブートストラップかどうかを示しますが、Primary Componentのリカバリプロセスには影響しません(訳注:bootstrapってなんだろ)
    • memberはPrimary Component内のノードのUUIDです

MODIFYING THE SAVED PRIMARY COMPONENT STATE

特定のノードを、特別な理由で加入させるという異常な状況のとき、Primary Componentの状態を手動で変更することができます。(訳注:どういう状況だ)

注意:通常時は、安全上の理由で、gvwstate.datの修正は避けるべきだ。予期しない結果をもたらすだろう。

安全に停止後、もしくは最初の起動時、自身のUUIDはランダムに割り当てられます。ノードはgvwstate.datファイルを見つけると、my_uuidフィールドからUUIDを探します。

手動で任意のUUIDを割りあてる場合、新しいPrimary Componentに強制的に加入させます。(?)

例えば、3つのノードがあったとして、クラスタに新しいPrimary Componentを同時に加入させたとします。3つのUUIDを生成して、各ノードに割り当てましょう。

各ノードのgwstate.datを編集します。

(訳注:my_uuidがd3124b〜が2つあるのは間違い?)

3ノードすべてをbootstrapフラグなしで起動させます。起動すると、Galera Clusterはそれぉれのgvwstate.datファイルを読み込みます。ファイルからUUIDとメンバーを引き出すと、ノードが新しいPrimary Componentに加入します。

おわりに

手動でgvwstate.datを編集するシーンがよくわからなかったですね。正常終了のときはこれをリセットし、予期せぬダウンのとき、リカバリ時にはこれを手がかりにするようです。

gvwstateはgalera view stateかな?似た感じのクラスタ状態を保存するファイルでgrastate.datもあります。

Restarting the Cluster — Galera Cluster Documentation

grastate.datはこっちに載ってるみたい。Getting Startedは飛ばしたんだけどな、ぐぬぬ。。。