Memo: Efficient Go

に公開

Go言語を書いていて「なぜこの書き方を?」と悩むことが多いので読んでみた。

1. ソフトウェア効率性が重要

  • 効率性は速度やリソースの利用効率だけではなく、保守性や費用対効果といった包括的な概念
  • 性能指標を明確に定義して、誤解を防ぐことができる
  • 最適化と可読性は、ソフトウェア設計が適切であれば両立可能
  • 市場投入までのスピードと長期的な効率性のバランスを取ることは、ソフトウェアエンジニアにとって重要なスキル

Q. 性能とは何か?
精度、効率、速度の要素の組み合わせで表現される。
「性能」には様々な意味が含まれている可能性があるので、定義を明確にする。

Topic:「最適化されたコードは可読性がない」の誤解
最適化=可読性低下であると極端な結論に陥りがち。「早すぎる悲観化」で最適化を犠牲にしてはいけない。
最適化で可読性が低下するのはソフトウェア設計がそもそも間違っている。

感想

普段のプログラミングでは効率は二の次でまず動くことを求めてしまう。
もし速度が遅くなればマシンリソースをスケールさせれば良いからだ。
正直、効率化が後々の性能に効いてくるのは想像が難しいが、ソースコードの書き方の統一のために効率性の高い書き方を選択するのは生産性向上につながりそう。

2. 効率的なGo入門

  • Goの言語仕様は"less is more"のパターンに従って、シンプルに保たれている
  • 依存パッケージはデフォルトで公開されている(バイナリ化されていない)
  • エラー処理方法が統一されている
  • Goは他言語と比較して効率的なコードが書きやすくなっている

Q.テスト関数のFuzz_, Exampale_は何に使う?
Fuzzはランダムな値を生成して関数の引数等に設定して、関数の安定性などをテストする。Exampleはドキュメントとしての役割を持つサンプルコードを記述できる。

感想

Goが実行環境、シンプルに保つ思想、エコシステムなど総合的に効率的なソースコードが書きやすい言語であると理解した。

3. 効率化の攻略

  • 効率化にはトレードオフが発生しない合理的な効率化と発生する意図的な効率化がある
  • 効率化の目標を非機能要件として定式化して取り組む

Q. RARE文書って何に使うか?
Resource-Aware Efficiency Requirements(リソースを考慮した性能要件)
開発する機能の目指す性能を表現するために用いる。レイテンシー、データソース量、CPU、メモリ容量などを指定する。

6. 効率性オブザーバビリティ

オブザーバビリティ

  • オブザーバビリティ(可観測性)はソフトウェア特性。外部シグナルから推測されるシステムの状態を知る能力。監視とは違う。
  • 代表的なシグナルはメトリクス、イベントログ、トレース
  • シグナル取得の実装には自動・手動があり、前者は内部実装を考慮したシグナル、後者はサイドカーなどで外形的なシグナルを計測する

メトリクスセマンティクス

セマンティクスとは計測した数字の意味を示す。

レイテンシー

  • 時間の単位を揃えておくことが重要
  • プログラムの中で様々なスコープでのレイテンシがあり、対処方法が異なる
  • レイテンシーは様々な要素が影響しているので、複数のメトリクスに対してパーセンタイルで評価する

CPU使用率

  • CPU時間(スレッドが各CPUコアで実行される時間)を使って評価する
  • 1000ms中500ms使用していたら、CPU使用率は0.5となる

メモリ使用量

  • ランタイムのヒープ統計
    メモリの割当量などruntime/mettricsで収集できる。

  • OSメモリページ統計
    プロセスごとのメモリ使用量を取得可能。
    いくつかメモリ使用量の統計値があるがRSS, WSSがGoのメモリ使用量で使用される。

    • VSS 仮想メモリ使用量、プログラム用に割り当てられたページ数、バイト数
    • RSS RAMに常駐しているページ数、バイト数
    • PSS 共有メモリページを全ユーザーに等しく分割したメモリ
    • WSS プログラムが作業を行うために現在しようしているページ数

感想

オブザーバビリティはSRE観点で出てくることが多いので、Goの技術書で紹介されたのが驚きだった。
前半のシグナル収集のところはDatadog等で日々実装を行っているので馴染みやすかったが、後半のCPUやメモリの話は理解が及ばなかった。本の後半の効率化の実例を読んだ後に戻ってきたい。

7. データ駆動効率性評価

tobe

Discussion