- 作者: 馬場マコト,土屋洋
- 出版社/メーカー: 日経BP社
- 発売日: 2017/12/19
- メディア: 単行本
- この商品を含むブログを見る
年の瀬になぜこれをたまたまKindleで買ったのか分からない。けど夢中になって一気に読破してしまった。 江副氏との接点が1つだけあって、東京大学新聞OBだということだ。ぼくも大学新聞の営業を少ししていたので親近感を持って読んだ。
自ら機会を創り出し、機会によって自らを変えよ
江副氏自身の著書も読みたくなった。
Who Gets What (フー・ゲッツ・ホワット) ―マッチメイキングとマーケットデザインの新しい経済学
マッチメイキングとマーケットデザインについて。
この分野がとてもいいと思うのは、ゼロサム・ゲームでないところ。仕事の多くは、何らかの資源の取り合いであることが多くて、競争を通じて市場や付加価値が拡大することはもちろんあるにせよ、競争が激しすぎて消耗していると感じることもある。
マッチメイキングは、その市場の作り方を工夫しようというもの。
腎臓交換、就職、学校選択、など必ずしもお金がやりとりされないものについても、何らかの取引を行う市場といえ、適切なデザインによって取引が改善する余地がある。
ゲーム理論をもう一度おさらいしたくなった。
GKEで走るScalaアプリのチューニングをjvisualvmでやったので手法をあとで振り返れるようにメモしておく。
要件としては、所与のマシンスペック・台数の範囲内で、スループットを最大化したいというもの。 さらに、RTBなので、安定した高速なレスポンス速度が求められる。具体的には1レスポンス20msecくらい。そのレスポンス速度自体はすでに達成できているので、それを崩さずに、スループットを上げる必要があった。
チューニングは、locust で負荷をかけながら行った。はじめはローカル環境からlocustを起動していたが、ある程度以上の負荷をかけようと思うと、ローカルからだとネットワークやCPUがボトルネックになってかけられない。そこでGCEでインスタンスを作って、そこからlocustを起動した。
locustは簡単にマスター・スレーブ構成のクラスタを作ることができる。もちろん、複数のインスタンスでクラスタを組んでもいいが、マルチコアのインスタンスを1つ起動して、その中で複数のスレーブを起動する形でもいい。
locust --host=[負荷をかけるURL] --master
locust --host=[負荷をかけるURL] --slave --master-host=127.0.0.1 &
この状態で、負荷をかけたまま、コンテナに kubectl exec -it
でログインして、
ss -ta
でコネクションをみるtop
でCPUの使用率やロードアベレージをみるをみて概況を掴んだ。
その後、 kubectl port-foward
してコンテナのJMXをローカルにポートフォーワードして、jvisualvmを起動した。
jvisualvmは高機能なツールで、これ1つで稼働中のアプリのjvmに関する多くの情報が得られる。今回使ったのは、
スレッドダンプはボタン1つでとれる。各スレッドのスタックトレースをみていき、各スレッドがどのように使われているか、ロックしているスレッドがないかを調べる。例えば
"pool-11-thread-231" - Thread t@1001 java.lang.Thread.State: WAITING at sun.misc.Unsafe.park(Native Method) - waiting to lock <2ffa4815> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "pool-11-thread-215" t@984 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at ch.qos.logback.core.OutputStreamAppender.writeBytes(OutputStreamAppender.java:197) at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:231) at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:102)
これはlogbackのログ出力だが実行がロックされていて、その先の pool-11-thread-215
をみると、ファイルIOを待っていることがわかる。
今回の場合は不要なログ出力だったので、それをしなくするようにした。
CPUサンプリングをすると、CPUを使っているホットスポットのメソッドを特定できる。
「セルフ・タイム(CPU)」のほうをみるのがポイント。これが実際にCPUを消費しているメソッドになるので、これをなんとかすることが、スループットを上げるためには必要になる。 今回は、この箇所から無駄な処理やIOを特定し、減らすということをした。
CPUサンプルのスナップショットをとれば、さらに呼び出しの経路とかスタックを細かく見ることができる。
参考
トランザクションまわりの挙動を調べるため。デバッグ用途なので、プロダクションで動かす想定は不要。
Logging | Django documentation | Django https://docs.djangoproject.com/en/1.8/topics/logging/
Django ORM の SQL を出力する方法まとめ - akiyoko blog http://akiyoko.hatenablog.jp/entry/2016/08/04/232531#%EF%BC%97settingspy-%E3%81%AE-LOGGING-%E3%82%92%E8%A8%AD%E5%AE%9A
DjangoでSQLログを出力したい - Qiita https://qiita.com/ariarijp/items/f6bfe69bd42896571eda
あとでやってみる。
今回のケースでいうと、Kubernetes内のPodにローカルからJMXにつないでjvisualvmを使ってチューニングすることが多かったのだが、下記の記事でやったように127.0.0.1のホスト指定が使えないケースが出てきてしまった。
-Djava.rmi.server.hostname=127.0.0.1
の設定を抜いてしまうと、そのままではつなぐことができなくなってしまう。というのは、Kubernetesのport-fowardコマンドは、127.0.0.1にBindする仕様のため(2017/12/14時点)。
Pull Requestも上がっているが、マージできない状況になってしまっている。
なんとかならないかと考えていたら、ポートフォワードすることによって解決できた。
echo "rdr pass inet proto tcp from any to any port 7000 -> 127.0.0.1 port 7000" | sudo pfctl -ef -
上記の設定は、7000番ポートにきたパケットを全て127.0.0.1:7000に送る。
ᐅ sudo pfctl -s nat (yamada/default) No ALTQ support in kernel ALTQ related functions disabled rdr pass inet proto tcp from any to any port = 7900 -> 127.0.0.1 port 7900
これによって、kubectl port-forwardでした際に、これまで通りjvisualvmにつなぐことができた。
元に戻すときは、
sudo pfctl -F all -f /etc/pf.conf
参考:
基本的にはここの通り。
Kubernetesの中で動くPodにJMXでつないで様子をみたいときがある。 そういうときは、まずPod名を調べて、kubectlコマンドでポートフォーワードして、jvisualvmなどのコマンドを使えばOK。 例えばJMXが7000番ポートで受け付ける場合は、
kubectl get pods
でPod名を調べ、
kubectl port-forward [Pod名] 7000
とすると、
Forwarding from 127.0.0.1:7900 -> 7900 Handling connection for 7900
このようにポートフォワーディングが始まるので、あとはjconsoleなり、jvisualvmなりでつなげる。 例えばjvisualvmでつなぐ場合は、下記のように設定する。
いろいろな情報を見るにはGUIがやっぱり便利。