CRDT in 15 minutes
大村 伸吾
@everpeace
CRDTとは
● CRDT = Conflict-free Replicated Data Type
○ コンフリクトしない複製可能なデータ
○ やり方によって二通りの呼び名がある:
■ Commutative Replicated Data Type(Operation-Based)
■ Convergent Replicated Data Type(State-Based)
● 分散環境でCAPのAとPの両立を実現
○ 強いAvailabilityと
○ ネットワーク分断への耐性
CRDTが実装されているOSS達
● Riak by Basho
● Roshi by SoundCloud (on the top of Redis)
● Akka Distributed Data by Akka Team
おさらいCAP定理
分散システムでは
● (Partition Tolerance) ネットワークが故障してても
● (Consistency) データの整合性を持って
● (Availability) 読み書きが常にできる
を3つ同時に満たすことはできなくて、満たせても2つまで、という定理。
CRDT は そのうち AとPを取る戦略のデータ構造 です
AとPを取るってどういうこと?
● Consistencyは無い ➔ 結果整合性しかない
○ システムが安定(特にネットワーク)すれば、そのうちデータに整合性が訪れる
○ 読めてもそのデータは整合性のあるデータとは限らない・・・
そのかわり
● ノードが生きてれば、ネットワーク死んでてもいつでも読書できる(Availability &
Partition Tolerance)
○ ローカルからはゼッタイ書込が成功する
○ ノードが故障しないかぎり、ネットワークが復帰すれば
書込による変更はゼッタイに波及して、そのうち整合性が訪れる
わかった気になるCRDT
● Consistencyは難しいので諦める
○ Writeの直列化はめちゃくちゃ大変
● ネットワーク上で複数の異なるバージョンのデータ(レプリカ)を存在させる
○ 複数のレプリカに別々に操作を施していいことにする
○ 他ノードで行われた操作を後からマージして結果整合性を保てるようにする
● データへの操作を「可換」なものだけに限定して、
● 最後にマージすれば、あら不思議
● 操作列が全部到達すれば全てのノードのレプリカのデータは収束する
○ カウンタを想像してください。バラバラに足されても、 countUp(n)という操作列が
全部各ノードに到達すれば最終的にカウンタの値は全部おなじになりますよね?
イメージ
● f, g が可換で、
● 初期値が一緒だったら、
● いつか操作 f と操作 g が施された状態になる
● (カウンタの場合は、countUp(n) しか操作が無いケース)
出典: A comprehensive study of Convergent and Commutative Replicated Data Types
CRDTにはやり方が二通りあります
● Operation-Based CRDT: Commutative Replicated Data Type (CmRDT)
○ データへ施された操作を送り合うタイプ
○ 操作は可換である必要がある
○ データサイズが大きい場合に有効そう
● State-Based CRDT: Convergent Replicated Data Type (CvRDT)
○ レプリカ自体を送り合うタイプ
○ レプリカをマージする演算は join semilatticeを成せば良い
■ join semilattice = 任意の2要素の最小上界を持つ半順序集合
● 数学的厳密さを無視すれば「可換なモノイド」と捉えちゃっても良い
■ 例: 最大値とか、和集合とか
● 最大値とか、和集合は順番ばらばらにマージしても最後に整合性取れる
○ データサイズが小さい場合に有効そう
※両者のパワーに違いはない(どっちもどっちをsimulateできる)
よく見るCRDTなデータ構造
● カウンタ:
○ Operation-Based
■ Op-Counter:
足し算・引き算は混じっても可換。 increment/decrementをやり取りしあう。受信した順番に適
用すればそのうち全部同じ値になる。
○ State-Based
■ G-Counter:
足し算だけのCounter。各ノードでどれだけカウントアップされたか?というベクトルをもつ。
マージは各要素のMaxを取ればいい
■ PN-Counter:
引き算も対応したCoutner。PositiveなベクトルとNegativeなベクトルの2つを状態として持
つ。マージ操作は、Positive側はmax, Negative側はmin
よく見るCRDTなデータ構造
● 集合
○ State-Based
■ G-Set:
追加しか出来ない集合。追加しかされないので、マージの時は和集合取るだけ
■ 2P-Set:
追加削除ができる。PN-Counterと同じで、追加された要素集合、削除された要素集合の2つ
を保持。マージはそれぞれ和集合とる。 PからNを取り除けば現在のデータ
● 注: 一度取り除いたデータは足せない
○ Operation-Based
■ Op-based 2P-Set: add, removeの操作をやり取りするだけ。各ノードでは追加された
要素の集合と、削除された要素の集合を保持。同じ要素に対する add, removeは可換
■ 他にもU-Set, OR-Set 等いろいろ亜種がある
よく見るCRDTなデータ構造
● より複雑なデータ構造だとMap, Register, Graph なんかも作れたりする
○ 詳しくは A comprehensive study of Convergent and Commutative
Replicated Data Types を参照
○ データのマージ、変更操作がしっかり記述されています
Riak における CRDT
● Riak 2.0 から登場
● インターフェースはHTTP
● 対応しているデータ
○ counter
○ set
○ map
http://docs.basho.com/riak/latest/dev/using/data-types/
Roshi における CRDT
● SoundCloud製, Go製
● Roshi ServerはHTTPインターフェースを持っている
● RedisのSorted SetがBackend
● 対応するデータ
○ LWW-element-set (Last-Writer-Wins)
■ 「最後に」addされるかremoveされたかで要素の所属が決まる集合
● 最後 = timestampベースの判断
● add, removeがredis の sorted setに保存されているらしく、
任意のtimepointでの集合が逆算可
https://developers.soundcloud.com/blog/roshi-a-crdt-system-for-timestamped-events https://github.
com/soundcloud/roshi
Akka における CRDT
● Scala製, Akka は Actorプログラミングツールキット
● Akka Distributed DataモジュールでCRDTを提供
○ バージョン 2.4.0 から登場
○ まだexperimentalモジュール(最新は2.4.2)
○ Akka Cluster 上で利用可能
● 対応するデータ
○ Counter, Register, Set, Map, MultiMap と色々ある
■ データ構造も色々あって自身で選べる
○ アプリノード上でCRDTが使えるのが強みかも
○ ※ Majority Quorumによる強い整合性を実現する Read/Write Primitiveもある
■ 右図中Replicatorを使うとできる模様
http://doc.akka.io/docs/akka/2.4.2/scala/distributed-data.html
CRDT おさらい
● 高いAvailabilityとPartition 耐性をもち、
➔ノードが生きてれば、ネットワーク死んでても、常に読み書きできる
● Consistencyは期待できないけど、
➔ 読めても整合性は無いかもしれない
● 結果整合性だけが期待できる
➔ネットワークが正常ならそのうち正しい値に収まる(書込がロストしない)
そんなデータです。
参考文献とか
● A comprehensive study of Convergent and Commutative
Replicated Data Types
○ コレを読むのが一番確実
● Riak 2.0のCRDTで遊ぶ
○ Basho 上西さんのわかりやすい解説
○ こっちも日本語で図付きでわかりやすく説明されている
● Akka Distributed Dataの参考文献のビデオも良さそう

CRDT in 15 minutes

  • 1.
    CRDT in 15minutes 大村 伸吾 @everpeace
  • 2.
    CRDTとは ● CRDT =Conflict-free Replicated Data Type ○ コンフリクトしない複製可能なデータ ○ やり方によって二通りの呼び名がある: ■ Commutative Replicated Data Type(Operation-Based) ■ Convergent Replicated Data Type(State-Based) ● 分散環境でCAPのAとPの両立を実現 ○ 強いAvailabilityと ○ ネットワーク分断への耐性
  • 3.
    CRDTが実装されているOSS達 ● Riak byBasho ● Roshi by SoundCloud (on the top of Redis) ● Akka Distributed Data by Akka Team
  • 4.
    おさらいCAP定理 分散システムでは ● (Partition Tolerance)ネットワークが故障してても ● (Consistency) データの整合性を持って ● (Availability) 読み書きが常にできる を3つ同時に満たすことはできなくて、満たせても2つまで、という定理。 CRDT は そのうち AとPを取る戦略のデータ構造 です
  • 5.
    AとPを取るってどういうこと? ● Consistencyは無い ➔結果整合性しかない ○ システムが安定(特にネットワーク)すれば、そのうちデータに整合性が訪れる ○ 読めてもそのデータは整合性のあるデータとは限らない・・・ そのかわり ● ノードが生きてれば、ネットワーク死んでてもいつでも読書できる(Availability & Partition Tolerance) ○ ローカルからはゼッタイ書込が成功する ○ ノードが故障しないかぎり、ネットワークが復帰すれば 書込による変更はゼッタイに波及して、そのうち整合性が訪れる
  • 6.
    わかった気になるCRDT ● Consistencyは難しいので諦める ○ Writeの直列化はめちゃくちゃ大変 ●ネットワーク上で複数の異なるバージョンのデータ(レプリカ)を存在させる ○ 複数のレプリカに別々に操作を施していいことにする ○ 他ノードで行われた操作を後からマージして結果整合性を保てるようにする ● データへの操作を「可換」なものだけに限定して、 ● 最後にマージすれば、あら不思議 ● 操作列が全部到達すれば全てのノードのレプリカのデータは収束する ○ カウンタを想像してください。バラバラに足されても、 countUp(n)という操作列が 全部各ノードに到達すれば最終的にカウンタの値は全部おなじになりますよね?
  • 7.
    イメージ ● f, gが可換で、 ● 初期値が一緒だったら、 ● いつか操作 f と操作 g が施された状態になる ● (カウンタの場合は、countUp(n) しか操作が無いケース) 出典: A comprehensive study of Convergent and Commutative Replicated Data Types
  • 8.
    CRDTにはやり方が二通りあります ● Operation-Based CRDT:Commutative Replicated Data Type (CmRDT) ○ データへ施された操作を送り合うタイプ ○ 操作は可換である必要がある ○ データサイズが大きい場合に有効そう ● State-Based CRDT: Convergent Replicated Data Type (CvRDT) ○ レプリカ自体を送り合うタイプ ○ レプリカをマージする演算は join semilatticeを成せば良い ■ join semilattice = 任意の2要素の最小上界を持つ半順序集合 ● 数学的厳密さを無視すれば「可換なモノイド」と捉えちゃっても良い ■ 例: 最大値とか、和集合とか ● 最大値とか、和集合は順番ばらばらにマージしても最後に整合性取れる ○ データサイズが小さい場合に有効そう ※両者のパワーに違いはない(どっちもどっちをsimulateできる)
  • 9.
    よく見るCRDTなデータ構造 ● カウンタ: ○ Operation-Based ■Op-Counter: 足し算・引き算は混じっても可換。 increment/decrementをやり取りしあう。受信した順番に適 用すればそのうち全部同じ値になる。 ○ State-Based ■ G-Counter: 足し算だけのCounter。各ノードでどれだけカウントアップされたか?というベクトルをもつ。 マージは各要素のMaxを取ればいい ■ PN-Counter: 引き算も対応したCoutner。PositiveなベクトルとNegativeなベクトルの2つを状態として持 つ。マージ操作は、Positive側はmax, Negative側はmin
  • 10.
    よく見るCRDTなデータ構造 ● 集合 ○ State-Based ■G-Set: 追加しか出来ない集合。追加しかされないので、マージの時は和集合取るだけ ■ 2P-Set: 追加削除ができる。PN-Counterと同じで、追加された要素集合、削除された要素集合の2つ を保持。マージはそれぞれ和集合とる。 PからNを取り除けば現在のデータ ● 注: 一度取り除いたデータは足せない ○ Operation-Based ■ Op-based 2P-Set: add, removeの操作をやり取りするだけ。各ノードでは追加された 要素の集合と、削除された要素の集合を保持。同じ要素に対する add, removeは可換 ■ 他にもU-Set, OR-Set 等いろいろ亜種がある
  • 11.
    よく見るCRDTなデータ構造 ● より複雑なデータ構造だとMap, Register,Graph なんかも作れたりする ○ 詳しくは A comprehensive study of Convergent and Commutative Replicated Data Types を参照 ○ データのマージ、変更操作がしっかり記述されています
  • 12.
    Riak における CRDT ●Riak 2.0 から登場 ● インターフェースはHTTP ● 対応しているデータ ○ counter ○ set ○ map http://docs.basho.com/riak/latest/dev/using/data-types/
  • 13.
    Roshi における CRDT ●SoundCloud製, Go製 ● Roshi ServerはHTTPインターフェースを持っている ● RedisのSorted SetがBackend ● 対応するデータ ○ LWW-element-set (Last-Writer-Wins) ■ 「最後に」addされるかremoveされたかで要素の所属が決まる集合 ● 最後 = timestampベースの判断 ● add, removeがredis の sorted setに保存されているらしく、 任意のtimepointでの集合が逆算可 https://developers.soundcloud.com/blog/roshi-a-crdt-system-for-timestamped-events https://github. com/soundcloud/roshi
  • 14.
    Akka における CRDT ●Scala製, Akka は Actorプログラミングツールキット ● Akka Distributed DataモジュールでCRDTを提供 ○ バージョン 2.4.0 から登場 ○ まだexperimentalモジュール(最新は2.4.2) ○ Akka Cluster 上で利用可能 ● 対応するデータ ○ Counter, Register, Set, Map, MultiMap と色々ある ■ データ構造も色々あって自身で選べる ○ アプリノード上でCRDTが使えるのが強みかも ○ ※ Majority Quorumによる強い整合性を実現する Read/Write Primitiveもある ■ 右図中Replicatorを使うとできる模様 http://doc.akka.io/docs/akka/2.4.2/scala/distributed-data.html
  • 15.
    CRDT おさらい ● 高いAvailabilityとPartition耐性をもち、 ➔ノードが生きてれば、ネットワーク死んでても、常に読み書きできる ● Consistencyは期待できないけど、 ➔ 読めても整合性は無いかもしれない ● 結果整合性だけが期待できる ➔ネットワークが正常ならそのうち正しい値に収まる(書込がロストしない) そんなデータです。
  • 16.
    参考文献とか ● A comprehensivestudy of Convergent and Commutative Replicated Data Types ○ コレを読むのが一番確実 ● Riak 2.0のCRDTで遊ぶ ○ Basho 上西さんのわかりやすい解説 ○ こっちも日本語で図付きでわかりやすく説明されている ● Akka Distributed Dataの参考文献のビデオも良さそう