- Speaker: Masayuki Izumi
- Twitter: izumin5210
ライブラリやツールなど、自分以外の人間が「ユーザ」となる開発では、その Interface / Experience が重要であり、生産性や開発の楽しさにも直結します。本セッションでは、自身のこれまでの経験・まわりからのフィードバックから集めた、Developer にとってより良い Interface / Experience なライブラリ・ツールを作るための Tips や考え方を紹介します。
- developer friendly なパッケージ
- simple
- 他のものと絡み合ってない
- 絶対的客観的
- easy
- 身近である, 親しみやすい
- 相対的, 主観的
- easy は悪ではない
- 開発の初速を高める
- simple を損なわずに easy なライブラリデザイン
- 郷に従う
- 慣習に従う
- e.g.
- err 戻り値の最後
- context は引数の最初
- functional option は
With
から始める
- context.Context
- ネットワークIO など時間がかかる処理がある時は必ず context を渡す
- context に span オブジェクトを仕込んだり計測にも用いられる
- Interceper/Middleware
- 処理前後にフックできる機構を作るパターン
- 拡張性を保つ
- redigo
- google-cloud-go
- コンストラクタにオプションを渡せる
- あらゆるものを差し替え可能にしておく
- e.g.
- API Client なら http.NetClient に触れるようにしておく
- e.g.
- コード生成
- 型を活かすためのコード生成
- e.g. ORM, DI
- Go の外に型定義がある場合に有効
- ユーザが生成後のコードを編集することがない様に
- Boilerplate 生成
- 型を活かすためのコード生成
- 勝手に色々やる
- いい感じに色々やる社内ライブラリの例
- ライブラリの init() で全部やってユーザには defer close() させるだけで必要なものが全部揃うライブラリ
- ビジネスロジックに関わるコードだとダメ
- いい感じに色々やる社内ライブラリの例
- Speaker: morikuni
- Twitter: inukirom
これこそGoにおけるエラーハンドリングのベストプラクティス。
- エラーとは
- 処理が失敗した時に発生する
- 既知と未知の2種類
- 未知のエラーが既知になるには
- エラーをハンドリングすることで既知の物になる
- Go の場合だと真の意味で未知なものは panic
- 既知にもレベルがある
- エラーに求められること
- 処理が失敗した原因を伝える必要がある
- アプリケーション
- エラーを識別できること(ハンドリングできる)
- errors.New
- type
- errCode
- interface でメソッドの有無
- clinet の場合は通信プロトコルで定義されているものを用いる
- エンドユーザ
- 問題解決のヒント
- メッセージはユーザが理解できる形式であることが望ましい
- 運用者
- 根本原因の調査, 解決する手助けになる情報が含まれていること
- コーススタック, 引数の情報
- Go でエラーをどう扱うか
- アプリ固有のエラーコードを定義し, エラーを識別する
- 既知の外部のエラーはエラーコードに変換する
- 定義したエラーコードのみを想定してエラーハンドリングする
- エンドユーザがエラーを解決できる場合にメッセージを追加する
- 必要に応じてコールスタック, 引数の情報を追加する
- 未知のものが出たらハンドリングを追加し, 既知にする
- github.com/morikuni/failure
- failure.Translate で err にエラーコードを付与する
- failure.Is でエラーコードで分岐する
- failure.CodeOf でエラーコードを取り出せる
- failure.Message で New や Translate のオプションとして渡せる
- failure.MassageOf でメッセージだけ取り出せる
- failure.New や Wrap を使うと自動でコールスタックが追加される
- failure.Context で引数の情報とかを追加できる
- xerrors の考え方の違い
- failure は error 型に Optional フィールドを足して拡張するイメージ
- xerrors はエラーを変換していくイメージ
- Speaker: Masayuki Matsuki
- Twitter: songmu
Goで外部プロセスを起動する方法をシステムプログラミングにまで踏み込んで解説します。また、外部コマンドのタイムアウトを正しくハンドリングするための、github.com/Songmu/timeoutパッケージの解説もおこないます。これはGNU timeoutのGo portingですが、GNU版との差異についても解説します。
- コマンドラッパー
- コマンドを引数で受けて実行しつつ, 他のこともやってくれる
- コマンドを起動する
- os/exec package
- cmd.Stdin とかが io.Reader/Writer とかになってる
- マージ出力
- io.MulutiWriter で複数 Writer に書き出せる
- 出力を維持しつつ, 出力を受ける
- io.TeeReader
- タイムスタンプを自動付与
- golang.org/x/text/transform.Transformer が便利
- コマンドを停止する
- 親が停止するときの後片付け
- 強制停止
- kill を使うのが定番
- kill はシグナルを送る
- プロセスはシグナルを受け取って, それに対応するアクションを行う
- SIGINT, SIGKILL, SIGTERM...
- シグナルハンドリング
- プロセスはシグナルをトラップしてハンドリングできる
- SIGKILL とSIGSTOP はハンドリングできない
- まず SIGTERM で正常数量を促すのが作法
- Go でコマンド停止
- exec.CommandContext がある
- タイムアウトもできる
- 内部的に p.Signal(kill) を呼び出している
- SIGKILL で強制停止している
- 孫があった時に止まらない
- Go の公式の見解
- 標準じゃないパッケージでやろう
- github.com/Songmu/timeout
- いきなり SIGKILL を送らない
- プロセスじゃなくてプロセスグループにシグナルを送る
- プロセスグループにシグナルを送る
- syscall.Kill に PID のマイナスを送る
- 一時停止しているプログラムはすぐには止まらない
- SIGCONT を送って強制的に起こす
- 終了コードを正しく取得する
- WaitStatus.ExitStatus はシグナルを受けた時は -1 になる
- Speaker: Kazuki Higashiguchi
- Twitter: hgsgtk
Go言語でのアプリケーション開発で、特にコンテナを前提とする場合の設計考慮点について話します。 例えば、Go言語でAPIを開発する場合、コンテナとして動かすことを前提とするケースが多いと感じます。コンテナベースで動かすことを前提とした場合、コンテナイメージ作成・アプリケーション監視において、考慮すべき点が出てくるでしょう。このトークでは、Go言語での実装にまで踏み込んだ上で、コンテナベースアプリケーションにおける設計の考慮点について話します。
- 設定情報
- 環境ごとに異なる
- 秘匿情報を含む
- 階層的管理したい
- 秘匿情報の管理 (必要以上に参照できない様にする)
- 設定情報はコードから取り除く
- 環境変数への格納
- イメージ不変性の原則
- Container Image のアプリは不変
- 環境変数を用いる
- config package
- API 起動時に環境変数から設定情報を取得
- caarlos0/env を使って struct にマッピング
- logging
- ログはイベントストリームとして扱う
- ファイルシステムに依存しない
- 全部のログは stdout, stderr に吐き出す
- 構造化ログを使う
- 情報抽出
- logger package
- stdout に吐き出す
- zap を使う
- 起動時に main で初期化関数を呼び出す
- ログの書き出しのタイミングでグローバルの logger を取り出して利用する
- monitoring
- 健康状態を伝える API の提供
- 依存サービスの利用状況も確認する
- ヘルスチェックを行うエンドポイントを作成
- Speaker: Yoshi Yamaguchi
- Twitter: ymotongpoo
Go standard toolkit provides benchmark, tracer and profiler out of the box and its ecosystem provides those extensions that fit large-scale systems. In this talk, I’ll introduce how you can start implementing performant applications with standard tools, and how you can expand it to larger scale app.
- observability
- システムのある種の属性のこと
- パフォーマンスチューニング
- input を与えて output を得る, output が期待している物になっているかを見る
- Unit test と同じ
- 比較する値はメトリクスになる
- パフォーマンスチューニングの始め方
- メトリクスを出す
- 全体観を知る, ボトルネックを見つける
- 特定の部分に対してベンチマークを書く
- Profile から初めて Trace に持っていく
- Profile
- runtime/pprof
- CLI, batch
- net/http/pprof
- server, deamon
- go tool pprof -http=":8888" で WebUI が見れる
- Flat がベタ書きされているもののみ (他の関数呼び出しの時間は除外)
- Cum が他の func 呼び出しも含めて全体
- 実線は関数呼び出し, 点線は間に小さい関数があるが省略されている
- runtime/pprof
- ベンチマーク
- testing.B
- for で b.N を使う
- go test コマンドに -bench オプションを渡す
- Trace
- runtime/trace
- net/http/trace
- Task -> Region -> Log
- Task 関数の大きな塊
- Region goroutine とかに
- trace.NewTask, defer task.Close()
- curl で trace のエンドポイント叩く
- go tool trace で UI で見る
- Speaker: po3rin
- Twitter: po3rin
Dockerに正式統合されたBuildKitをGoで扱う方法について発表します。
BuildKit は Goで実装されている為、Goのソースコードを読むことでGoを使ったDockerfile解析ツールや、独自のBuildKit LLB frontendを作成できます。
今回の発表ではGoでどのようにBuildkitが記述されているかをコードを追いながら、Goを使ったDoコンテナイメージフロントエンドの解析ツールの作り方や、独自のコンテナイメージフロントエンドの作り方にも触れて行く為、Goでコンテナ技術を理解する大きな1歩になるでしょう。
- BuildKit
- 環境変数設定する
- build が並列に動いたりしてくれる
- LLB
- BuildKit のコアとなるデータ構造
- グラフの矢印を折っても循環しない
- protbuf で定義されている
- stage の中での共通部分もまとめてくれたりしてくれる
- Dockerfile を LLB に変換, それを buildkitd に送ってる
- Dockerfile2LLB という関数で Dockerfile の byte を渡すといい感じに変換してくれる
- Dockerfile2LLB
- Dockerfile を AST に変換
- Speaker: ktr
- Twitter: ktr_0731
fzf や peco のような、インタラクティブにリストから特定の要素を検索・選択できるようなツールの登場は、コマンドラインにおける表現をより一層豊かにさせました。しかし、行指向には限界があり、こういった fuzzy finder はその能力を十分に発揮することができていません。このセッションではコマンドライン fuzzy finder が抱える問題を説明し、その問題を fuzzy finder をライブラリとして提供することで解決することを試みた話をします。
- fuzzy finder の問題
- 行志向
- 組み込む際の問題
- 行志向
- Unique にしないとわからない
- 情報量を増やすと見辛い
- 補助情報も検索対象になる
- 組み込む際の問題
- まずコマンドライン fuzzy finder をインストールする必要がある
- ツールが認識できる様に環境変数に入れる
- fuzzy finder as library
- 組み込む際にツールのインストールが不要になる
- github.com/ktr0731/go-fuzzy-finder
- Speaker: nasa9084
- Twitter: nasa9084
Quota、あるいはRate Limitという単語を聞いたことがありますか?あるサービスのリソース単位の割当量をQuota、その中でも特に、APIのリクエスト数など、ある一定時間に対してかけられた制限をRate Limitなどと呼びます。本セッションでは、Quota as a Serviceを実装するに至った経緯や、実際に実装していくにあたって検討したアルゴリズムやOSSとして公開されているQuotaライブラリについて紹介・解説、実装で考慮する必要があった課題とその解決についてお話します。
- Quota
- 割り当て
- Rate Limit とかでよく使われる
- モニタリングシステムなのでリクエストがめっちゃくる
- Rate Limit を設けたい
- Token Bucket
- トラフィック平均の量を制限する
- バーストについてはある程度許容する
- バッファとか Queue で実装する
- バケツにチケットをためてリクエストが来るたびに1つずつ取っていく
- チケットがなくなったらそのリクエストは弾く, 一定時間でバケツにチケットを増やしていく
- Leaky Bucket
- 最大量を制限する
- バーストも許容しない
- ピークに対して制限をかけるので帯域を全てうまく使えない可能性がある
- ATM のネットワークが似た様なもの使ってる
- 一定のキャパシティのバケットから設定した帯域の分だけリクエストが漏れてくるようなアルゴリズム
- Fixed Window Counter
- 現実の時間あたりのリクエスト数を制限する
- 一定の時間の幅あたりの一定のリクエストを制限
- 10 - 11 時で xxx/req みたいな
- 固定された時間でリクエストを制限するのでずれた時間で見たときに制限できていないことがある
- Sliding Window Counter
- 今の時間からある時間までのリクエストを制限する
- Fixed Window Counter の改良
- bucket4j
- Java
- Token Bucket
- Stable for multi-sthread
- 1アプリの中でステートを持つ
- ratelimit
- python
- decorator
- 1アプリでステートを持つ
- Quota Service
- suare/quotaservice
- Go
- gRPC
- Token Bucket
- 良さそうだけど WIP
- 実装の参考にした
- lyft/ratelimit
- Go
- gRPC
- Envoy と一緒に使う
- suare/quotaservice
- golang-standards/project-layout