寝ても覚めてもこんぴうた

プログラム書いたり、ネットワーク設計したり、サーバ構築したり、車いじったり、ゲームしたり。そんなひとにわたしはなりたい。 投げ銭は kyash_id : chidakiyo マデ

今日 (2019/09/10) 現在のGAE/goをUPDATEする際の注意点、俺まとめ

f:id:chidakiyo:20190910182707j:plain

Appengine/goが過渡期とでもいいましょうか、
日々変化も目まぐるしく、いろいろ気をつけるべき点もありそうなので雑にまとめました。
ご参考まで。(2019/09/10現在)

GAE/go 1.9 は終わり

f:id:chidakiyo:20190910182745p:plain

画像のとおりです。

警告: Go 1.9 ランタイム バージョンは非推奨になりました。2019 年 10 月 1 日以降、新しいデプロイではこのバージョンを使用できなくなります。2019 年 10 月 1 日までに、Go 1.11 または Go 1.12 を使用するようにアプリケーションをアップグレードしてください。

とあるので、今年の10月1日以降はgo1.9でのデプロイは不可能になります。
すでにデプロイしているものは動くんじゃないか(未確認)と思いますが、速やかに移行しましょう。
go1.11 への移行は比較的容易だと思います。(appengineパッケージも利用できるので)

追記: すでにデプロイされているバージョンは引き続き利用できるようです。 [1]

f:id:chidakiyo:20190911134641p:plain

GAE/go 1.11 は気をつけろ

個人的に気になる点は3点、

  • ランタイムのパフォーマンスが 1.9 より少々悪い
  • 非appengineパッケージのライブラリのRPC部分にメモリリークの問題が有りそう
  • RPCのタイムアウトに気をつけて!

ランタイムのパフォーマンスに関しては、レスポンスの時間などは特に差を感じませんが、
CPUの利用量とメモリの使用量の増加があるように感じています。
Stackdriverのグラフで見た感じで2-3割り程度の差があるように見えます。(ざっくり

非appengineパッケージ(cloud.google.com/go/datastore など)を利用した際に今日現在でRPC部分にメモリリークする箇所がありそうです。
そのため、appengineパッケージをあえて利用することで問題を回避できます。(ですが次の問題があります)

appengineパッケージのRPCに関しては、2nd-genランタイムは多くのRPCを実行しているようで、比較的頻繁にタイムアウトするケースがあります。
service bridge HTTP failed などのログが出力される場合には internal/net.go の以下の画像の箇所のtimeoutを伸ばしてあげると良いようです。(現在修正し様子を見ようとしているところです)

f:id:chidakiyo:20190910183656p:plain

GAE/go 1.12 はまだよくわかりません

一応(?)1.12対応で実装しているものありますが、app.yamlで1.11の設定でデプロイしているので厳密にはよくわかっていません。(1.11と違いがないかもしれません。)

注意点としては、↑のgo1.11でも書いたメモリリークの問題は1.12ランタイムではappengineパッケージが利用不可になっているため、現状、回避策がないと思います。
大量にRPCを実行しているような場合にはインスタンスタイプを上げるなどして神に祈る必要がありそうです。

まとめ

1.9からの移行を皆様急いでいるかと思いますが、ライブラリ併せてのupdateは若干罠があるので(今日 2019/09/10 現在)、
一旦 GAE/go1.11 環境に appengine ライブラリを利用したままの移行が今日現在、私のオススメの予感です。

おまけ

[1] Feature Deprecations  |  App Engine Documentation  |  Google Cloud

fix · f81/appengine@15ec82a · GitHub

GAE/go1.11 で Stackdriver Profiler を使ってみる

f:id:chidakiyo:20190822202047j:plain

appengine go1.11以降でgoでもプロファイラが使えるようなので初期設定だけやってみます。
内容的にはほぼ こちら の内容です。

Stackdriver Profiler は何ができるの?

Goの場合には、CPU、ヒープ、競合、スレッドに関するプロファイリングが可能です。
その他、競合プロファイリングやスレッドプロファイリング等があるようです。ここはこの記事では説明しません。

GAE/go アプリケーションにプロファイラを組み込む

ドキュメントには アプリケーションにパッケージをインポートしてから、コードのできるだけ早い段階でProfilerを初期化する とあるので、mainロジックの早い段階で以下のように初期化すると良いと思います。

以下の例は ginを利用しています。

import (
    "cloud.google.com/go/profiler"
    "github.com/gin-gonic/gin"
    "google.golang.org/appengine"
    "net/http"
)

func main() {
    if err := profiler.Start(profiler.Config{
        DebugLogging: true,
    }); err != nil {
        // TODO: Handle error.
    }

  route := gin.Default()
  http.Handle("/", route)
  route.GET("/", func(context *gin.Context){
    context.String(http.StatusOK, "hello!")
  })
    appengine.Main()
}

プロファイラのAPIを有効化する

プロファイラを利用するためにはAPIの有効化が必要です。
WebUIから Profiler API を検索し、有効化しても良いですし、
コマンドで gcloud services enable cloudprofiler.googleapis.com と実行しても良いです。

いずれかの方法でAPIを有効化します。

作成したappengineアプリケーションをデプロイする

デプロイ方法は特にこの記事では説明しません。
デプロイ完了の後に、アプリケーションに何度かアクセスし、 hello! とレスポンスが帰ってくることを確認します。

プロファイラを確認する

いよいよメインのプロファイラの確認です。
プロファイラの画面 にアクセスし、確認します。

CPU time

f:id:chidakiyo:20190822201626p:plain

Heap

f:id:chidakiyo:20190822201615p:plain

Allocated heap

f:id:chidakiyo:20190822201604p:plain

Threads

f:id:chidakiyo:20190822201552p:plain

まとめ

まずは使えるようになるという意味ではここまで。
また時間があればプロファイラの使い方の記事でも書こうかと思います。

Go で StartsWith/EndWith、前方一致/後方一致はないの?

f:id:chidakiyo:20190815155700j:plain

Javaで育った私としては、前方一致/後方一致は StartsWith/EndWith というイメージが勝手にありますが、
goを書いているとたまにど忘れするので備忘録。

go での前方一致/後方一致

goでももちろん前方一致/後方一致のための関数は用意されています。

stringsパッケージの HasPrefix/HasSuffix がそれです。
もうほぼこれで答えなんですが、サンプルは以下のようになります。

import "strings"

~~snip~~

strings.HasPrefix("hello world", "hello") // -> true
strings.HasSuffix("hello world", "world") // -> true

簡単ですね。
ではでは。

参考

https://golang.org/pkg/strings/#HasPrefix https://golang.org/pkg/strings/#HasSuffix

gcloud コマンドで TaskQueue(TQ)/Cloud Tasksを操作する

f:id:chidakiyo:20190814093728j:plain

皆さんTQつかってますか。
ちゃんと使うとめちゃくちゃ便利なTQ(Cloud Tasks)ですが、コマンドでサクッと作ったり消したりしたい(特に消したい)というのがあったので記事にしました。

TQを作成する

以下のようなコマンドでTQを作成します。

gcloud --project ${PROJECT_ID} beta tasks queues create hoge-test

--project ${PROJECT_ID} は gcloud コマンドに対して事前に gcloud config set project ${PROJECT_ID} などを実施している方は抜いても実行可能です。

TQを操作するAPIが有効化されていないプロジェクトでは初回以下のような表示が出ますので y と押してエンター押し有効化しましょう。

API [cloudtasks.googleapis.com] not enabled on project [000000000000].
 Would you like to enable and retry (this will take a few minutes)?
(y/N)?  

(有効化していない場合には有効化完了のログが出力された後に) Queue作成が Created queue [QUEUE_NAME]. のようなログとともに完了します。

UIからQueueの作成を確認

Cloud Tasks のWebUIから作成したTQが確認できます。

f:id:chidakiyo:20190814093532p:plain

コマンドからTQの作成を確認

以下のようなコマンドを実行します

gcloud --project ${PROJECT_ID} beta tasks queues list

結果は以下のように表示されます

QUEUE_NAME  STATE    MAX_NUM_OF_TASKS  MAX_RATE (/sec)  MAX_ATTEMPTS
hoge-test   RUNNING  1000              500.0            100

TQを削除する

TQの削除もコマンドから実行できます。
GAEの queue.yaml で管理していると削除したTQが残りがちなのでそういう場合にはコマンドで消してしまいましょう。

以下のようなコマンドを実行します。

gcloud --project ${PROJECT_ID} beta tasks queues delete hoge-test

削除の際には y/n を入力する必要があります
--quiet オプションを gcloud コマンドのオプションとしてつけることで y/n 入力を省くことができます。

create-app-engine-queue コマンドってなんやねん

createの他に create-app-engine-queue というオプションもあります。
作成したものは見かけ上(WebUI/commandともに)違いがなさそうですが、appengine用のTQを作成する際にはこちらのコマンドを使ったほうが良いのかな [要出典]

まとめ

TQを作成する際のオプションはいろいろ細かくあるんですが、
今回はひとまずシンプルなものを作成して、削除することがコマンドでできるよ、という記事でした。

ではでは。

Fault tolerantに関する読み物

f:id:chidakiyo:20190805160330j:plain

たびたび人と話していて、この資料のことを思い出すんだけど、
そのたびに検索するのがしんどいのでメモとして残す。

Building Fault Tolerant Microservices というプレゼン

プレゼンの資料はこれ

https://www.jfokus.se/jfokus16/preso/Building-Fault-Tolerant-Microservices.pdf

こちらの解説しているQiitaと合わせて読むと理解しやすい。

"Building Fault Tolerant Microservices" というプレゼンがとても良かった話 - Qiita

YouTubeに動画も上がっていたので、英語のヒアリング辛くない人はこちらもおすすめ。

Building Fault Tolerant Microservices - YouTube

安定性のパターン大全 (とその実装) という記事

Release It! 本番用ソフトウェア製品の設計とデプロイのために という本の内容に関して書いている

安定性のパターン大全 (とその実装) - Qiita

Release It! はこのような本。

2008年のJolt Award一般書部門で、"Manage It!"とともにProductivity Winner を受賞した原書を翻訳するもの。動くだけではない製品としてのソフトウェアでは、開発だけでなく運用の面でも設計の時点から知っているべき事柄やノウハウが多々ある。本書ではそれらをパターン/アンチパターンとして解説していく。

他にも良い読み物があればぜひコメントで教えて下さい。

ab(ApacheBench) 的な負荷ツール hey を試す

f:id:chidakiyo:20190722182814j:plain

ちょっとした負荷試験をしたい場合に、abが入っていればいいのですが、そうも行かない場合も多いので、go製で簡単にインストールできる hey を試します。

負荷ツールのタイプは2種類ある

HTTPの負荷ツールには2タイプあります。

  1. レスポンスが返される限り全力でリクエストするタイプ(秒あたりのアクセス数が一定ではないタイプ)
  2. 時間あたり定められた数のリクエストを決められた時間実行するタイプ

簡単にするため、

  1. 全力タイプ

  2. 定量タイプ

とこの記事では呼んでみますw

全力タイプ には、この記事で紹介する hey や、 ab(ApacheBendh)などがあります。

定量タイプ には、Gatling や、以前私が記事を書いた Vegeta などがあります。

アプリケーションがどこまで耐えられるか死ぬまで殴るというテストの際には 1. の全力タイプ、 メモリリークや長期の動作の確認などのためのテストの際には 2. の定量タイプなどを利用する場合が多いと思います。

heyのインストール

閑話休題

heyはgo製ツールなので、goがインストールされた環境で以下のコマンドで簡単にインストールすることができます。

go get -u github.com/rakyll/hey

単純なGETリクエストをしてみる

単純なGETリクエストをしてみます。

hey https://chidakiyo.example.com // URLはサンプルです

結果はこんな感じ

Summary:
  Total:    0.2199 secs
  Slowest:  0.1970 secs
  Fastest:  0.0055 secs
  Average:  0.0539 secs
  Requests/sec: 909.5376


Response time histogram:
  0.005 [1] |
  0.025 [149]   |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.044 [0] |
  0.063 [0] |
  0.082 [0] |
  0.101 [0] |
  0.120 [0] |
  0.140 [0] |
  0.159 [0] |
  0.178 [0] |
  0.197 [50]    |■■■■■■■■■■■■■


Latency distribution:
  10% in 0.0068 secs
  25% in 0.0073 secs
  50% in 0.0080 secs
  75% in 0.1895 secs
  90% in 0.1921 secs
  95% in 0.1939 secs
  99% in 0.1969 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0241 secs, 0.0055 secs, 0.1970 secs
  DNS-lookup:   0.0169 secs, 0.0000 secs, 0.0693 secs
  req write:    0.0001 secs, 0.0000 secs, 0.0017 secs
  resp wait:    0.0291 secs, 0.0050 secs, 0.1010 secs
  resp read:    0.0004 secs, 0.0001 secs, 0.0021 secs

Status code distribution:
  [200] 200 responses

パラメータに関して

先程 hey https://chidakiyo.example.com という形で実行していますが、default値によるアクセス数(並列数)でリクエストが実行されています。

オプションはほぼabと同じ(ような気がしている)で、

-n オプションが送信するリクエスト数(デフォルトは200)

-c オプションが並列に実行する数(デフォルトは50)

となるので、オプションを省いても以下のコマンドと等価になります。

hey -n 200 -c 50 https://chidakiyo.example.com

その他オプションはこのような感じになります。

-q レートリミット。 最初に全力タイプとしていましたが、定量タイプとしても使えるようです。(デフォルトは設定されていません)

-z 期間指定。 -z 10s, -z 3m などのように実行する期間を指定できます。

-o 出力タイプ。 -o csv とすることでCSVでの出力もできます。

-m HTTP method。 GETのサンプルを実行していますが、POST, PUT, DELETE, HEAD, OPTIONSも実行できます。

-H HTTP Header。 HTTPヘッダーを付与することができます。

-t リクエストごとのタイムアウト。(デフォルトは20秒、0で無限とできる)

-A HTTP Accept header。

-d HTTP Request body。

-D HTTP Request body をファイルから入力する。

-T Content-type。

-a Basic認証 username:password の形式で渡す

-x HTTP Proxy

-h2 HTTP/2 を有効化する

そんなかんじ。