Slide 1

Slide 1 text

Conflict-free replicated data types: распределенные данные в деталях Max Klymyshyn Tech Lead at Takeoff Technologies  / 5

Slide 2

Slide 2 text

Работа Tech Lead, Takeoff Technologies, 207– CTO @ ZAKAZ.UA and CartFresh, 202 Team Lead @ oDesk (now Upwork), 200 Project Coordinator @ 42 Coffee Cups, 2009 2 / 5

Slide 3

Slide 3 text

Сообщество соорганизатор PapersWeLove Kyiv соорганизатор PyCon Ukraine сооснователь KyivJS сооснователь LvivJS соорганизатор PiterPy соорганизатор Hotcode судья UA Web Challenge 3 / 5

Slide 4

Slide 4 text

Takeoff Technologies 4 / 5

Slide 5

Slide 5 text

Распределенная система The best material model of a cat is another, or preferably the same, cat. Norbert Wiener 5 / 5

Slide 6

Slide 6 text

Схема Client 1 Client 2 Client n message1 messagen messagen message1 message1 messagen messagen+1 Figure: Server is just a client 6 / 5

Slide 7

Slide 7 text

Ограничения сети Задержки Потери TCP пакетов или сообщений Нарушение порядка доставки сообщений Дубликаты Head-of-Line blocking 7 / 5

Slide 8

Slide 8 text

Чего мы хотим добиться? Чтобы все участники получали сообщения Избежать потери данных (data losses) Чтобы было понятно как разрешать ограничения сети 8 / 5

Slide 9

Slide 9 text

Три проблемы распределенних систем divergence (расхождение): ∪n i=1 o1 i ̸= ∪m j=1 o2 j causality-violations (нарушение порядка): o1 → o3 intention-violations (нарушение намерений): o1||o2 9 / 5

Slide 10

Slide 10 text

Модели целостности CONSISTENCY MODELS 0 / 5

Slide 11

Slide 11 text

Модель консистентности обещание или контракт между разработчиком и системой, на которой будет запущен его код следование правилам системы будет гарантировать определенные свойства данных  / 5

Slide 12

Slide 12 text

Strong Consistency “strong consistency” все изменения применяются последовательно (т.е. sequential with no operations overlap) в глобальном порядке Узкое горлышко : маленькая пропускная способность и большие задержки (из-за консенсуса): RAFT/PAXOS/Zab можновы брать либо availability, либо partition-tolerance 2 / 5

Slide 13

Slide 13 text

Weak Consistency никаких гарантий после записи Read-Your-Writes hack 3 / 5

Slide 14

Slide 14 text

Eventual Consistency ∀i, j : f ∈ ci ⇒ f ∈ cj, Convergence and Termination properties RIAK, MONGO, Cassandra, Couch 4 / 5

Slide 15

Slide 15 text

Strong Eventual Consistency ... То же что и Eventual Consistency and ∀i, j : ci = cj ⇒ Si ≡ Sj: корректные реплики, получившие одинаковы апдейты будут иметь эквивалентное состояние CALM: консистентность как логическая монотонность 5 / 5

Slide 16

Slide 16 text

Топология репликции ОБМЕН ТРАФИКОМ И ДОСТУПНОСТЬ 6 / 5

Slide 17

Slide 17 text

Fully connected (or mesh network) replication 7 / 5

Slide 18

Slide 18 text

Careful replication :) 8 / 5

Slide 19

Slide 19 text

Асинхронная репликация Клиенту возвращается ответ об успешной операции после успешной отправки в канал Следствие - нет гарантии консистентности со всеми нодами, очередь лога репликации может серьезно отставать (т.е. потенциально data-loss) 9 / 5

Slide 20

Slide 20 text

Кворум Клиенту возвращается ответ об успешной операции после записи на Vw > V /2 где V - общее количество нод (голосов), Vw - количество нод доступных для записи Vr + Vw > V где Vr - количество голосов (нод) доступных для чтения 20 / 5

Slide 21

Slide 21 text

Подходы Локинг (Distributed Locking) Один активный участник Транзакции Tentative Транзакции Версионирование/тэггирование Выполнение в обратном порядке (reversible execution) 2 / 5

Slide 22

Slide 22 text

Conflict-Free Replicated Data Types OR CRDT 22 / 5

Slide 23

Slide 23 text

CRDT Поддержка конкурентных операций на нескольких устройствах Офлайн-режим Long-running SAP (Facebook/Gmail/Soundcloud-типа) В целом проблема одно из решений по работе с асинхронными или конкрутентными сторонами, например плагины для редактора (Xi editor) 23 / 5

Slide 24

Slide 24 text

Решения доставки Event Stream (Pull) WebSTOMP/MQTT Aeron (Websocket), Akka etc. Pusher.com Google Cloud Pub/Sub Amazon SNS 24 / 5

Slide 25

Slide 25 text

Conflict-free replicated data types (CRDT) – типы данных без конфликтов Свойства полурешентки (⊔ or LUB – Least Upper Bound, наименьшая верхняя грань): коммутативность – ∀x, y : x y = y ⊔ x ассоциативность – x ⊔ (y ⊔ z) = (x ⊔ y) ⊔ z идемпотентность – x ⊔ x = x 25 / 5

Slide 26

Slide 26 text

Strong Eventual Consistency C = [c1, ..., cn], ∀i, j : ci = cj ⇒ si ≡ sj 26 / 5

Slide 27

Slide 27 text

ACID 2.0 ACID .0: atomicity, consistency, isolation, durability ACID 2.0: associative, commutative, idempotent, distributed 27 / 5

Slide 28

Slide 28 text

Counter 1 + 1 28 / 5

Slide 29

Slide 29 text

+ not idempotent 1 + 1 ̸= 1 29 / 5

Slide 30

Slide 30 text

∪ – sets are good 1 ∪ 1 = 1 30 / 5

Slide 31

Slide 31 text

Прочие свойства (1 ∪ 2) ∪ 3 = 1 ∪ (2 ∪ 3) 1 ∪ 2 = 2 ∪ 1 3 / 5

Slide 32

Slide 32 text

CRDT Transport ci CRDT State (con- vergent) Conflict Resolution Semantics Application access API Si 32 / 5

Slide 33

Slide 33 text

CRDT: пример свойств messages = [ { tag: 1, site: '1', payload: { key: 'val' } }, { tag: 1, site: '1', payload: { key: 'val' } }, { tag: 1, site: '2', payload: { key1: 'val1' } }, { tag: 2, site: '1', payload: { key2: 'val2' } }, { tag: 0, site: '2', payload: { key0: 'val0' } } ] // idempotency, messages.reduce( (v, c) => v.filter( m => m.tag == c.tag && m.site == c.site ).length == 0 ? v.concat([c]) : v, []); // partial order messages.sort(/* ...tag, site... */) 33 / 5

Slide 34

Slide 34 text

CRDT: GCounter export class GCounter { constructor(counters) { this.counters = counters; } increment(id) { return new GCounter(Object.assign({ [id]: (this.counters[id] || 0) + 1}))} query() { return Object.values(this.counters) .reduce((a, b) => a + b, 0); } merge(counter) { let sites = Object.keys(counter.counters) .concat(Object.keys(this.counters)); return new GCounter(sites.reduce( (merged, site) => Object.assign( merged, {[site]: Math.max( merged[site] || 0, counter.counters[site] || 0)}), this.counters)); } } 34 / 5

Slide 35

Slide 35 text

CRDT: GCounter payload let counters = { 1: 0 2: 0 ... N: 0} 35 / 5

Slide 36

Slide 36 text

CRDT: PNCounter class PNCounter { constructor(p, n) { this.n = n; this.p = p} increment() { return new PNCounter(this.p.increment(), this.n); } decrement() { return new PNCounter(this.p, this.n.increment()); } query() { return this.p.query() - this.n.query(); } merge(pncounter) { return new PNCounter( this.p.merge(pncounter.p), this.n.merge(pncounter.n)); } } 36 / 5

Slide 37

Slide 37 text

CRDT: MVRegister Figure S1 S2 S3 set(“v”) “v” set(“v3”) “v”, “v3” Figure: MVRegister Concurrent Operation 37 / 5

Slide 38

Slide 38 text

CRDT: MVRegister export class MVRegister { constructor(id, register) { this.id = id; this.register = register; set(value) { return new MVRegister( this.id, Object.assign(this.register, {[this.id]: value}))} query() {return Object.values(this.register); } merge(register) { let state = this.register[this.id] === undefined ? {} : {[this.id]: this.register[this.id]}; return new MVRegister(this.id, Object.assign(register.register, state)) } } 38 / 5

Slide 39

Slide 39 text

CRDT: MVRegister Figure S1 S2 S3 set(“v”) “v” set(“v3”) “v”, “v3” Figure: MVRegister Concurrent Operation 39 / 5

Slide 40

Slide 40 text

CRDT: MVRegister const repr = (arr) => arr.length === 0 ? '[]' : '["' + arr.join('", "') + '"] function example_mvregister() { let log = (op, r1, r2) => console.log("[OP] " + op + ": r1=" + repr(r1.query()) + ", r2=" + repr(r2.query())); let r1 = new MVRegister(1, {}); let r2 = new MVRegister(2, {}); log("register1", r1, r2); r1 = r1.set("key1") log("r1.set(key1)", r1, r2); r2 = r2.merge(r1); log("r1 U r2", r1, r2); r1.set("v1"); log("r1.set(v1)", r1, r2) r2.set("v2") log("[CONCURRENT] r2.set(v2)", r1, r2) r2 = r2.merge(r1); log("[MERGED]", r1, r2); } 40 / 5

Slide 41

Slide 41 text

CRDT: MVRegister Output [OP] register1: r1=[], r2=[] [OP] r1.set(key1): r1=["key1"], r2=[] [OP] r1 U r2: r1=["key1"], r2=["key1"] [OP] r1.set(v1): r1=["v1"], r2=["key1"] [OP] [CONCURRENT] r2.set(v2): r1=["v1"], r2=["key1", "v2"] [OP] [MERGED]: r1=["v1", "v2"], r2=["v1", "v2"] 4 / 5

Slide 42

Slide 42 text

JSON CRDT Replica p: Replica q: {“key”: “A”} {“key”: “A”} {“key”: “B”} {“key”: “C”} {“key”: {“B”, “C”}} {“key”: {“B”, “C”}} network communication doc.get(“key”) := “B”; doc.get(“key”) := “C”; Figure: Конкуретные присвоения в регистре по ключу doc.get(“key”) репликами p и q. 42 / 5

Slide 43

Slide 43 text

CRDT: Типы Register: LWW или Multi-Value (как Dynamo или Couchdb) Counter только растущий G-Set – множество с возможностю исключительно добавления 2P-Set – множество, где один уникальный элемент можно удалять только один раз (G-Set + Tombstones set) LWW-Element-Set – LWW на базе vector clocks OR-Set – тэгированные элементы, тэги помещаются в множество Tombstones WOOT, LOGOOT, Treedoc, RGA, LSEQ для упорядоченных списков 43 / 5

Slide 44

Slide 44 text

Инструменты Roshi by Soundcloud Riak 2.0: Counters, Flags, Sets, Registers, Maps Redis Labs CRDT Y-js – framework for offline-first p2p shared editing on structured data Swarm (and forever-in-pre-alpha tool) replikativ.io – p2p distributed system framework GUN framework: p2p distributed framework 44 / 5

Slide 45

Slide 45 text

Кто использует CRDT? Facebook TomTom League of Legends SoundCloud Bet265 RIAK Distributed Database 45 / 5

Slide 46

Slide 46 text

Blockchain AND MERKLE TREES 46 / 5

Slide 47

Slide 47 text

LinkedList 47 / 5

Slide 48

Slide 48 text

Hash function 48 / 5

Slide 49

Slide 49 text

MerkleTree 49 / 5

Slide 50

Slide 50 text

Blockchain 50 / 5

Slide 51

Slide 51 text

Thanks @maxmaxmaxmax 5 / 5