• mysqlパフォーマンス改善への道(その1、現状の確認)

    パワー不足のmysqlをチューニングしてみます。 こんばんわ。プラットフォーム担当の宮下です。 今回は、バックアップ兼集計用に稼働しているmysqlのレプリケーションンサーバの パフォーマンス改善していきたいと思います。 これまでにもいくつか対策はしてきましたが、まずは環境をおさらいします。 ◇稼働してる環境は、AWSのEC2でlargeインスタンスを使用しています。 サービスは、OpenPNEを使用したSNSのサービスとなります。対象のMysqlはバックアップとデータ集計が目的で稼働しています。 (本番サービスでは使用していません) ◇mysqlのバージョンはちょっと古くて「5.0.77」になっています。multiで起動させていていて この他に開発環境用のmysqlも稼働していたりします。 ちなみに今の遅延秒数は、「1512561 秒」でまだ増加中です。 ◇これまでに変更した点ですが、 「innodb_buffer_pool_size」を512Mから2028Mまで増加、 「innodb_flush_log_at_trx_commit」を2から0に変更、 (リカバリの精度よりもスループットを優先) 「key_buffer_size」を32Mから300Mに変更、 「query_cache_size = 0」にして無効化しました。 効果は、DISKのI/Oが半分くらい減りましたが、遅延解消とまではいってません。 ◇最後にmuninで取得しているデータを確認します。 遅延が日々増えています。たまに減る事もありますが要因は分かりません。 常にDISKのread I/Oが大量に発生しています。 原因ははっきりしていて、DBデータに画像や動画データが格納されている為となります。 buffer pool sizeでは収まり切らないデータサイズなので常にDISKのread/writeが発生しています。 またMyISAMとInnodbが混在していてリソースが効率的に利用出来ていない事や、 OpenPNEが「delete aaa filename LIKE ‘%bbb%’」というクエリを大量に発行している事 などが解決すべき課題がたくさんあります。 現状を整理した事で、次回からは一つずつ改善対策を実施していきたいと思います。
    ...
  • 瀕死の技術ブログを復旧した話

    こんにちわ。 今回は主に(当ブログの)mysqlデータベース復旧のお話になります。 担当のお方が 「waordpressだとinnodbよりmyisamのほうが早いらしいので、 変える前にinnodbのmy.cnfのパラメータいじくってベンチマークとろうとした」 ことをきっかけにDBのデータがぶっ壊れました。 mysql5.6ならmyisam使わなくても参照専用トランザクション使うよう改造できれば早いらしいよという話はおいといて。(5.5だし) DBデータが読めなくてwordpressの管理画面にログインできなくなってしまいました。 -————————————————– 130528 11:59:24 [ERROR] Missing system table mysql.proxies_priv; please run mysql_upgrade to create it 130528 11:59:24 [ERROR] Native table ‘performance_schema’.’events_waits_current’ has the wrong structure 130528 11:59:24 [ERROR] Native table ‘performance_schema’.’events_waits_history’ has the wrong structure 130528 11:59:24 [ERROR] Native table ‘performance_schema’.’events_waits_history_long’ has the wrong structure
    ...
  • AmazonEBSでraid0を組んだ時のパフォーマンス検証

    AmazonEBSでraid0を組んだ時のパフォーマンス検証 EBSを組むと早いはなしを検証したい testでマルチ、ラージなら結構こうかある説がある模様。 既存移行の方法も検討(バイナリログ等のディレクトリ分けるところからかと。) 公式のユーザガイド(EBSPerformance) EBS自体が冗長構成組まれているのでraid0でいいと思われる。 インスタンスディスク(ローカルディスク、エフェメラルディスク)を使ってRAID0 EBSでRAID0を組むことは、RAID10(ミラーのストライプ)と同等である Largeインスタンス以上であれば、1台よりも2台の方がディスクI/O性能が目に見えて上がりました エフェメラルディスク(stopすると消えるほうのディスク)でraid0したい場合の起動コマンド例 [shell] ec2-run-instances ami-e965ba80 –region us-east-1 –key id_rsa –group sg-a4866fcc –placement-group test –instance-type cc2.8xlarge -b “/dev/sdb=ephemeral0” - b “/dev/sdc=ephemeral1” -b “/dev/sdd=ephemeral2” “/dev/sdf=ephemeral3” [/shell] ・ラージでEBSディスクを2つ追加して起動してログインする [shell] # df -h Filesystem Size Used Avail Use% Mounted on /dev/xvde1 9.9G 867M 8.5G 10% / none 3.
    ...
  • IDCフロンティア セルフクラウド入門編

    IDCフロンティアのセルフクラウドでAPI環境を用意するまで ~その1~サーバを起動する 始めまして。プラットフォーム担当の宮下です。 かねてから利用している、「IDCフロンティア クラウドセルフタイプ」の利用方法について基本的な流れを案内していきたいと思います。 会社としてもう今回は、仮想マシンの起動までの簡単な流れを説明させて頂きます。 パブリッククラウドは各社で独自の管理コンソールがあって慣れるまではそれぞれにくせがあります。その辺についても今後触れていければと思います。 仮想マシン作成 作成したユーザ/パスワードでログインしたら、〔ホーム〕→〔ダッシュボード〕から〔仮想マシン作成〕で作成を開始します。 OSの選択 次に起動するOSを決めていきます。リストをスクロールすると標準で用意されたテンプレートがたくさん出てきますのでお目当てのOSタイプが見つかるまで頑張って探してみて下さい。 (特にOSの指定が無ければLATESTの中から選び、ミドルウェアが必要かどうかで決めれば良いと思います) 今回はAPIツールを使用する環境を作りたいのでLATESTのLAMP環境OSを選びます。 〔[LATEST] LAMP or LVS(keepalived) or HAProxy or API Access Tool or Scalr or Elecoma or Yahoo! Cloud Storage Access Tools〕 を〔選択〕します。 マシンスペックの選択 次にサーバのスペックを決めます。 これはどこのクラウドでも同じだと思います。必要な用途に応じて最適なマシンスペックを選びます。 今回は最小の〔XS〕(1CPU/メモリ0.5GB)を選択します。 追加DISKの選択 次に追加DISKの設定をを行います。 OSデータ以外にコンテンツやログといった大きな容量を使用する場合は、ココでDISKを増設しておきます。 あとで追加もできますので必要が無ければ追加無しで進めます。なお今回はAPIツール用なのでDISKの追加は行いません。 SSH鍵の設定 最後にSSH鍵を設定します。 始めての時はまだSSH鍵が登録されていないので新規にSSH鍵を作成します。 生成された秘密鍵はSSH接続時やAPIツールを使用する際に必要となりますので大切に保管しておきます。 仮想マシン申し込み 登録した内容を最終確認して仮想マシン作成を開始します。 内容に差異が無ければ同意するにチェックして、〔申し込み〕を選ぶと作成が開始します。 最初の1台目の仮想マシンを作成する時には注意が必要です。赤字の注意事項に書かれている内容を確認しておきます。
    ...
  • MHAの動作確認と切替検証

    MHAの動作確認と切替検証 前回のつづきです。以下の図のように切り替わるようテストします。 ※本検証はマスタ1台、スレーブ2台、マネージャ1台構成。(多段構成は中間ノード障害時の復旧が猥雑になるので回避) スレーブにmanagerを同居させるとpurge_relay_logsとかぶると上手く切り替わらない可能性があるようです。 ※2台しかない場合で上手く切り替わらないことがあるようです。以下参考。 http://heartbeats.jp/hbblog/2013/05/mysql-mha-haproxy.html ⑥ 起動前チェック ・sshの動作チェック [shell] # masterha_check_ssh –conf=/etc/app1.cnf [/shell] OKな場合最終的に以下のように出力される [shell] Tue Oct 23 15:02:22 2012 - [info] All SSH connection tests passed successfully. [/shell] ・replicationの動作チェック [shell] # masterha_check_repl –conf=/etc/app1.cnf [/shell] OKな場合最終的に以下のように出力される(※mysql5.6からはMHAのバージョンによってはbinlog-checksum=NONEにしないとここで失敗するかもしれません) [shell] MySQL Replication Health is OK. [/shell] ※失敗するパターン レプリケーションのフィルタリングルールが合っていない LVSとMHAマネージャが相乗りの場合、チェックタイミングが重複しホスト毎DBサーバに拒否されてしまう(要flush hosts;) ⑦更新VIP用IFファイルを確認 db01/db02
    ...
  • MHA(MasterHighAvailabilityManager)の導入設定

    MHA(MasterHighAvailabilityManager)の導入設定 使用バージョン:mha4mysql-manager-0.53-0、MySQL-5.5 ①簡単な利点などの解説 MHAとはmysqlのマスタ障害時に最新のスレーブをマスタとして他のスレーブの差分を補完しマスタの向き先を変えてくれるプロダクト。 Heartbeat+mon+mysqlに比べるとreplicationの再構成も行ってくれるので切り替わってもDBがシングルにならないのが利点。(3台以上の構成の場合) 作者のスライド 公式サイト MHAの制約:mysql5.0以上、SBR(ステートメントベースレプリケーション)の場合LOAD DATA INFILEを使えない ※マネージャはadminサーバ、ノードはDBサーバ(マスタ・スレーブ共通) ② マネージャにてインストール ※以下、admサーバから実施 ・インストール [php] wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.53-0.noarch.rpm yum –enablerepo=rpmforge install \ perl-Config-Tiny \ perl-Time-HiRes \ perl-Log-Dispatch \ perl-Parallel-ForkManager \ perl-Params-Validate yum install perl-DBD-MySQL rpm -ivh mha4mysql* [/php] 入ってなかったら [shell]yum install –enablerepo=remi mysql mysql-server perl-DBD-MySQL[/shell] ※マネージャはmysql-serverいらないかも ③ ノードにてインストール ※以下、dbサーバから実施
    ...
  • DEVLABはNginx環境に移行しました

    2013年3月末週、DEVLABサイトの環境移管を人知れず行ってました。 今週の4/2頃まではDEVLABにアクセスした人の中には、サイトが表示されなかったり、不具合が起きていた人もいたかもしれませんが、それらはすべて環境移管に伴う余波としてご理解いただけますと幸いです。まぁ、DEVLABの存在意義と運営方針の一つとして、「インターネットに関わる技術の研究開発のためには恐れずに何でもやってみよう!」というコンセプトを持っているので、今後もISAO社のDEVLABに関わるエンジニアの「好奇心の趣くままに」「衝動的に」「たとえサイトが壊れるとしても」色々とやって行くので、もしサイト来た時に変な動きをしていても ―― お、今何かやっているのかな?――と、温かく見守っていただきたいです(単なるバグの可能性もありますが、それも含みで)。 そんなこんなで、DEVLABの環境を今までのApache環境から今流行りのNginx環境に移管した次第。 さらに、noSQLデータベースの「MongoDB」やNode.jsもインストールして、今後は「リアルタイムWEBアプリケーション」の開発もできるように整備したのですが、これはISAO社のエンジニア向けの環境整備なので、DEVLAB側には今のところ影響はないかと。 さて、巷では「Nginx+リバースプロクシ+WordPress」の構成でWordPressのサイトパフォーマンスが劇的に向上すると云われているので、早速本DEVLABでもその施策を実施してみました。 結果、1ページ単位での表示レスポンス(レイテンシー)は特に変化はなかった(単ページ単位だと、逆にレスポンスはApacheの方が勝ってました…が、体感速度的には変わらなかった)のだが、Jmeterで負荷テストしてみたら、多数の同時リクエストが発生した際のNginxのレスポンスはかなり驚異的な向上が見られた次第。 実際にDEVLABのTOPページのリクエストレスポンスを比較したら、Nginx環境ではApacheの約23倍ほどもレスポンスが向上しました。 いやぁ、Nginxスゴイ!という感想でした。 ま、DEVLABは常時負荷が高まるほどアクセスされないので、今のところNginx環境も宝の持ち腐れ的な感があるんですけどね…。
    ...
  • Contact Form 7 でエラー時用画面にリダイレクトする方法

    Contact Form 7では、管理画面の、各フォームごとの編集画面の「その他の設定」に、 on_sent_ok: "window.location.href = 'リダイレクト先のURL';" と入力すれば、Contact Form 7 の処理終了後に、設定したURLにリダイレクトしてくれます。 しかし、この設定をすると、成功しても失敗しても同じURLに遷移するため、送信が成功したか失敗したかわかりません。 画面遷移ではなく、メッセージの表示をさせる場合では、成功時と失敗時でメッセージが切り替えられており、その処理にはJavaScriptを使っているはずです。 そこで、Contact Form 7 のjsファイルを改変して、エラー時にエラー時用のリダイレクトURLへ遷移させることにします。 /pm_webform/wp-content/plugins/contact-form-7/includes/js scripts.js 67行目付近の以下の行 } else { の下に以下の行を追加すると、失敗時用のリダイレクトURLへ遷移できます。 window.location.href = "失敗時用リダイレクトURL"; 同様に、57行目付近の以下の行 } else if (1 == data.mailSent) { の下に以下の行を追加すると、成功時用のリダイレクトURLへ遷移できます。 window.location.href = "成功時用リダイレクトURL";
    ...
  • Contact Form DB でチェック処理

    Contact Form DB でテーブルへの insert を行う前に、何らかのチェック処理を入れたい場合、フックを使います。 function my_form_chk( $cf7 ) { // 入力フォームの値取得 foreach ($cf7->posted_data as $posted_name => $posted_value) { // 元の値は変えないため別変数へ $posted_name_2 = $posted_name; $posted_value_2 = $posted_value; // 値の整形 $posted_nameClean = stripslashes($posted_name_2); $posted_value_2 = is_array($posted_value_2) ? implode($posted_value_2, ', ') : $posted_value_2; $posted_valueClean = stripslashes($posted_value_2); // それぞれの変数に代入 if( $posted_nameClean == 'a' ) { $input_param_a = $posted_valueClean; } if( $posted_nameClean == 'b' ) { $input_param_b = $posted_valueClean; } if( $posted_nameClean == 'c' ) { $input_param_c = $posted_valueClean; } } // チェック処理 if ( $input_param_a !
    ...
  • Contact Form DB のテーブルについて

    Contact Form 7 というアンケートフォームのプラグインは、メールを送信するだけなので、DBへデータを格納するようにするプラグインが Contact Form DB です。 両プラグインをWordPressに入れることで、手軽に入力フォームの内容をDBに格納できます。 しかし、この Contact Form DB で作られるテーブルが曲者でした。 WordPressの管理画面から Contact Form DB の管理画面を表示すると、入力フォームから入力されたデータの一覧を表示でき、それを見るとあたかも一つのフォームからの投稿が一つのレコードとして格納されているように見えます。 しかし、実際のテーブルには、入力フォームの input 一つ一つがそれぞれ1レコードとして登録されます。 入力項目が3つのフォームだと、1回の投稿で3つレコードが登録されるわけで、それぞれのレコードには、それぞれの入力項目の内容のみが、投稿時間と入力フォーム名と入力項目名をキーに記録されるのです。 ちなみにテーブル構造は下記の通り。 mysql> DESC wp_cf7dbplugin_submits; +-------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+-------+ | submit_time | decimal(16,4) | NO | MUL | NULL | | | form_name | varchar(127) | YES | MUL | NULL | | | field_name | varchar(127) | YES | MUL | NULL | | | field_value | longtext | YES | | NULL | | | field_order | int(11) | YES | | NULL | | | file | longblob | YES | | NULL | | +-------------+---------------+------+-----+---------+-------+ 6 rows in set (0.
    ...
  • iPhoneやiPadで撮影した画像を他のデバイスで見ると自動で回転してしまう場合の対処法

    .iphone { position: relative; height: 123.75px; width: 62.5px; border-radius: 8.75px; margin: 12.5px auto; background: -webkit-linear-gradient(-165deg, rgba(255,255,255,0.4), rgba(255,255,255,0.15) 35%, transparent 35%), -webkit-linear-gradient(top, transparent 21.25px, #222222 21.25px, #151515 102.5px, transparent 102.5px), -webkit-linear-gradient(top, #000, #0a0a0a); background-repeat: no-repeat; background-size: 100% 100%, 55px 100%, 100% 100%; background-position: 0 0, 3.75px 0, 0 0; box-shadow: 0 0 0 0.
    ...
  • PATH_INFOを取得してhiddenに代入

    URLにパラメータをくっつけて、GETで送信する場合、 http://www.example.com/?param0=aaa&param1=bbb という感じで渡して、受け取るときは $param0 = $_GET['param0']; $param1 = $_GET['param1']; または $param0 = $_REQUEST['param0']; $param1 = $_REQUEST['param1']; というようにするのが一般的ですが、以下のように、 http://www.example.com/aaa/bbb/ で値を渡して、受け取りは $param = split("[/\.]", $_SERVER["PATH_INFO"]); とすると、$param[0] に「aaa」が、$param[1] に「bbb」が代入されます。 さて、これを WordPress でやろうとすると、「aaa」とか「bbb」をURLとして処理しようとしてしまい、当然パーマリンクや実体があるわけではないので、表示できません(実体があればそちらを表示しちゃう)。 WordPress では PATH_INFO を使わない方がよさそうなのですが、使わざるを得ない場合、WordPress とは関係なく、一旦 PATH_INFO を受けるプログラムを作成し、そこから何かしらの方法で WordPress にパラメータを渡すようにします。 受け方は上記の通りなので、あとは渡し方になるのですが、手軽なのは GET でリダイレクトする方法でしょう。 $url = "遷移先URL?param0=" . $param0 . "&param1=" . $param1; header("HTTP/1.
    ...
  • wp_insert_attachment() で新規 insert

    wp_insert_attachment() のリファレンスには、 wp_insert_attachment( $attachment, $filename, $parent_post_id ); と書かれており、$parent_post_id を指定する必要があります。つまり、事前に posts テーブルに何らか insert して、そのレコードの post_id を指定することとなります。 でも、新規で画像情報を登録したくて、でも紐づく投稿がまだ無い場合、post_id が無いわけで、どうするべきか調べてみました。 WPのソースを追ってみて、実際に試してみたところ、 wp_insert_attachment( $attachment, $filename, 0 ); というように、$parent_post_id = 0 とすることで、新規で insert されます。 ちなみに、$attachment には、 $wp_filetype = wp_check_filetype(basename($filename), null ); $wp_upload_dir = wp_upload_dir(); $attachment = array( 'guid' => $wp_upload_dir['url'] . '/' . basename( $filename ), 'post_mime_type' => $wp_filetype['type'], 'post_title' => preg_replace('/\.
    ...
  • スクリプトで WordPress の DB にアクセスしたい

    WordPress の DB にスクリプトからアクセスしたい場合、単純に MySQL にアクセスして処理すればいいのですが、何らかの理由で WordPress の関数を使いたい場合(画像の投稿をスクリプトで行う等)は、 require_once('wp-blog-header.php'); でOKなのですが、一部のメソッドは直接そのメソッドが記述されたソースをインクルードする必要があります。 例えば、カテゴリ登録するための wp_insert_category() を使いたい場合、 require_once('/wp-admin/includes/taxonomy.php'); とする必要があります。/wp-admin/includes/にクラスがあるので必要なものを探しだして、インクルードします。 また、wp-blog-header.phpをインクルードするということは、例えば、HTTPSで必ずアクセスさせたり、ログインユーザのみに見せるといったようなWebの制限をfunction.phpなどに入れて、サイト全体に制限かけた場合、影響を受けます。 そこで、そういった制限を入れた場合は、その制限処理に、 if ( ! preg_match( '/^(script.php|hogehoge.*.php)/', basename( $_SERVER['SCRIPT_NAME'] ) ) ){ // 制限処理 } のように除外したいスクリプト名(上記の場合、「script.php」か「hogehoge.*.php」にマッチするスクリプト)を指定して、処理から除外する必要があります。 これをしない場合、スクリプトを実行すると、制限に引っかかり、処理が止まります。
    ...