【DDIA 読破】1章 信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション

この記事は、[気合いで DDIA 読破 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ddia) 2日目の記事です。

なお、この連載にて「本書」とは以下の書籍を指します。私の読書メモが必ずしも筆者の意図を正確に反映しているとは限りませんので、実際に購入されることをお勧めします。

https://amzn.asia/d/hcsP75P

# 第I部 データシステムの基礎

第I部は、以下の4章から構成されています。

- 1章 信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション
- 2章 データモデルとクエリ言語
- 3章 ストレージと抽出
- 4章 エンコーディングと進化

ちなみに、このGitHub Copilot とともに書いているのですが、多少表現にズレがあるものの書籍の内容について知識があるようで不思議です。調べたら GitHub で中国語訳が大公開されていたりするようで、大丈夫なのかな〜の気持ちになっております。

本連載においては倫理に従った引用に留めるつもりですが、もし問題視されて法的な紛争等が生じた場合、私個人の責任にて対応いたします。[^1]

# 読書メモ: 1章

1章では、"データシステム" という抽象的な語彙の説明から入ります。

通常我々はデータ指向アプリケーションを構築するにあたって DB、キャッシュ、検索インデックス、キューなどの道具を使いますが、「こいつらを全部ひっくるめて "データシステム" の一部として捉えよう」という話です。

## 1.1 データシステムに関する考察

なぜ異なる道具をひっくるめて「データシステム」として見るのかというと、

- それぞれの境界線が曖昧[^2]
- データ処理に関する要求の拡大

という理由が挙げられています。そのため、単一の道具で問題を解決するのではなく、複数の道具をいい感じに組み合わせるのがアプリケーションの役割だよ、ということを言っています。

それゆえ、「アプリ開発者は（合成された）データシステムの設計者でもある！」という印象深いメッセージを発信しています。

ところでデータシステムの設計は超絶ムズくて、いろいろな要素が影響を与えます。本書では、数ある影響因子[^3]のうち重要な3つの課題をピックする、ということです。

それが、信頼性、スケーラビリティ、メンテナンス性です。

これらのワードは、はっきり意味を理解されずに使われているらしく、そこの目線合わせをするのが本章の役割とのことです。

## 1.2 信頼性

信頼性とは、一言で表すと **「何か問題が生じたとしても正しく動作し続けること」** です。

その上で、周辺語彙について以下のように整理しています。

| 用語 | 意味 |
| :-- | :-- |
| fault | 問題を起こしうるもの |
| fault tolerant | システムが fault を見越して対処できる状態（＝resilient） |
| 障害 | システムが全体として必要なサービスのユーザー提供を止めてしまった場合 |

なお、fault tolerant と言っても、考えられるすべての fault に対して対処できるわけではない[^4]ので、「どのような fault に対して耐えられるか」の議論が重要だそうです。

fault への対処は、 **回復** と **回避** の2つに分類されて、基本は前者を目指すべきだけど（セキュリティのリスクなど）後者のアプローチの方が良い場合もあるよ〜という話とともに、意図的に fault を発生させる Chaos Monkey のようなアプローチを紹介しています。

この後、ハードウェア・ソフトウェア・人間のエラーについて4ページほど割いて深掘りしていますが、ブログ書く体力的にもきついのと、本書を読む価値を損なってしまうのは避けたいので、詳細は割愛します。大雑把にいうと、「3つのエラーは列挙した逆順にヤバいよね」という内容です。

最後に「クリティカルな領域じゃなくても信頼性は大事だよ」という SRE 啓発的な話がやってきて、本節は幕を閉じます。

## 1.3 スケーラビリティ

スケーラビリティとは、一言で表すと **「負荷の増大に対してシステムが対応できる能力のこと」** です。

これは一次元のラベルではなく、様々な側面に注目して議論する必要があるとのことです。「それはそう」と言ってしまえばそれまでなのですが、この節ではより具体的な例を挙げながら、いくつかの関連トピックを紹介しています。

### 1.3.1 負荷の表現

まず、 **「負荷はパラメータによって表現できる」** という話から始まります。最適なパラメータはシステムのアーキテクチャによって異なり、種類（リクエスト数・キャッシュヒット率など...）や統計量といった観点から多様なものです。

ここで Twitter が例示されます。ツイートの投稿とタイムラインの表示という2つの機能について、この二つを実現するためのアーキテクチャが2通り提示されました。一つめはシンプルなリレーショナルスキーマによる実現、二つめは書き込みのファンアウトと表示のキャッシュで構成されるパイプライン処理です。この辺り詳しい内容が気になる方はぜひ本書をご購入ください。

なお、注釈にて **ファンアウト** という語彙が電子工学由来のものであることに言及した上で、この分野での定義を **「入力されたリクエストを処理するのに必要となる他サービスへのリクエスト数」** としており、自分の日常的な使い方とは若干誤差があるように感じました。[^5]

話は戻って、Twitter における主な負荷の課題はファンアウトなので「ユーザーごとのフォロワーの分布こそが負荷を表現するパラメータだ」ということになります。もちろんこれは例に過ぎないものですが、他のアプリケーションにおける負荷の表現にも同様の原理が適用できます。

### 1.3.2 パフォーマンスの表現

負荷を表現できたら、次は負荷の増大によって導かれる影響、つまりはシステムのリソースとパフォーマンスの関係性を考える必要があります。という訳でパフォーマンスの表現について考えていくことになるのですが、代表的にはオンデマンド処理のレスポンスタイムや、バッチ処理のスループットが挙げられます。

ここで、話は一気にレスポンスタイム全振りになるのですが、まず「レイテンシとレスポンスタイムは違うよ」という話が出てきます。滅茶苦茶ざっくり言うと前者はサーバー目線で、後者はクライアント目線。つまり後者が大事、ということです。

次に、レスポンスタイムを表現する上で、以下の注意点が挙げられています。

1. 分布として見るのがいいよ
2. パーセンタイルを使うといいよ

経験がある人間からすると「それはそう」なんですが、続けて提示される Amazon の例にはとても説得力がありました。Amazon では内部的なサービスのレスポンスタイムに対する要件を p99.9 で示しているようで、「なぜ "外れ値" っぽいものに拘るのか？」と言われると、 **特に処理に時間がかかるユーザーは太客の可能性が高い** ということだそうです。もちろん出典もついていました。[^6]

その後、SLO の話が出てきた後に「だいたいテイルレイテンシってキューイング遅延（HoL ブロッキング）だから、やっぱレイテンシよりレスポンスタイムだよな」という話に戻ります。なお、「負荷試験では、擬似ユーザーはレスポンスを大人しく待っていてはいけないよ（人工的な計測値の歪みが生じるから）」という言及が飛び込んできて面白かったです。[^7]

そして、パーセンタイル深掘りコーナーが登場して、興味深い記述が連発します。

まず一つめに、**マイクロサービスの場合テイルレイテンシは超重要** らしいです。図を使ってわかりやすく表示されているのですが、リクエスト対象が増えるとテイルレイテンシに当選してしまう確率が上がるし、当然それに律速されるという話です。これは **テイルレイテンシの増幅** と呼ばれるようです。さっきの太客理論と直交するような響きもありますが、あんまり単純に物事を考えない方がいいし、これもこれで蓋然性があると思います。

二つめに、実装・集計に関する以下の言及がありました。これも出典付きです。[^8]

> 時間の分解度を下げたり複数のマシンのデータをまとめたりするためにパーセンタイル値を平均することは、数学的に意味がないことに注意してください。レスポンスタイムのデータを集計するための正しい方法は、ヒストグラム同士を加算することです。

こういう話が出てくるとウキウキしますね。自分もつい最近 [酒ゲーGCP](https://sake-game.connpass.com/) というイベントで LT をした際に以下のようなスライドを使ったのですが、負荷の表現方法に対する解像度や確信は、とても大切だと思っています。

![酒ゲー資料](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317486/0c7de2e4-beec-cfd3-f149-a3281188e865.png)

### 1.3.3 負荷への対処のアプローチ

負荷を表現するパラメータとパフォーマンスを計測するためのメトリクスについて述べたので、ここからはスケーラビリティに関してきちんと議論を始められます（原文ママ）らしいです。そうか〜やっと本題か〜という気持ちになりますが、この本を書いた人の方が3億倍ぐらい大変なので、めげずにやっていきます。これが序の口と思うと恐ろしい......。

ということで、スケールアップ・スケールアウトの話が出てきて、「必ずしもスケールアウトの方が良い訳ではないし、優れたアーキテクチャは融合して使ってることも多いよ」という教えが提示されます。

そして、 **エラスティック** という語彙の説明に移ります。[^9] これは **「負荷の増大を検知して自動的にコンピューティング リソースを追加できるシステム」のことを言うそうです。なるほど偉い。

次に「ステートフルなデータシステムを分散環境に移行させるのは難しいから極力避けるのが一般通年だったけど最近は分散データシステムを最初から使うのがデフォルトになりつつある」という話に移ります。TiDB Serverless とかそういう系のソリューションですね。

最後に全体を俯瞰して、「もちろん大規模なシステムのアーキテクチャはアプリ固有の度合いが強まりがちだけど、それでも共通するパターンやビルディング ブロックは活用できよね。これも本書でカバーするよ」という話で本節は終わります。

最後の部分をあっさり済ませてしまって罪悪感があるのですが、含蓄と示唆のある語り口で書かれているので、修辞に注目するためにも、ぜひ本書をご購入の上原文を読んでいただきたいところです。

## 1.4 メンテナンス性

すみません、これ以上温めたくないので一旦ここまでで公開します。後ほど余力があれば追記いたします。

# 【宣伝】会社のアドベントカレンダー

私が働いている[面白法人カヤック](https://www.kayac.com/)でも、Qiita のアドベントカレンダー企画をやっています。

Qiita に投稿している記事は会社と直接関係ありませんが、企画の運営をしているのは私です。

どんどん面白い記事が投稿されていますので、ぜひご覧ください！

https://qiita.com/advent-calendar/2023/kayac-group

# 修正リクエストを受け付けています

この記事は GitHub で管理しています。以下のリポジトリに Pull Request を送っていただければ、記事内容の修正を検討いたします。（コメント欄に書いていただいても構いません。）

https://github.com/ebi-yade/qiita/blob/main/public/ddia-2023-day02.md

[^1]: なお、（少なくとも日本語版には）引用に関する詳細なガイドラインが記載されていないため、このような方針としました。
[^2]: Redis と Apache Kafka を例に出しています。
[^3]: 関わる人々のスキルから、工数、法的な規制まで様々
[^4]: 機械が壊れるぐらいならともかく、地球が滅亡するような場合は流石に無理だよねっていう話です。
[^5]: 自分は「負荷のために処理を他サービスによる並列処理に逃す手法、及びその実装」みたいな意味で使いがちです。
[^6]: https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf
[^7]: 心当たりがあります。気をつけよう。
[^8]: https://orangematter.solarwinds.com/2016/11/18/why-percentiles-dont-work-the-way-you-think/
[^9]: 個人的には "弾力的" という表現を使っていないことに、どのような意図があるのか知りたいです。