SlideShare ist ein Scribd-Unternehmen logo
1 von 43
Распределенные данные:
CRDT-структуры данных в
JavaScript
Максим Климишин
Head of Software Architecture at Takeoff Technologies
 / 43
Работа
Head of Software Architecture, 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 / 43
Сообщество
соорганизатор PapersWeLove Kyiv
соорганизатор PyCon Ukraine
сооснователь KyivJS
сооснователь LvivJS
соорганизатор PiterPy
соорганизатор Hotcode
судья UA Web Challenge
3 / 43
Takeoff Technologies
4 / 43
Зачем?
5 / 43
Распределенная система
Поддержка конкурентных операций на нескольких
устройствах
Офлайн-режим
Long-running SAP (Facebook/Gmail/Soundcloud-типа)
6 / 43
Пример распределенной системы
7 / 43
Пример распределенной системы
схема
Client 1 Client 2 Client n
message1
messagen
messagen
message1
message1
messagen
messagen+1
Figure: Server is just a client
8 / 43
Три проблемы конкурентности
divergence (расхождение): ∪n
i=1o1
i ̸= ∪m
j=1o2
j
causality-violations (нарушение порядка): o1 → o3
intention-violations (нарушение намерений): o1||o2
9 / 43
CAP Theorem
0 / 43
DCS Triangle
Decentralized - означает децентрализованость и
server-free
Consistent - консистентность означает что все ноды
видять одни и те же данные в одно и то же время
Scale - означает что у сети есть достаточно
производительности, чтобы работать в масштабах
планеты
 / 43
DCS Triangle
2 / 43
Strong Consistency
“strong consistency” все изменения применяются
последовательно (т.е. sequential with no operations
overlap) в глобальном порядке
Узкое горлышко : маленькая пропускная способность
и большие задержки (из-за консенсуса):
RAFT/PAXOS/Zab
можновы брать либо availability, либо partition-tolerance
3 / 43
Weak Consistency
никаких гарантий после записи
Read-Your-Writes hack
4 / 43
Eventual Consistency
∀i, j : f ∈ ci ⇒ f ∈ cj, Convergence and Termination
properties
RIAK, MONGO, Cassandra, Couch
5 / 43
Strong Eventual Consistency
... То же что и Eventual Consistency
and ∀i, j : ci = cj ⇒ Si ≡ Sj: Correct replicas that have
delivered the same updates have equivalent state
CALM: consistency as logical monotonicity
6 / 43
Подходи сходу
Локинг
Один активный участник
Транзакции
Tentative Транзакции
Версионирование/тэггирование
Выполнение в обратном порядке (reversible execution)
7 / 43
Conflict-Free Replicated
Data Types
OR CRDT
8 / 43
Системные уровни
Надежный способ доставки сообщений (reliable
multicast)
Схождение состояния или консистентность
9 / 43
Ограничения сети
Задержки
Потери TCP пакетов или сообщений
Нарушение порядка доставки сообщений
Дубликаты
Head-of-Line blocking
20 / 43
Решения доставки
Event Stream (Pull)
WebSTOMP/MQTT
Aeron (Websocket)
2 / 43
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
22 / 43
Strong Eventual Consistency
C = [c1, ..., cn], ∀i, j : ci = cj ⇒ si ≡ sj
23 / 43
Counter
1 + 1
24 / 43
+ not idempotent
1 + 1 ̸= 1
25 / 43
∪ – sets are good
1 ∪ 1 = 1
26 / 43
Other properties of sets
(1 ∪ 2) ∪ 3 = 1 ∪ (2 ∪ 3)
1 ∪ 2 = 2 ∪ 1
27 / 43
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... */)
28 / 43
CRDT в DCS Triangle
29 / 43
CRDT
Transport ci
CRDT
State (con-
vergent)
Conflict
Resolution
Semantics
Application
access API
Si
30 / 43
CRDT: Replication strategies
pubsub + periodic full state update (STOMP etc.)
Server Sent Events (SSE) in, Websockets out
3 / 43
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));
}
}
32 / 43
CRDT: GCounter payload
let counters = {
1: 0
2: 0
...
N: 0}
33 / 43
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)); }
}
34 / 43
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))
}
}
35 / 43
CRDT: MVRegister Figure
S1 S2 S3
set(“v”)
“v”
set(“v3”)
“v”, “v3”
Figure: MVRegister Concurrent Operation
36 / 43
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.
37 / 43
JSON CRDT
{}
{“a”: {}}
{“a”: {“x”: “y”}}
{mapT(“a”): {“x”: “y”},
listT(“a”): [“z”]}
{}
{“a”: []}
{“a”: [“z”]}
{mapT(“a”): {“x”: “y”},
listT(“a”): [“z”]}
network communication
doc.get(“a”) := {};
doc.get(“a”).get(“x”) := “y”;
doc.get(“a”) := [];
...idx(0).insertAfter(“z”);
Figure: Конкуретное присвоение значений разного типа одному
JSON ключу
38 / 43
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 для
упорядоченных списков
39 / 43
Инструменты
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
40 / 43
Свой CRDT тип
+ Относительно мало кода
+ Хорошо расширяется
+ Работает очень предсказуемо в рамках своей
модели
+ Консистентно даже при плохой сети (с задержкой)
+ Работа оффлайн
- Распределенная модель тяжело заходит
- Сложно заниматься GC
- Дополнительный гемор в оптимизации (δ-mutation)
4 / 43
Кто использует CRDT?
Facebook
TomTom
League of Legends
SoundCloud
Bet265
RIAK Distributed Database
42 / 43
Thanks
@maxmaxmaxmax
43 / 43

Weitere ähnliche Inhalte

Ähnlich wie JS Fest 2018. Максим Климишин. Распределенные данные: CRDT-структуры данных в JS

20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Computer Science Club
 
Опыт разработки статического анализатора кода
Опыт разработки статического анализатора кодаОпыт разработки статического анализатора кода
Опыт разработки статического анализатора кода
Andrey Karpov
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
Technopark
 
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кодаSECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
Конференция разработчиков программного обеспечения SECON'2014
 
Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)
Ontico
 

Ähnlich wie JS Fest 2018. Максим Климишин. Распределенные данные: CRDT-структуры данных в JS (20)

Лекция 9. Программирование GPU
Лекция 9. Программирование GPUЛекция 9. Программирование GPU
Лекция 9. Программирование GPU
 
Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3
 
KharkivJS 2017: Коллаборативные системы и CRDT
KharkivJS 2017: Коллаборативные системы и CRDTKharkivJS 2017: Коллаборативные системы и CRDT
KharkivJS 2017: Коллаборативные системы и CRDT
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 
Опыт разработки статического анализатора кода
Опыт разработки статического анализатора кодаОпыт разработки статического анализатора кода
Опыт разработки статического анализатора кода
 
Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?Статический анализ: ищем ошибки... и уязвимости?
Статический анализ: ищем ошибки... и уязвимости?
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
 
SAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в кодеSAST и Application Security: как бороться с уязвимостями в коде
SAST и Application Security: как бороться с уязвимостями в коде
 
Blind SQL Injections. Достаточно ли хороши ваши тесты?
Blind SQL Injections. Достаточно ли хороши ваши тесты?Blind SQL Injections. Достаточно ли хороши ваши тесты?
Blind SQL Injections. Достаточно ли хороши ваши тесты?
 
Миграция данных из Oracle в Postgres
Миграция данных из Oracle в PostgresМиграция данных из Oracle в Postgres
Миграция данных из Oracle в Postgres
 
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
 
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кодаSECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)
 
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
 
Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)
 
TMPA-2013 Tsytelov Trifanov Devexperts
TMPA-2013 Tsytelov Trifanov DevexpertsTMPA-2013 Tsytelov Trifanov Devexperts
TMPA-2013 Tsytelov Trifanov Devexperts
 
Андрей Ситник
Андрей СитникАндрей Ситник
Андрей Ситник
 
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
 
Расширение библиотеки Slick
Расширение библиотеки SlickРасширение библиотеки Slick
Расширение библиотеки Slick
 

Mehr von JSFestUA

Mehr von JSFestUA (20)

JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in productionJS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
 
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript PerformanceJS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
 
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
 
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
 
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
 
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
 
JS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstackJS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Александр Товмач. JAMstack
 
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
 
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
 
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developersJS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
 
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
 
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
 
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the ScaleJS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
 
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratchJS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
 
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотятJS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
 
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for RustJS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
 
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
 
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проектіJS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
 
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядроJS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
 
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
 

JS Fest 2018. Максим Климишин. Распределенные данные: CRDT-структуры данных в JS

  • 1. Распределенные данные: CRDT-структуры данных в JavaScript Максим Климишин Head of Software Architecture at Takeoff Technologies  / 43
  • 2. Работа Head of Software Architecture, 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 / 43
  • 3. Сообщество соорганизатор PapersWeLove Kyiv соорганизатор PyCon Ukraine сооснователь KyivJS сооснователь LvivJS соорганизатор PiterPy соорганизатор Hotcode судья UA Web Challenge 3 / 43
  • 6. Распределенная система Поддержка конкурентных операций на нескольких устройствах Офлайн-режим Long-running SAP (Facebook/Gmail/Soundcloud-типа) 6 / 43
  • 8. Пример распределенной системы схема Client 1 Client 2 Client n message1 messagen messagen message1 message1 messagen messagen+1 Figure: Server is just a client 8 / 43
  • 9. Три проблемы конкурентности divergence (расхождение): ∪n i=1o1 i ̸= ∪m j=1o2 j causality-violations (нарушение порядка): o1 → o3 intention-violations (нарушение намерений): o1||o2 9 / 43
  • 11. DCS Triangle Decentralized - означает децентрализованость и server-free Consistent - консистентность означает что все ноды видять одни и те же данные в одно и то же время Scale - означает что у сети есть достаточно производительности, чтобы работать в масштабах планеты  / 43
  • 13. Strong Consistency “strong consistency” все изменения применяются последовательно (т.е. sequential with no operations overlap) в глобальном порядке Узкое горлышко : маленькая пропускная способность и большие задержки (из-за консенсуса): RAFT/PAXOS/Zab можновы брать либо availability, либо partition-tolerance 3 / 43
  • 14. Weak Consistency никаких гарантий после записи Read-Your-Writes hack 4 / 43
  • 15. Eventual Consistency ∀i, j : f ∈ ci ⇒ f ∈ cj, Convergence and Termination properties RIAK, MONGO, Cassandra, Couch 5 / 43
  • 16. Strong Eventual Consistency ... То же что и Eventual Consistency and ∀i, j : ci = cj ⇒ Si ≡ Sj: Correct replicas that have delivered the same updates have equivalent state CALM: consistency as logical monotonicity 6 / 43
  • 17. Подходи сходу Локинг Один активный участник Транзакции Tentative Транзакции Версионирование/тэггирование Выполнение в обратном порядке (reversible execution) 7 / 43
  • 19. Системные уровни Надежный способ доставки сообщений (reliable multicast) Схождение состояния или консистентность 9 / 43
  • 20. Ограничения сети Задержки Потери TCP пакетов или сообщений Нарушение порядка доставки сообщений Дубликаты Head-of-Line blocking 20 / 43
  • 21. Решения доставки Event Stream (Pull) WebSTOMP/MQTT Aeron (Websocket) 2 / 43
  • 22. 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 22 / 43
  • 23. Strong Eventual Consistency C = [c1, ..., cn], ∀i, j : ci = cj ⇒ si ≡ sj 23 / 43
  • 25. + not idempotent 1 + 1 ̸= 1 25 / 43
  • 26. ∪ – sets are good 1 ∪ 1 = 1 26 / 43
  • 27. Other properties of sets (1 ∪ 2) ∪ 3 = 1 ∪ (2 ∪ 3) 1 ∪ 2 = 2 ∪ 1 27 / 43
  • 28. 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... */) 28 / 43
  • 29. CRDT в DCS Triangle 29 / 43
  • 31. CRDT: Replication strategies pubsub + periodic full state update (STOMP etc.) Server Sent Events (SSE) in, Websockets out 3 / 43
  • 32. 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)); } } 32 / 43
  • 33. CRDT: GCounter payload let counters = { 1: 0 2: 0 ... N: 0} 33 / 43
  • 34. 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)); } } 34 / 43
  • 35. 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)) } } 35 / 43
  • 36. CRDT: MVRegister Figure S1 S2 S3 set(“v”) “v” set(“v3”) “v”, “v3” Figure: MVRegister Concurrent Operation 36 / 43
  • 37. 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. 37 / 43
  • 38. JSON CRDT {} {“a”: {}} {“a”: {“x”: “y”}} {mapT(“a”): {“x”: “y”}, listT(“a”): [“z”]} {} {“a”: []} {“a”: [“z”]} {mapT(“a”): {“x”: “y”}, listT(“a”): [“z”]} network communication doc.get(“a”) := {}; doc.get(“a”).get(“x”) := “y”; doc.get(“a”) := []; ...idx(0).insertAfter(“z”); Figure: Конкуретное присвоение значений разного типа одному JSON ключу 38 / 43
  • 39. 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 для упорядоченных списков 39 / 43
  • 40. Инструменты 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 40 / 43
  • 41. Свой CRDT тип + Относительно мало кода + Хорошо расширяется + Работает очень предсказуемо в рамках своей модели + Консистентно даже при плохой сети (с задержкой) + Работа оффлайн - Распределенная модель тяжело заходит - Сложно заниматься GC - Дополнительный гемор в оптимизации (δ-mutation) 4 / 43
  • 42. Кто использует CRDT? Facebook TomTom League of Legends SoundCloud Bet265 RIAK Distributed Database 42 / 43