詳解システム・パフォーマンス 3章「オペレーティングシステム」輪読メモ

詳解システム・パフォーマンス 第2章「メソドロジ」メモ - ゆううきメモ の続き。今回は第3章「オペレーティングシステム

システムパフォーマンス分析では、オペレーティングシステムとそのカーネルについての理解は必要不可欠だ。システムコールがどのように実行されるか、CPU がどのようにスレッドをスケ ジューリングするか、限られたメモリがパフォーマンスにどのような影響を及ぼすか、ファイルシステムは I/O をどのように処理するかなどのシステムのふるまいについて、あなたは頻繁に仮説を立て、それをテストすることになる。これらのふるまいを理解するためには、オペレーティングシステムとカーネルの知識を使わなければならない。

Brendan Gregg,西脇靖紘,長尾高弘「詳解システム・パフォーマンス」, オライリージャパン p.85

議論

章の内容をベースに議論したことは以下の9点である。議論した内容なので、事実でない可能性があることに注意。

  • カーネル空間とユーザー空間の違い
  • プロセスとスレッドの違い
  • selectとepollの違い
  • システムライブラリとはなにか
  • mallocは何をやっているのか
  • forkのCoWはなにをやっているのか
  • forkとcloneの違い
  • goroutineはスレッドか
  • キャッシング層が多すぎる

カーネル空間とユーザー空間の違い

カーネル空間といっても、プロセスとは独立したまとまった空間があるわけではおそらくない。 (図3-8プロセス環境を見ながら) 1つのプロセスの中にカーネル空間とユーザーアドレス空間がある。 カーネル空間では、メタデータとして、PIDなどをもつ。カーネルのコードでは、task_struct構造体として表現される。 (http://lxr.free-electrons.com/source/include/linux/sched.h#L1511) 他には、ファイルディスクリプタカーネル空間に確保される。ユーザー空間にはディスクリプタIDのみを確保する。 ユーザー空間は、実行ファイル、(共有)ライブラリ、ヒープ、スレッドのスタックなどをもつ。 softirqdみたいなカーネルスレッドだと、カーネル空間しかなさそう。

select/pollとepollの違い

select/poll はカーネル空間上のファイルディスクリプタをループで舐めるのでO(n)となり、監視するディスクリプタ数が多いと遅い。 一方で、epollはカーネル側でディスクリプタの状態をもつので、状態変化したものだけユーザー空間に返すことができる (エッジトリガ通知)。

詳細は、「Linuxプログラミングインタフェース」 63章 高度なI/Oモデル を参照。

システムライブラリとはなにか

glibcとか。glibcには例えば、mallocとかがある。mallocシステムコールではなく、ライブラリ関数。

MySQLで、jemallocを使うとスレッド数に対するスケーラビリティが向上する例がある。最近、社内でハマった。 MySQL performance: Impact of memory allocators (Part 2)

プロセスとスレッドの違い

カーネルはタスク (プロセス or スレッド or カーネルスレッド) という単位で、実行スケジューリングする。つまり、プロセスとスレッドは同等に扱われる。 では、プロセスとスレッドはカーネルコンテキストにおいてなにが異なるのか。 前述のように、タスクはtask_struct構造体で表現される。スレッドの場合は、あるスレッドを表現するtask_struct構造体の一部のメンバー変数が、スレッドの生成元であるプロセスと同じポインタを指しているだけではないか。この共有される一部のメンバー変数には、ヒープ領域などが含まれるはず?

mallocは何をやっているのか

ヒープメモリから要求するサイズの空き領域を探索して返す。(このときはシステムコールを実行しない?) 要求するサイズの空き領域がなければ、brk()により、ヒープメモリサイズを拡張する。

ヒープメモリの最初のアロケートはいつ行われる?forkされたときに親プロセスからコピーされるはず。原祖であるinitプロセスではどうしてるのか。

forkのCoW (Copy On Write) は何をやっているのか

fork直後に、新規の仮想メモリアドレス領域を子プロセスの領域として確保される。 しかし、子プロセスの仮想メモリアドレスのマッピング先は、親プロセスの物理メモリアドレスである。 というのがCoWの仕組みのはず?

ちなみに、vforkは、仮想メモリやページテーブルのコピーすら作らない。

forkとcloneの違い

forkは子プロセスを生成し、cloneはスレッドを生成するために使われる。cloneは関数を渡すインタフェース。cloneはスタックを別途割り当てる。cloneはflagsにより、親子で共有する属性を指定できる。 スレッドと一口に言っても、共有している属性が場合によって異なることがありそう。

  • CLONE_FILES: 親子プロセス間でファイルディスクリプタテーブルを共有する
  • CLONE_FS: 親子プロセス間でファイルシステム関連の属性を共有する
  • CLONE_IO: 親子プロセス間で I/O コンテキストを共有する
  • CLONE_VM: 親子プロセス間で仮想メモリを共有する

Linuxプログラミングインタフェース」 28章 プロセスの作成とプログラムの実行:詳細 より。

goroutine はスレッドか

goroutineはスレッド(ここではカーネルのtask_structで表現されるスレッド)と1対1対応するわけではない。「タスク」ではない。言語処理系側の実行コンテキスト(グリーンスレッド)である。ただし、M個のスレッド上で、N個のgoroutine (N > M) を動かすことはできる。このようなスレッドの多重化のために、言語処理系上でどのような実装が必要なのかはあまりわかっていない。

キャッシング層が多すぎる

  1. アプリケーションキャッシュ (アプリケーションプロセス上のメモリにキャッシュ?)
  2. Webサーバキャッシュ (nginxのキャッシュなど)
  3. キャッシングサーバー (memcachedなど)
  4. データベースキャッシュ (MySQLのバッファキャッシュなど)
  5. ディレクトリキャッシュ
  6. ファイルメタデータキャッシュ
  7. OSのバッファキャッシュ
  8. ブロックキャッシュ
  9. ディスクコントローラーキャッシュ
  10. ストレージアレイキャッシュ’
  11. オンディスクキャッシュ

とにかくディスクI/Oの遅さをなんとかするために、キャッシュをはさみまくっていることがわかる。

この章でのいくつかの疑問もしくは疑問に対する仮説は後の章で解説されるか、Linuxプログラミングインタフェース読めばわかりそう。 その場にいるオペレーションエンジニアと、我々は言語処理系の実装がわからないという会話をした。処理系もシステム系領域なので、やっていく必要がある。

詳解 システム・パフォーマンス

詳解 システム・パフォーマンス

書籍「Designing Data-Intensive Applications」下読み

全体として何に関する本か

ストレージとデータ処理技術に関する基礎概念について、原理と実践の両方の観点を通して、読者がdata-intensive applicationsを構築するための技術選択の意思決定を助ける本である。 この分野は、NoSQL、ビッグデータ、スケーラビリティ、ACID、CAP定理、結果整合性、シャーディング、MapReduceなどバズワードで溢れており、正しい知識を身につけることが難しいため、本にまとめたのではないかと考える。

この本では、タイトルに「データベース」や「分散システム」と書かず、「Data-Intensive Applications」 としている。これは、大量で複雑なデータを扱うアプリケーションというのは、万能のデータベースが1つあれば賄えるものではなく、複数のストレージやデータ処理技術を組み合わせて構築するという切り口であるためである。

どのような構成で知識や概念を展開しているか

この本は3つのパートで構成されている。

  • Part 1では、data-intensive applicationsの設計を支える基礎概念について議論する。reliability/scalability/maintainability、データモデルとクエリ言語、ストレージエンジン、データシリアライゼーションのためのフォーマットとスキーマエボリューション。
  • Part 2では、1台のマシン上のデータから複数のマシンに分散されたデータに移行する。レプリケーション、パーティショニング/シャーディング、トランザクション、一貫性、合意。
  • Part 3では、キャッシュや検索インデックスなど、異なる複数のデータベースを統合する必要のあるヘテロジニアスなアプリケーションについて議論する。バッチ処理、ストリーム処理など。最後に、全てをまとめて、将来的にreliable, scalable, maintenableなアプリケーションを構築するためのアプローチを議論する。

この本を読んで達成したいこと

リバースプロキシ、アプリケーションおよびRDBMSによる、伝統的なサーバサイドのWebアプリケーションアーキテクチャでは耐えられないワークロードに対処するアーキテクチャを設計するために必要な知識・原理を理解すること。 具体的には、各ツール(KafkaやCassandra、Hadoopなど)の原理的な限界を議論できるようになること。

そのアーキテクチャというのは、高度に発達したシステムの異常は神の怒りと見分けがつかない - IPSJ-ONE2017 - ゆううきブログにある観測のためのアーキテクチャであり、大量かつ多次元なデータ収集と多様な参照パターンが必要であると予想できる。

Designing Data-intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems

Designing Data-intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems

著者のMartin Kleppmannは、ケンブリッジ大学の分散システム研究者。その前は、LinkedInとRapportiveで大規模データインフラストラクチャに携わるソフトウェアエンジニアとして働いていたとのこと。

他の方の感想

www.facebook.com

MySQLの同期レプリケーションで複数の更新クエリを1トランザクション内で発行すると速くなるケース

っていう話をいちりんちゃんこと id:ichirin2501 に聞いた。

MySQLで準同期レプリケーションまたは同期レプリケーションを使って、マスター・スレーブ構成で運用している場合、マスターはコミット後、スレーブが更新イベントを受け取ってログに書き込むまで待つようになる。

ところが、例えばRDSでMulti AZ配置するケースのように、マスター・スレーブ間のネットワーク遅延が大きい場合、スレーブがイベントを受け取るまでのレイテンシが大きくなるので、準同期レプリケーションで性能が落ちることがある。

このとき、AUTOCOMMITを有効にして更新クエリごとにコミットしているケースと比較して、明示的に複数の更新クエリを1つのトランザクション内で発行させると、性能が向上するケースがある。なぜなら、スレーブが更新イベントをまとめて受け取るようになり、1リクエスト内の一連のクエリ実行に要するマスター・スレーブ間のイベント往復回数が減るためだ。

write I/Oをバッファして、まとめてフラッシュすると性能が向上するという話と似ている。

【追記】

Multi-AZ 配置 - Amazon RDS | AWS に、RDSのMulti AZ配置では同期物理レプリケーションを使用しているとある。これはDRBDみたいなものなのだろうか。

詳解システム・パフォーマンス 第2章「メソドロジ」メモ

書籍「詳解システム・パフォーマンス」 下読み - ゆううきメモ の続き。今回は第2章「メソドロジ」。

パフォーマンスアナリストが複雑なシステムに立ち向かうときに、パフォーマンス問題を起こ している場所を特定し、問題を分析するためにどこから始め、どのような手順を踏んだらよいかを示してくれるのがメソドロジである。 Brendan Gregg,西脇靖紘,長尾高弘「詳解システム・パフォーマンス」, オライリージャパン p.15

この章で興味深かったのは以下の7点である。

  • Known-Unknowns
  • リソース使用率の定義と飽和(Saturation)の概念
  • ワークロード分析(workload analysis)とリソース分析(resource analysis)
  • USEメソッド
  • 競合とコヒーレンスのスケーラビリティプロファイルの差
  • 待ち行列理論
  • ヒートマップ

Known-Unknowns

パフォーマンスについて知れば知るほど、知らないことが増えるという話。そもそも知らないと認識していない状態であるUnknown-Unknownに対して、コンピュータシステムのアーキテクチャとシステム固有のアーキテクチャを人間が知ることで、徐々にパフォーマンス特性を理解しているというのが現状である。今のモニタリングツールでは、Unknown-UnknownをKnownにするためのサポートができていない。システムのモデリングをもう少し自動化できないかどうか。

リソース使用率の定義と飽和(Saturation)の概念

リソース使用率には、時間ベースの定義と能力ベースの定義がある。前者は

サーバーまたはリソースがビジー状態だった時間の平均的な割合 Brendan Gregg,西脇靖紘,長尾高弘「詳解システム・パフォーマンス」, オライリージャパン p.61

後者は

システムやコンポーネント(ディスクドライブなど)は、一定のスループットを提供できる。どのパフォーマンスレベルでも、システムやコンポーネントは、持っている能力の一定の割合を使って動作している。この割合を使用率と呼ぶ。 Brendan Gregg,西脇靖紘,長尾高弘「詳解システム・パフォーマンス」, オライリージャパン p.61

前者の特徴は、使用率が100%になっても要求を受け付けられることである。後者は、それ以上の要求を受け付けられない状態である。必ずしも両方の情報が提供されているとは限らない。

飽和は、処理できるよりもリソースに対する要求がどれくらい多いかを表す。能力ベースの使用率が100%を超えたときに、キューイングが始まると発生する。

USEメソッド

筆者のBrendan Greggがおそらく勧めているであろう分析メソッド。エラーがあるか=>使用率が高いか=>飽和があるかを各リソースについてチェックする。ロールごとにリソースリストがあると便利かもしれない。

競合とコヒーレンスのスケーラビリティプロファイルの差

x軸スレッド数、y軸スループットとしたときに、競合とコヒーレンスでグラフの形状が異なる。競合発生時は、スループットの傾きが小さくなるだけだが、コヒーレンス発生時はスループットが低下する。データのコヒーレンシを維持するために、各スレッドに伝搬するなどのオーバヘッドが発生し、このオーバヘッドはスレッド数が増加するたびに大きくなるため。

待ち行列理論

コンピュータシステムのコンポーネントは、キューイングシステムとしてモデリングできることが多い。 「負荷が倍になったら平均応答時間はどうなるか。」、「プロセッサを追加すると、平均応答時間にどのような影響が及ぶか。」、「負荷が倍になったとき、システムは 90 パーセンタイルの応答時間を 100m 秒未満にすることができるか。」といった問いに答えるために使える。

ヒートマップ

散布図の密度が高すぎてみにくい場合、ヒートマップが使える。

詳解 システム・パフォーマンス

詳解 システム・パフォーマンス

書籍「詳解システム・パフォーマンス」 下読み

詳解システム・パフォーマンス輪読を始めた。初回は、全体把握と第1章。

全体把握というのは、書籍「本を読む本」でいうところの読書の第2段階「点検読書」のうち組織的拾い読みに該当する。さらに同著には、積極的読書のためには質問をすることが重要と書かれており、点検読書の段階では、「全体として何に関する本か」、「何がどのように詳しく述べられているか」に関する質問に答えるとよい。自分の考えでは、「この本を読んで達成したいことは何か」という質問にも、点検読書の間に答えられるとよいと思っている。

全体として何に関する本か、何がどのように詳しく述べられているか

システムパフォーマンス分析に関する本である。特に、まえがきに書かれているように、「オペレーティングシステム、そ してオペレーティングシステムのコンテキストにおけるアプリケーションのパフォーマンスについての本」である。

具体的には、システム全体とシステムの代表的な要素(CPU、メモリ、ファイルシステム、ディスク、ネットワークなど)に関して、パフォーマンス分析に必要なメンタルモデルの構築、分析とチューニングの手法が、具体的なケースの紹介としてではなく、方法論として書かれている。

この本を読んで達成したいことは何か

2つある。ひとつは、エンジニアの勘に頼らない、システムパフォーマンスの分析ができるようになること。もうひとつは、高度に発達したシステムの異常は神の怒りと見分けがつかない - IPSJ-ONE2017 - ゆううきブログ に書いたシステムモデルの構築の足がかりにすること。

詳解 システム・パフォーマンス

詳解 システム・パフォーマンス