demitas2
demitasでシェルスクリプトを使っていた部分がつらくなってきたので、Goで書き直したもの。
ssocreds
AWS SSOの一時的なクレデンシャルを出力するやつ。
poslog
posgresql.log
をパースしてNDJSONで出力するやつ。
RDS(PostgreSQL)でクエリログをON(log_statement=all
)・OFF(log_statement=none
)、さらにexportしたときの性能の変化が気になったので、pgbenchで負荷テストを行ってみた。
EC2のc5.xlargeインスタンスから実行
以下のようなスクリプトを実行
#!/bin/bash echo "$(date +%FT%TZ): start" for i in 64 128 192 256; do echo "$(date +%FT%TZ): $i" pgbench -q -i -s 100 sleep 10 pgbench -c $i -T 180 if [ $i -ne 256 ]; then sleep 60 fi done echo "$(date +%FT%TZ): end"
log_statement
だけ変更
MySQLでpgbenchと同じようなTPC-B likeなテストを実行するツールを書いた。
pgbenchと同様のtcpb-likeなテストを実行する負荷テストツール。
pgbenchとだいたい同じSQLが実行されると思うが、TPC-Bの仕様をきちんと満たしているかは不明。
先日の記事でMySQLでの同様のテストを行った場合の結果が気になったので作成してみた。 初期データの投入が遅かったりバグがなにかありそうだけれど、とりあえず簡単なテストではうまく動いた。
READMEにあるとおりで、pgbenchと似たような感じで使える。
$ qb -d root@/ -i -s 10 dropping old database... creating database... creating tables... generating data... analyzing tables... $ qb -d root@/ -n 10 01:00 | 10 agents / run 2603958 queries (2559 tps) { "DSN": "root@/", "StartedAt": "2022-05-08T17:36:46.173678+09:00", "FinishedAt": "2022-05-08T17:37:46.177411+09:00", "ElapsedTime": 60, "NAgents": 10, …
PostgreSQLとMySQLのきちんとした性能の比較にはならないが、同様のテストを両方で実行したい向きには手軽だと思う。
かるーくMySQLエンジンでAuroraとRDSの比較を行ったが、PostgreSQLほど性能に差異がない感じだった。 追記型アーキテクチャはAuroraと相性悪いのかなぁ…よくわからない。
PostgreSQLエンジンでAuroraとRDSでpgbenchを使った負荷テストを行った。
#!/bin/bash . .rds for i in 8 16 32 48 64; do echo "--- $(date +%FT%TZ) RDS $i" pgbench -i -s 100 -q pgbench -c $i -T 210 sleep 60 done echo "--- $(date +%FT%TZ) RDS end"
RDSがSingle-AZだったのでMulti-AZで追試。
MySQLエンジンでTPC-B(tpcb-like)を軽く検証したので、結果を張っておく。
※ツールが違うのでPostgreSQLエンジンの値とは直接比較できない点に注意のこと
ヒューマンリーダブルなURLでesa.ioの記事を開くやつを作った。
http://your-esaop.example.com/foo/bar/zoo
のような感じの記事のパスを指定したURLを開くと esa.io の https://[team].esa.io/posts/12345
というURLにリダイレクトするWebアプリ。
記事が存在しなかったときは、新規作成画面になる。
https://[team].esa.io/posts/posts/new?category_path=%2Ffoo%2Fbar%2Fzoo
また、末尾が /
だとカテゴリ内の記事の一覧のURLにリダイレクトする。
http://your-esaop.example.com/foo/
→ https://[team].esa.io/#path=%2Ffoo
要OAuthのアプリケーション登録。 cf. https://docs.esa.io/posts/185
Javaの日付フォーマットとCRON式を使ったプレースホルダも使える。
例えばアクセスした日が 2022/03/21
だとして、以下のように記事を開く。
http://your-esaop.example.com/日誌/${yyyy/MM/dd}
→ 日誌/2022/03/21
を開くhttp://your-esaop.example.com/週次MTG/${*,*,*,*,5|yyyy/MM/dd}
→ 週次MTG/2022/03/25
を開くapt-transport-s3をGoに移植してapt-transport-s3-goを作った。
aptのリポジトリとしてS3を利用できるようにするやつ。 すでにapt-transport-s3が存在しているのだがあまりメンテナンスされている様子がなく、またpythonやpython-configobjに依存しているのでコンテナから使いづらい。ECSのタスクロールにも対応してなさそう。
あと作ってから気がついたがapt-golang-s3というのもあるが、こちらはソースコードからのインストールがやや手間そう。apt-transport-s3同様にECSのタスクロールに対応していなさそう。
という感じで主に
にS3を利用するために作成した。
※なおS3のバケットに置くリポジトリのファイルはaptlyなどで作成する必要がある*1
まずS3のリージョンを設定する。
echo 'Acquire::s3::region ap-northeast-1;' > /etc/apt/apt.conf.d/s3 # リージョンはURIに組み込みたかったが良い文法が思いつかなかった
それからsources.listを作成する。
echo 'deb s3://my-bucket/repo/ xenial main' > /etc/apt/sources.list.d/s3.list
これであとはapt update
apt install
すればS3からパッケージをインストールできる。
なお、LoadDefaultConfig以外でのクレデンシャルのロードは、現状やっていない。
APT Method Interfaceというaptコマンド?とapt transport?とのインタフェースの仕様があって、これに従ったプロトコルでapt↔apt transportでメッセージをやりとりする。
標準入出力でやりとりする HTTP/1 みたいなテキストのプロトコルで、標準入力から
601 Configuration Config-Item: Acquire::http::Proxy=http://example.com
というメッセージを受け取ったら設定を行い
600 URI Acquire URI: s3://example.com/key Filename:Packages.downloaded
というメッセージを受け取ったらを行い、最後に
201 URI Done URI: s3://example.com/key Filename:Packages.downloaded
というメッセージを返すというなかシンプルなプロトコルでわかりやすかった。
*1:www.aptly.infoが落ちている…(2022/02/26現在)リリースも滞っている感じ
Goのスタックトレース事情については、以下を参照のこと。
現状では標準ライブラリにスタックトレースが実装されていないので、とりあえずpkg/errorsを使っている*1が、スタックトレースの表示がめちゃくちゃ見にくい。
package main import ( "fmt" "os" "github.com/pkg/errors" ) func main() { err := f1() fmt.Printf("%+v", err) } func f1() error { return errors.Wrap(f2(), "from f1()") } func f2() error { return errors.Wrap(f3(), "from f2()") } func f3() error { _, err := os.Open("not_found") return errors.Wrap(err, "from f3()") }
なのでもう少しきれいに表示するライブラリを作った。
pperr.Print(err)
以下のように表示される。
若干重い処理をしているが、エラー発生時は仕方ないということにした。
DatadogはAPMに統合されたエラートラッキング機能を提供していて、Golangにも対応している。 APMの1リクエストに紐付いたエラーを表示できるが、スタックトレースの抽出が貧弱であんまりイケてない。
router.HandleFunc("/hello", func(rw http.ResponseWriter, r *http.Request) { span, _ := tracer.SpanFromContext(r.Context()) err := f1() if err != nil { rw.WriteHeader(http.StatusInternalServerError) span.SetTag(ext.Error, err) } else { fmt.Fprintln(rw, "hello") } })
上記のようにspan.SetTag(ext.Error, err)
するとこのような表示になる。
ext.ErrorDetails
にpkg/errorsのスタックトレースをセットしているが、コンソールに表示されるのはtakeStacktrace()
のほうらしい。
なので直接ext.ErrorStack
を設定する。
span.SetTag(ext.Error, err) span.SetTag(ext.ErrorStack, pperr.Sprint(err))
一応、スタックトレースが表示されるが、インデントが潰れてあんまり見やすくない。
なのでインデントを全角スペースするという微妙なことをする。
さらにErrorTypeとして*errors.withStack
が表示されてもうれしくないので、直近のcause error typeを表示するようにする。
span.SetTag(ext.Error, err)
span.SetTag(ext.ErrorStack, pperr.SprintFunc(err, pperr.NewPrinterWithIndent(" ")))
span.SetTag(ext.ErrorType, pperr.CauseType(err))
これでまあまあ見やすくなったと思う。
ちなみにext.ErrorType
にスタックトレースをセットするというさらによろしくなさそうなことをすると、全角スペースは不要になる。
span.SetTag(ext.ErrorType, pperr.Sprint(err))
エラー表示の機能的にはSentryと大きな違いはなさそうだけれど、UXがだいぶ劣っているのでDatadogにはもう少し頑張って欲しい。 (フィードバックしたらなんとかなるだろうか)