strace for Perl Mongers

65
strace for Perl Mongers zentooo @ DeNA

description

YAPC::Asia 2014の発表スライドです。

Transcript of strace for Perl Mongers

Page 1: strace for Perl Mongers

strace for PerlMongers

zentooo @ DeNA

Page 2: strace for Perl Mongers

自己紹介

Page 3: strace for Perl Mongers

@zentoo or @zentooo

Page 4: strace for Perl Mongers

「愛と勇気と缶ビール」

Page 5: strace for Perl Mongers

モバゲーオープンプラットフォーム

Page 6: strace for Perl Mongers

元・落語研究部

Page 7: strace for Perl Mongers

※トークにオチはありません

Page 8: strace for Perl Mongers

straceとはプロセス内で発行されているシステムコールをtraceするため

のツール

Page 9: strace for Perl Mongers

その前に、システムコールって何よ?

Page 10: strace for Perl Mongers

システムコールは、アプリケーションが叩くOSの "API"

File I/O (open, lseek, write, read, close)Network (socket, bind, listen, accept, connect)Memory (brk, sbrk, mmap)Process (fork, wait, kill)Thread (pthread_create)

Page 11: strace for Perl Mongers

システムコールを経由せずPerlでファイルI/Oできるか?

Page 12: strace for Perl Mongers

システムコール抜きでPerlで新しいプロセスを作れるか?

Page 13: strace for Perl Mongers

システムコール抜きでPerlでネットワークプログラミングが出来るか?

Page 14: strace for Perl Mongers

アプリケーションはOSの手の平の上

Page 15: strace for Perl Mongers

突然ですが

Page 16: strace for Perl Mongers

Q. Webアプリケーションの仕事って何よ?

Page 17: strace for Perl Mongers

A. HTTPリクエストを受けてHTTPレスポンスを返すことだ

よ!

Page 18: strace for Perl Mongers

Q. HTTPリクエストを受けてHTTPレスポンスを返すってど

ういうことだよ!

Page 19: strace for Perl Mongers

A. acceptしてreadしてwriteしてcloseだよバカヤロー!

Page 20: strace for Perl Mongers

まあ落ち着け

Page 21: strace for Perl Mongers

Webアプリのお仕事1. HTTPリクエストを受ける2. <この間に僕らのドラマがある>

MySQLへのアクセスmemcachedへのアクセス(データの整形、logの書き込みetc)

3. </この間に僕らのドラマがある>4. HTTPレスポンスを返す

Page 22: strace for Perl Mongers

システムコール語に翻訳すると...1. int fd = accept(...); // リクエスト受けて2. read(fd, ...);   // リクエストの内容読んで3. <この間に僕らのドラマがある>

socket, connect, write, read, closeopen, write, read, close

4. </この間に僕らのドラマがある>5. write(fd, ...);   // レスポンス返す

Page 23: strace for Perl Mongers

さらに省略すると1. int fd = accept(...); // リクエスト受けて2. read(fd, ...);   // リクエストの内容読んで3. <僕らのドラマ />4. write(fd, ...);   // レスポンス返す

Page 24: strace for Perl Mongers

DEMO #1 - just to strace

Page 25: strace for Perl Mongers

straceを読む時のキホン (1)↓システムコール名 返り値↓read(5, "GET / HTTP/1.0\r\nHost: xxx-xxxxxx"..., 131072) = 308 ↑引数(バッファなどの場合はよしなに展開される)

Page 26: strace for Perl Mongers

straceを読む時のキホン (2)fd (ファイルディスクリプタ) に注目する

↓コレread(5, "GET / HTTP/1.0\r\nHost: xxx-xxxxxx"..., 131072) = 308

Page 27: strace for Perl Mongers

fd (ファイルディスクリプタ)ファイルやネットワークソケットなどを抽象化した構造体へのポインタ(0, 1, 2) = (stdin, stdout, stderr)それ以降は昇順に振られる

Page 28: strace for Perl Mongers

fd with fileint fd = open("/tmp/yapc2014", ...);read(fd, buffer);write(fd, buffer);close(fd);

Page 29: strace for Perl Mongers

fd with client socketint fd = socket();connect(fd, addr, ...);read(fd, buffer);write(fd, buffer);close(fd);

Page 30: strace for Perl Mongers

fdを追うのが捜査の基本ファイルの生存期間

openで返ってきたfdがcloseに渡されるまでクライアントサイドでのソケットの生存期間

socketで返ってきたfdがcloseに渡されるまでサーバサイドにおけるクライアントソケットの生存期間

acceptで返ってきたfdがcloseに渡されるまで

Page 31: strace for Perl Mongers

Webアプリのstraceを読む時のキホン// こっからaccept(4, {sa_family=AF_INET, ...)}, [16]) = 5(中略)read(5, "GET / HTTP/1.0\r\nHost: xxx-xxxxxx"..., 131072) = 308(中略)write(5, "HTTP/1.1 200 OK\r\nDate: Sun, 10 A"..., 2218) = 2218// ここまでが一つのリクエスト/レスポンス// keepaliveしてないならここで close

Page 32: strace for Perl Mongers

DEMO #2 - strace web app

Page 33: strace for Perl Mongers

あくまで基本なので例外もTwiggy, Twiggy::Preforkなどevent-drivenなサーバ(epoll_wait)multi socket listenしてる時のStarlet (select)

Page 34: strace for Perl Mongers

Webアプリのお仕事(再掲)だいたいの場合 赤字の部分 で問題になる

HTTPリクエストを受ける<この間に僕らのドラマがある>

MySQLへのアクセスmemcachedへのアクセス(データの整形、logの書き込みetc)

</この間に僕らのドラマがある>HTTPレスポンスを返す

Page 35: strace for Perl Mongers

注目ポイント - MySQLsocket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 10fcntl(10, F_SETFL, O_RDONLY) = 0fcntl(10, F_GETFL) = 0x2 (flags O_RDWR)fcntl(10, F_GETFL) = 0x2 (flags O_RDWR)fcntl(10, F_SETFL, O_RDWR|O_NONBLOCK) = 0connect(10, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.1"fcntl(10, F_SETFL, O_RDWR) = 0poll([{fd=10, events=POLLIN|POLLPRI}], 1, 4000) = 1 ([{fd=10, revents=POLLIN}setsockopt(10, SOL_SOCKET, SO_RCVTIMEO, "\2003\341\1\0\0\0\0\0\0\0\0\0\0\0\0"setsockopt(10, SOL_SOCKET, SO_SNDTIMEO, "\2003\341\1\0\0\0\0\0\0\0\0\0\0\0\0"setsockopt(10, SOL_IP, IP_TOS, [8], 4) = 0setsockopt(10, SOL_TCP, TCP_NODELAY, [1], 4) = 0setsockopt(10, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0

Page 36: strace for Perl Mongers

注目ポイント - memcachedsocket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 8fcntl(8, F_GETFL) = 0x2 (flags O_RDWR)fcntl(8, F_SETFL, O_RDWR|O_NONBLOCK) = 0connect(8, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("10.0.0.1"poll([{fd=8, events=POLLOUT}], 1, 250) = 1 ([{fd=8, revents=POLLOUT}])getsockopt(8, SOL_SOCKET, SO_ERROR, [-511598409602301952], [4]) = 0setsockopt(8, SOL_TCP, TCP_NODELAY, [1], 4) = 0sendmsg(8, {msg_name(0)=NULL, msg_iov(6)=[{"set", 3}, {" csrf_token:", 20}, read(8, 0x59f9f50, 1536) = -1 EAGAIN (Resource temporarily unavailable)poll([{fd=8, events=POLLIN}], 1, 300) = 1 ([{fd=8, revents=POLLIN}])read(8, "STORED\r\n", 1536)

Page 37: strace for Perl Mongers

DEMO #3 - strace web appwith DB and memcached

Page 38: strace for Perl Mongers

プログラムは思ったとおりに動かない

同じクエリを複数回発射してる思ってたよりcache missしてる無駄にretryしてるTCP Connection使いまわせてないTCP Connectionちゃんと切れてない

Page 39: strace for Perl Mongers

実例 #1 - memcached retryproblem

Page 40: strace for Perl Mongers

+180msとあるAPIのレスポンスが、リリース後に約180ms劣化50ms or dieなら4回くらい死なないといけないレベル

Page 41: strace for Perl Mongers

容疑者Cache::Memcached::Fastのラッパーモジュール

(更新差分があったので)

Page 42: strace for Perl Mongers

家宅捜索strace -p $pid -e 'trace=sendmsg'

(Cache::Memcached::Fastがsendmsgを使うのは知っていた)

Page 43: strace for Perl Mongers

物証sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 13}sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 13}sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 13}sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 13}sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote1:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote1:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote1:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote1:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote2:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote2:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote2:", sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_remote2:",

Page 44: strace for Perl Mongers

ネタばらしラッパーモジュールにretry機能 (maxで3回) が入っていたCache::Memcached::Fastのgetはcache missとその他のエラーを区別できないcache missの度に3回retryしてた

retry間隔は20msec20 msec × 3 (retry) × 3 = 180 msec

そのhit rateはどうなん?という話はありつつもget系はretryしない修正を入れて解決

Page 45: strace for Perl Mongers

物証 - with timestamp22:45:34.517703 sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 22:45:34.537967 sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 22:45:34.558936 sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 22:45:34.579275 sendmsg(6, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, {" cache_local:", 22:45:34.587428 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:34.608296 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:34.628673 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:34.649146 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:35.135129 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:35.155516 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:35.176027 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3}, 22:45:35.196453 sendmsg(11, {msg_name(0)=NULL, msg_iov(4)=[{"get", 3},

Page 46: strace for Perl Mongers

straceしてみると一目瞭然嘘をつかないツールに頼る

Page 47: strace for Perl Mongers

嘘をつかないツールstracetcpdumpgdb

Page 48: strace for Perl Mongers

嘘をつくもの人の記憶アプリのログ時にはアプリのコード

Page 49: strace for Perl Mongers

実例 #2 - accept(2)thundering herd

Page 50: strace for Perl Mongers

What is thundering herd"The thundering herd problem occurs when a largenumber of processes waiting for an event are awokenwhen that event occurs, but only one process is able toproceed at a time." - Wikipedia多くのプロセスが特定のトリガーで同時に動き出すが、実際の処理は一個のプロセスでしか行われない (または行われるべき) 時にリソースが無駄になる問題よくあるのはデータのremote cacheがexpireした時に一気にDBへのクエリが走る、とか

Page 51: strace for Perl Mongers

accept(2) and prefork server複数プロセスが同時に一つのsocket fdをacceptし、それぞれブロックLinux kernelがよしなにqueueingしてくれるので、リクエストが来た時に起き上がるプロセスは一つだけ

(参考)http://d.hatena.ne.jp/naoya/20070311/1173629378

Page 52: strace for Perl Mongers

accept(2) and event-driven/multi-process server複数プロセスが同時に一つのsocket fdをepoll_waitで監視listen socketがread可能 = acceptが可能になった時点でepoll_waitしてる全てのプロセスが起き上がる一つのプロセスがacceptに成功他のプロセスは空振って失敗 (EAGAIN)

Page 53: strace for Perl Mongers

accept(2) thundering herdaccept(2)の空振りがプロセス数とリクエスト数の掛け算で発生

loadが上がるvmstatで見ると...

usとsyとcsの値が盛り上がる (50, 50, 100000とか)プロセス間のcontext switch増えすぎが起因かと思われる

Page 54: strace for Perl Mongers

DEMO #3 - EAGAIN and againand again

Page 55: strace for Perl Mongers

解決策そもそもがevent-drivenなんだしそんなに大量にプロセスあげなくていいよね深淵な理由により100プロセスくらいに (前は300くらいあった)

Page 56: strace for Perl Mongers

余談現状のアーキテクチャだと割とどうしようもない気がしている

Monocerosみたいにacceptするプロセスとリクエストを処理するプロセスを完全に分けるとか?

event-drivenとマルチプロセスは食い合せが悪い with PerlIO::AIO (AnyEvent::IOのbackend) とかも割とシングルプロセス前提な実装だったり...

Page 57: strace for Perl Mongers

まとめに入ります

Page 58: strace for Perl Mongers

straceのわるいところムダな情報がおおい (慣れればどうにでもなるが)たまに起こる系の事象には向いてない (Devel::KYTProfとかでログ出した方がよい?)

Page 59: strace for Perl Mongers

straceのよいところ事前設定が不要で、プロセスにattachするだけですぐ見れるWebアプリケーションの気持ちが分かる

Page 60: strace for Perl Mongers

straceだと分からないことシステムコールを伴わない純CPUバウンドな無駄な処理アプリケーションでの無駄loop, deep recursion効率の悪いアルゴリズムとか-d NYTProf

トランスポート層以下での問題tcpdumpとかtsharkとかngrepとか使いましょう

Page 61: strace for Perl Mongers

straceで分かることリクエスト受けて、レスポンス返すまでのフローデータアクセスの実態実際に何回memcachedからgetしてるか、何回DBみにいってるか実際にcacheされているdata実際に発行しているSELECT文

その他、開発者の予期していない挙動

Page 62: strace for Perl Mongers

結び当たり前だけどstraceは万能のツールじゃない使えば明日から捗るとかそんなこともないでも、使い方が分かっていればお手軽・強力Webアプリの気持ちが分かる

Page 63: strace for Perl Mongers

参考文献

安いし、電子書籍版(英語しかないけど...)おすすめ日本語版もあるけど1000ページ超、つまり書籍ではなく武器全部読む必要なし、リファレンスとしても便利

↑の本はおすすめだけど、突然読むのは敷居が高いのでとかの方が最初はいいかもし

れない

The Linux Programing Interface

ふつうのLinuxプログラミング

Page 64: strace for Perl Mongers

宣伝 (?)Web+DBの2014年10月号に記事(Perl Hackers Hub)を書かせ

て頂くことになりました

Page 65: strace for Perl Mongers

ご静聴ありがとうございました