GitHub Actionsからさくらクラウドのコンテナレジストリ(Lab)にイメージをpushする
こちらのリポジトリが完成形です。
ここで紹介しているコンテナレジストリはLabプロダクトになります。「Labプロダクト」では、新機能の動作検証およびフィードバック収集を目的として、さくらのクラウドにおける開発中サービスを実験的に提供しておりますので、ご注意ください。
マニュアルはこちら
「Labプロダクトとは」も合わせてご確認ください。
コンテナレジトストリの作成
さくらのクラウドのメニューからコンテナレジトストリを選び、「追加」ボタンを押します。
公開・非公開は目的に応じて選択してください。
コンテナレジストリができたら、push/pullするためのユーザを作成します。
権限も適したものを選びましょう。今回はGitHub Actionsからpushを行うので、「Push & Pull」がよさそうです。
このアカウントはコンテナレジストリにのみ使われるアカウントになります。
GitHubリポジトリにシークレット登録
コンテナイメージを作成するリポジトリの Settings -> Repository secrets にて、先ほど作成した id とパスワードを SAKURACR_USER、SAKURACR_PASSWORDとして登録しました。
workflow YAMLの作成
リポジトリの .github/workflow/
以下にコンテナイメージの作成とコンテナレジストリ(Lab)にpushするためのYAMLファイルを作成します。
さくらのコンテナレジストリ(Lab)はDocker開発元が提供するDocker Hub互換のレジストリサービスであり、プロトコルにも互換性があります。GitHub Container RegistryやAWSのコンテナレジストリにpushする際に利用できる docker/login-action
と docker/build-push-action
の Actionを特にカスタマイズすることなく使えます。
http-dump-requestでは次のようにファイルを作成しました。
name: release on: # gitのtagが作られた時 push: tags: - "v[0-9]+.[0-9]+.[0-9]+" jobs: build_and_push: runs-on: ubuntu-latest env: IMAGE_NAME: http-dump-request REGISTRY: nomadscafe.sakuracr.jp steps: - name: checkout uses: actions/checkout@v2 # tagを入手 - name: Set tag to environment variable id: set-tag run: echo ::set-output name=version::${GITHUB_REF#refs/*/} - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to Sakura Container Registry uses: docker/login-action@v1 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.SAKURACR_USER }} password: ${{ secrets.SAKURACR_PASSWORD }} - name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.set-tag.outputs.version }}
このファイルをコミットしgit tagを作成すると、狙い通りイメージの作成とさくらのコンテナレジトストリ(Lab)へのpushができました。
2021年1月現在、コンテナレジストリ(Lab)にはイメージの一覧機能がないので、今回つくったコンテナは以下のコマンドでレジストリからpullして実行ができることで動作を確認しました。
$ docker run -p 3000:3000 nomadscafe.sakuracr.jp/http-dump-request
おまけ
http-dump-request について
似たようなモノはたくさんありそうですが、検証の際に使える http request をそのままレスポンスとして返す Go のサーバです。
こんな感じで表示できます。上記で紹介しておりますが、 nomadscafe.sakuracr.jp/http-dump-request
から docker pull
して利用できます。
2020年に買って良かったもの
ほぼ1年間家で仕事をすることになり、自宅の机まわりの環境をこれまで以上に整えてきた1年だったので「#買って良かった2020」というお題で書いてみる。
ヘッドホンとマグカップ
奥さんから誕生日にもらったソニーの WH-H910N。色はアッシュグリーンです。ありがとう。
ワイヤレスで軽くてつけ心地がよく、ノイズキャンセルもあってとても気に入っています。
夏は冷たい飲み物、冬は暖かい飲み物を飲むために買ったKEYUKAのマグカップ。偶然にもヘッドホンと同じ色味でいい感じです。
また、Apple Musicのサブスクリプションも加入しました。
仕事しながら聞いてますが、「おしりたんてい」の「ププっとふむっと解決ダンス」だったり鬼滅の刃の曲が最もよくかかっているような気がします。
椅子
家で長く座って作業ができる椅子がない、ということで在宅勤務になってまず購入したのが椅子。
オフィスチェアの多くは黒い色ですが、割と大きい黒い物体が家にあると、家の中が暗くなりそうということで、オカムラのシルフィーのホワイトフレーム、座面はベージュを選びました。
届くまでに1ヶ月以上かかり、その間は折り畳み椅子でなんとかなんとか過ごしてましたが、背面フレームのデザインもよく満足。
椅子と言えば、ISUCON10個人スポンサーでいただいたアウトドアチェアもよい。
子供たちがよく座っています。941さんありがとう。
ちなみに机は場所的な問題で、ニトリの小さめの机
キーボード
今はBAROCCO MD770 RGB BTを使ってます。真ん中にMagic Trackpadをおくスタイル。左右分離型だいぶ慣れてきましたが、電話をしながら片手で打てないという弱点があります。
Magic Trackpadをそのままおくと低すぎて使いにくいので、百均で買った耐震マットを二枚重にして下にくっつけてます。
普段はFILCOの左右分離型のウレタンリストレストをキーボードの前において使っています。
冬対策
窓の近くに机を置いているので、寒いということで、こちらのパネルヒーターを買ってみた。
足の裏はもちろん、ブランケットを上にかければ簡易こたつになりとても暖かい。奥さんも小さいホットカーペットを買って机の下で使っています。
Apple Watch
Series 6を初購入。
Apple Watch Hermèsの赤色のレザーストラップにしました。1時間に1度立ち上がったり、20秒手を洗っているだけで褒めてくれるので自己肯定感がある。運動も気にし。。。
スタンドはEINBANDさんのAppleWatch木製スタンド。充電器のところはぴったりとハマったりではないので剥がせるタイプの両面テープで固定している。
最近はRaspberry Piを買ったので、homebridgeいれてApple WatchのホームアプリやSiriからLチカして喜んでいます。
来年は何買うかな~
ISUCON10予選問題で EC2 c6g.2xlarge vs c5.2xlarge をやってみる
少し前にISUCON10予選問題のスコアアップに取り組んでいたので、その成果を使い、EC2 Graviton2 インスタンスとIntel CPUのインスタンスでスコアを比較してみます。
ISUCON10予選問題チャレンジをしていた時のスレはこちら
ISUCON10予選のベンチマーク、Macbook Pro上で、23000まででるようになった。Xeon Gold 6148 x2上だと37000。
— kazeburo. (@kazeburo) 2020年10月28日
ここではISUCON10予選時のように複数台用意するのではなく、1台のサーバでGoのアプリケーションとMySQLを動作させ、同じサーバ上からベンチマークを実行しています。
準備
初期データを作る際のdockerコンテナでarm64対応していないものがあるため、Intel CPUのインスタンスで作成してscpする方法を取りました。
まず、 c5.2xlarge
のインスタンスを起動して準備していきます
# 依存のインストール sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common python3-pip git curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # Dockerをいれる sudo add-apt-repository \ "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io sudo gpasswd -a $USER docker # 一度logout & login # docker-compose を pip でインストール sudo pip3 install -U docker-compose # Goのインストール curl -fsSL https://golang.org/dl/go1.15.6.linux-$(dpkg --print-architecture).tar.gz | sudo tar -C /usr/local -xzf - export PATH=$PATH:/usr/local/go/bin echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh # 初期データ作成で使うコマンドのインストール go get github.com/orisano/wayt export PATH=$PATH:$HOME/go/bin echo 'export PATH=PATH=$PATH:$HOME/go/bin' | tee -a ~/.bashrc # ISUCON10 予選問題をgit cloneして初期データ作成 git clone https://github.com/isucon/isucon10-qualify.git cd isucon10-qualify/initial-data pip3 install -r requirements.txt make
初期データ作成時に一度止まってしまいましたが、Ctrl-Cしてもう一度実行したらうまく動きました。
MySQLをインストールして、ユーザ作成をします。簡単なパスワードになるので気をつけましょう。
sudo apt install mysql-server sudo mysql > CREATE USER 'isucon'@'%' IDENTIFIED BY 'isucon'; > GRANT ALL ON *.* TO `isucon`@`%`; > CREATE DATABASE isuumo;
ここまでできたら c6g.2xlarge
側の準備をします。
c6g.2xlarge
でインスタンスを起動し、
sudo apt-get update sudo apt-get install -y mysql-server git make export PATH=$PATH:/usr/local/go/bin echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh sudo mysql > CREATE USER 'isucon'@'%' IDENTIFIED BY 'isucon'; > GRANT ALL ON *.* TO `isucon`@`%`; > CREATE DATABASE isuumo;
このあと、Intel CPUのインスタンスから、isucon10-qualify
ディレクトリを scpで Graviton2 のインスタンスにコピーすれば準備完了です。
初期状態でのスコア比較
まず、Intel CPUである c5.2xlarge での初期スコア
isuumoアプリを make
して起動
cd isucon10-qualify/webapp/go make ./isuumo
別ターミナルを開き、ベンチマークを実行します。
cd isucon10-qualify/bench make ./bench
初期スコア
初期状態ではタイムアウトも多くますが、最終的に以下のスコアになりました。
c5.2xlarge
での初期スコア
2020/12/23 13:26:06 bench.go:102: 最終的な負荷レベル: 8 {"pass":true,"score":1335,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":34}],"reason":"OK","language":"go"}
c6g.2xlarge でも同じようにターミナルを2つ開いてアプリケーションとベンチマークを実行します。
c6g.2xlarge
での初期スコア
2020/12/23 14:18:14 bench.go:102: 最終的な負荷レベル: 9 {"pass":true,"score":1552,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":48}],"reason":"OK","language":"go"}
初期状態では、c6g.2xlarge
の方が 16%
ほどスコアがよいという結果になりました。
ベンチマーク時の負荷の様子を top
コマンドでみると次のようになっておりました。
c5.2xlarge
top - 14:15:39 up 10 min, 3 users, load average: 7.18, 2.64, 0.96 Tasks: 146 total, 2 running, 144 sleeping, 0 stopped, 0 zombie %Cpu(s): 85.6 us, 3.2 sy, 0.0 ni, 10.3 id, 0.5 wa, 0.0 hi, 0.4 si, 0.0 st MiB Mem : 15549.2 total, 12448.3 free, 929.9 used, 2171.0 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 14411.4 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 777 mysql 20 0 2989500 506064 37208 S 638.9 3.2 9:38.23 mysqld 1331 ubuntu 20 0 1526204 34796 7164 S 44.9 0.2 0:36.05 isuumo 1486 ubuntu 20 0 1521292 139536 7692 S 30.0 0.9 0:07.15 bench
c6g.2xlarge
top - 14:18:03 up 16 min, 3 users, load average: 5.98, 2.22, 1.13 Tasks: 189 total, 2 running, 187 sleeping, 0 stopped, 0 zombie %Cpu(s): 92.9 us, 4.0 sy, 0.0 ni, 1.7 id, 0.3 wa, 0.0 hi, 1.1 si, 0.0 st MiB Mem : 15709.3 total, 11525.9 free, 880.3 used, 3303.1 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 14661.9 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3516 mysql 20 0 3049328 490156 34860 S 707.0 3.0 11:29.75 /usr/sbin/mysqld 4896 ubuntu 20 0 1598624 40468 6208 S 39.5 0.3 0:46.90 ./isuumo 5193 ubuntu 20 0 1661656 153140 6860 S 33.9 1.0 0:13.45 ./bench
明らかにMySQLがボトルネックですが、c6g.2xlarge の方がidleが少なくCPUをよく使えているようにみえます。
感想戦ブランチでのスコア比較
次に、私のブランチへ切り替えてスコア比較をしてみます。
ブランチはこちら
効果があまりなかったものもありますが、主な変更点は次のようになります。
- nazotte検索に空間インデックスを利用
- 検索用テーブルと、データ用テーブルを分離してMySQLの負荷を削減
- 検索用インデックスの追加。
- 検索時にrangeクエリにならないようrangeIDカラムを作成しtriggerにてデータ投入
- 検索時にSQL_CALC_FOUND_ROWSを利用。結果をキャッシュしておき、同条件での検索時はSQL_CALC_FOUND_ROWSをつけずにキャッシュを利用する
- chairとestateは全てインメモリキャッシュ。検索時は
SELECT id
をする - 検索結果やchairとestateをキャッシュする際は、JSON化したものをキャッシュする
- bot判定を最適化
- fiber (fasthttp) へのフレームワーク変更
- MySQLに秘伝のタレを入れる
いれたMySQLに秘伝のタレ
disable-log-bin innodb_doublewrite = 0 innodb_flush_log_at_trx_commit = 0 innodb_flush_method = O_DIRECT innodb_adaptive_hash_index = 0
感想戦ブランチでのスコア
c5.2xlarge
での感想戦ブランチスコア
$ ./bench 2020/12/23 14:34:27 bench.go:78: === initialize === 2020/12/23 14:34:32 bench.go:90: === verify === 2020/12/23 14:34:32 bench.go:100: === validation === 2020/12/23 14:34:34 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:36 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:38 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:38 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:38 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:38 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:39 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:34:39 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:35:32 bench.go:102: 最終的な負荷レベル: 11 {"pass":true,"score":41462,"messages":[],"reason":"OK","language":"go"}
初期状態では負荷レベルが最大の11までには届きませんでしたが、ここでは7秒ほどで最大に達し、最終スコアは4万を超えてきました。これはMacbook Pro上でやっていたときより若干良い結果
c6g.2xlarge
での感想戦ブランチスコア
ubuntu@ip-10-0-11-141:~/isucon10-qualify/bench$ ./bench 2020/12/23 14:36:20 bench.go:78: === initialize === 2020/12/23 14:36:30 bench.go:90: === verify === 2020/12/23 14:36:31 bench.go:100: === validation === 2020/12/23 14:36:33 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:34 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:35 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:36 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:36 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:36 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:37 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:36:38 load.go:181: 負荷レベルが上昇しました。 2020/12/23 14:37:31 bench.go:102: 最終的な負荷レベル: 11 {"pass":true,"score":39460,"messages":[],"reason":"OK","language":"go"}
Intel CPUに比べると5%ほど低いスコアです。何回か実行してみましたが、4万に届くことはありませんでした。
ベンチマーク実行中の負荷をtopコマンドでみると次のようになっていました。
c5.2xlarge
top - 14:45:24 up 39 min, 3 users, load average: 3.68, 2.66, 2.15 Tasks: 147 total, 2 running, 145 sleeping, 0 stopped, 0 zombie %Cpu(s): 57.6 us, 4.3 sy, 0.0 ni, 36.8 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st MiB Mem : 15549.2 total, 10447.3 free, 2096.7 used, 3005.3 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13346.3 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3879 ubuntu 20 0 1663700 163836 7724 S 277.3 1.0 1:00.39 bench 1691 mysql 20 0 3335408 651500 37268 S 189.7 4.1 22:25.35 mysqld 3650 ubuntu 20 0 2572288 1.0g 15200 R 45.0 6.7 2:13.37 isuumo
c6g.2xlarge
top - 14:40:43 up 39 min, 3 users, load average: 1.44, 1.86, 1.69 Tasks: 185 total, 1 running, 184 sleeping, 0 stopped, 0 zombie %Cpu(s): 58.2 us, 3.6 sy, 0.0 ni, 37.0 id, 0.0 wa, 0.0 hi, 1.2 si, 0.0 st MiB Mem : 15709.3 total, 9707.4 free, 2011.2 used, 3990.7 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13669.2 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 7423 ubuntu 20 0 1810080 205848 6788 S 268.8 1.3 0:59.13 ./bench 5417 mysql 20 0 3724652 652440 35008 S 203.0 4.1 18:10.73 /usr/sbin/mysqld 7352 ubuntu 20 0 2499408 986528 14492 S 38.9 6.1 0:50.62 ./isuumo
感想戦ブランチでは全体のCPU使用率が下がっています。大きな差ではありませんが、Intel CPUの方がMySQLのCPU使用率が小さくベンチマークとisuumoアプリのCPU使用率が大きいようにみえます。
感想など
tasksetコマンドを使い、benchコマンドが使うCPUを1個に絞った結果も合わせたグラフが次ようになります。
Graviton2はIntel CPUのインスタンスに比べてシングルスレッドのパフォーマンスが低めというベンチマーク結果もありますが、
この結果からも初期状態ではMySQLでのマルチスレッド性能が、感想戦ブランチではベンチマーカーのシングルスレッド性能がスコアに影響しているのかなと考えております。
感想戦ブランチではGraviton2のインスタンスの方がスコアが低いという結果になってしまいましたが、インスタンスのコストはGraviton2の方が20%ほど低く、スコアをコストで割った数値ではGraviton2の方が高くなるでしょう。
armなインスタンスの利用ではミドルウェアのパッケージやdockerのイメージが用意されていないことがあるなど、いくつか困難にぶつかることはありますが、パフォーマンスがよくコストメリットも大きいのでやはり使っていくといいんじゃないかと思いますね~
Re: 結局、Go言語をやめる理由はなかった件
すみません、ISUCONのアレに火がついてしまったので..。 Advent Calendarとはとくに関係がありません。
こちらの記事をみて、気になってしまったので interpolateParams
の追加とMySQLチューニングをしてベンチマークを回してみました。
ベンチマークの環境が公開されているのは素晴らしいですね。
8vCPU/16GB Memのc5a.2xlargeなEC2のインスタンスを起動して、以下の手順にしたがってdockerとdocker-composeをインストールしました。OSはUbuntu 20.04を使いました。
上記のbenchmarkのrepositoryをgit cloneし、compose build && compose upします。
$ git clone https://github.com/okdyy75/bench-docker.git $ sudo docker-compose build $ sudo docker-compose up -d
まず何も変更しない状態でのスコア結果は、
$ sudo docker-compose run --rm python sh -c 'cd python; pip install -r ./requirements.txt && time python bench.py' 平均秒数:9.670429 real 1m 36.73s user 0m 6.25s sys 0m 2.79s
Go言語
$ sudo docker-compose run --rm golang sh -c 'cd go; go build . && time ./go' 平均秒数:11.70815524 (0x0,0x0) real 1m 57.08s user 0m 3.84s sys 0m 10.83s
たしかに、Go言語の結果の方が少し悪くなっています。
ここで元記事にてmethaneさんから指摘のあった interpolateParams
の設定をいれます。
diff --git a/www/go/bench.go b/www/go/bench.go index 5c56714..a4b86d0 100644 --- a/www/go/bench.go +++ b/www/go/bench.go @@ -37,7 +37,7 @@ func getDB() *sql.DB { } dsn := fmt.Sprintf( - "%s%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true", + "%s%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&interpolateParams=true", user, password, host, port, name) db, err := sql.Open("mysql", dsn)
そうすると、結果は
平均秒数:10.540287 real 1m 45.40s user 0m 2.99s sys 0m 6.26s
となり、pythonに追いつかないまでも、改善はしています。
ところで、ベンチマークを何回か動かしながら気になったのは、スコアが振れが大きく、iowaitがそれなりでているとところです。(Maki-Daisukeさんはioの影響を抑えるためNVMe SSDのついたインスタンスを使われておりました)
$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 1 0 11964048 140004 3405756 0 0 0 7872 8115 13468 1 2 95 2 0 0 0 0 11964048 140004 3405932 0 0 0 7656 6939 11857 1 2 93 4 0 0 1 0 11956236 140004 3414672 0 0 0 16284 7068 12074 1 1 94 4 0 0 1 0 11956236 140004 3414672 0 0 0 7768 8375 14349 1 2 94 3 0 1 0 0 11956236 140004 3414672 0 0 0 7464 7463 12275 2 1 96 2 0 0 1 0 11955480 140004 3415720 0 0 0 8780 7971 12701 2 1 97 0 0 0 1 0 11955480 140004 3415720 0 0 0 7712 8561 13845 1 2 97 0 0 0 1 0 11955480 140004 3415720 0 0 0 7780 7966 13032 1 1 96 1 0 0 1 0 11954472 140004 3416496 0 0 0 8788 7051 12944 2 1 90 7 0 0 1 0 11964536 140004 3405576 0 0 0 9592 9176 16006 2 1 92 4 0 2 0 0 11964284 140004 3405832 0 0 0 8220 7737 13731 1 1 92 5 0 1 0 0 11964252 140004 3405928 0 0 0 8056 8078 12893 1 1 97 0 0 0 1 0 11955416 140004 3414756 0 0 0 16132 6565 11829 1 1 91 7 0 2 0 0 11955416 140004 3414756 0 0 0 7056 7333 12482 1 1 94 3 0
また、CPUも全然使えてません。
これはMySQL側がボトルネックになっている可能性が高いとみて、対ISUCON用秘伝のタレを投入して、再度実行してみました。
my.cnf を作成。4つのパラメータを追加
$ cat docker/mysql/my.cnf [mysqld] innodb_doublewrite = 0 innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT_NO_FSYNC innodb_adaptive_hash_index = 0
compose.ymlに追記して、mysqlを再起動
$ git diff diff --git a/docker-compose.yml b/docker-compose.yml index 94b3dc7..e39de9b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: volumes: - "./.data/mysql:/var/lib/mysql" - "./log/mysql:/var/log/mysql" + - "./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf" ports: - "3306:3306" # php-fpm ################################################ $ sudo docker-compose restart mysql Restarting bench-docker_mysql_1 ... done
結果は
平均秒数:1.518821 real 0m 15.21s user 0m 6.12s sys 0m 1.69s
Go言語(interpolateParams=false)
平均秒数:1.770360 real 0m 17.70s user 0m 3.04s sys 0m 7.85s
Go言語(interpolateParams=true)
平均秒数:1.196632 real 0m 11.96s user 0m 2.26s sys 0m 4.95s
interpolateParamsが有効のGo言語が最速になりました。最初の10倍近い高速化ですね。
MySQLが高速化したことで順位が入れ替わるところはもう少し深堀してもいいかと思いますが、Pythonにしたってかなり速くなってますので、これくらいなら正直どの言語でやってもいいのではないかと思います。仲良くしましょう
Go言語を実行中のvmstatは以下のようになりました。
vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 12075152 140028 3363636 0 0 10 453 441 22 1 1 98 1 0 0 0 0 12075152 140028 3363636 0 0 0 0 139 257 0 0 100 0 0 0 1 0 12015176 140028 3387952 0 0 0 25772 1950 2773 5 1 93 1 0 1 0 0 11968016 140028 3391408 0 0 0 12732 31447 60372 9 7 84 1 0 1 0 0 11967732 140028 3391376 0 0 0 4660 42484 86361 7 8 85 0 0 1 0 0 11967748 140028 3391360 0 0 0 14592 35933 73675 6 6 87 1 0 1 0 0 11967256 140028 3391228 0 0 0 6964 38245 77879 7 7 86 0 0 2 0 0 11966928 140028 3391416 0 0 0 13028 36928 75262 6 7 87 0 0 2 0 0 11966816 140028 3391440 0 0 0 7352 37506 76638 7 7 86 0 0 1 0 0 11968984 140028 3391440 0 0 0 14120 32657 71858 8 7 85 0 0 1 0 0 11969976 140028 3391468 0 0 0 15564 33490 69433 7 7 86 1 0 2 0 0 11969976 140028 3391468 0 0 0 3392 40593 82689 7 8 85 0 0 1 1 0 11971740 140028 3391440 0 0 0 15568 35473 72960 6 7 86 1 0 2 0 0 11973520 140028 3391476 0 0 0 5420 36698 76628 8 7 85 0 0 1 0 0 11973344 140028 3391476 0 0 0 13000 37315 77527 6 7 87 0 0 1 0 0 11973392 140028 3391536 0 0 0 8284 34950 71476 6 8 86 0 0 2 0 0 11973408 140028 3391536 0 0 0 13840 38778 79834 6 7 86 1 0 1 0 0 11974132 140028 3391544 0 0 0 8692 37283 74883 7 7 86 0 0 3 0 0 11974132 140028 3391544 0 0 0 10444 37224 77928 6 8 86 0 0 2 0 0 11973108 140028 3391608 0 0 0 15688 34599 71052 6 7 86 1 0 0 0 0 11980788 140028 3391728 0 0 0 6868 33311 72294 7 8 84 0 0 0 0 0 12069692 140028 3363668 0 0 0 2588 2979 4393 1 1 98 0 0
iowaitが小さくなり、user, systemが以前より高くあがるようになりました。
topだと
top - 07:43:15 up 2:16, 2 users, load average: 0.43, 0.11, 0.05 Tasks: 169 total, 1 running, 168 sleeping, 0 stopped, 0 zombie %Cpu(s): 6.2 us, 3.9 sy, 0.0 ni, 85.9 id, 0.4 wa, 0.0 hi, 3.6 si, 0.0 st MiB Mem : 15827.2 total, 11689.1 free, 689.4 used, 3448.7 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 14833.8 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 44962 systemd+ 20 0 1377796 216128 20612 S 77.4 1.3 1:29.73 mysqld 47046 root 20 0 710064 10828 3836 S 60.5 0.1 0:06.25 go
ようになり、1vCPU 使い切りそうなぐらいまできてました。
ちなみに、MySQLのデータディレクトリをみんな大好きtmpfsにおくと、
Go言語(interpolateParams=true)
平均秒数:1.106469 real 0m 11.06s user 0m 2.45s sys 0m 5.07s
平均秒数:1.394543 real 0m 13.97s user 0m 6.15s sys 0m 1.70s
もう少しだけ速くなります。
まとめ
ミドルウェア含めたベンチマークを行う時は、ミドルウェアやOSの設定なども気を配るのがいいですね。広い視点を保つためもにもISUCONは役に立つ。
コマンドを実行しその終了ステータスコードメトリクス化するMackerelカスタムプラグイン
Mackerel Advent Calendar 2020 15日目の参加記事です。
キャッシュの更新やなんらかの同期を行うコマンドなどをcronにて実行している場合、メンテナンスや一時的なネットワークの不調によりコマンドがエラーになっても問題ないが、一定時間以上エラーが続くと困る、みたいなことはあると思われます。
mackerelでは、cronのコマンドがエラーになった際に、通知する方法としては mkr wrap が利用できます。
crontabに
* * * * * mkr wrap -- /path/to/your-batch ...
とすることで、コマンドが失敗した際に、アラートをあげることができます。ただmkr wrapでは1度でもエラーとなるとアラートとなってしまうため、前述したような一定時間エラーになっても問題ないものでもアラートが上がってしまいます。
そこで、mackerel-agentをcrondのように利用し、コマンドが終了ステータスコードをメトリクス化するカスタムプラグインを作成し、ホストのメトリック監視にてエラーが続いている状況がないかを確認する方法を考えました。
mackerel-plugin-command-status
できたのが、こちらのmackerelカスタムプラグインです
元々Perlでさっと作ったものでしたが、この記事を書くためにGoで書き直しました。mkr plugin install
で導入が可能です。
使い方
メトリクスの名前を指定し、ハイフン2つのあとに実行するコマンドを書きます。
mackerel-agent.conf で実行する場合はこんな形になります。
[plugin.metrics.update-cache] command = "/path/to/mackerel-plugin-command-status --name update-cache --timeout 10s -- /path/to/cmd-fetch-cache"
そして、5回以上(5分以上失敗し続けている場合)アラートをあげたいという場合は
こんな形で閾値を設けることで、監視ができるのではないかと思います。
あとがき
Mackerelで監視されていないとあるサーバがサービスに投入されてしまっていたことで障害に気づくのが遅れた問題に対して、1分毎にcronでホストのステータスをmackerelのapiから取得しておいて、consulサービスのチェックスクリプトからそれを確認し、workingでなかったらサービスから自動で外れるという対策を行っておりました。
ところが、mackerelの障害・メンテナンス時にcronのエラー通知が大量にきてあたふた対応が必要になってしまっていたので、なんとかそれを避けるために考えた仕組みです。ただし、これでもmackerelがメンテナンス終了するタイミングでアラートが来てしまうのが悩ましいところ。
作ってみたもののこれ以外の用途には使ってない感じですが、いい使い道があればどうぞー。
cgoを利用した Go project を GitHub Actions でクロスコンパイル&リリースを行う
check-lastlogというmackerel監視pluginを作ってるのですが、
こちらは /var/log/lastlog
を読むために一部cgoを使っています。mackerelのpluginなので一つ前の記事で紹介した方法で
リリースしたいところなのですが、GoReleaserでは、cgoへの依存があるプロジェクトのクロスコンパイルがサポートされていないため、ひと工夫必要になります。
check-lastlogではこちらのxgoを使う方法でクロスコンパイルし、GoReleaserでGitHub Releaseにアップロードをしています。
出来上がったGitHub Actionsのワークフローはこちら
https://github.com/kazeburo/check-lastlog/blob/master/.github/workflows/release.yml
xgoでのクロスコンパイル
xgo はGoのクロスコンパイルの環境がはいったDockerのイメージと各環境をターゲットとしたビルドを行うコマンドを提供しています。
check-lastlogではGitHub Actionが用意されているこちら
を使いました。こちらはforkしたxgoを使っているようです。
check-lastlogのワークフロー、.github/workflows/release.yml
の前半ではxgoを使ってクロスコンパイルしています。
name: release on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" jobs: goreleaser: runs-on: ubuntu-latest env: BIN_NAME: check-lastlog steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set tag to environment variable id: set-tag run: echo ::set-output name=version::${GITHUB_REF#refs/*/} - name: Build with xgo uses: crazy-max/ghaction-xgo@v1 with: xgo_version: latest go_version: 1.15.x dest: build prefix: ${{ env.BIN_NAME }} targets: linux/amd64,linux/arm64 v: true x: false ldflags: -s -w -X main.version=${{ steps.set-tag.outputs.version }} - name: Check build dir run: ls -lR build
ghaction-xgo のパラメータは次のようになってます。
- dest: ビルドしたバイナリを格納するディレクトリ
- prefix: バイナリのファイル名。後ろに
-${OS}-${Arch}
がつきます - targets: クロスコンパイルするターゲット。カンマで区切る
- v: ビルドしたファイル名の表示
- x: ビルドの際のコマンドなどの表示
また、GoReleaser ではldflagsをデフォルトでいくつか設定してくれますが、xgoはそうではないので、-w -s
と -X main.version
を追加しています。
これでビルドが完了すると、dest
で指定したディレクトリにバイナリができます。
> Run ls -lR build build: total 3428 -rwxr-xr-x 1 runner docker 1806024 Dec 2 09:12 check-lastlog-linux-amd64 -rwxr-xr-x 1 runner docker 1703448 Dec 2 09:12 check-lastlog-linux-arm64
アーカイブ作成とGitHub Releaseへのアップロード
あとは、GitHub Releaseへのアップロードだけではあるのですが、check-lastlog はmackerel監視プラグインなので、mkr plugin install
対応をさせます。
mkr plugin install
対応するためにはファイル名が {{ .ProjectName }}_{{ .Os }}_{{ .Arch }}.zip
でzipでアーカイブする必要があります。なのでShellで頑張ってzipをつくりました。
- name: Zip binaries run: | cd build for file in ./* ; do mkdir $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}') && cp ${file} $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}')/${{ env.BIN_NAME }} && zip $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}').zip -j $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}')/${{ env.BIN_NAME }} ../README.md ../LICENSE; done shasum -a 256 *.zip > ${{ env.BIN_NAME }}_${{ steps.set-tag.outputs.version }}_checksums.txt ls -lR ./
バイナリだけではなく、README.mdやLICENSEファイルもアーカイブに同梱しています。また、checksum用のファイルも作っています。GoReleaserのchecksumがsha256なので、同じようにshasumコマンドを使ってみました。
そして最後にGitHub Releaseにアップロードするのですが、CHANGESも作ってくれるGoReleaserを使います。
まず、GoReleaserの設定ファイル .goreleaser.yml
# Use for generating CHANGELOG builds: - binary: check-lastlog skip: true release: github: owner: kazeburo name: check-lastlog extra_files: - glob: "build/*.zip" - glob: "build/*_checksums.txt"
ビルド(builds)は skip:true で止めることができました。成果物がない場合、archiveの作成も行われないようでした。GoReleaserで作ったパッケージのかわりに、xgoとShellで作ったzipとchecksumファイルをextra_filesに指定してアップロードしてもらいます。
GitHub Actionsのワークフローは goreleaser/goreleaser-action
を使いました。
- name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 with: version: latest args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GoReleaser 便利
まとめ
xgoを使うとGoReleaserのみでクロスコンパイルする場合にくらべて実行時間は伸びてしまいますが、cgoを使っているGo Projectでもlinuxのamd64, arm64に対応したパッケージを作ることができました。
GitHub ActionsとGoReleaserでmkr plugin install対応mackerel pluginをリリースする
Mackerel Advent Calendar 2020 9日目の参加記事です。隙間で書きました。
最近 mackerel pluginをリリースするときは、ほぼ全てGitHub ActionsとGoReleaserを使ってビルドとリリースしています。
GoReleaserはこちら
GoReleaserはGoのprojectをクロスプラットフォームでビルドし、GitHub Releaseなどにアップロードしてくれるツールです。これのおかげでかなりリリース作業が楽になりました。
準備
mackerel pluginのrepositoryに .goreleaser.yml
というファイルを作ります。
builds: - binary: mackerel-plugin-linux-process-status goos: - linux goarch: - amd64 - arm64 archives: - format: zip name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" release: github: owner: kazeburo name: mackerel-plugin-linux-process-status
こちらは mackerel-plugin-linux-process-status という plugin の設定ファイルです。linuxのみサポートなので、linux/amd64およびlinux/arm64用にバイナリをビルドします。
mkr plugin install
に対応したpluginはアーカイブのファイル名が(REPOSITORY_NAME)(GOOS)(GOARCH).zipという命名規則になっていることが必要です。
なので、archivesの name_templateに {{ .ProjectName }}_{{ .Os }}_{{ .Arch }}
を指定します。
これで、GoReleaserの準備は完了で、手元で、goreleaser --rm-dist
を実行すると、最新のタグを取得してビルドとGitHub Releaseへのアップロードを行ってくれます。楽。
また、GoReleaserは以下のような簡単なCHANGESを作ってくれるのもとても気に入っています。
GitHub Acitons を使う
ここまでできていたら、tagがつけられたらGitHub Acitonsでビルドとリリースを自動化するだけ。
.github/workflows/release.yml
などファイルを作成し
name: release on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" jobs: goreleaser: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - name: Setup Go uses: actions/setup-go@v2 with: go-version: 1.15 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 with: version: latest args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GoReleaser用のActionが用意されているので、これを使うだけ
上記はサンプルそのままですな。
これで、
git tag v${VERSION} git push origin v${VERSION}
するだけで自動でパッケージの作成とリリースができるようになりました。簡単。
後書き
最近、公開してあったたくさんのmackerel pluginを一気にGitHub Actionsを利用するようにしたり、arm64での動作確認を行ってました。 その過程でtag追加を楽にするコマンドを作ったり、cgo含むprojectのGitHub Actionsでのクロスコンパイルをやってたりした話はまた今度できたらと思います。