日記マン

動画広告プロダクトしてます。Go, Kubernetesが好きです。

GoはネットワークI/Oをどう実現しているか

goroutine自体はOSスレッドに多重化してスケジュールされる。
ランタイムでは goroutine関数をG、OSスレッドをM、GをMに割り当てるスケジューラをP、と名称し実装されている。

qiita.com

ではG全てがI/O実行を行いブロック状態になった場合、Gに紐づかれたMがそのままブロック状態になるのだろうか。
100個のgoroutineが同時にI/O待ちのときに、100個のOSスレッドがI/O待ちの状態になっているのか。

結論からいうとならない。なぜならラインタイム以下で非同期I/Oを実現している。
ネットワークI/Oの場合はGoの標準ライブラリではあたかもブロッキングI/Oのようなインターフェイスを提供しているが、
Goランタイム(で動くsysmonという特別なワーカー)が待ち状態のgoroutineのI/Oを非同期I/Oに変換している。
(Linux環境ではepoll(7)を使う)
そのためOSスレッド自体はネットワークI/O待ちのブロック状態にならずに別のgoroutineの実行を受け入れることができる。

続きを読む

Goのサーバサイドアプリケーションのパフォーマンス可視化に向けたメトリクス設計

最近はGoで書いたアプリケーションをKubernetesで運用し始めたが、
アプリケーションの内部状態を計測できるようにObservabilityの確保にトライしている。

「Observabilityがなぜ必要だと考えるか」について山口さんのエントリはとても学びになった。

ymotongpoo.hatenablog.com

顧客に対し、不便や不満のないようにサービスを提供できているか。
リソースの状態のみならずサービスの健康状態を表すアプリケーションレベルのメトリクスは、可観測性の確保において重要になる。
例えばHTTP応答レイテンシやエラー率などである。
Goならばメモリ管理がGCなのでランタイムレベルのメトリクスも重要になる。
例えばGCの発生頻度や実行レイテンシ。
これらをアプリケーションプロセス側がメトリクスを収集可能に実装することをInstrumentationと呼ぶ。

続きを読む

GoにおけるDBクライアントの設計とObservabilityの確保

Goで sql.DB を扱ってMySQLを扱うとき、
インターフェイスの実装、チューニングできる設定値への理解、Observabilityをどのように確保すればよいか。
ある程度知識がまとまってきたのでアウトプットする。
(実際は sql.DB にない構造体バインディングが欲しかったので sqlx.DB を使っている。)

DBクライアント

func main() {
    stop := utils.SignalHandler(logger)
    cleanup, err := adapter.SetupMySQL(cfg, logger)
    defer func() {
        <-stop
        cleanup()
    }()
     
    db := adapter.GetMySQL()
    // ...
}

DBクライアントのセットアップ関数を実行しクリーンアップ用のコールバックを受け取るインターフェイス

続きを読む

KubernetesのServiceAccount/RBACによる認証・認可

ユーザではなくプログラムからKubernetesのリソースを操作する際、認証はServiceAccount, 認可はRBACの方法が一般的になる。
ServiceAccountの挙動周りを知りたかったのでまとめ。

Kubernetesの認証・認可

Kubernetesのアカウントは人間によるユーザアカウントと、サービスアカウントの二種類がある。
ユーザアカウントは、Kubernetesの認証に利用されるもののKubernetesの管理下ではない。
従って kubectl などで作成・削除することはできない。
対しサービスアカウントは、Kubernetesによって作成され管理される、Kubernetes内のコンポーネントやPodなどで利用されるアカウント。

続きを読む

Goでプログラムを正常に終了する

CNCF系のOSSをコードリーディングしていると、(KubernetesとかPrometheusとかLokiとか)
Go言語の模範的な書き方を学ぶことができて有意義だったりする。
今回は読んでてためになったリファレンスな記述の1つとして、
OSシグナル(ctrl-C)などを受け取ったときに正常終了するためのメモ。(graceful shutdown)

以下の種類のプログラム別にまとめる。

  • デーモンプログラム
  • バッチジョブ
続きを読む

Lokiとpromtailことはじめ

Grafana チームから、ログ収集ソリューションとして Loki がOSSとして公開された。
GAに向けてベータリリースであるがすでに GitHub Star も 7000 に届く勢い。
Prometheus のようなラベリングが可能で、軽量なログソリューションと謳ってる。

https://github.com/grafana/loki

Kubernetes でログ周りどうしようかなーとツールを探していたころに、
Loki を知ったので色々触ってみた。
そして、Lokiの構成要素である promtail について調べてみた。

Loki 概要

| log | <-- | promtail | --> | loki | <-- | Grafana (Explore) | <-- | User |

Loki は ログを収集するエージェントの promtail と、そのログを受け取り保存・クエリエンジンを搭載する Loki で構成される。
Like, Prometheus, but for logs. のキャッチコピー通り、Prometheus のラベリングなど似た機能を持つ。
また、Grafana (>=6.0) にネイティブサポートされており、
Grafanaのダッシュボードで、Prometheus のメトリクスを眺め、Lokiでログを分析し、
問題となるコードを発見・修正する、といった一連の動きを親和性のあるこれらのツールでインテグレーションし、
コンテキストスイッチを減らすことが期待できるとしている。

f:id:i101330:20190818141913p:plain
loki-slide

https://speakerdeck.com/grafana/grafana-loki-like-prometheus-but-for-logs

続きを読む

DaemonSetの名前解決でハマったのでメモ

Kubernetesで、Pod内部のコンテナ同士は、localhostで通信できる。
では、Pod同士の通信には、基本的にはServiceで公開したもの同士で、割り振られるDNSを利用して通信できる。
https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pods

続きを読む