2011/08/20

札幌MySQL#1に行ってきました

札幌MySQL勉強会

箇条書きですがメモを載せておきます

MySQL MHA

目的

  • SPOFをなくしたい
  • マスターのSPOFをなくすのは難しい

障害対応の課題

  • レプリケーションは非同期
  • どのスレーブが最新か判断する必要がある
  • スレーブ間のズレを修正する
  • これを全自動でやる

アーキテクチャ

  • Pure Perl
  • MySQL 5.0以降
    • binary logのformat versionの都合で5.0から
  • MySQL-MasterHA-Manager
    • Config::Tiny, Lod::Dispatch, Parallel::PreforkManager, DBD::mysql
  • MySQL-MasterHA-Node
    • DBD::mysql

内部的な動作

  • SQLスレッドが実行を終えるまで待つ
  • 会心スレーブのリレーログのヘッダを解析して各スレーブに適用する

特徴

  • マスターの稼働監視からフェイルオーバーまでを自動でできる
  • フェイルオーバーが秒単位で可能
  • 非同期レプリケーションでもスレーブ間の同期が取れる
  • 任意のスレーブを新マスターにできる
  • いくつかの箇所から外部スクリプトを呼ぶ昨日がある
    • 電源OFFやIPアドレスのフェイルオーバーなどに使う
  • インストール/アンインストールにあたり現在のmysqldプロセスやレプリケーションを止める必要がない
  • MHA自体は追加の負荷をかけない
  • ストレージエンジンに依存しない
  • バイナリログのフォーマットに依存しない
    • statementでもrawでも大丈夫

拡張ポイント

ケーススタディ

  • DeNAのサービスに対してMHAを導入
  • MySQLは滅多にクラッシュしないけど、OS、H/W障害によって落ちる
  • OSダウンによるフェイルオーバーには、ダウン検知に10秒、フェイルオーバーに4秒
    • マスターの生死判定
    • フェイルオーバー可否判定
    • フェイルオーバー処理

デモ

  • 3台構成 Master1 Slave2
    • master centos6-1
    • slave centos6-2
    • slave centos6-3
  • 設定ファイルでスレーブの中からマスターになる候補を決められる
  • masterha実行時にどのサーバーがmasterか自動検知

既存のソリューションに対する優位性

  • マスター障害でも整合性をたもってレプリケーションを再開できる
  • スタンバイサーバがいらない
  • フェイルオーバー時間が高速
    • アクティブ/スタンバイ構成のDRBDでは1分単位
  • MySQL Cluster/Galeraに対する優位性
  • MySQL-MMMは怖い

その他の特徴

  • 任意のスレーブを新マスターにできる
  • フェイルバックをするのが面倒
  • 準同期レプリケーションを併用することで、データ消失をほぼ防げる

サービスの増強と縮退

  • ゲームタイトルの人気を正確に見積もることは困難
  • 想定外の人気が出た場合
    • スレーブを追加
    • 水平分割でマスターを増やしていく
    • マスタのH/Wを増強する

マスターを別マシンに移行したい

  • マスターを別マシンに移す
  • メンテナンス時間を設ければ簡単
  • ダウンタイムなしでマスターに切り替えるのが理想
  • 0.5から3秒くらいでできれば多くの場合は許容範囲

書き込みブロックをどうするか

  • アプリケーションのユーザをdropする
    • 新規だけエラーになる
    • 接続済みはエラーにならない
    • 接続済みのセッションが終了しない限り、更新がおわらに
  • set global read_only = 1
  • OSCのときは3秒で切替だったけど、最適化して1秒くらいになった

MHAでの高速マスター切替

  • masterha_master_switchで手動切替もできる
  • 切替前と切替後の構成を表示して、確認がある
  • webアプリなら一回エラーになっても、もう一回クリックして動けば許される雰囲気
    • 今のところ苦情はきてない

質問

  • slaveの昇格の設定
  • MasterHA自体が落ちた場合は
    • pacemakerとかでMasterHA自体をHAする

MySQL開発者向けチューニング

ディスクI/O性能を常に意識する

  • HDDは遅い

一部のクエリだけが問題を起こす

  • 1%の法則
  • 代表的な悪い例
    • 大量のレコードをスキャン
    • 個々の実行効率は悪くないが大量に実行される
      • スロークエリにはでない
      • 何かツールを後で紹介
    • 長時間ロックを保持

tcpdumpとmk-query-digest

  • スロークエリログが有効になっていなくても実行頻度の高いクエリを取れる

クエリの実行計画に注意する

  • EXPLAINの読み方を習得する
  • MySQLのオプティマイザが判断を謝ることがあるので気をつける
    • とくにsortが絡む場合
      • FORCE INDEXを使う
    • コストベースなので、テスト環境と本番環境で実行計画が異なることがある

計算量とランダムアクセスを意識する

  • SELECT xx FROM t WHERE xxx LIMIT 100000, 20

スレーブの性質を理解して使う

  • スレーブはシングルスレッド
    • CPU効率の悪い更新処理はスレーブ遅延を招く
    • innodb pluginの圧縮とか
    • 長時間かかる処理はその実行時間分だけレプリ遅延になる
  • テンポラリテーブルとの相性がわるい

トランザクションを意識する

myslowtrancaptureで遅いトランザクションを特定する

  • githubにある
  • 実行に一定時間以上かかったトランザクションを探し出す
  • 誰がロックしているかも表示する

データサイズに常に気を配る

  • 必要以上に大きなデータ型を使うべきではない
    • datetimeよりtimestamp
    • varcharよりint
    • intよりもsmallint
  • 古いデータをメインテーブルから削除する
  • index

INDEX

  • ルート→ブランチ→リーフ→実データ

範囲検索を注意して使う

  • データを削除するとき
    • delete文で削除されるものをslaveで空読みして、メモリに載せてから実際にdeleteしてレプリ遅延を防ぐ

Covering Index(インデックスだけを使う検索)

  • SELECT key1 FROM th1 WHERE key1 IN (1,2,3)
  • explainでusing indexになっていればOK

マルチカラムインデックスと範囲検索

  • カーディナリティに注意

Covering Indexに帰着させる

  • SELECT a,b FROM tbl WHERE secondary_key < 100;
  • a, bをindexにしておく
    • indexを安易に増やすのがいいのか考える

INSERT性能とメモリ量の関係

  • リーフブロックにもうエントリーが入らなくなると、追加のブロックが確保される
  • ランダムINSERTは虫食い状態になりやすい
    • indexサイズが増える
    • ディスクI/Oが増える
  • インメモリでINSERTを完結させる
    • 10000rows/s超える
  • 高速ストレージでも実は状況はさほど改善しない
    • insert buffer? ランダムinsertでも毎回readしない
    • FusionIOでも5000rows/s程度
  • 時系列データはレンジパーティション
    • indexはパーティション毎に作られる

データブロックがどのように読まれるか

  • 全体の3%しかアクセスしなくても、ブロック単位で読み込むので思ったよりも多くメモリが必要
  • 剰余ベースは効率がわるい
  • 範囲ベースの振り分けは効率がいい

Blogテーブルの扱いを考えてみる

  • タイトル、本文
  • 大抵の人は一覧しかみない!
  • 長いBLOB/TEXTは全クエリを遅延させる
    • 本文が別ブロックにはいってしまうことがあるから
  • 本文を別テーブルに切り出す 1:1関連

ロック競合

  • ロックは必要になるまで確保せず、不要になったらすぐにCOMMIT/ROLLBACKで解放する
  • ロックを確保した後に、何秒もかかる可能性のある処理をしない

Version Numberデザイン

  • 楽観ロック
  • テーブルにVERSION列を追加

SELECT *を多用しない

  • 必要な列だけ返すこと

省スペース化

  • JSONデータ等でkeyを小さくするとか

データ型の指針

  • FLOATを使わない
  • NOT NULLを使う
  • TEXT/BLOBを使わない 
  • UNSINGEDを使う
  • INT(1)は1バイトじゃない

EXPLAINを見る

  • type=indexかつ「Extra: Using index」ではないクエリは使用不可
  • 巨大LIMITはダメ
  • covering indexにする

LEFT OUTER JOINしない

ストレージエンジンを混在させない

  • キューサーバとしてQ4Mを独立して用意するのはあり

重複したインデックスを持たない

  • INDEX(c1), INDEX(c1,c2)

LOAD DATAを使わない

  • レプリケーション遅延を招く
  • LOAD中にマスターがクラッシュすると、フェイルオーバーできないことがある

複数マスター間でのデッドロックに注意

  • 異なるmysqldでのデッドロックは自動検出されない
  • アプリ側でIDのソート順にロックをかけることで回避できる

履歴系データはレンジパーティション

2011/07/31

Sapporo.js 2011-07-31 参加レポート #sapporojs

今日はSapporo.js 2011-07-31に参加してきましたので、そのレポートを。
次回も可能であれば参加したいです。

5.4 関数型

写経

    var mammal = function(spec) {
        var that = {};

        that.get_name = function () {
            return spec.name;
        };

        that.says = function() {
            return spec.saying || '';
        };

        return that;
    };

内部にプライベートなthatを用意してカプセル化を実現

    var dog = mammal({name:"Dog", saying: "Bow"});

    document.writeln(dog.get_name()); // Dog
    dog.name = "Cat";
    document.writeln(dog.get_name()); // Dog

引数が分かりづらいのでこうして見る

  • 型チェックの追加
  • specに必要なkeyを明示的にする

改善後

    var mammal = function(spec) {
        var that = {};

        if ( typeof spec === 'object' && spec ) {
        } else {
            throw "spec should be an object';
        }
        var name   = spec.name   || 'mammal';
        var saying = spec.saying || '';

        that.get_name = function() {
            return name;
        };

        that.says = function() {
            return saying;
        };

        return that;
    };

改善前のはspecを先に定義しておけば、nameを書き換えられる

    var dogSpec = { name: "Dog", saying: "Bow" };
    var mydog = mammal(dogSpec);
    console.log(mydog.get_name()); // Dog
    dogSpec.name = "Cat";
    console.log(mydog.get_name()); // Cat

改善後のように変数、関数を別定義にしておけばちゃんとカプセル化される


Q. 最初に出てきた引数myは必要なのか?

    var mammal = funciton (spec, my) {
        // 省略
    };

A. 本に使用例も出てきてないし、誰もいい使い方が思いつかないから必要なさそう


親の関数をoverrideする前に変数に入れておけばOK

    var coolcat = function(spec){
        var that = cat(spec),
            super_get_name = that.superior('get_name');

        that.get_name = function(n) {
            return 'like ' + super_get_name() + ' baby';
        };

        return that;
    };

    var myCoolCat = coolcat({name: "Bix"});
    console.log(myCoolCat.get_name());

P.63までやった。次回は 5.5 オブジェクトのパーツ(P.64) から


LT

jQueryを読んでみよう @tricknotes さん

まずはgitからソースコードを持ってくる

git clone https://github.com/jquery/jquery.git

buildするにはREADMEを嫁

  • node.js 0.2
  • git 1.7
  • GNU make 3.8

今のHEADは1.6.3pre

いきなりsourceを読んで前回敗北したのでtestを見ていく

  • QUnitで書かれてる
  • test/index.htmlをブラウザで開くと実行していく様子が見れる
  • test/unit/*.jsがテストコード
  • test codeから読むと何がしたいコードなのかわかるので、そこを頼りに読み解く

jQueryのcodeの中にはThe Good Partsがいっぱいある

    var jQuery = (function(){})(); // 無駄なglobal varをつくらない

Sapporo.js-webの裏事情 @tricknotes さん

Sapporo.js-web

  • nodeで動いてる
  • JoyentCloud

    • 通常はxxxxx.no.deというドメインになる
    • グローバルIPも貰える
    • sshも使える
    • git pushでdeploy
    • 1ヶ月くらい申請でかかる!
    • gcc v3.4.6, makeとかは入ってた
    • solarisの模様

ベースはLooseleaf.JSで作成

githubでサイト自体も公開

@onjiro_mohyahya さんがテーマのベースを作るので、その後pull-requestをお待ちしてます

2011/07/17

Hokkaido.pm#5の参加レポート一覧(7/22更新)

Hokkaido.pm#5に参加レポートで発見できたものを載せておきます
blogに書くまでが勉強会なので、運営スタッフへの文句でもいいので書いていただけるとありがたいです。

2011/07/18 13:40
@akiymさん、@hirataraさん(LT)追記

2011/07/18 22:02
@lapis_twさん追記

2011/07/19 23:54
@nekokakさん追記

2011/07/21
@koji_magiさん、@keroyonn_さん追記

2011/07/22 0:01
@xtetsujiさん追記

2011/07/16

Hokkaido.pm #5

Hokkaido.pm#5のメモを公開しておきます。

Perl/SDL @charsbarさん

  • SDLの紹介
  • ニコ動に動画もある
  • CPANにあるよ
  • Perl Foundationの肝いりの詳細な資料あり
  • Rubyでは本まででてる!
  • Marc LehmannさんがGames::Sokoban
  • Games::Sokoban::ControllerをCPANにupした
    • ascii artでまずかいた
    • その後SDL化
  • 動くものができるのでLTとかにいいよ!

xtetsujiさん

  • リモートメールの中の人
  • Apache + mod_perl2
  • 古いCGIを改修とかの仕事がまわってくることもあるので対処用としても使える
  • mod_perl1 1996, mod_perl2 2002
  • mod_perl1とmod_perl2で文法違うから気をつけて
  • mod_rewriteのリファクタリングとかをPerlTransHandlerを使う
  • Apache2でSMTPサーバ
    • posftfix pipeとかではメール受信時のforkコストが高い
    • 重たいモジュールもごりごり使える
  • qpsmtpd
    • 良さげ
    • エンジン切替ができる

libperl++ lapis_tw

  • 動きませんでした
  • PODとReadmeの中身が違う
    • ライブラリのバージョンも違う
    • MSVCで使えるって書いてあるけど、やっぱり使えない
  • TODO、XXX、FIXMEだらけ!
  • 次回までに動作させる

@nekokakさん

  • @akiymaさんが推しまくったのでこれた
  • API, gateway開発
  • お母さん役
  • DevOps的な社内取り組み
  • YAPC::Asia 2010 省サーバ運用でベストスピーカー賞次点
  • カンファレンスは情熱をもらうところ
  • 自プロダクトを使いたけど、今のプロジェクトでは使えない
    • 折り合いをつける
    • ドックフード -> eat your own dog food
    • 自分で使うために作る
    • 有りもので満足できないなら作る or すごい人に凄い人に作ってもらう
  • DBIx::Connector
    • 有名で評価も高いけど、DBIx::Handlerを作った
    • Ore Oreを見極める
  • 尊敬するエンジニア
    • 樋口さん
      • MySQLのHandlerSocket
      • 使えそうなケースがあったので相談したけど、「InnoDBでいいんじゃない?」
      • 超かっこいい
    • tokuhirom
      • 凄いとんがってる
      • 豪快エンジニア
      • 仲間を大事にすr
      • エンジニア視点でビジネスのことを考える
      • 監視にも積極的
    • 他にもいっぱい
  • 本当に必要なのかを考える
    • 導入難易度
    • 運用
    • パフォーマンス
  • ビジネス的に是か
  • エンジニアとしての意識
    • 作るだけで終わらない
    • 使うだけで終わらない
      • フィードバックを送る
    • やるなら徹底的に
  • 自分自身
    • 社会人2,3年目までリーマンプログラマ
    • WEB+DBのPerlHacker座談会記事で目覚める
    • Shibuya.pmに出席
  • やってきたこと
    • CPANモジュールを漁る
    • blog書く
    • module書く
    • CPANにup
    • 転職
    • Shibuya.pm LT
    • YAPC::Asia
  • DevOps
    • 開発者と運用者の垣根をなくす
    • 自分たちのサービスに愛を
    • 運用者と開発者のコラボ
  • YAPC::Asia 2011
    • もうすぐスピーカー応募始まるよ
    • いつも同じメンツ?
  • WEB+DBのPerlHackersHubに寄稿

テスト駆動開発 @dont_cocoa

  • 初スピーカー
  • 仕事ではほとんどPHP
  • 今はPerl
  • TDDBC札幌
    • @t-wadaさんが講
    • 講義
    • ペアプロ形式
    • 2二日目はテストの無いレガシーコードを
  • 半年間実践
  • 基本
    • 仕様からテストコードを最初に起こす
    • 最初は失敗させる
    • 実装
    • テスト実行 -> 成功
  • 一気に書きたいのを堪えて、テストが通る最低限のコードだけ書く
  • バグ
    • 再現コードを書いてから、修正
  • やってみて感じたこと
    • 見通しのよいコードを書ようになた
    • 進捗状況がわかりやすくなった
    • テストの粒度が重要
    • 作業量は変わらない

LT

Base64を再実装する @akiymさん

  • Base64では読みあげられない
  • じゃあ日本語だ
  • Acme::Collector64

道具のいらないHello, world koji**さん

  • perldoc

ウイスキーとPerl @hirataraさん

  • uWSGI
  • dotcloud
  • nonblockingモードがある
    • Coro, AnyEventを見る
  • fastroute
  • subscribe

2011/06/30

ExtUtils::MakeMakerでMETA.ymlにmeta情報を追加する方法

repository情報をCPANに載せたい

githubで管理しているモジュールをCPANに上げたら、(誰かがpull requestを送ってくれるかもしれないので)repository情報をCPANに載せたいところです。

Module::Installを使用している場合は、 auto_set_repositoryを使うと勝手にセットしてくれますが、ExtUtils::MakeMakerでの書き方を知らなかったので調べました。

META_MERGEを使う

    WriteMakefile(
        NAME         => 'MyApp',
        VERSION_FROM => "lib/MyApp.pm",
        ABSTRACT => 'My great Application!!',
        PREREQ_PM => {
            'ExtUtils::MakeMaker'     => 6.31,
            'ExtUtils::Install'       => 1.46,
        },
        META_MERGE => {
            resources => {
                license => 'http://dev.perl.org/licenses/',
                repository => 'git://github.com/example/myapp.git',
            },
        },
        LICENSE   => 'perl',
    );

META_ADDでも追加できるがMETA_ADDはdefaultのmeta情報を上書きするので、とりあえずMETA_MERGE使っておけってExtUtils::MakeMakerのPODに書いてありました。

2011/06/29

App::pfswatchをリリースしました(0.04に合わせて修正)

2011-07-01 追記

配布場所

http://beta.metacpan.org/module/App::pfswatch

概要

ファイルの変更を検知して、指定のコマンドを実行するツール

インストール

CPANから

    cpanm App::pfswatch

CPANで見つからない場合はgithubから

    git clone git://github.com/ysasaki/p5-app-pfswatch.git
    cd p5-app-pfswatch
    cpanm .

使い方

App::pfswatchに付属しているpfswatchコマンドを使います

2011-07-01 0.04で修正

-eは残りの引数すべてをCOMMANDとして受け取るようになりました

    $ pfswatch lib/ -e echo Hello, world

監視するパスを与えない場合はカレントディレクトリが監視対象になります。
指定のコマンドを実行後はまた監視状態に戻ります

2011/04/09

Log::Minimalの出力先をファイルに変更するLog::Minimal::Fileを書いてみた

配布場所

github https://github.com/ysasaki/p5-log-minimal-file

インストール

git clone git://github.com/ysasaki/p5-log-minimal-file.git
cd p5-log-minimal-file
cpanm .

作成した理由

Log::Minimalの手軽さがナイスだったのですが、出力先をファイルに変更するのがめんどうだったので作成しました。

使い方

Log::Minimal::File->guard($filename)を呼ぶとguardオブジェクトが返ってきて、
guardオブジェクトが消えるまでは指定したファイルに書きこまれます。

    use strict;
    use warnings;
    use Log::Minimal;
    use Log::Minimal::File;
 
    infof("send to STDOUT");
 
    my $guard = Log::Minimal::File->guard('/tmp/your.log');
    infof("send to your.log");
    undef $guard;
 
    infof("send to STDOUT");

TODO

  • Log::Minimal::Fileの名前で大丈夫か?
  • 別途Log::Minimalをuseするのはなんかカッコ悪い
  • 実装方法がいまいちな気がする