初めに
こんにちは id:o108minmin です。
サービスを運営しているとユーザーから「アプリがなんとなく重い」とフィードバックを受けることがありがちです。
今回はその付近を計測するとっかかりを紹介します。
基本編
今回の構成
- アプリケーションサーバー1台
- Ubuntu
- c-small
- クライアント1台
- 自宅
サーバー構築
自分の前回の記事と同じようにサーバーを構築します。
blog.clouddirect.jp.fujitsu.com
今回のファイアウォールは下記のように設定してください。
(IPアドレスは自宅のものを入力してください)
webアプリ構築
golang 1.20の標準ライブラリで最低限のアプリケーションを構築します。
(今回は簡単のため、接続元を制限した上でhttpで通信します。https化は各自で行ってください)
package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(http.StatusOK) fmt.Fprint(w, "{\"message\":\"ok\"}") }) httpServer := &http.Server{ Addr: ":8080", Handler: http.DefaultServeMux, } log.Printf("Run app %s ...\n", httpServer.Addr) log.Fatal(httpServer.ListenAndServe()) }
root@ubuntu:/home/root$ go run main.go
クライアント側構築
自宅のPCであれば何でも良いですが、今回はN100を搭載したミニPCを採用します。
先日購入しましたが、小型で安価の割に高性能で楽しいです。
今回はOSをUbuntuに入れ替えて使用します。
- Trigkey G5
- インテル®プロセッサー N100
- 16GB DDR5 4800MHz
- Ubuntu 22.04
package main import ( "fmt" "net/http" "os" "time" ) func main() { file, _ := os.OpenFile("res.csv", os.O_WRONLY|os.O_APPEND, 0666) defer file.Close() tic := time.Now() req() toc := time.Now() print(toc.Sub(tic)) fmt.Fprintln(file, tic.Format(time.RFC3339), ",", toc.Sub(tic).Microseconds()) //書き込み time.Sleep(5 * time.Second) } func req() { url := "http://{ニフクラのサーバーのIPアドレス}:8080" // 改善点: エラー処理を追加する resp, _ := http.Get(url) resp.Body.Close() }
一定時間毎にリクエストするため、シェルスクリプトを利用します。
#!/bin/sh for i in `seq 0 39` do go run main.go & sleep 5 done
計測
touch res.csv sh stat.sh
可視化
今回は簡単のためexcelでそれっぽく表示します。
こんな感じで見えますが、今回は特に意味のあるデータにはなりません。
わざと壊してみる
HandleFuncに細工をして、意図的に遅延させてみます。
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // 毎時39分付近だけ遅延させる if time.Now().Minute() == 39 { time.Sleep(3 * time.Second) } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(http.StatusOK) fmt.Fprint(w, "{\"message\":\"ok\"}") })
可視化するとこんな感じです。意図的に遅延させた39分付近だけおかしくなっていることが一目でわかります。
今回は意図的におかしくしたアプリなのでわかりましたが、本来は複数の要素が複雑に絡みあうので今回のような簡易な測定でわかることは稀です。
発展編
これだけでは「アプリがなんとなく重い」の解析としてはまったく足りないので、発展編として下記を用意しました。
サーバー側:トレーシング導入
対象webアプリのソースコードを変更できるようであればトレーシングを導入する方が詳細なプロファイリングが可能です。
opentracingなどを参考にトレーシングを導入すればアプリ内部のボトルネックを可視化でき、多角的な視点で分析することができます。
クライアント側:elasticを利用し、恒常的に記録、可視化する
今回のプログラムはcsvファイルが肥大化し続けるため、恒常的に動かすには全く向いていません。
恒常的に動かすためにはelasticなどの基盤を利用すると良いです。
注意: この紹介はelastic社の公式情報ではありません。elastic社から承認されておらず、elastic社とは関係ありません。
複数環境で計測する
複数のロケーション、時間帯、回線経由で測定したときの違いを比較したときの挙動を比較すると傾向が見えてくるかもしれません。
- モバイル回線
- ニフクラの他のインスタンス
- 他社クラウド・他社VPS
- アプリケーションが動いているサーバー
最後に
今回はすぐできる簡単な計測と可視化を実施しました。
ネットワークが絡むアプリのボトルネックの調査は一朝一夕で行かないことが多いので根気強くやっていきましょう。