SYM's Tech Knowledge Index & Creation Records

「INPUT:OUTPUT=1:1以上」を掲げ構築する Tech Knowledge Stack and Index. by SYM@設計者足るため孤軍奮闘する IT Engineer.

データ指向アプリケーションデザイン 勉強会メモ

データ指向アプリケーションデザイン 勉強会メモ

勉強会の内容+ α(メモ)

ref:

データ指向

  • オブジェクト指向:オブジェクトを中心にプログラムを設計
  • データ指向:「データ量」「データの複雑さ」「データの変化速度」を中心に考える設計

データ表現

データ量少ない場合:データの表現、生成しやすさを重視

  • テキストデータフォーマット:CSV, JSON, XML など
  • バイナリデータフォーマット:MessagePack, Thrift, Protocol Buffers, Apache Avro
    • (データとして完結している)自己記述型(self-describinig)データフォーマット
      • 例外:ProtocolBuffers はデータ自体にスキーマを含まない(self-describinig ではない)

データ量多い場合(データ基盤):省メモリ、圧縮しやすさ、ストレージの格納しやすさを重視 データを節約してコンパクトにする方法

  • テーブルフォーマット
  • 行指向(row-oriented)フォーマット
    • RDBMS でよく使われる
    • 1行ずつ表現
    • レコード単位で更新しやすい
  • 列指向(column-oriented)フォーマット
    • 同じ型のデータを集めると圧縮しやすい
    • 分析クエリに特化したフォーマット
      • 高速(キャッシュに乗りやすい)
      • SIMD 演算(1つの命令で複数演算器を動かすコンピュータ演算のやり方)も活用しやすい
    • 単一レコードを複数のカラムブロックで表現するため更新が大変(オーバヘッドも高)
    • 例:Apache Request

データアクセス頻度

読込が頻繁

  • 変化しない = 不変データ(イミュータブル)
    • 蓄積されるログ(列指向フォーマットと相性〇)
  • 読み込み特化型 (read-intensive)
    • データへの高速なアクセス、分析の速さが問われる
    • 高速化手法(データを分散)
      • パーティショニング(シャーディング)
        • データを時間範囲(1h, 1d 等)、キー範囲などで分割
        • 必要なデータのみにアクセスが済む、別領域に分かれるため並列アクセス可(高速化)
      • レプリケーション
        • 同じデータを複数個所(マシン、ディスク)に配備し、並列アクセス&耐障害性を確保
      • 実体化ビュー(Materialized View)
        • 一度計算したクエリ結果を保存、再利用可能にする

更新が頻繁(データが 1 か所の場合)

  • 書き込み特化型(write-intensive)

  • 更新対象を素早く見つけられる必要がある = 高速検索

    • → 解決策:インデックス
      • ディスク上のデータを高速に見つけるためのデータ構造
      • B-Tree、Hash index、SSTable(Sorted String Table)
B-Tree
  • ディスク上のページに、次ページへのルックアップテーブルを格納
    • RDBMS では 基本 CREATE INDEX 命令で作られる
    • ※ 1 回の CREATE INDEX で 1 つの B-Tree が作られる。B-Tree を複数作ると更新時にそれらすべて更新する必要があるのでその分更新速度が落ちる
  • 高い更新性能を発揮。空き領域にデータ挿入しやすいため
  • ページ数が増えても木の深さはあまり増えないため、ディスクのランダムアクセスを減らせる=アクセスの回数を減らすのに役立つ
発展:Log-Structured Merge (LSM) Tree

さらに更新が頻繁な場合にも対応できる。(最近よく使われている)

  • レコードの追加、コンパクション操作(恐らくメモリコンパクション=空き領域の断片化を解消して連続した広い空間に再編。メモリ上を整理して合成する操作)を分離
    • ランダムアクセスに強いメモリ上にどんどん追加。更新される旅にメモリ上をソート
    • バックグラウンドで、定期的にソート済みのデータと合成(marge sort)して次レイヤーに保存(L0,L1,… = ディスク、外部ストレージなど)
  • 性能特性
    • 更新時のランダムアクセスを減らせる(シーケンシャルなアクセスなため)
    • 各種オーバヘッドがある
      • 読み込み時に各レイヤーにアクセスする必要がある
      • 書き込みの増幅(Write Amplification)が生じる (次レイヤーに書き出すため同じデータの書き込みが複数回生じる)

例:LevelDB、RocksDB(C++)、AWS S3(Rust) など

分散データ(データが複数個所)

データを複数個所(複数ノード)に分散する場合、考えるべき問題の複雑さが数段上がる

  • ノード間でデータを送受信するために、分散システムが必須
    • 分散ステートマシン=各ノードが同じ状態になる必要がある(membership)
    • (サーバ間のデータを整える目的で) サーバ・クライアント間でのデータ通信も必要(HTTP 上で実装されることが多い)
  • 複数のノードで頻繁に更新がある場合
    • 同期(ロック取得、タイムアウトトランザクション、ログのリプレイ)
    • どのノードの状態が正解かを決めるための合意(consensus)プロトコルが必要
      • (基本的には) 多数決(Quorum)で決める。 Paxos、2PC など
      • あるいは、そもそも調整を避ける(conrdination avoidance)手法もある
  • 障害対応
    • エラーハンドリング
    • エラー時のリトライ
    • 冪等性(同じ操作を 2 回繰り返しても大丈夫なように設計)
    • 障害からの復旧・リカバリ
    • ノードが嘘を付く(間違ったデータを返す)ビザンチン障害と呼ばれる

以上を踏まえて、システムが正しく動作するように設計する必要がある

24 時間 365 日稼働するサービス設計

  • 稼働率:許容されるダウンタイム
    • 99.9 % availability = 8.7 時間/年
    • 99.99 % availability = 53 分/年
    • 99.999 % availability = 5 分/年
  • アプリケーションのデプロイ (その際には止める必要があるが)
    • サービスが動き続ける必要がある
      • =複数バージョンのアプリケーションが同時稼働する(できる必要がある)
    • デプロイ中、あるいはクラッシュ時に通信が遮断される
      • (そのため) クライアント側でリトライ(再実行)処理を実装する必要がある
        • アップグレード中にリクエストが失敗してもリトライすることで次バージョンにトラフィックを流すことができる
  • 冪等性
    • リトライが起こる前提で設計
      • リクエストが成功したがレスポンスが通信障害などによりクライアントに届かなかった場合に、リトライされても問題ないようにする必要がある
      • =同じ操作(リクエスト)が繰り返されても、データを重複登録させない
    • リクエストに UUID などを付けて重複チェック
Compute - Storage の分離 (常にデプロイし続けるための設計)
  • 近年の標準
  • 常にデプロイし続けられるよう、クエリ実行(Compute)とストレージ(Storage)を分離
    • クエリエンジンとストレージを別々にスケールしたり、ローリングアップグレード(同じ機能を持った複数サーバ構成のシステムをアップデートする手法の一つで、システムの稼働状態を維持しながら1台ずつ順番にアップデートしていく方法)

例:SnowflakeAmazon Redshift(データウェアハウスサービス)など

分散トランザクション

そもそもトランザクション処理
  • ACID :Atomicity(不可分性)、Consistency(一貫性)、Isolation(独立性/分離性)、Durability(永続性)
  • 分離性(Isolation)が最も重要
    • 直列化可能性(Serializability)が基本
      • トランザクションが1つずつ実行されたのと変わらない状態を維持
      • オーバヘッドが大きいため現実的には使われにくい(使う場合は考える必要がある)
    • 解消する手段:弱い分離性
      • Read-Committed、Snapshot Isolation、MVCC(Multi-version concurrency contorol)
    • 妥協しないアプローチ:Serializable Snapshot Isolation (SSI)
      • トランザクション異常(anomaly)の種類
        • ファントム(まだ存在しないレコードに、どうロックをかけるか)※SSI だと防げない
        • Write Skew(同じスナップショットを読んで、違う場所に書き込む)
      • Repeatable Read (ダーティリード:なし、ノンリピータブル:なし、ファントム:あり)とは違う
分散トランザクションの世界
  • 複数ノード間、または複数システム間でトランザクションを実装
    • 一貫性、合意、耐障害性
    • 線形化可能性(linearizability)が重要
      • レプリカが複数あっても、ユーザにはコピーが 1 つしかないように見せる
      • 更新操作が終了した途端、全ノードが同じデータを見られるように保証する
    • 実装するために必要な技術要素 (本 9 章)
      • リーダー選出(leader election)
      • サービスディスカバリ
      • メンバーシップ管理
    • 使用例:Zookeeper、etcd(Kubernetes 内部で使用)
    • 異なった方向性のアプローチ(2022 ~)
極み:Amazon Aurora (SIGMOD 2018)

AWS Aurora: AWS Aurora とは?その特徴とは?

  • クラウド向けリレーショナルデータベース
  • 分散版 MySQL
    • 6つのレプリカを作成
    • 2 copy × 3 AZs 。AZ が一つ落ちても quorum (多数決) が取れる = 4/6
  • MySQL のデータベース操作を「ログ書き込み」のみに特化して簡略化
    • ストレージノードがログを分配、各インスタンスでログをリプレイして同じデータを持つ
      • データのコピーには gossip プロトコル(ランダムにノードを選んで配信、同期システムなしに実装できる)
    • さらに、トランザクション処理も同期をなるべく取らずに処理(Coordination Avoidance)
      • 各ノードの返信を待つ 2 相コミット(2PC)を使わなくても良いよう、MySQL の裏側のストレージ全体を再設計

データの複雑さ

テーブルの意味の変化

  • 従来:RDBMS にある最新データ(Snapshot)
  • 現代:
    • 時間とともに変化するデータ、そこから表す派生するデータ(derived data)を表す
  • 列指向クエリエンジンの発展により、分析クエリが容易になり導出データ(derived data)が大量に
  • バッチ処理とストリーム処理の区別がなくってくる位いろんなデータが作られる

導出データ (derived data)

  • 1つデータから数千の導出データが作られることも (実例:Treasure Data 社)
  • クエリで生成されるデータの依存関係や、データ履歴を管理する必要がある
    • 解決法:
      • dbt:クエリの依存関係を記述できる SQL compiler
      • 新しい Table Format:Delta Lake、iceberg、Apache Hudi など
        • テーブルの更新履歴の確認やスナップショットの管理(time travel)ができる

分散バッチ処理

バッチ処理Unix コマンドでのデータ処理に近い(コマンドのパイプ繋ぎ)

分散(複数ノード)で実行するアイディア

  • Spark (2009)
    • Microsoft DryadLINQ (2008) のアイディアがベース
    • UNIX コマンドのような命令(小さいプログラム)を並列・分散実行するイメージ
  • MapReduce (Google 2004, Hadoop 2006)
    • Mapper (key-value)のペアを出力。
    • Reducer:同じ Key に属する Value を集めて集計結果を出力
    • フレームワーク側が自動で分散実行
      • MapSide Join、Broadcast/Hash Join など様々なテクニックが誕生。SQL も実行可(Hive)

ストリーム処理

  • バッチ処理:保存されているデータに対してクエリ実行
  • ストリーム処理:
    • クエリをデータの入力側に送り、常時クエリを実行し続ける
    • あるいはデータの変更をとらえ処理する。 マイクロバッチ、CDC(Charge Data Capture)
  • (上記の概念を上手にまとめたのが )Dataflow Model の概念が必要
    • 時系列データ処理方法の分類・パターンの定義
    • 遅れてやってくる(late arraival)データの処理を埋め合わせる必要性を提示
      • event time(データを捉えた時刻), processing time(データがシステムで見えるようになった時刻)を 2 次元の watermark で管理
      • 2 次元の軸を分割してもれなくデータを処理する

SLO:システムパフォーマンスのはかり方

事業者が定義・合意した SLA を履行するために、サーバーやネットワーク、ストレージなどの各領域の稼働率、性能、可用性、セキュリティ、サポートといった項目ごとに、パフォーマンスの目標値

  • 平均値を見るだけでは、データ規模が大きく性能が遅くなりやすい重要顧客の様子が見えてこない
  • p99.99 の極端な領域での改善は、コストの割りに利益を生まないこともある

まとめ

  • データ指向アプリケーションデザイン
    • 分散データシステム入門の決定版
    • より深い世界に踏み込むための手引き
    • 最新は自分で情報収集する必要あり。英語論文など