Closed5

k6 + Echo + go-sqlite3 + Litestream + Linode Object Storage 簡易負荷試験メモ

voluntasvoluntas

注意

とっても雑な検証なので参考などにはしないでください。ちょっとした興味で自分用に調べてるだけです。

結論

Echo を利用した秒 1 万リクエストを超えないウェブサービスで、かつ SQLite の機能で要件がみたせるのであれば、SQLite + Litestream 十分と判断出来る結果だった。

利用技術

検証サーバ

  • 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 アプリ

Image from Gyazo

voluntasvoluntas

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 拡張がある。

JSON Functions And Operators

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
)
voluntasvoluntas

select count でリクエスト数と同じ数、データが登録されてるか確認する

sqlite> select count(*) from t;
468703
voluntasvoluntas

litestream replicate

litestream replicate <db-name>.db s3://<bucket-name>.ap-south-1.linodeobjects.com/<db-name>
voluntasvoluntas

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にクローズされました