Slide 1

Slide 1 text

イミュータブルな データベース @xorphitus (2015-10)

Slide 2

Slide 2 text

競合状態の回避方法 唐突だが、競合状態はどうやって防ぐか? DB の前にここでプログラミングの世界の手法をおさらいしてみる プリエンプティブ 協調的 排他制御 イミュータブル メッセージ パッシング トランザクショナル メモリ 競合状態の回避

Slide 3

Slide 3 text

じゃあ、DB もイミュータブルだな

Slide 4

Slide 4 text

それはつまり

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Datomic とは ● CRUDのうち C と R しかない ○ 一度作られたデータはイミュータブルである ● 追記型 ○ 変更は、同一 ID で新しいレコードを追加する ○ ただし PostgreSQL と違って過去の履歴を全て保持 するモデル ○ 削除は、同一 ID で打ち消しを意味するレコードを追加する ● クエリは Datalog という Prolog のサブセット ● プロプライエタリ というスペックなのだが、その背後には独自の論理モデルがある模様

Slide 7

Slide 7 text

Datomic の思想 ● これまでの DB は場所指向だった ○ PLOP (Place-Oriented Programming) ○ リソースが希少だった時代、新しい情報は、古い情報のあった場所に上書きすることで、空間 (ディ スクとメモリ) を節約する必要があった ■ 情報は場所に紐付いた存在となった ■ そして DB サーバは、場所の管理を頑張らないといけなくなった ● いや、今そんな貧しい時代じゃねえし ○ だいたい、ここでいう「場所」って情報と関係ない概念だよね ○ あと、過去にあった情報、すなわちその時点における事実は変わらない ■ 例えば、人間が引っ越しをしても過去の住所が UPDATE されるわけではない ● 場所指向をやめたらかっこいいアーキテクチャにできるよ! ○ いまここ

Slide 8

Slide 8 text

場所指向で何が悪い? ● DB サーバの担ってる以下の責任を、一箇所で行う必要が出てくる ○ トランザクション ○ データ一貫性の維持 ○ インデキシング ○ ストレージの I/O ○ クエリの受け付け ● ディスクとメモリの何処に何があるか、を各々が把握して動く状態 ○ PostgreSQL 的な追記型アーキテクチャでも上記は同じ場所に配置されていて問題解決していな い ○ また、App から分断された世界が作られることでインピーダンスミスマッチが起きる ● これらを分解したい ○ 各々がシンプルになり、特定の処理に特化でき、好きな場所に再配置可能 ○ (分散っぽい話になってきた )

Slide 9

Slide 9 text

で、場所指向をやめる ● 新しいデータは、一方的に蓄積していこう ○ 一度積まれたデータの更新・削除はもう考えない ○ 少し低いレイヤで起きていることは、 RDB でいう履歴テーブルみたいな状態 ○ 富豪的な時代になったものである ● こうした一方的なデータストレージに対し、それっぽい抽象 I/F つけたら諸々分離で きるんじゃね? ○ …と、いうことなんじゃないかな ○ 質問は受け付けません

Slide 10

Slide 10 text

ちなみにデータモデルはこんな感じ ● 田中さんの fact を追加 ○ {id: 1, name: ‘田中’, address: ‘東京都渋谷区神南’} ● 田中さんが引っ越したので fact をさらに追加 ○ {id: 1, name: ‘田中’, address: ‘東京都神田錦町’} ● で、2 レコードになる ○ 最初の fact は immutable ○ クエリでは、特に指定がなければ現在の fact が取得される ○ 過去に遡って取得もできる

Slide 11

Slide 11 text

で、なんやかんや色々あって

Slide 12

Slide 12 text

Datomic のアーキテクチャ Peer, Strage Service, Transactor の 3つから構成される 詳細は後述するが Datomic は複数サービスの集積である ● Storage Service はただデータを入れるだけ のサーバ ● Peer は AP に組み込まれ、Storage Serivice からデータ取得をする ● Transactor は上記2つから分離した、トラン ザクション処理専門部分

Slide 13

Slide 13 text

Peer のお仕事 ● App のプロセスに (ライブラリとして) 組み込まれて動作するもので ● Query を処理して ● Storage Service から該当するデータを取得し ● App のメモリ内のキャッシュする ○ 各 fact はイミュータブルからキャッシュし放題 ■ キャッシュも背後のストレージも、 App からしたら意識することなく扱える ● 一般的な RDB に対するメリット ■ App のサーバを複数立てれば、 DB の Read 性能はスケールする ■ ちなみに LRU ■ この層に memcached を使うこともできるっぽい ○ 新たな fact が積まれた場合、Transactor がそれを各 Peer にブロードキャストする (後述)

Slide 14

Slide 14 text

Transactor のお仕事 ● Write (追記) は全て Transactor (ぶっちゃけSPOF的) が Peer からの指示で担う ○ Transactor は全ての処理をトランザクションとし、シリアルに行う ○ なので Write 時にロックとらなくてもいいし、とってない ● 何それ怖えー、となりそうだが、設計思想としては ○ 他の処理は全部 Peer に寄せてるんだから Transactor クッソ軽い ○ こいつ落ちても各 Peer は生きてるし Read は継続可能 ○ Hot Standby 機を立ときゃいいわけだし ○ そもそも Transactor が高負荷になるものに Datomic 使うのが間違いの元 ■ 他の技術を使いましょう ○ (あと、よく考えたら MySQL の Master だって似たようなもんだじゃね? ) ● Write したら Peer にブロードキャストして Peer 内 Index を更新する

Slide 15

Slide 15 text

Strage Service のお仕事 ● ファイルシステムを抽象化して ○ Peer にデータを提供する ○ Transactor から書き込まれる ● RDBMS や KVS (選択可能) が抽象化技術として使われる ○ ファイルシステムに直接触ることはない

Slide 16

Slide 16 text

Storage Service 層ってどうなってるの? Backend に MySQL を選択するとこれだけ… CREATE TABLE datomic_kvs ( id varchar(640) NOT NULL, rev integer, map text, val longblob, CONSTRAINT pk_id PRIMARY KEY (id) ) ENGINE=INNODB

Slide 17

Slide 17 text

まとめのような何か ● 旧来の RDBMS が一手に担っていた各部分が分散されるようになった ● Write はシリアルに実行される ○ 軽量な Transactor が順次実行する ● Read は App に分散される ○ App のプロセス内で積極的にキャッシュし、各 App のノードはそこから読み出す ○ クエリ処理〜データ取得 (キャッシュヒットすれば ) が分散処理される