Open7

「わかばちゃんとつくって、壊して、直して学ぶ NewSQL入門」をちびちびとやっていく

りっく|ヤオヨロズビットりっく|ヤオヨロズビット

エンジニア仲間の輪読会で、次の本が「わかばちゃんとつくって、壊して、直して学ぶ NewSQL入門」になったので、メモがてら綴っていきます

りっく|ヤオヨロズビットりっく|ヤオヨロズビット

Chapter 1 はじめてのNewSQL

冒頭の「DoorDash」というサービスのNewSQL移行事例
https://thenewstack.io/how-doordash-migrated-from-aurora-postgres-to-cockroachdb/

名前だけ知ってたCookroachDBってNewSQLの一種だったのか👀

CookroachDBの記事も良さげ
https://www.cockroachlabs.com/blog/aurora-postgres-to-cockroachdb/

NewSQLの定義って?

明確な定義はないらしいけど、以下のような特徴がNewSQLっぽさのよう

  • スケールイン・スケールアウトが自由自在
  • SQLが利用できる!トランザクションも使えるからデータの一貫性が担保できる

NewSQLが流行ってきてる理由

  • クラウドの増加
    • NoSQLのスケーラビリティは魅力的だけどSQLも使いたい、というニーズに応えられる
  • 設計運用負担の軽減
    • 障害対応の多くがアーキテクチャとして自動化されている
  • 無停止運用の増加
    • ローリングアップデートができるので無停止運用ができる
りっく|ヤオヨロズビットりっく|ヤオヨロズビット

ここまで読んでNewSQL一択なのでは?という気持ちになったのでAIさんに弱点を聞いてみた

NewSQL(分散SQL)の弱点・課題

1. レイテンシ(遅延)の増加

  • データを複数ノード・複数リージョンでレプリケーションするから、書き込みやトランザクションにかかるレイテンシが高くなりやすい。
  • 特に「同期レプリケーション(強整合性)」を選んだ場合、ノード間の通信時間がボトルネックになる。
    👉 グローバル分散は強いけど、単一リージョンでミリ秒単位の超高速処理には向きにくい。

2. 運用コストと複雑さ

  • 分散クラスタを維持するためのオペレーション(モニタリング、障害対応、ノードの追加・削除)が複雑。
  • Aurora や RDS みたいに「ほぼマネージドでお任せ」にはならず、SREやDBAの知識が必要。
  • クラウドのマネージドサービスを使わないと、自前運用はかなりヘビー。

3. クエリ最適化の難しさ

  • 分散環境では、JOIN や集約クエリが複数ノードを跨いで実行されるため、性能が読みにくい。
  • 例えば「大きなテーブル同士を JOIN」する場合、データシャーディングの仕方次第で爆遅になることもある。
    👉 分析系(OLAP)よりもトランザクション系(OLTP)に強いとされるのはこのため。

4. 互換性の制限

  • 「PostgreSQL 互換」と言っても、実はすべての拡張機能やトリッキーなSQLが完全対応しているわけじゃない。
  • たとえば CockroachDB では一部の PostgreSQL 拡張や関数は未対応だったり、動作が異なることがある。
    👉 既存のアプリをそのまま完全移行できるとは限らない。

5. スループットの限界

  • 「ノードを増やせば無限にスケール!」と言われがちやけど、実際はトランザクション整合性を保つためのオーバーヘッドがある。
  • 特に強整合性(Serializable isolation)をデフォルトで保証しているDB(CockroachDBなど)では、高スループット環境でのロック競合が発生しやすい。
    👉 超高頻度トランザクションでは、NoSQL(Cassandra, DynamoDB)に軍配が上がることもある。

6. コスト(料金・リソース効率)

  • 分散のためにストレージもネットワークも余分に消費する。
  • 同じデータ量を保存しても、冗長化・複製で ストレージコストが高くなる。
  • また、クラウド提供元のマネージド NewSQL(Spanner, AlloyDB Omni, CockroachDB Dedicated)は料金も高め。

まとめ

  • 整合性・可用性・スケーラビリティを同時に満たすために、
    - → レイテンシ・運用難易度・コストを犠牲にしている。
  • トランザクション重視でグローバル分散したい → NewSQL
  • 分析やバッチ中心 → DWH (BigQuery, Snowflake)
  • 圧倒的スループット優先 → NoSQL
  • 小規模〜中規模・シンプル運用 → RDB (Postgres, MySQL, Aurora)
りっく|ヤオヨロズビットりっく|ヤオヨロズビット

Chapter2 NewSQLクラスターを構築してみよう

tiup playground

でいろいろ試せる環境がさっと立ち上がるのありがてぇ

用語の整理

  • TiDBノード
    • SQLを解釈してTiKVに伝える役割
    • コンピューティングノード
  • PDノード
    • 各ノードの配置状況やクラスター全体の現在の状況を収集・管理
    • クラスター管理ノード
  • TiKVノード
    • 実際のデータの保管場所
    • ストレージノード
りっく|ヤオヨロズビットりっく|ヤオヨロズビット

Chapter3 SQLを学び、NewSQLクラスターで実行してみよう

教科書のSQLとかはここにまとまってる
https://github.com/bohnen/bbf-newsql/blob/main/commands_summary.md

気になったところ

SQLの基本的なところなので気になったとこだけメモ

idをINCREMENTするには注意が必要

NewSQLは分散データベースなので、連番の実装方法に工夫が必要なこともある。

外部キーで関連づけられたテーブルが別々のサーバーに配置されることがある

NewSQLはデータを複数のサーバーに分散して保存することがあるので、外部キーで関連づけられたテーブルが別々のサーバーに配置されることがある。
その場合、JOINでテーブル結合する時にサーバーを跨いだりしないといけない(ただしそういう処理は隠匿してあるが、RDBに比べるとパフォーマンスは落ちる)
パフォーマンス向上のために、同じサーバーに配置する設定が可能なNewSQLもある。

=> 弱点として挙げられてた「クエリ最適化の難しさ」の大変さがなんとなく想像つくなぁ

NewSQLはオートスケールしない

勝手には増えず、手動で台数を操作する必要がある

NewSQLは一般的に外部キーが使えない

書籍で扱ってるTiDBは使えるけど、使えないNewSQLが結構多い

NewSQLはレプリカがない

ぜーんぶプライマリだからレプリカがない。プライマリとは。

りっく|ヤオヨロズビットりっく|ヤオヨロズビット

Chapter4 NewSQLの処理の流れを見てみよう

参照系の処理の流れ

登場人物は「TiDB」「PD」「TiKV」

  1. クライアントからクエリ送信
    ユーザーやアプリケーションからTiDBにクエリを投げる
    MySQLプロトコルを利用している
  2. TiDBサーバーのターン(SQL解析と最適化)
    1で受け取ったSQLを解析し、実行計画を立てる
    TiDBサーバーはTiKVのデータ取得APIを呼び出す(並列実行)
  3. TiKVサーバーのターン(データ取得)
    データを検索して結果を返す
  4. TiDBサーバーのターン(データのまとめ)
    結果をまとめてクライアントに送る

PDはなにしてる?

「PD」は2でTiDBが作った実行計画を最適化するときの相談役

リージョンとは

PDはデータの読み書きや保存の単位としてリージョンと呼ばれるデータの塊をつかう
1リージョンだいたい96MBくらいがデフォルト
TiKV は Key-Value ストアだから、すべてのデータは「Key」と「Value」で保存される
たとえば、

{name: "Alice", age: 20, gender: "F"}

みたいなSQLの1レコードがKey-Valueストアに登録されると

Key = (tableID, rowID) 
Value = {name="Alice", age=20, gender="F"}をバイナリにしたもの

つまり具体的にはこんな感じのデータで保存される

Key: t_45_r_1
Value: 0x0341416c6963651401

これが96MB分詰まってるのがTiKVの1リージョンと。

リージョンリーダー/リージョンフォロワー

TiKVのデータは冗長化されている(標準で3コピー。3台のTiKVサーバーに同じデータがある)
リージョンごとにリーダーのTiKVサーバーを決めている
リーダーはそのリージョンに関して読み書きの両方を請け負う。(読みに関してはフォロワーが手伝うモードもある)
リーダーじゃないTiKVサーバー(フォロワー)はリーダーの同期をする

このTiKVのリージョンリーダーが偏らないように調整するのがPDの役割
だから、TiDBが作った実行計画をどうやったら効率よく問い合わせできるのかの相談を引き受けられる

更新系の処理の流れ

  1. クライアントからのクエリ送信
  2. TiDBサーバーでのクエリ解析とトランザクション管理
    TiKVへの書き込みは複数のサーバーにまたがる
    なのでトランザクションで確実に管理するのがTiDBのキモ
    なのでトランザクションは2フェーズコミットで、①更新対象のロックの取得、②確定として実際の書き込みを行う
  3. TiKVへのデータの書き込み
    TiKVリーダーに書き込む
    リーダーに書き込まれたデータはRaftというアルゴリズムでフォロワーに確実に同期される
  4. 結果をクライアントへ返す

書き込まれたデータを複数サーバーで保持するので障害に強いDBになっていると

タイムスタンプ

NewSQLは分散処理なので、処理順の管理にタイムスタンプが重要
タイムスタンプは時刻をベースに一意の番号(シリアル値)を組み合わせたもの。TSO(Time Stamp Oracle)とも呼ばれる。
TiDBは更新時に、レコードに更新時点のTSOを与えてバージョン管理している
トランザクションの際にはTSOを利用して、他のトランザクションの影響を受けないようにしている

りっく|ヤオヨロズビットりっく|ヤオヨロズビット

Chapter5 1つずつ壊してみよう

1台構成のクラスターを壊してみよう

ハンズオン!
tiup playground で立ち上げた環境でkillコマンドを使って壊していく

各1台構成だと、どれが落ちても使えなくなる。
TiDBはtiup playground scale-out --db 1 で復活できる(データを持たないため)
TiKVは1台構成の場合、データ不整合が生じている可能性があるため、scale-outコマンドで簡単に復旧できない
PDサーバーもリーダーとリージョンの紐付けというデータを保持しているからTiKVと同じ理由で簡単に復旧できない