趣味と仕事の違い、現場で求められるアプリケーションの可観測性

9.6K Views

March 17, 22

スライド概要

2022年技育祭用スライド

profile-image

LIFULL HOME'Sを運営する株式会社LIFULLのアカウントです。 LIFULLが主催するエンジニア向けイベント「Ltech」等で公開されたスライド等をこちらで共有しております。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

2.

趣味と仕事の違い、 現場で求められるアプリケーションの可観測性 株式会社LIFULL 相原 魁 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

3.

1.紹介 2.趣味のアプリケーションでやりがちなこと 目次 3.仕事のアプリケーションで求められるもの 4.アプリケーションの可観測性の勘所 5.おまけ(時間があれば) Copyright© LIFULL Co.,Ltd. All Rights Reserved.

4.

自己紹介 - 株式会社LIFULL 相原 魁 - ソフトウェアエンジニア スペシャリスト(Platform Engineering, SRE) - 仕事ではKubernetesをベースとした内製PaaS KEELを開発・運用 - 趣味では主にRustを書いています - 全文検索ライブラリ - 分散検索エンジン - eBPF Copyright© LIFULL Co.,Ltd. All Rights Reserved.

5.

自己紹介 - 株式会社LIFULL 相原 魁 - ソフトウェアエンジニア スペシャリスト(Platform Engineering, SRE) - 仕事ではKubernetesをベースとした内製PaaS KEELを開発・運用 - 趣味では主にRustを書いています - 全文検索ライブラリ - 分散検索エンジン - eBPF 分散システムを開発する中で可観測性に注力 Copyright© LIFULL Co.,Ltd. All Rights Reserved. 可観測性のプラットフォームも開発する立場

6.

「したい暮らしに、出会おう。」をコンセプトに掲げ、簡単で便利な住まい探しをお手伝いする不動産・住宅情報の総合サービスです。 物件の探しやすさや住まいに関する情報の見つけやすさ、検討がしやすくなるように、様々な機能や情報を拡充していきます。 今後も、ユーザーに寄り添いながら、ともに理想の住まい探しを実現します。 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

7.

LIFULLの内製PaaS KEEL - コマンドを1発叩くだけで完璧なアプリケーション実行環境が手に入る内製PaaS - デプロイ、セキュリティ、可観測性、信頼性、パフォーマンス - コードジェネレータを中心とした開発者体験の提供 - Pull Requestを作成するとプレビューできる機能やLint, Content Trustまで備える - https://www.lifull.blog/archive/category/Kubernetes Copyright© LIFULL Co.,Ltd. All Rights Reserved.

8.

本日のゴール 可観測性に優れたアプリケーションを実装できるようになる ※少しWebに寄った話になります ※後でリファレンスとして使えるよう説明的な資料にしているので今全てを理解する必要はないです Copyright© LIFULL Co.,Ltd. All Rights Reserved.

9.

趣味のアプリケーションでやりがちなこと Copyright© LIFULL Co.,Ltd. All Rights Reserved.

10.
[beta]
エラーをとりあえずでロギングするだけ
func doSomething() *RetVal {
retval, err := maybeError()
if err != nil {
log.Printf("an error occurred: %+v", err)
}
return retval
}
Copyright© LIFULL Co.,Ltd. All Rights Reserved.

11.

そもそもエラーをハンドリングをしない func doSomething() *RetVal { retval, _ := maybeError() return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

12.
[beta]
Rustだったらunwrap()するだけとか
fn doSomething() RetVal {
let result: Result<RetVal> = maybeError();
let retval = result.unwrap();
retval
}

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

13.

Rubyなら全ての例外をもみ消したり def doSomething do maybeError rescue {} end Copyright© LIFULL Co.,Ltd. All Rights Reserved.

14.

実行時間の計測をログで頑張る func doSomething() *RetVal { start := time.Now() retval := maybeSlow() elapsed := time.Since(start) log.Printf("maybeSlow took: %s", elapsed) return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

15.

そもそも実行時間を気にしない func doSomething() *RetVal { retval := maybeSlow() return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

16.
[beta]
折角もらったエラーを適当に標準エラーする

func main()
retval, err := doSomething()
if err != nil {
fmt.Fprintf(os.Stderr, "%+v", err)
}
}
func doSomething() (*RetVal, error) {...}
Copyright© LIFULL Co.,Ltd. All Rights Reserved.

17.

仕事のアプリケーションで求められるもの Copyright© LIFULL Co.,Ltd. All Rights Reserved.

18.

趣味と仕事の違い - 開発者である自分自身だけが未来永劫メンテナンスし続けるわけではない - 実装に詳しくない人が状況を判断できる必要がある Copyright© LIFULL Co.,Ltd. All Rights Reserved.

19.

趣味と仕事の違い - 開発者である自分自身だけが未来永劫メンテナンスし続けるわけではない - 実装に詳しくない人が状況を判断できる必要がある ソースコードを読むことも書き換えることもなく必要な情報を取得できる Copyright© LIFULL Co.,Ltd. All Rights Reserved.

20.

可観測性 - 可観測性(observability)とは、システムの外部出力を観測することでシステムの内部状態を推 測可能かどうかの尺度である。 - 引用: 状態空間 (制御理論)#可観測性 - microservicesの流行などによってシステムの構成が複雑化して重要性が増してきている Copyright© LIFULL Co.,Ltd. All Rights Reserved.

21.

Primary Signals 可観測性の基本的な3つのシグナル Metrics Traces Copyright© LIFULL Co.,Ltd. All Rights Reserved. Logs

22.

Metrics - 特にフォーマットのないテキストデータ - 出力方法 Traces Copyright© LIFULL Co.,Ltd. All Rights Reserved. Logs - アプリケーションからファイルに書き込む - アプリケーションから標準出力・標準エラーする

23.

アプリケーションログ - エラーをはじめアプリケーション内のイベントを記録するログ Copyright© LIFULL Co.,Ltd. All Rights Reserved.

24.

HTTPサーバのアクセスログ - HTTPのサーバがリクエストを受けた時のログ Copyright© LIFULL Co.,Ltd. All Rights Reserved.

25.

監査ログ - 誰が何をしたかというイベントを記録するログ - 主に認証のあるアプリケーション等で出力する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

26.

Metrics - インデックス付きの数値データ - OpenMetricsで標準化が進んでいる - 数値データであるためLogsと比較して安価 Traces Logs - 出力方法 - エージェントが外部から観測して出力 - アプリケーション内で計測して出力 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

27.

余談: OpenMetrics - Prometheusというモニタリングシステムを参考に標準化されたフォーマット - summary, gauge, counter, statesetといったいくつかのデータタイプでMetricsを表現 - エージェントあるいはアプリケーションがこのフォーマットに従って出力する - Datadogをはじめ多くのモニタリングシステムがサポート Copyright© LIFULL Co.,Ltd. All Rights Reserved.

28.

CPU, Memory Usage - Linuxでは /proc から取得することができる - /proc はプロセスの情報を持つ擬似ファイルシステム - /proc/<PID>/statでは14, 15個目がCPUに関する情報 - 実際はエージェントが勝手に収集してくれていることが大半 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

29.

アプリケーションのエラー数 - アプリケーション内部のエラー数のカウンタ - Logsでも表現できるがコストの観点からMetricsであるとよい 引用: kubernetes/autoscaler Copyright© LIFULL Co.,Ltd. All Rights Reserved.

30.
[beta]
Garbage Collectorに関する情報
- ランタイム内に持っているGCの情報
- アプリケーション内で収集して出力する
pp GC.stat
#{:count=>13,
# :heap_allocated_pages=>50,
# :heap_sorted_length=>69,
# :heap_allocatable_pages=>19,
# :heap_available_slots=>20383,
# :heap_live_slots=>20256,
# :heap_free_slots=>127,
# :heap_final_slots=>0,
# :heap_marked_slots=>17090,
# :heap_eden_pages=>50,
# :heap_tomb_pages=>0,
# …}
Copyright© LIFULL Co.,Ltd. All Rights Reserved.

31.

ミドルウェアの各種情報 - ミドルウェアによって出力されているMetrics - e.g. ngx_http_stub_status_module - エージェントが収集しに行って出力する - ミドルウェア自身が直接出力するケースも増えてきている Copyright© LIFULL Co.,Ltd. All Rights Reserved.

32.

余談: Prometheus Exporter - Metricsを出力するためのPrometheus用のエージェント - PrometheusのMetrics表現はOpenMetricsと互換性があるため広く利用できる - OSSとして多くのPrometheus Exporterが存在する - MySQL Server Exporter - Redis Exporter - NGINX Prometheus Exporter - cAdvisor - 利用するミドルウェアに対応するPrometheus Exporterを探すことができる - EXPORTERS AND INTEGRATIONS Copyright© LIFULL Co.,Ltd. All Rights Reserved.

33.

インデックスとカーディナリティ - MetricsはラベルというKey-Valueを元にインデックスする - ラベルの数が多いとカーディナリティが高くなりコスト増 - e.g. {uri=”/items/1”}, {uri=”/items/2”}, … {uri=”/items/9999”} - こういった詳細な情報の表現はLogsの方が向く Copyright© LIFULL Co.,Ltd. All Rights Reserved.

34.

Metrics - 依存関係を持つメタデータの有向非巡回グラフ - Spanというデータ構造の集合からなる Traces Logs - OpenTelemetryで標準化が進んでいる - 計測も保存も比較的コストが高い - サンプリング(間引き)をすることが一般的 - 出力方法 - アプリケーション内で計測して出力 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

35.

余談: OpenTelemetry - OpenTracingとOpenCensusが統合されて生まれたプロジェクト - OpenTracingはTracesの標準化をしていたプロジェクト - OpenCensusはTracesとMetricsの収集を補助するライブラリ - OpenTracingはベンダー中立にPropagationするための仕様を策定していた Copyright© LIFULL Co.,Ltd. All Rights Reserved.

36.

引用: Jaeger documentation Copyright© LIFULL Co.,Ltd. All Rights Reserved.

37.

Span 引用: Jaeger documentation Copyright© LIFULL Co.,Ltd. All Rights Reserved.

38.

Span Trace 引用: Jaeger documentation Copyright© LIFULL Co.,Ltd. All Rights Reserved.

39.

Span - 開始・終了のタイムスタンプとKey-Valueのラベル等を持つ - 0つ以上の親となるSpanを持つことができる 引用: OpenTracing Specification Copyright© LIFULL Co.,Ltd. All Rights Reserved.

40.

Propagation - アプリケーションをまたいだ依存関係を持つことができる - アプリケーション間の依存関係はHTTPヘッダで引き回す - W3C Trace Context - traceparent Header - trace-id - parent-id - sampled - microservicesの依存関係を可視化することができる Copyright© LIFULL Co.,Ltd. All Rights Reserved.

41.

再掲 実行時間の計測をログで頑張る func doSomething() *RetVal { start := time.Now() retval := maybeSlow() elapsed := time.Since(start) log.Printf("maybeSlow took: %s", elapsed) return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

42.

再掲 実行時間の計測をログで頑張る func doSomething() *RetVal { start := time.Now() maybeSlowが複雑な依存関係を持つ場合Metricsだけでは調査しづらい retval := maybeSlow() Tracesも収集することで依存関係のボトルネックを探せるようにしたい elapsed := time.Since(start) log.Printf("maybeSlow took: %s", elapsed) return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

43.

OpenMetricsとExemplars - OpenMetricsは外部のデータに対する参照を持つことができる - ExemplarsというKey-Value - MetricsとTracesを関連付けることができる 引用: Exemplars | Grafana Labs Copyright© LIFULL Co.,Ltd. All Rights Reserved.

44.

ここまでのまとめ - 実装に詳しくない人が状況を判断できるよう可観測性が重要 - 可観測性には3つの性質の違う主要なシグナルがある - Logs: 自由度が高くフォーマットを持たないテキストデータ - Metrics: 詳細な情報を安価に表現するインデックスつきの数値データ - Traces: 複雑な依存関係を表現できるメタデータの有向グラフ - それぞれ補完しあう関係にあるため組み合わせて使う - Metricsはコストが安いが詳細情報や依存関係を持てない - Logsは詳細情報を持てるがコストが高い - Tracesは依存関係を持てるが表現が限定的でコストが少し高い Copyright© LIFULL Co.,Ltd. All Rights Reserved.

45.

余談: 周辺エコシステム - Logs - Grafana Loki, ElasticSearch - Amazon CloudWatch Logs - Cloud Logging - Metrics - Prometheus(Cortex) - All-in-one - Datadog - NewRelic - Grafana(?) - OSSのObservability Platform - Loki, Cortex, TempoのGrafana Labsが開発 - Amazon CloudWatch - Cloud Monitoring - Traces - Grafana Tempo, Jaeger - AWS X-Ray - Cloud Trace Copyright© LIFULL Co.,Ltd. All Rights Reserved. OpenMetrics, OpenTelemetry含め殆どがCNCF周りのもの

46.

余談: CNCF - > Cloud Native Computing Foundationは、オープンソースでベンダー中立プロジェクトのエコシ ステムを育成・維持して、このパラダイムの採用を促進したいと考えてます。 私たちは最先端 のパターンを民主化し、これらのイノベーションを誰もが利用できるようにします。 (https://github.com/cncf/toc/blob/main/DEFINITION.md) Copyright© LIFULL Co.,Ltd. All Rights Reserved. 引用: CNCF Landscape

47.

引用: CNCF Landscape Copyright© LIFULL Co.,Ltd. All Rights Reserved.

48.

ケーススタディ: レスポンス速度の遅延 1.どうやらレスポンス速度が遅くなっているらしいと監視から通知を受け取る 2.まずはMetricsからどんなアプリケーションのどのリクエストが遅延したか確認 foo Applicationの /bar が遅延していた 3.次はLogsでfoo Applicationの /bar でエラーログが出力されていないかどうかを確認 このリクエストはrequestid=bazでこのrequestidにエラーログはなかった 4.Tracesでrequestidを調べるとMySQLにクエリしていてその速度が遅延していた 5.MySQLに関するMetricsを確認すると同時間帯に接続数が増大していた Copyright© LIFULL Co.,Ltd. All Rights Reserved.

49.

アプリケーションの可観測性の勘所 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

50.

エラーハンドリング 指針 1. エラーをどう取り扱うかは呼び出し元に決めさせる - Logs, Metricsはエラーを起点とすることが多い - エラーハンドリングを正しくしていないと出力しづらい 2. 必要なコンテキストを付与する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

51.
[beta]
再掲
エラーをとりあえずでロギングするだけ
func doSomething() *RetVal {
retval, err := maybeError()
if err != nil {
log.Printf("an error occurred: %+v", err)
}
return retval
}
Copyright© LIFULL Co.,Ltd. All Rights Reserved.

52.

再掲 そもそもエラーをハンドリングをしない func doSomething() *RetVal { retval, _ := maybeError() return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

53.
[beta]
再掲
Rustだったらunwrap()するだけとか
fn doSomething() RetVal {
let result: Result<RetVal> = maybeError();
let retval = result.unwrap();
retval
}

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

54.

再掲 Rubyなら全ての例外をもみ消したり def doSomething do maybeError rescue {} end Copyright© LIFULL Co.,Ltd. All Rights Reserved.

55.
[beta]
指針
1.
2.

エラーをどう取り扱うかは呼び出し元に決めさせる
必要なコンテキストを付与する
①

func doSomething() (*RetVal, error) {
retval, err := maybeError()
② 独自のエラー型・例外でラップするなど
if err != nil {
return nil, xerrors.Errorf("failed to execute maybeError: %w", err)
}
return retval, nil
}

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

56.

余談: 例外を乱用しない - 例外でラップする例を挙げたが例外は乱用してはならない - フロー制御として使うにはコストが高い - 例外はあくまで”例外”であるため普段起こりうるフローでは利用しない - Replacing Throwing Exceptions with Notification in Validations - エラーハンドラ Copyright© LIFULL Co.,Ltd. All Rights Reserved.

57.

Logs 指針 1. ユーザの個人情報など秘匿情報を記録しない - 秘匿情報が記録されたログは閲覧者が制限される - 可観測性が満たされない 2. どのイベントに紐づくログであるかを記録する 3. 分析のしやすいフォーマットにする Copyright© LIFULL Co.,Ltd. All Rights Reserved.

58.

HTTPのURIに秘匿情報を含めない - アクセスログにそのままpasswordが記録されてしまう GET /secrets?password=foobar HTTP/1.1 Host: example.com User-Agent: curl/7.58.0 Accept: */* 指針: ユーザの個人情報など秘匿情報を記録しない Copyright© LIFULL Co.,Ltd. All Rights Reserved.

59.
[beta]
外部からの入力をそのままログにしない
- パラメータとしてユーザの電話番号を受け取っていた場合ログに出力されてしまう

def validation(parameters)
parameters.each do |parameter|
if rules[parameter[:key]].valid?(parameter[:value])
STDERR.puts "#{parameter[:value]} is invalid"
end
end
end

指針: ユーザの個人情報など秘匿情報を記録しない

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

60.
[beta]
再掲
折角もらったエラーを適当に標準エラーする

func main()
retval, err := doSomething()
if err != nil {
fmt.Fprintf(os.Stderr, "%+v", err)
}
}
func doSomething() (*RetVal, error) {...}
Copyright© LIFULL Co.,Ltd. All Rights Reserved.

61.

HTTPサーバならRequestIDを含める - 慣例的にHTTPではX-Request-Idというヘッダでリクエストを一意に識別する - 最前段のHTTPサーバで発行して、各HTTPクライアントはそれを引き回す - これをアクセスログやエラーログに含めておくとリクエストをまとめて検索できる 指針: どのイベントに紐づくログであるかを記録する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

62.

ログの出力元やStack Traceを含める - ソースコードのどこで原因となるイベントが発生したかを調べられる必要がある - Stack Traceはデータ量が大きい反面、情報量が多い - ログを見た後、詳細な調査が必要なエラーでStack Traceを出力することが多い - 前述の通り呼び出し元がエラーを受け取りStack Traceを出力する 指針: どのイベントに紐づくログであるかを記録する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

63.

必要に応じてJSONで出力する - 主要なLogsのObservability PlatformはJSONをParseする機能を備えている - HTTPサーバのアクセスログなどログを元に分析する場合はJSONが好ましい - syslogやLTSVなどその他のフォーマットもあるがPlatformのサポートが厚いのはJSON 指針: 分析のしやすいフォーマットにする Copyright© LIFULL Co.,Ltd. All Rights Reserved.

64.

余談: ログレベル(持論) - ログレベルとは対象のログの深刻度を示すもの - 一般に以下のようなログレベルが採用されることが多い - DEBUG - INFO - WARN - ERROR - CRITICAL - ログは前述の通りコストが高いため無視されるログは必要がない - 不用意にログレベルを増やすと無視されるログを増やすことに繋がる - 全てのエラーは等しく対応をすべきだとして以下のみから始めることが多い - DEBUG - INFO - ERROR Copyright© LIFULL Co.,Ltd. All Rights Reserved.

65.

Metrics 指針 1. USEメソッド - Utilization - Saturations - Errors 2. REDメソッド - Rate - Errors - Duration Copyright© LIFULL Co.,Ltd. All Rights Reserved.

66.

USEメソッド - Brendan Greggによって提唱されたMetrics収集の方法論 - あるリソースに対してUtilization, Saturations, Errorsを収集する - 各リソースのMetricsの例示は The USE Method を参照 - ハードウェアリソースはエージェントが既に収集していることが多い - エージェントの不足分やソフトウェアリソースをUSEメソッドに従って収集する ECONNREFUSED - 古典的なTCPサーバで考えた場合 - Utilization: ActiveなWorker数 / 総Worker数 - Saturations: Backlogに積まれたIn-QueueなConnection数 - Errors: ECONNREFUSEDが返った数 Master Worker Copyright© LIFULL Co.,Ltd. All Rights Reserved. Worker Worker

67.

引用: The USE Method Copyright© LIFULL Co.,Ltd. All Rights Reserved.

68.

REDメソッド - USEメソッドがリソース単位であることに対してREDメソッドはサービス単位 - REDメソッドの適用先はより限定的 - It is fair to say this method only works for request-driven services(The RED Method) - あるサービスに対してRate, Errors, Durationを収集する - microservicesの場合はデータストア含む依存するサービスに対して収集を考える - 検索エンジンで考えた場合 - Rate: 検索エンジンに対するRequests per second - Errors: レスポンスのエラー数 - Duration: レスポンスのレイテンシ Copyright© LIFULL Co.,Ltd. All Rights Reserved.

69.

再掲 実行時間の計測をログで頑張る func doSomething() *RetVal { start := time.Now() retval := maybeSlow() elapsed := time.Since(start) log.Printf("maybeSlow took: %s", elapsed) return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

70.

再掲 実行時間の計測をログで頑張る func doSomething() *RetVal { start := time.Now() retval := maybeSlow() この手のものはMetricsとして管理してコストを安くしたい elapsed := time.Since(start) log.Printf("maybeSlow took: %s", elapsed) return retval } Copyright© LIFULL Co.,Ltd. All Rights Reserved.

71.

出力の方法 - アプリケーションがOpenMetrics形式でMetricsを出力する - Prometheusのクライアントライブラリを入れるなど - アプリケーションのMetricsをエージェントが収集して出力する - nginxの/nginx_statusをNGINX Prometheus Exporterが出力するなど Copyright© LIFULL Co.,Ltd. All Rights Reserved.

72.

メソッドに従うことのメリット - Metricsは収集した後に監視・可視化をするが、処理を共通化させやすい - 抜け漏れなくMetricsを収集することができる - これらはあくまで指針であるためアプリケーション固有のものは別途収集する - Garbage Collectorの情報 - アプリケーションの状態 - ランタイム固有のグリーンスレッドの数 Copyright© LIFULL Co.,Ltd. All Rights Reserved.

73.

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

74.

- CPUの使用率にPod間の偏りが存在する(Sticky Session下での過負荷など) - cgroupで設定したlimits.memoryまでメモリを使い切れていない - メトリクスの収集に失敗している - NetworkのReceiveでパケットが落とされている - NetworkのTransmitでパケットが落とされている - Podがrestartを短時間に繰り返している - Podがスケジュール待ちなど不正な状態が継続している - PodのHealthCheckが失敗している - 全てのPodのHealthCheckが失敗している - PodがImageの取得に失敗するなどして待機状態になっている - Podのメモリが不足し始めている - Nodeのリソース不足などが原因でPodが大量に退避させれている - Podがスケールアウトの限界に近付いている - Podのエラーレートが増加している - Podの特定のURIのエラーレートが増加している and more... Copyright© LIFULL Co.,Ltd. All Rights Reserved.

75.

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

76.

Traces 指針 1. とりあえずOpenTelemetryを使っておく Copyright© LIFULL Co.,Ltd. All Rights Reserved.

77.

再掲 余談: OpenTelemetry - OpenTracingとOpenCensusが統合されて生まれたプロジェクト - OpenTracingはTracesの標準化をしていたプロジェクト - OpenCensusはTracesとMetricsの収集を補助するライブラリ - OpenTracingはベンダー中立にPropagationするための仕様を策定していた Copyright© LIFULL Co.,Ltd. All Rights Reserved.

78.

再掲 余談: OpenTelemetry - OpenTracingとOpenCensusが統合されて生まれたプロジェクト - OpenTracingはTracesの標準化をしていたプロジェクト - OpenCensusはTracesとMetricsの収集を補助するライブラリ OpenTelemetryもOpenCensusに引き続き各言語向けにライブラリを提供 - OpenTracingはベンダー中立にPropagationするための仕様を策定していた Copyright© LIFULL Co.,Ltd. All Rights Reserved.

79.

Copyright© LIFULL Co.,Ltd. All Rights Reserved.

80.

OpenTelemetry SDKの機能 - OpenMetrics, OpenTracing(OpenTelemetry)に準拠したMetrics, Tracesの出力 - Prometheusのクライアントライブラリを別途入れる必要なし - 各種クライアントの自動Metrics, Traces収集, 自動Propagation - HTTPクライアント - DBクライアント - とりあえずOpenTelemetryを入れるだけで外部IOへのTracesは概ね完了 - IOを伴わない部分のTracesは後から考えれば十分 - 個別でSpanを埋める対応が必要となる - Metricsは自身での追加のMetricsの収集が必要 - Log Data ModelでログのサポートもあるがSDK側は未実装が多い - 将来はこれだけでLogsまで任せられる可能性も Copyright© LIFULL Co.,Ltd. All Rights Reserved.

81.

再掲 HTTPサーバならRequestIDを含める - 慣例的にHTTPではX-Request-Idというヘッダでリクエストを一意に識別する - 最前段のHTTPサーバで発行して、各HTTPクライアントはそれを引き回す - これをアクセスログやエラーログに含めておくとリクエストをまとめて検索できる 指針: どのイベントに紐づくログであるかを記録する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

82.

再掲 HTTPサーバならRequestIDを含める - 慣例的にHTTPではX-Request-Idというヘッダでリクエストを一意に識別する - 最前段のHTTPサーバで発行して、各HTTPクライアントはそれを引き回す - これをアクセスログやエラーログに含めておくとリクエストをまとめて検索できる OpenTelemetry導入後は代わりにtrace-idを利用することができる 指針: どのイベントに紐づくログであるかを記録する Copyright© LIFULL Co.,Ltd. All Rights Reserved.

83.

まとめ エラーハンドリング 1. エラーをどう取り扱うかは呼び出し元に決めさせる 2. 必要なコンテキストを付与する Logs 1. ユーザの個人情報など秘匿情報を記録しない 2. どのイベントに紐づくログであるかを記録する 3. 分析のしやすいフォーマットにする Metrics 1. USEメソッド 2. REDメソッド Traces 1. とりあえずOpenTelemetryを使っておく Copyright© LIFULL Co.,Ltd. All Rights Reserved.

84.

最後に - 可観測性は実装に詳しくない人が状況を判断するために必要 - 仕事の現場では自身だけがメンテナンスし続けるわけにはいかない - 指針に従ってPrimary Signalsを収集することで可観測性を向上させることができる - それぞれは補完しあうためどれも欠けてはならない 可観測性やパフォーマンスのような非機能要件こそ腕の見せ所 可観測性に優れたアプリケーションを実装しましょう CNCFでも可観測性(Observability)は大きなトピックで投資価値は十分あると思います Copyright© LIFULL Co.,Ltd. All Rights Reserved.

85.

おまけ Copyright© LIFULL Co.,Ltd. All Rights Reserved.

86.

プロファイラ - プログラム実行中の関数の呼び出し回数や実行時間などを計測するためのソフトウェア - 実行時にオーバーヘッドを伴うものが多く開発時に利用することが一般的 - プログラムのボトルネックを特定できる - 代表的なソフトウェア - Linux perf - Valgrind - google/pprof - Go - V8’s sample-based profiler(google/pprof-nodejs) - Node.js Copyright© LIFULL Co.,Ltd. All Rights Reserved. 引用: https://github.com/google/pprof

87.

sample-based profiler - 統計的なアプローチで精度と引き換えにオーバーヘッドを最小化するプロファイラ - google/pprof - V8’s sample-based profiler(google/pprof-nodejs) - 定期的にコールスタックを読んで収集する - Event profilerは精度が高い一方でイベント数が多くオーバーヘッドが大きい - Linux perfは両方に対応している Copyright© LIFULL Co.,Ltd. All Rights Reserved.

88.

継続的プロファイリング - プロファイラはオーバーヘッドが大きく開発時しか利用できなかった - sample-based profilerと言えどもオーバーヘッドはある - それらを利用した継続的プロファイリングを提供するサービスが開始 - Cloud Profiler - Datadog Continuous Profiler - 継続的プロファイリングでは1分間に10秒間だけのようにプロファイリングする - Tracesと比較して個別で対応することなく関数のボトルネックを探すことができる - プロファイリングはネットワークを跨ぐことはできないためその点でTracesは有用 - 可観測性を更に向上させるSignalの一つとなりつつある Copyright© LIFULL Co.,Ltd. All Rights Reserved.

89.

eBPF - eBPFはLinuxカーネルにおけるJavaScriptのようなもの - JavaScriptと同様にサンドボックスなVM上で稼働する - JavaScriptがHTMLにすることと同様にLinuxカーネルのイベントに処理をアタッチする - C言語でeBPFプログラムを記述するとそれがカーネル空間で安全に実行される - ユーザ空間に渡す必要がないから高速 - 様々なイベントに対応していて可観測性に対して大きな力を持つ - kprobe/kretprobe: カーネルの関数呼び出し・終了 - uprobe/uretprobe: バイナリの任意のオフセットの関数の呼び出し・終了 - 可観測性の他にセキュリティ分野でも注目されていてCNCFの熱いトピックの一つ - アプリケーションに影響を与えることなく危険なsyscallの実行を監視したり Copyright© LIFULL Co.,Ltd. All Rights Reserved.

90.

PyroScope - オープンソースの継続的プロファイリングのプラットフォーム - Cloud Profiler他と同様にgoogle/pprofなどを使いながら継続的プロファイリングをする - eBPFのサポートもありより小さいオーバーヘッドでの実行が期待できる - ※ 現時点ではbccに依存していていくつかの問題がある - 興味があれば: BPF Portability and CO-RE Copyright© LIFULL Co.,Ltd. All Rights Reserved.

91.

再掲 LIFULLの内製PaaS KEEL - コマンドを1発叩くだけで完璧なアプリケーション実行環境が手に入る内製PaaS - デプロイ、セキュリティ、可観測性、信頼性、パフォーマンス - コードジェネレータを中心とした開発者体験の提供 - Pull Requestを作成するとプレビューできる機能やLint, Content Trustまで備える - https://www.lifull.blog/archive/category/Kubernetes Copyright© LIFULL Co.,Ltd. All Rights Reserved.