よろしくお願いします。今日はGoの紹介と負荷試験の話をします。
今日のスライドは大体AIが作ったんですが、AI臭をなくすため全ての太字を削除しています(笑)
全体はレビューしていますが妙な点があれば教えてください。
SmartHRでプロダクトエンジニアをしています。バックエンド本職の期間は短めですが、GoとRailsは業務で触ってきました。
(10秒)
TODO: 公開されたら更新
ちょっと宣伝です。福岡でゆるいAI勉強会をやってます。興味あればぜひ。
(10秒)
前半はGoの紹介を軽めに5分、後半は負荷試験の実践的な話を10分です。詳細はスライドを後で見てもらえれば。
(15秒)
先に断っておくと、自分の経験はRailsとGoなのでその2つの比較になります。だいぶ過去の話も含むのでご了承ください。
(15秒)
GoはGoogleが作った言語で、とにかくシンプルです。クラスも例外もない。ビルドが速くてワンバイナリになる。そしてGoroutineという軽量スレッドが言語組み込みです。
(30秒)
これが典型的なGoのコードです。例外を投げるんじゃなくて、戻り値でerrorを返す。if err != nilのパターンはGoを書いてると何百回も書きます。詳しくはスライドを見てください。
(20秒)
goというキーワードで関数を別スレッドとして起動、chanで値を受け渡す。並行処理がこんなに簡単に書ける。これがGoの大きな特徴です。
(20秒)
標準ライブラリだけでHTTPサーバもJSONも画像処理も書ける。Go自体がフレームワークみたいなもんです。
(15秒)
バックエンドで使うと、Railsみたいに全部入りのフレームワークじゃなくて、自分たちで設計する文化が強い。でも非同期処理やシャーディングみたいな踏み込んだことをやるときは、むしろGoの方が作り込みやすい。
(25秒)
一方Railsは全部揃った状態でスタートできる。どっちが上とかじゃなくドメインとの相性の問題です。
(15秒)
まとめると、Goはシンプルで並行処理に強い。設計する気持ちがあればすごくいい言語です。前半はこんなところで。
(15秒)
さて、ここからが本題の負荷試験の話です。
(5秒)
また言い訳なんですが、負荷試験もここ2年ぐらいの経験なので、試行錯誤中の話として聞いてください。
(10秒)
なぜ負荷試験をするかというと、繁忙期を乗り切れるか知りたいからです。人事労務SaaSだと五十日や年末調整がピーク。障害になってから直すのでは信頼を損ねます。
(20秒)
スコープとしては、毎回「何を確認するか」を絞ります。DBのスペックなのか台数なのか、AパターンBパターンで比較したり、ベスト設定でのrpsを測ったりします。
(20秒)
負荷試験、Goとかなら小さいものなら自前でも書けるんですが、まあフレームワークに乗った方がいいです。有名どころとしてLocustとk6を紹介します。
(10秒)
LocustはPythonでシナリオを書く。うちのチームで使ってます。マルチワーカーがやりやすいのがメリット。デメリットは若干色々な動作が重い印象なのと、分析が弱めなところ。
(15秒)
こんな感じでPythonのクラスでシナリオを書きます。taskデコレータの数字がリクエストの割合。シンプルですね。
(10秒)
もう一つがk6。JSでシナリオを書けて、Go製なので速い。分析基盤との連携もしやすいらしい。正直k6の方がいいかもと思いつつ、既存資産があるので移行は後回しです。
(15秒)
k6のシナリオはこんな感じ。vusが仮想ユーザー数で、default関数が1ユーザーの振る舞い。
(10秒)
hey, wrk, abのようなコマンド一発でシュッと試験できるやつも使ってたりします。特徴は書いてあるとおり。
補足ですが、仮想ユーザーっていうのはロボットみたいなもので、シナリオ通りに動いて、待ち時間を挟んで、ループする。これが基本の動きです。さっきの関数の一巡が1ユーザー。
(15秒)
ここで一つデモ的な構成を紹介します。サーバはGoのechoでTODOアプリ、クライアントはk6でCRUDを回す。
(10秒)
サーバ側はこんな感じでechoでルーティングを定義するだけ。実装はシンプルなCRUDです。コードは公開するので後で見てください。
(10秒)
k6側はこんな感じ。50VUが2分間、それぞれ独立してCRUDを回します。__VUと__ITERでユーザーごとにデータが分かれる。最後のsleepがThink Timeですね。
(20秒)
ここからは実際のサービスでどうやっているかの話です。
(5秒)
全体の流れはこの6ステップです。最後のネクストアクションの割り出しが一番大事。順番に見ていきます。
(10秒)
まず計画。前回やれてないことの確認と、今回のスコープを絞る。全部一気に変えると何が効いたかわからなくなるので、1〜2個に絞ります。
(15秒)
シナリオは実トラフィックベースです。ピーク日のリクエストをLog AnalyticsやBigQueryで抽出して、パスごとの割合を出して、それに合うようにシナリオを調整します。
(20秒)
下準備として、ワーカ数やDBスペックの変更、データ投入など。手順書にしておくのが大事です。
(10秒)
以前は共用環境だったので調整が大変でしたが、今は専用環境を用意してシュッとできるようにしました。ただ外部サービスとの連携があるとまだ調整が必要で、ここは改善したい。
(15秒)
実施は計画通りにやるだけ。大事なのはメトリックの保存を忘れないこと。終わったあと取り直せないので。この辺りもあまりに人間業なので、k6だとうまくやれるんですかねえ。
(10秒)
分析はレイテンシの分布、中央値や90パーセンタイルを見る。rpsが安定しているか。ユーザシナリオが最後まで回ったか。APMでどの処理がボトルネックかを確認します。
(20秒)
ここが一番大事なパートです。最大のボトルネックを特定する。アプリケーション側の例をまず上げましょう。N+1ならアプリ改善、read heavyならレプリカやキャッシュ、CPUバウンドなら台数を増やしてrpsの伸びを見る。
(20秒)
一方システム全体で見ると、DB側はmasterのCPUが上がりすぎてないか、レプリカに寄せられないか。Webアプリ側はCPU利用率やスケールアウトのスムーズさを確認します。
(15秒)
まとめると、とはいえ、ネクストアクションにはアプリの課題が出がちなんです。問題になるエンドポイントは実はそんなに多くない。だからこそドメインに詳しいバックエンドエンジニアが対応した方がスピードが上がる。
(20秒)
ということで、負荷試験はバックエンドエンジニアも詳しい方がいいと思っていて、今回はその入り口として紹介しました。興味があればぜひ自分のチームでも主導してみてください。ありがとうございました。
(15秒)