サバフェスに参加してきました。

サバフェスに参加して1週間でやった事などをまとめて報告させて頂きます。
いきなりですが、レギュレーションについていくつか質問があったのですが、
質問受付期間中に聞きそびれるというミスをしたので後半はかなり自由な解釈のもと、
作業をしました。
途中のスコア等は全然残してなかったので書いてません。

やったこと

月曜日

寝てましたね。

火曜日

寝てました。

水曜日

やっと頂いたpdfを読んでインスタンスを起動させました。
1台起動させて残り4台の起動は一緒にやってたメンバーに任せて寝ました。

木曜日

nginx(openresty-1.4.3.3) + php-fpm(5.5.6) + MySQL5.6で環境構築
nginxのproxy_cacheで頑張ればって思ってたので上記の環境にしました。
ページが見れるようになったところで寝ました。

金曜日

とりあえず分散させるために、全台にnginx + php-fpmをインストールして、
1台だけ前段にproxyの設定をいれたサーバを用意しました。
ちなみにphp5.5.6はapcがないのでZend OPcacheを使用。
nginxのproxy_cacheで頑張ればって思いでしたがあまりスコアがでず、
とりあえず疲れたので寝ました。

土曜日

apcとの性能を比べるために、php5.4.22をインストールるして切り替えてみる。
Zend OPcacheの方が少し早かったのでphp5.5.6に戻す。
ngx_pagespeedも試してみましたがあまり結果が変わらず。

この時点で優勝する為にはもっと工夫しないと思い試行錯誤を始めます。
勝手な解釈のもとproxyサーバとしてならhaproxyやvarnishを使ってもいいのでは?
とか思いこみ、haproxyを入れる。スコアの伸びがいまいちだったので、
やっぱりvarnishにする。

varnishにした時点で5位以内にはいったりするようになったのですが、
やっぱりやるからには優勝したい!!!って事でここでとっておきの秘密兵器投入
postのスコアの方がgetよりも高かったので、postで好成績を出せば、
勝てるって思いました。

nginx + lua + MySQLで、wp-comments-post.phpを実装。
(コメントの投稿以外はできませんし、コメント投稿についても動作の保証はしませんので使う方は、
ご自身の責任のもとお願いします。)
レギュレーション的にnginxで実装するぶんにはグレーなはずっ!
というかどれくらい早くなるか試してみたかったんです。
この為に、nginxをコンパイルして入れてました。

夜中に実装が終わって朝のベンチを待とうと思って寝ました。

日曜日

朝起きたら、最終兵器を投入したはずがpostが0件になってたので絶望。
とりあえず何故か調べるためにベンチでポストされたデータをみてたら、
1度のベンチで100万件を超えるデータは入っており、wpのコメントのページが
タイムアウトしてました。

100万件も処理しなくていいので、処理を減らす方向に。

5台つかってサーバを3台に。
1台目はnginx + php-fpm
2台目はmemcache
3台目はmysql

これでも80万件ちかくpostされてて、タイムアウト。
ってことでmemcacheを使ってpostされた数をカウントして、
mysqlに入るデータを抑制するように修正。
(いくつかバグがあったのでそれを合わせて修正しました。)
タイムアウトをのばしたり、phpのmemory_limitを-1にしたりして、
出来るだけタイムアウトしない設定にして、自前でベンチをはしらせてたところ、
7万件くらいまでなら処理できる事がわかったのでとりあえず最後のベンチ前に
5万7千くらいに閾値を設定してました。
そしてついに最後のベンチで、 暫定1位に。

f:id:yokoninaritai:20131125183606p:plain

あとは寝る前に、cacheのexpireの時間を10分→5分にして閾値を6万5千くらいにしました。
5分にしたのは最後に走ったベンチマークのpostの処理が5分以内で終わってので、
本番の測定際もちゃんと動くだろうと想定して変更しました。
ちゃんと想定通りの動作をしていればいいのですが。

ちなみに、luaの処理の部分は下記のような形で実装しました。
(HOST,USER,PASSWORDについてはblogを書くにあたって変更しました。)

        location /wp-comments-post.php {
            content_by_lua '
                ngx.req.read_body()
                local args    = ngx.req.get_post_args()
                local id      = args["comment_post_ID"]
                local author  = ngx.quote_sql_str(args.author)
                local email   = ngx.quote_sql_str(args.email)
                local url     = ngx.quote_sql_str(args.url)
                local comment = ngx.quote_sql_str(args.comment)
                local agent   = ngx.quote_sql_str(ngx.req.get_headers()["User-Agent"])

                local memcached = require "resty.memcached"
                local memc, err = memcached:new()
                if not memc then
                    ngx.log(ngx.ERR,"failed to instantiate memc: ", err)
                    ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
                    return
                end

                memc:set_timeout(1000) -- 0.1 sec
                local ok, err = memc:connect("<MEMD_HOST>", "11211")
                if not ok then
                    ngx.log(ngx.ERR, "failed to connect: ", err)
                    ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
                    return
                end

                local max_id = 56591
                local rid, err = memc:incr("count",1)
                if not rid then
                   rid, err = memc:set("count", 1, 300)
                   -- ngx.log(ngx.ERR,":",rid,":",max_id,":",err)
                end
                -- ngx.log(ngx.ERR,":",rid,":",max_id)

                if tonumber(rid) > tonumber(max_id) then
                    return ngx.redirect("http://"..ngx.var.host.."/?p="..id.."#comment-1", ngx.HTTP_MOVED_TEMPORARILY)
                end
                memc:set_keepalive(0, 100)

                local mysql = require "resty.mysql"
                local db, err = mysql:new()
                local ok, err, errno, sqlstate = db:connect{
                    host = "<DB_HOST>",
                    port = 3306,
                    database = "wordpress",
                    user = "<USER>",
                    password = "<PASSWOED>"
                }

                local res, err, errno, sqlstate = db:query(
                    "INSERT INTO wp_comments (comment_post_ID,comment_author,comment_author_email,comment_author_url,comment_content,comment_date,comment_date_gmt,comment_agent) VALUES ("..id..","..author..","..email..","..url..","..comment..",NOW(),UTC_TIMESTAMP(),"..agent..")"
                )
                -- ngx.say(res.affected_rows, " rows inserted into table cats ","(last insert id: ", res.insert_id, ")")

                local result, err, errno, sqlstate = db:query("SELECT comment_count FROM wp_posts WHERE ID = "..id.."")
                for idx, records in pairs(result) do
                    for key, record in pairs(records) do
                        -- ngx.log(ngx.ERR, record)
                        record = record + 1
                        -- ngx.log(ngx.ERR, record)
                        local bytesend, err = db:send_query("UPDATE wp_posts SET comment_count="..record.." WHERE ID = "..id.."")
                        -- ngx.log(ngx.ERR, bytesend,":",rid,":",id,":",err)
                    end
                end
                local ok, err = db:set_keepalive(0, 100)

                ngx.redirect("http://"..ngx.var.host.."/?p="..id.."#comment-"..res.insert_id.."", ngx.HTTP_MOVED_TEMPORARILY)
            ';
        }

まとめと反省

後で思ったのですが最初の認識として、クラウドでkeepalivedが使えないという勝手な思い込みにより、lvsを使わなかったのは本当に反省です。
プロファイリングや、可視化する対応をいれた方がもっとボトルネックがはっきりしたのではないかと思います。
phpは遅い。(postのハイスコアはすべてluaのおかげです。)
今回初めてlua入門しましたが、これだけ早ければ別の機会でも使えそうだなと思いました。
かなり自由にやりましたので楽しかったです。
ちなみに一緒にやってたメンバーはなにしてたかと言うと、ここではあまり言えませんが何もしてません。

最後に書いておきますが今回のnginxのレギュレーションに違反する可能性は考えました。
禁止事項に「 WordPressショートカット 」というのがあった為です。
最初にも書いた通り最初にきちんと質問してできればよかったと思っております。

今回のような機会を作って頂いたidcフロンティアの方々ありがとうございました。
運営の方々、参加されたみなさま、お疲れさまでした!

puppetの--testオプション

puppetのバージョンアップでハマったので、メモ代わりにblogにします。

今更な感じではありますが、puppet-0.25とpuppet-2.6の--test(-t)オプションは若干内容が変更されてます。

  • puppet-0.25
puppet/application/puppetd.rb
119     # Enable all of the most common test options.
120     def setup_test
121         Puppet.settings.handlearg("--ignorecache")
122         Puppet.settings.handlearg("--no-usecacheonfailure")
123         Puppet.settings.handlearg("--no-splay")
124         Puppet.settings.handlearg("--show_diff")
125         Puppet.settings.handlearg("--no-daemonize")
126         options[:verbose] = true
127         options[:onetime] = true
128         options[:waitforcert] = 0 unless @explicit_waitforcert
129     end
  • puppet-2.6のテストオプション
puppet/application/agent.rb 
135   # Enable all of the most common test options.
136   def setup_test
137     Puppet.settings.handlearg("--ignorecache")
138     Puppet.settings.handlearg("--no-usecacheonfailure")
139     Puppet.settings.handlearg("--no-splay")
140     Puppet.settings.handlearg("--show_diff")
141     Puppet.settings.handlearg("--no-daemonize")
142     options[:verbose] = true
143     Puppet[:onetime] = true
144     options[:detailed_exitcodes] = true
145   end

2.6からdetailed_exitcodesが有効になってる事によってexit_statusが変わります。

  • 0: 正常終了
  • 2: 変更あり
  • 4: 失敗
  • 6: 変更と失敗あり

capistranoから実行するときは--testオプションつけたままだと、処理が中断されるので要注意です。
解決方法としては、--testオプションを使わずに個々にオプションを書きましょうってことでした。

sudo /usr/sbin/puppetd --ignorecache --no-usecacheonfailure --no-splay --show_diff --no-daemonize --verbose --onetime 

puppet-server-0.25で、puppet-2.6の環境で特に問題なさそうに動いてました。
やってる事がシンプルだってのもあるとは思うんですが。

baserCMS勉強会でトークさせていただきました。

少し前ですが、7/28にbaserCMS勉強会でトークさせていただきました。

勉強会の内容はbaserCMSのテーマについてだったのですが、デザイン経験のない僕がテーマの話してもって事だったので、ロリポップの簡単インストールについてとレンタルサーバでの運用について話させていただきました。
ちょっとトラブルもありましたは、無事終わってほっとした感じです。

その後の自習では、テーマ作成をやっいたのですが一度しかテーマを作成した事がなかったので、とても勉強になりました。ありがとうございます。
baserCMSもこれからテーマがどんどん増えていくといいですね。

もしよかったらチューニングの勉強会の時にも声かけていただけると、
もっと色々お話ができると思いますのでよろしくお願いします。

あと会場をお貸しいただいたデジハリ福岡校さんありがとうございました。

YAPCのトークに採用されました。

久しぶりにblog書きます。

タイトルにもある通り、YAPCのトークに採用していただきました。
すごく嬉しいです。

トーク内容は GitHubを使った開発とデプロイ です。

まさか今年はトークさせていただく事になるとは思ってませんでしたので、自分自身すごく驚いてます。去年までは勉強会もほとんど参加してなかったのですが、今年から出来る限り参加してトークしたりしてきました。まだまだ前で話すのは慣れてないですが、バッチリ資料作って本番に挑みます。

内容は上にも書いてありますが、ロリポップの開発環境まわりを改善している話をしたいと思います。開発環境の改善はいまも継続中ですので、その辺の話をしたいと思います。

皆さんのお役に立てるような話ができるように頑張ります。

Fukuoka Perl Workshop #21に参加してきました。

今回は2回目の参加でした。

JPAさんのご協力により今回はJPA牧さん、@nekokakさんに来ていただきました。
本当にありがとうございます。
簡単に当日のメモを書いていきます。

間違い等あれば補足していただけると助かります。

山本さん(@dragon3)

  • Plack-App-GitSmartHttpについて。

山本さんが作成された、Plack-App-GitSmartHttpの紹介でした。
ちょっと名前が長くて覚えにくいですね。(名前募集中との事でした。)
git server の簡易版で、導入がすごく簡単でした。
必要なのはインストールして、app.psgiを作成するだけ。

  • install
cpanm Plack::App::GitSmartHttp
  • app.psgi
Plack::App::GitSmartHttp->new(
    root          => 'repos',
    upload_pack   => 1,
    received_pack => 1
)->to_app;

- upload_pack:    cronを許可するかどうか。
- received_pack:  pushを許可するかどうか。

発火村なんかする時にすごく便利って思ったので、是非利用してみたいと思います。
セキュリティまわりは、自分でしっかりやる必要があるようです。

桜井さん(@kiwanami)

桜井さんの作成された、Emacs DBIの紹介でした。
DEMOから始まりましたが、エディターでDBの操作ができるのが衝撃でした。
ソースの中にSQLとか書いてて、確認で実行したい時なんか便利ですね。
SQLなれてない方は、SQLの保管もしてくれるそうです。
普段はEmacsですが、サーバで作業される時はvimをつかわれるとの事でした。
やっぱそうなりますよね。
Emacs DBIの利用にあたっては、RPC-EPC-Service、DBIDBIのドライバのインストールが必要です。

牧さん(@lestrrat)

  • STFについて。

STFとはオブジャクトストレージです。
オブジェクトストレージといえば弊社でも使っているMogileFSしか知りませんでしたが、STFPSGI互換だったり、プロトコルがHTTPだったりします。
もともとapacheのモジュールとして作られたなど、いまに至る歴史の話から、実際に運用の話をしていただけました。
冗長性についても、自動的にリカバリもやってくれるみたいです。
素敵なシステムですね。
残念ながら、僕の勉強不足であまり理解できてない箇所も多々ありますがまずは一度使ってみたいと思います。

小林さん(@nekokak)

  • Clutchについて。

ClutchとはGearmanのようなJobQueueServerです。
業務を改善の為のシステムを作成する際、ちょっとしたtoolsを作成される際にGearmanを入れるのが嫌だというところから、作成されたそうです。
こういうクイックハック的な所をもっと勉強していきます。
クイックハックの話はSoftware Design 2012年3月号に書いてたそうなのでアマゾンで注文しました。
Gearmanは通信するのに中間管理のdaemonが必要ですが、Clutchはclient->workerで直接通信するそうです。
管理するdaemonが少なくていいのは運用する人にとってはいいですね。
パフォーマンス的にも、Gearmanより早いようです。
いまapiで非同期処理の箇所があるので、試してみたいと思ってます。

牧さん(@lestrrat)

  • ZeroMQについて。

@nekokakさんからあつい要望で本日2度目の発表をしていただけました。
ZeroMQはメッセージングライブラリになります。
メッセージのキューイングを行ってくれます。
牧さんが即興でコードを書きながら説明してくださいました。
本当にすごかったです。
現在はVersion2と3があるようですが、Version2を使った方がいいとのことでした。
Version2と3では、一部互換性がないようです。
互換性のない箇所については、メモしてなかったwww

春山さん(@Spring_MT)

  • 10xLabの紹介

去年のYAPCで釣られちゃって福岡に来たみたいです。
いまは九大学研都市でお仕事されてるそうです。
まだまだ人が足りないようなので、募集中とのことでした。
現在はrubyで開発をされてるそうです。
いまならなんと、まかないがでるそうです。

まとめ

perlの勉強会については前々回のFukuoka.pmと去年のYAPCに続き3回目の参加でした。
最近はあまりperlを書かなくなりましたが、勉強会に参加して書きたくなりました。
牧さんも@nekokakさんも今回初対面でしたが、すごく話しやすく素敵な人でした。
牧さんは料理もされるそうで、すごくグルメなんだと思います。
@nekokakさん前日は屋台で飲んで当日も3次会までご一緒させていただきました。

今回fukuoka.pmでなぜかチャラい感じのキャラになってますが決してチャラくないです!!!

僕にとっては、刺激的な1日だったと思います。
お世話になりました。
また是非福岡にこられてください。
今年はYAPCでLTできるように、頑張ります。

最後に

ご支援いただきましたJapan Perl Association (JPA)、株式会社ヌーラボさんほんとにありがとうございました。

このblogを読んでいただけた方、ありがとうございます。
普段からblogを書く癖がないので非常に読みにくくて本当に申し訳ありません。
今後blogを書く中でもう少し読みやすくなるように頑張ります。

発表していただいた資料と、CPANのなど

資料につきましては、気づき次第随時追加していきます。

dragon3さんの発表して頂いた資料
桜井さんのEmacsDBI紹介blog
牧さんのSTFのblog
nekokakのCluchのblog

第3回チューニンガソンに参加してきました。

久しぶりのblogになります。

Zusaarでチューニンガソンの東京会場のページを見つけたときすでに、

参加者がいっぱいだったので諦めてましたが、

福岡でも開催されるとしり急いでエントリーしました。

当日の朝から開始まで

当日実は寝坊しそうで、会場到着はギリギリでした。

まーそんな中始まったチューニンガソンですが、

blojsomのチューニングが今回のお題でした。

えっとblojsomってなに?

tomcat + java ???

javaとかわかんないし、tomcatなんて使った事ないし。。。

ってところ始まりました。

まずは、blojsomがなんなのかgoogle先生に聞くところから始めました。

やったこと

そんな感じで結果は6位でした。

これから簡単に僕がやった事を書いていきます。

まずやったのがMySQLのチューニング

(っていうかこれで駄目ならもう無理って思ってました。)

innodbだったので、innodb周りの設定やquery_cacheの変更を行いました。

変更した箇所はこんな感じです。

query_cache_size=512M
innodb_buffer_pool_size=1280M
innodb_log_file_size= 256M
innodb_log_files_in_group = 3
innodb_log_buffer_size = 32M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method=O_DIRECT

こんなかんじで、MySQLの設定かえましたが、たいしてスコアが伸びず。。

とりあえずMySQL5.5.22もソースからインストールしたんですが、

なぜかうまく動作せずといった感じでした。

次にやったのが、ファイルシステムまわりのチューニングです。

  • メモるの忘れたのでやった事だけ。
    • 書き込みバリアの使用を無効化。(barrier=0)
    • メタデータの非同期書き込みを許可。(data=writeback)
    • no journaling modeにする。

変更後はドキドキしながら、サーバの再起動をしました。

この時点でもたいしてスコアが伸びず。。。

途方にくれた感じで最後のやったのがtomcatの設定でした。

これまたgoogle先生に聞いてみると、

JAVA_OPTSとかCATALINA_OPTSとかあるみたいだけど、どこに設定すればいいかわからず。

とりあえず設定ファイルを色々みてたら、tomcat6.confってのに記述があるのを発見しました。

何設定したらいいかわかんなかったので、CATALINA_OPTSを設定してみました。

設定項目はこんな感じでした。
このあたりはよくわからずに設定してました。

CATALINA_OPTS="-server -Xmx1024M -Xms512M -Xss512k"

-server : サーバ用VMを起動
-Xmx    : ヒープ全体の最大値
-Xms    : ヒープ全体の最小値
-Xss    : スレッドスタックサイズ

あとは設定でログの出力をoffしました。

これでやっと50を超えるスコアがでるようになりました。

今回の反省点

  • もっときちんとデータをとってメモリのチューニングをするべきでした。
    • いまのメモリの使用量とかの把握がちゃんとできてなかったので、メモリの最適な値が設定できてませんでした。
  • アプリケーションの入れ替えをやらなかった事。
    • 動かなくなる事が怖かったので、入れ替えをやる勇気がありませんでした。
    • 今回はjava + tomcatといったさわった事のない環境で、挑戦しなったのが一番よくないと思ってるので、次回はどんどんチャレンジしていきます。

最後に

第三弾チューニンガソンを開催して頂いた、株式会社ゼロスタートの皆様本当に有難う御座いました。
リモートで福岡から参加させていただき、楽しく参加できました。

福岡でのサテライトを企画してくださった、@murajun さん、会場を提供していただいた、ギルドカフェ・コスタ様、有難う御座いました!
次回は是非優勝目指して頑張ります。

参加者の皆様お疲れ様でした!