Closed5
k6 + Echo + go-sqlite3 + Litestream + Linode Object Storage 簡易負荷試験メモ
注意
とっても雑な検証なので参考などにはしないでください。ちょっとした興味で自分用に調べてるだけです。
結論
Echo を利用した秒 1 万リクエストを超えないウェブサービスで、かつ SQLite の機能で要件がみたせるのであれば、SQLite + Litestream 十分と判断出来る結果だった。
利用技術
-
Load testing for engineering teams | Grafana k6
- Grafana に買収された Go で書かれた負荷試験ツール
- JS でシナリオが書ける
-
Litestream - Streaming SQLite Replication
- SQLite リアルタイムバックアップツール
-
mattn/go-sqlite3: sqlite3 driver for go using database/sql
- Litestream も使ってる
- 安心と信頼の mattn 印
-
Echo - High performance, minimalist Go web framework
- 高性能な Go ウェブフレームワーク
- 時雨堂がスポンサーしてる
-
クラウドコンピューティング&Linuxサーバー|Alternative toAWS |Linode
- Akamai に買収された格安クラウドサービス
- オブジェクトストレージは容量 250 GiB / 転送量 1 TiB で月 $ 5
検証サーバ
- Vultr のベアメタル
検証方針
- Litestream に HTTP 経由で負荷をかける
- ローカルホストが速度的には一番でるので負荷としてはちょうど良さそう
- 書き込みデータが小さい方が速度が稼げそう
k6 結果
$ k6 run --vus 500 --duration 30s script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
output: -
scenarios: (100.00%) 1 scenario, 500 max VUs, 1m0s max duration (incl. graceful stop):
* default: 500 looping VUs for 30s (gracefulStop: 30s)
running (0m30.4s), 000/500 VUs, 468703 complete and 0 interrupted iterations
default ✓ [======================================] 500 VUs 30s
data_received..................: 30 MB 987 kB/s
data_sent......................: 53 MB 1.8 MB/s
http_req_blocked...............: avg=27.84µs min=608ns med=1.1µs max=110.03ms p(90)=1.71µs p(95)=2.12µs
http_req_connecting............: avg=26.31µs min=0s med=0s max=109.95ms p(90)=0s p(95)=0s
http_req_duration..............: avg=31.98ms min=67.82µs med=1.25ms max=4.13s p(90)=78.47ms p(95)=128.8ms
{ expected_response:true }...: avg=31.98ms min=67.82µs med=1.25ms max=4.13s p(90)=78.47ms p(95)=128.8ms
http_req_failed................: 0.00% ✓ 0 ✗ 468703
http_req_receiving.............: avg=13.09µs min=3.9µs med=11.27µs max=16.04ms p(90)=16.74µs p(95)=19.75µs
http_req_sending...............: avg=8.59µs min=2.91µs med=5.33µs max=102.52ms p(90)=8.69µs p(95)=10.63µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=31.96ms min=56.21µs med=1.23ms max=4.13s p(90)=78.45ms p(95)=128.78ms
http_reqs......................: 468703 15424.053535/s
iteration_duration.............: avg=32.04ms min=89.14µs med=1.28ms max=4.13s p(90)=78.51ms p(95)=128.84ms
iterations.....................: 468703 15424.053535/s
vus............................: 500 min=500 max=500
vus_max........................: 500 min=500 max=500
30 秒で 468703 リクエスト。秒 15424 リクエスト処理できてる。
k6 script.js
シナリオはひたすら POST するだけ。
import http from 'k6/http';
export default function () {
http.post('http://127.0.0.1:3001/rpc/put-object');
}
top
spam は echo アプリ
echo
POST 時のデータとかは投げず、POST 受け取ったらハードコードされた小さな JSON データを雑に突っ込んでるだけ。
func (s *Server) rpcPutObject(c echo.Context) error {
_, err := s.db.Exec(`INSERT INTO t (json) VALUES ('{"age":10, "name":"yamada", "class":"A"}');`)
if err != nil {
zlog.Debug().Err(err).Send()
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
return c.NoContent(http.StatusNoContent)
}
テーブル
id と json (JSON 型) を利用。
CREATE TABLE t (
id INTEGER PRIMARY KEY AUTOINCREMENT,
json JSON
);
あまり知られていないが SQLite は JSON 拡張がある。
go.mod
go 1.18
require (
github.com/goccy/go-yaml v1.9.5
github.com/labstack/echo-contrib v0.12.0
github.com/labstack/echo/v4 v4.7.2
github.com/mattn/go-sqlite3 v1.14.12
github.com/rs/zerolog v1.26.1
github.com/shiguredo/lumberjack/v3 v3.0.0
)
select count でリクエスト数と同じ数、データが登録されてるか確認する
sqlite> select count(*) from t;
468703
litestream replicate
litestream replicate <db-name>.db s3://<bucket-name>.ap-south-1.linodeobjects.com/<db-name>
litestream restore
resotre で復元して、count の結果を見る。
$ litestream restore -o /tmp/<db-name>.db s3://<bucket-name>.ap-south-1.linodeobjects.com/<db-name>
2022/05/07 08:16:25.867966 restoring snapshot 8d3d3e5bf9b07a2a/0000000000000000 to /tmp/<db-name>.db.tmp
2022/05/07 08:16:27.778841 applied wal 8d3d3e5bf9b07a2a/0000000000000000 elapsed=877.987115ms
2022/05/07 08:16:27.939611 applied wal 8d3d3e5bf9b07a2a/0000000000000001 elapsed=160.757478ms
2022/05/07 08:16:28.063934 applied wal 8d3d3e5bf9b07a2a/0000000000000002 elapsed=124.314088ms
2022/05/07 08:16:28.178737 applied wal 8d3d3e5bf9b07a2a/0000000000000003 elapsed=114.791354ms
2022/05/07 08:16:28.313562 applied wal 8d3d3e5bf9b07a2a/0000000000000004 elapsed=134.813814ms
2022/05/07 08:16:28.437850 applied wal 8d3d3e5bf9b07a2a/0000000000000005 elapsed=124.2775ms
--- 中略 ---
2022/05/07 08:17:01.491100 applied wal 8d3d3e5bf9b07a2a/00000000000000c3 elapsed=177.082254ms
2022/05/07 08:17:01.797006 applied wal 8d3d3e5bf9b07a2a/00000000000000c4 elapsed=305.880661ms
2022/05/07 08:17:01.970052 applied wal 8d3d3e5bf9b07a2a/00000000000000c5 elapsed=173.035001ms
2022/05/07 08:17:02.143314 applied wal 8d3d3e5bf9b07a2a/00000000000000c6 elapsed=173.25345ms
2022/05/07 08:17:02.376112 applied wal 8d3d3e5bf9b07a2a/00000000000000c7 elapsed=232.789246ms
2022/05/07 08:17:02.550038 applied wal 8d3d3e5bf9b07a2a/00000000000000c8 elapsed=173.917538ms
2022/05/07 08:17:02.662462 applied wal 8d3d3e5bf9b07a2a/00000000000000c9 elapsed=112.415203ms
2022/05/07 08:17:02.665428 applied wal 8d3d3e5bf9b07a2a/00000000000000ca elapsed=2.95488ms
2022/05/07 08:17:02.665435 renaming database from temporary location
$ sqlite3 /tmp/<db-name>.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> select count(*) from t;
468703
このスクラップは2022/06/04にクローズされました