chike0905の日記

何者かになりたい

Data-Intensive Applications: Chapter 1

DBとかをちゃんと理解する必要があると痛感し始めたので、ずっと積読していた以下の本を読んでまとめていく。

www.oreilly.com

Chapter 1 Reliable, Scalable, and Maintainable Applications

  • 多くのデータ志向(Data-Intensive)アプリケーションは以下の機能を持っている
    • のちにデータを発見できるようデータを保存する(database)
    • 高負荷な操作の結果を高速化のために記録する(chache)
    • ユーザにデーやをキーワードなどで検索またはフィルタできる(search-index)
    • 非同期処理を行うために、他のプロセスへメッセージを送信する(stream-processing)
    • 周期的に蓄積されたデータを分割する(batch processing)
  • これらが曖昧に聞こるとしたら、それらは 「良い抽象化」 が行われている
    • ユーザは細部を意識しなくとも利用できる
  • しかし現実的には、それぞれのデータベースシステムは、異なる要件を持ち、異なる特徴を持つため、そこまで単純ではない
    • 本書では、それらの原理や実践を解説する

Thinking About Data Systems

  • 本書で着目するシステムの要素は以下
    • Reliable: システムはいかなる逆境に直面しても正常に動き続ける
      • 正常: 許容されるレベルの正しい機能が動作する
      • 逆境: ハードウェア/ソフトウェアの故障、ヒューマンエラー
    • Scalable: システムが成長するとともに、合理的な方法で処理する手段が存在する
    • Maintainable: 多くの人々がそのシステムを操作しても、生産的に動作することが可能であるべき
      • 多くの人々の操作: エンジニアリング、オペレーション、新しいユースケースに対して対応する、現在の動作をメンテナンスする

Reliability

  • 典型的なソフトウェアのReliabilityとは以下のような特性
    • アプリケーションはユーザが期待した機能を提供する
    • ミスや、ソフトウェアの意図しない利用においても許容する
    • 必要とされるユースケースに対して、意図されたデータロードやボリュームの元でパフォーマンスを保つ
    • 認証されていないアクセスや、不正利用を妨げる
    • たとえ悪いことが起きても、正常に動作し続ける
  • 「悪いこと」はfaultと呼ばれ、faultを予期し、それらと強調するシステムを「fault-tolerant」や「resilient」と呼ぶ
    • どんな「fault」に対して予期を行うのかを議論しなければならない
    • 「fault」と「failure」は異なる
      • fault: システムの性能から議論されるコンポネントに対する障害
      • failure: システムが完全に停止するなどで、ユーザにサービスが提供できなくなる障害
  • faultをゼロにすることは不可能
    • 「fault-tolerant」はfailureを起こさないようにfaultを避けること
  • 直感に反して、fault-tolerantシステムにおいて、faultを慎重に扱うほど、faultの発生率は増加する

Hardware Faults

  • 多くの機器を動かす時、常にfailureは起こりうる
    • ハードディスクの故障、RAMの故障、停電etc...
    • MTFFの議論
  • 機器故障に対応するために、冗長性の確保はよくある対処
    • 近年まで、ハードウェアによる冗長性を確保することはアプリケーションにとって有効な手段だった
      • 1台のコンピュータが完全に故障することは稀であるため
    • しかし、データリュームと、アプリケーションの必要とする計算力が増えるにつれ、多くの機器を組み合わせる必要が出てきた
    • したがって、システム全体がfailureに陥らないために、ハードウェアのfault-tolerantに加えて、ソフトウェアでfault-tolerantを確保するテクニックが求められるようになった

Software Errors

  • ソフトウェアのfaultは、複数機器にまたがるため、予期することが難しく、予期せぬハードウェア故障よりもfailureを産みやすい
    • 特定の入力によってソフトウェアのバグが発現し、全てのアプリケーションサーバがクラッシュする
    • 共有リソースを使うプロセスが暴走する
    • サービスが依存するシステムが低速化、応答しなくなる、あるいは異常な応答をする
    • 特定のfaultが他のコンポネントのfaultのトリガーとなり、連鎖的にfaultが発生する
  • これらを引き起こすバグは、通常とは異なる環境・入力によって引き起こされるまで発見されずに放置されることが多い
  • ソフトウェアのバグの問題を即座に解決する方法はない
    • 細かい操作がそれらを助ける
      • システムとのインタラクションや、推測を注意深く考える
      • プロセスを独立させる
      • プロセスのクラッシュや再起動をハンドルする
      • システムの挙動を計測、監視、分析を行う

Human Errors

  • ソフトウェアは人間によってデザイン、構築され、そのオペレーションも人間が行う
    • 人間はunreliableである
  • Unreliableな人間に対して、システムをReliableにするアプローチがある
    • エラーとなる機会を最小限になるようにシステムを設計する
    • failureを引き起こす部分と、人間がミスを起こしやすい場所を切り分ける
    • 全てレベルに対してのテスト(Unitテスト、インテグレーションテスト、そしてマニュアルテスト)を実施する
    • failureの影響を最小化するために、ヒューマンエラーからの迅速かつ簡易なリカバリを許容する
    • パフォーマンやエラーレートなどの詳細かつ明確な監視を実施する
    • 良いマネジメントプラクティイスやトレーニングを作成する

Scalability

  • システムがreliableであったとしても、それは必ずしも続くということを意味しない
    • 以前よりより多くのデータ量を扱うことで破られる可能性がある
  • Scalabilityはシステムがロードの増加をうまく扱うことができるかどうかを示す指標
    • もしシステムをある方法で増強すると、どのような点が向上するのか?
    • ロードの増加に対して、どのように計算資源を追加できるか?

Describing Load

  • ロードは少数のパラメータ(load parameter)で表現される
  • Twitterの例: Home TimeLineの更新
    • あるユーザがフォローしているユーザのツイートを収集しなければならない
    • 手法1: ユーザのフォロイーを取得し、そのフォロイーのツイートを検索する
    • 手法2: ユーザのHome TimeLineをキャッシュし、その更新のみ検索する
    • 当初は手法1だったが、多くのフォロイーを持つユーザのロードに対応できないため、手法2を導入した
      • 現在では組み合わせて利用されている

        Describing Performance

  • ロードが増加した場合、どのように対応できるか
    • システムのリソースを追加した時、どのようにパフォーマンスに影響するか?
    • ローフォが増加した時、どのくらいのリソースを追加すればパフォーマンスを変えずに動作できるか?
  • パフォーマンスの考え方
    • パフォーマンスを考える時、計測値は単体で考えるのではなく、その分散(distribution)を考えるべき
    • あるリクエストに対する応答時間を考える時、計測値は測定毎に様々な影響を受けた値になる
    • 1つの共通の視点は平均(ここではmean)だが、これは多くのユーザのあくまで平均であり、実際のユーザの体感する時間を示すわけではない
    • もう一つの指標は、中央値(median)
      • 半分の人はその時間内にレスポンスを受けることがわかる
    • さらなる外れ値などを考慮したい際は、より多くの割合による値を用いることができる
      • 90%、99%、99.9%の人がレスポンスを受ける時間
      • ただし、高い割合による値を早くするのは、システム管理者の管理下を超えた要素が多く存在するため、容易ではない
    • それらの目標値を定義するためService Level Objectives(SLO)、Service Level Agreements(SLA)を定義する

Approaches for Coping with Load

  • ロードパラメータが増加した時、どのようにパフォーマンスを維持したら良いだろうか
    • scaling up: 垂直スケール、マシンパワーの増強など
    • scaling out: 水平スケール、複数台マシンによる分散処理
  • 近年のシステムでは柔軟性(elastic)を備えている
    • ロード増加を検知すると計算資源を自動で追加する
    • しかし、複数台のマシンを協調させるとシステムの複雑性が増す
    • 分散システムのツールと抽象化が高度化したことによりアプリケーションから透過的に用いることが可能となった
  • 大規模なシステムのアーキテクチャは大抵、特定のアプリケーションへ最適化されている
    • そのために、良くscaleするアーキテクチャでは、増加する共通のロードパラメータを推測することが必要

Maintaniability

  • ソフトウェアのコストの多くは、開発自体ではなく、その運用メンテナンスである
    • メンテナンスが行われていない、すでにサポートされていないコンポネントなどを用いるシステムをレガシーなシステムと呼ぶ
    • レガシーなシステムに対して、一般的な提案を与えるのは困難
    • しかし、レガシーシステムの影響を最小限に留める努力はできる
  • Maintaniabilityを考えるための3つのデザイン
    • Operability: スムーズにシステムを稼働させることがオペレータにとって容易であること
    • Simplicity: 新しいエンジニアがシステムを理解することが容易であること
    • Evolvability: エンジニアが新しい機能を追加したり、要件が変わるような想定されていないユースケースへの対応などが容易であること

Operability: Making Life Easy for Operations

  • 「良いオペレーションは悪いソフトウェアに制限され、良いソフトウェアは悪いオペレーションに制限される」
  • 良いオペレーションの例
    • 故障状態などに陥ったとしても、それを監視し、迅速に復旧できる
    • 問題の原因をトレースできる
    • ソフトウェアやプラットフォームを最新に保つ
    • 問題のある更新を避けるために、異なるシステムがお互いに与える影響を把握する
    • 将来起こる問題を予測し、発生する前に解決する
    • デプロイ、設定、マネジメントなどのグッドプラクティスやツールを確立する
    • 複雑なメンテナンスタスクを実施する(プラットフォームの移行など)
    • 設定変更によるシステムのセキュリティを管理する
    • プロセスを定義しオペレーションを予測可能にして、運用環境を安定的に維持する
    • 個人が離脱したとしても運用可能なように、システムに関する組織の知識を蓄積する
  • 上記を実現するための取り組み例
    • 質の良い監視により、システムの内部や挙動を可視化する
    • 標準的なツールを用いて自動化や統合化を行う
    • 個人の機器への依存を避ける
    • 理解しやすいドキュメントを提供する
    • 予測可能な部分は自動化し、必要に応じてマニュアルコントロールにする
    • 予測可能な挙動を提示する

Simplicity: Mannaging Complexity

  • ここでは、ソフトウェアの機能を削る必要性を解くのではなく、「意図しない」複雑性を持たせないようにすることを意味する
  • そのための良い手法は、「抽象化」である

Evolvability: Making Change Easy

感想

データを扱うシステムに関する書籍として、ブロックチェーンを研究するにあたり一度は通読しなければならないと思っていた。ここで示されている概念だけでも、ブロックチェーンが課題としている部分が多々あり、そのあたりの整理をしていくにあたり面白い議論が展開されることが期待でき、1章から今後が楽しみである。