3時に寝て8時半に起きた。夜眠れなくて、野菜サラダに目玉焼きをのせて食べたり、お茶をわかしてボトルに入れ替えたりしてた。休日だと時間に余裕があるせいか、空き時間に自炊してなにか作ることが多い。
豆苗の再生栽培
朝ご飯は野菜サラダと納豆を、お昼ご飯は豚肉としめじと2回目の豆苗を炒めたものを目玉焼きでとじたものを食べた。豆苗のパッケージに食べた後の根を水に浸しておけばまた生えてくるとあったので試しにやってみた。キッチンという日当たりのよくない場所で育てたせいか、薄い緑色の苗が生えてきた。
今回は適当に育てた。再生栽培のコツ を読んで次はもうちょっとちゃんと育ててみよう。
データ指向アプリケーションデザイン
6章パーティショニングを読んだ。昔からパーティショニングとシャーディングの違いはなんだろう?と漠然と思っていた。パーティションの設計 を読むと、3つのパーティション分割があげられている。
- 水平的パーティション分割 (シャーディング)
- 列方向のパーティション分割
- 機能的パーティション分割
パーティショニングは大規模なデータセットをデータ分割するための手法または概念として広い意味をもって使われるように読める。一方でシャーディングと呼ばれるものは水平パーティショニングのことを指している。いま分散データベースで一般的に使われている仕組みがそうなのかもしれない。本書では水平・垂直のパーティショニングの定義は行われていないが、次の説明が出てくる。おそらく主に水平パーティショニングを意図しているのではないかと思う。まとめはこんな感じ。
用語の混乱
ここで パーティション と呼んでいるものは、 MongoDB 、 Elasticsearch 、 SolrCloud では シャード と呼ばれています。これは HBase では リージョン 、 Bigtable では タブレット 、Cassandra や Riak では vnode 、 Couchbase では vBucket と呼ばれています。とはいえ最も確立されている用語は パーティショニング なので、本書ではこの呼び方を使っていきます。
パーティショニングも普通に開発をしていたらデータベースの設計で必要になるので身近な概念と言える。だいたいは知っている内容ではあったけど、パーティショニングとセカンダリインデックスの仕組みとか考えたことがなかった。Cassandra ではセカンダリインデックスをうまく設計しないとパフォーマンスに影響を与えることからあまり使われない傾向にあると思う。
大規模なデータセットを小さな部分集合にデータ分割することをパーティショニングと呼ぶ。パーティショニングが必要になるのは、単一のマシンで保存や処理をするのが現実的ではないほどのデータがある場合になる。パーティショニングが目標とするのは、データやクエリの負荷を複数のマシン間で均等に分配し、ホットスポット(不均衡に高い負荷がかかるノード)が生じないようにすること。パーティショニングが均等になっておらず、一部のパーティションが他に比べて多くのデータやクエリを受け持っているような状態は スキュー(skew) と呼ばれる。そのためには、データに適したパーティショニングのスキームを選択し、クラスタへのノードの追加やクラスタからのノードの削除が生じたときにパーティション群をリバランシングする。
パーティショニングのアプローチとして主に2つがある。
- キーの範囲によるパーティショニング
- キーはソートされ、1つのパーティションには何らかの最小値と最大値の間にあるすべてのキーが保存される
- キーをソートすることで、範囲に対するクエリが効率的に処理できるというメリットがある
- アプリケーションが頻繁にアクセスするキーがソート順の中で近接していると、ホットスポットが生じるリスクがある
- 通常このアプローチでは、パーティションのリバランシングはパーティションが大きくなりすぎたときにその範囲を2つに分割することによって動的に行われる
- ハッシュパーティショニング
- ハッシュ関数がそれぞれのキーに対して適用され、1つのパーティションにはハッシュの一定の範囲を保存される
- この方法ではキーの順序が失われるので範囲に対するクエリは非効率になるが、負荷分散より均等にしやすい
- ハッシュによってパーティショニングを行う場合は、事前に固定数のパーティションを作成し、各ノードに複数のパーティションを割り当てておき、ノードの追加や削除が行われた場合にはパーティションをそのままあるノードから他のノードに移動させるのが一般的となる。また、動的パーティショニングも利用できる
ハイブリッドなアプローチを取ることもできる。たとえば複合キーを使い、キーの一部でパーティションを決め、他の部分でソート順を決めるといったやり方がある。Cassandra のプライマリーキーはこのアプローチを採用している。また、セカンダリインデックスもパーティショニングする方法が2つある。
- ドキュメントによってパーティショニングされたインデックス(ローカルインデックス)
- セカンダリインデックスをプライマリキー及び値と同じパーティションに保存する
- 書き込みの際に更新しなければならないパーティションが1つですむ
- セカンダリインデックスの読み取りにはすべてのパーティションに対する スキャッタ/ギャザー が必要となる
- 語によってパーティショニングされたインデックス(グローバルインデックス)
- セカンダリインデックスはインデックスが張られた値を使って独立にパーティショニングされる
- セカンダリインデックスのエントリには、プライマリキーのあらゆるパーティションのレコード群が含まれる
- ドキュメントが書き込まれる際には、セカンダリインデックスの複数のパーティションを更新しなければならない
- 読み取りは単一のパーティションだけで処理できる
クエリを適切なパーティションにルーティングする手法は、データベースに限った話題ではなく、サービスディスカバリ と呼ばれる一般的な問題である。有名な OSS として ZooKeeper がある。これにはシンプルなパーティションを認識するロードバランシングから、洗練された並列クエリ実行エンジンまで様々である。すべてのパーティションは、ほぼ独立に動作できるように設計されている。パーティショニングされたデータベースが複数のマシンにまでスケールできるのはそのおかげである。