SlideShare une entreprise Scribd logo
1  sur  98
LIVING IN EVENTUALLY
CONSISTENT REALITY
INTRODUCTION
Bartosz Sypytkowski
▪ @Horusiath
▪ b.sypytkowski@gmail.com
▪ bartoszsypytkowski.com
 Eventual consistency with CRDTs
 Existing solutions
 CRDT – basics and optimizations
 Different notions of time
AGENDA
CASE STUDY
YouTube v2.0
VIDEO
STREAMING
Alice
VIDEO
STREAMING
Alice
VIDEO
STREAMING
Alice
VIDEO
STREAMING
Alice
SINGLE WRITER
REPLICATION
LET’S ADD A VIDEO VIEW COUNTER
PAGE VIEWS
MULTI-MASTER
REPLICATION
CAN WE SYNCHRONIZE DATA SAFELY WITHOUT A NEED
FOR CONSENSUS?
CONFLICT-FREE REPLICATED DATA TYPES
State
based
State
delta
based
Operation
based
Pure
operation
based
Simple
protocol
Complex
structures
Complex
protocol
Simple
structures
USE CASES
1. Sync data over the network with large
latencies
2. Sync data between periodically
disconnected devices
3. Navigation
4. Chat applications
5. Collaborative text editing
6. Mobile advertising
7. Edge computing
CRDT IN
THE WILD
Riak database operation based
AntidoteDB database operation based
Amazon DynamoDB database
Azure CosmosDB database (multi-master) custom (state based)
Redis CRDB database state based
Lasp Erlang library delta/state based
Akka.DistributedData JVM/.NET library delta/state based
Eventuate JVM library operation based
Roshi Go library state based
Automerge Javascript library operation based
STATE BASED CRDT
101
LEADER
FOLLOWER
REPLICATION
READS
Leader
Follower Follower
LEADER
FOLLOWER
REPLICATION
WRITES
Leader
Follower Follower
LEADER
FOLLOWER
REPLICATION
WRITES
Leader
Follower Follower
LEADER
FOLLOWER
REPLICATION
WRITES
Leader
Follower Follower
ROUND TRIP
TIMES
Source: https://speakerdeck.com/ept/local-first-software-returning-data-ownership-to-users
COMPAR
ING
VECTOR
CLOCKS
MASTERLESS
REPLICATION
COMPAR
ING
VECTOR
CLOCKS
MASTERLESS
REPLICATION
COMPAR
ING
VECTOR
CLOCKS
MASTERLESS
REPLICATION
WE DON’T NEED CONSENSUS, IF INDIVIDUALLY WE
ALWAYS REACH THE SAME CONCLUSION
CONVERGENCE
1. Commutative: x • y = y • x
2. Associative: (x • y) • z = x • (y • z)
3. Idempotent: x • x = x
HOW TO KEEP
THINGS IN SYNC
CASE #1
DISTRIBUTED VIEW COUNTER
G-COUNTER
GROWING ONLY
COUNTER
const GCounter = {
empty() {
return {};
},
increment(counter, id) {
counter[id] = (counter[id] || 0) + 1;
},
value(counter) {
return Object.values(counter).reduce((sum, x) => sum + x, 0);
},
merge(existing, incoming) {
Object.keys(incoming).forEach(id => {
const incomingVal = incoming[id];
const existingVal = existing[id] || 0;
existing[id] = Math.max(incomingVal, existingVal);
});
}
};
G-COUNTER
A 2
B 1
C 1
VALUE
G-COUNTER
A 2
B 1
C 1
VALUE
(2 + 1 + 1) => 4
G-COUNTER
GROWING ONLY
COUNTER
const GCounter = {
empty() {
return {};
},
increment(counter, id) {
counter[id] = (counter[id] || 0) + 1;
},
value(counter) {
return Object.values(counter).reduce((sum, x) => sum + x, 0);
},
merge(existing, incoming) {
Object.keys(incoming).forEach(id => {
const incomingVal = incoming[id];
const existingVal = existing[id] || 0;
existing[id] = Math.max(incomingVal, existingVal);
});
}
};
G-COUNTER
A 1
B 3
A 2
B 1
C 1
MAX
MERGE
G-COUNTER
A 1
B 3
A 2
B 1
C 1
A 2
B 3
C 1
MAX(1, 2)
MAX
MAX(3, 1)
MAX(0, 1)
MERGE
G-COUNTER
GROWING ONLY
COUNTER
const GCounter = {
empty() {
return {};
},
increment(counter, id) {
counter[id] = (counter[id] || 0) + 1;
},
value(counter) {
return Object.values(counter).reduce((sum, x) => sum + x, 0);
},
merge(existing, incoming) {
Object.keys(incoming).forEach(id => {
const incomingVal = incoming[id];
const existingVal = existing[id] || 0;
existing[id] = Math.max(incomingVal, existingVal);
});
}
};
CASE #2
DISTRIBUTED “LIKE” COUNTER
PN-COUNTER
POSITIVE
NEGATIVE
COUNTER
const PNCounter = {
empty() {
return { inc: GCounter.empty(), dec: GCounter.empty() };
},
increment(counter, id) {
GCounter.increment(counter.inc, id);
},
decrement(counter, id) {
GCounter.increment(counter.dec, id);
},
value(counter) {
return GCounter.value(counter.inc) - GCounter.value(counter.dec);
},
merge(existing, incoming) {
GCounter.merge(existing.inc, incoming.inc);
GCounter.merge(existing.dec, incoming.dec);
}
};
PN-COUNTER
POSITIVE
NEGATIVE
COUNTER
const PNCounter = {
empty() {
return { inc: GCounter.empty(), dec: GCounter.empty() };
},
increment(counter, id) {
GCounter.increment(counter.inc, id);
},
decrement(counter, id) {
GCounter.increment(counter.dec, id);
},
value(counter) {
return GCounter.value(counter.inc) - GCounter.value(counter.dec);
},
merge(existing, incoming) {
GCounter.merge(existing.inc, incoming.inc);
GCounter.merge(existing.dec, incoming.dec);
}
};
CASE #3
VOTING SYSTEM – SURVEY PARTICIPATION TRACKING
G-SET
GROWING ONLY
SET
const GSet = {
empty() {
return {};
},
add(set, item) {
set[item] = 1;
},
value(set) {
return Object.keys(set);
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => existing[item] = 1);
}
};
G-SET
GROWING ONLY
SET
const GSet = {
empty() {
return {};
},
add(set, item) {
set[item] = 1;
},
value(set) {
return Object.keys(set);
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => existing[item] = 1);
}
};
SET UNION
CASE #4
DISTRIBUTED SHOPPING CART
G-MAP
+
PN-COUNTER
const ORCart = {
empty() {
return {};
},
add(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.increment(counter, id);
cart[item] = counter;
},
remove(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.decrement(counter, id);
cart[item] = counter;
},
value(cart) {
return Object.keys(cart).reduce((result, item) => {
result[item] = PNCounter.value(cart[item]);
return result;
}, {});
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => {
const x = existing[item] || PNCounter.empty();
const y = incoming[item];
PNCounter.merge(x, y);
existing[item] = x;
});
}
};
G-MAP
+
PN-COUNTER
const ORCart = {
empty() {
return {};
},
add(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.increment(counter, id);
cart[item] = counter;
},
remove(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.decrement(counter, id);
cart[item] = counter;
},
value(cart) {
return Object.keys(cart).reduce((result, item) => {
result[item] = PNCounter.value(cart[item]);
return result;
}, {});
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => {
const x = existing[item] || PNCounter.empty();
const y = incoming[item];
PNCounter.merge(x, y);
existing[item] = x;
});
}
};
G-MAP
+
PN-COUNTER
const ORCart = {
empty() {
return {};
},
add(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.increment(counter, id);
cart[item] = counter;
},
remove(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.decrement(counter, id);
cart[item] = counter;
},
value(cart) {
return Object.keys(cart).reduce((result, item) => {
result[item] = PNCounter.value(cart[item]);
return result;
}, {});
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => {
const x = existing[item] || PNCounter.empty();
const y = incoming[item];
PNCounter.merge(x, y);
existing[item] = x;
});
}
};
G-MAP
+
PN-COUNTER
const ORCart = {
empty() {
return {};
},
add(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.increment(counter, id);
cart[item] = counter;
},
remove(cart, item, id) {
var counter = cart[item] || PNCounter.empty();
PNCounter.decrement(counter, id);
cart[item] = counter;
},
value(cart) {
return Object.keys(cart).reduce((result, item) => {
result[item] = PNCounter.value(cart[item]);
return result;
}, {});
},
merge(existing, incoming) {
Object.keys(incoming).forEach(item => {
const x = existing[item] || PNCounter.empty();
const y = incoming[item];
PNCounter.merge(x, y);
existing[item] = x;
});
}
};
CASE #5
TWITTER - LIST OF FOLLOWERS
G-SET
GROWING ONLY
SET
1. Can only grow
2. No (safe) semantics for removing values
CAN WE COMPOSE G-SETS INTO REMOVE-AWARE SET?
2P-SET
TWO PHASE SET
const TwoPhaseSet = {
empty() {
return { add: GSet.empty(), rem: GSet.empty() };
},
add(set, item) {
GSet.add(set.add, item);
},
remove(set, item) {
GSet.add(set.rem, item);
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
if (!set.rem[item]) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
GSet.merge(existing.add, incoming.add);
GSet.merge(existing.rem, incoming.rem);
}
};
2P-SET
TWO PHASE SET
const TwoPhaseSet = {
empty() {
return { add: GSet.empty(), rem: GSet.empty() };
},
add(set, item) {
GSet.add(set.add, item);
},
remove(set, item) {
GSet.add(set.rem, item);
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
if (!set.rem[item]) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
GSet.merge(existing.add, incoming.add);
GSet.merge(existing.rem, incoming.rem);
}
};
2P-SET
ISSUES
1. Once removed, element cannot be
reinserted.
2. Requires tombstones to be always
present.
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
timeline
VALUE
[ A, B ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
Insert
C:T3
timeline
VALUE
[ A, B ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
Insert
C:T3
A:T1
B:T2
C:T3
ADDREM
timeline
VALUE
[ A, B, C ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
Remove
C:T4
A:T1
B:T2
C:T3
ADDREM
timeline
VALUE
[ A, B, C ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
Remove
C:T4
A:T1
B:T2
C:T3
ADDREM
timeline
A:T1
B:T2
ADD
C:T4
REM
VALUE
[ A, B ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
A:T1
B:T2
C:T3
ADDREM
timeline
A:T1
B:T2
ADD
C:T4
REM
Insert
C:T5
VALUE
[ A, B ]
COMPAR
ING
VECTOR
CLOCKS
OBSERVED
REMOVE SET
A:T1
B:T2
ADDREM
A:T1
B:T2
C:T3
ADDREM
timeline
A:T1
B:T2
ADD
C:T4
REM
Insert
C:T5
A:T1
B:T2
C:T5
ADDREM
VALUE
[ A, B, C ]
LAST WRITE
WINS SET
const LWWSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item) {
set.add[item] = (new Date()).getTime();
set.rem[item] = undefined;
},
remove(set, item) {
set.add[item] = undefined;
set.rem[item] = (new Date()).getTime();
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
const addedAt = set.add[item];
const removedAt = set.rem[item] || 0;
if (addedAt >= removedAt) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
a[item] = Math.max(b[item], a[item] || 0);
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
LAST WRITE
WINS SET
const LWWSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item) {
set.add[item] = (new Date()).getTime();
set.rem[item] = undefined;
},
remove(set, item) {
set.add[item] = undefined;
set.rem[item] = (new Date()).getTime();
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
const addedAt = set.add[item];
const removedAt = set.rem[item] || 0;
if (addedAt >= removedAt) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
a[item] = Math.max(b[item], a[item] || 0);
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
LAST WRITE
WINS SET
const LWWSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item) {
set.add[item] = (new Date()).getTime();
set.rem[item] = undefined;
},
remove(set, item) {
set.add[item] = undefined;
set.rem[item] = (new Date()).getTime();
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
const addedAt = set.add[item];
const removedAt = set.rem[item] || 0;
if (addedAt >= removedAt) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
a[item] = Math.max(b[item], a[item] || 0);
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
SYSTEM
CLOCK
TIMESTAMP
1. Requires clocks to be in sync.
2. Doesn’t say anything about concurrent
updates.
VECTOR CLOCKS
TO THE RESCUE
COMPAR
ING
VECTOR
CLOCKS
PARTIAL
ORDERING
Equals
A 2
B 3
C 1
A 2
B 3
C 1
=
=
=
COMPAR
ING
VECTOR
CLOCKS
PARTIAL
ORDERING
Equals Greater than
A 2
B 3
C 1
A 2
B 3
C 1
A 2
B 3
C 2
A 2
B 3
C 1
=
=
=
=
=
>
COMPAR
ING
VECTOR
CLOCKS
PARTIAL
ORDERING
Equals Greater than
Less than
A 2
B 3
C 1
A 2
B 3
C 1
A 2
B 3
C 2
A 2
B 3
C 1
A 2
B 2
C 1
A 2
B 3
C 1
=
=
=
=
=
>
=
<
=
COMPAR
ING
VECTOR
CLOCKS
PARTIAL
ORDERING
Equals Greater than
Less than Concurrent
A 2
B 3
C 1
A 2
B 3
C 1
A 2
B 3
C 2
A 2
B 3
C 1
A 2
B 2
C 1
A 2
B 3
C 1
A 1
B 3
C 1
A 2
B 2
C 1
=
=
=
=
=
>
=
<
=
<
>
=
VECTOR
CLOCK
const VectorClock = {
merge: GCounter.merge,
increment: GCounter.increment,
compare(a, b) {
function partialCompare(result, id) {
if (result === null) return result;
const aval = a[id] || 0;
const bval = b[id] || 0;
if (aval > bval) {
if (result === -1) return null;
else return 1;
} else if (aval < bval) {
if (result === 1) return null;
else return -1;
} else return result;
}
var result = Object.keys(a).reduce(partialCompare, 0);
return Object.keys(b).reduce(partialCompare, result);
}
};
ADD-WINS
OBSERVED
REMOVE SET
const AWORSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.rem[item] = undefined;
set.add[item] = clock;
},
remove(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.add[item] = undefined;
set.rem[item] = clock;
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
var addClock = set.add[item] || {};
var remClock = set.rem[item] || {};
if (VectorClock.compare(addClock, remClock) !== -1) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
var aclock = a[item] || {};
var bclock = b[item] || {};
VectorClock.merge(aclock, bclock);
a[item] = aclock;
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
ADD-WINS
OBSERVED
REMOVE SET
const AWORSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.rem[item] = undefined;
set.add[item] = clock;
},
remove(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.add[item] = undefined;
set.rem[item] = clock;
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
var addClock = set.add[item] || {};
var remClock = set.rem[item] || {};
if (VectorClock.compare(addClock, remClock) !== -1) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
var aclock = a[item] || {};
var bclock = b[item] || {};
VectorClock.merge(aclock, bclock);
a[item] = aclock;
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
ADD-WINS
OBSERVED
REMOVE SET
const AWORSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.rem[item] = undefined;
set.add[item] = clock;
},
remove(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.add[item] = undefined;
set.rem[item] = clock;
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
var addClock = set.add[item] || {};
var remClock = set.rem[item] || {};
if (VectorClock.compare(addClock, remClock) !== -1) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
var aclock = a[item] || {};
var bclock = b[item] || {};
VectorClock.merge(aclock, bclock);
a[item] = aclock;
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
ADD-WINS
OBSERVED
REMOVE SET
const AWORSet = {
empty() {
return { add: {}, rem: {} };
},
add(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.rem[item] = undefined;
set.add[item] = clock;
},
remove(set, item, id) {
var clock = set.add[item] || set.rem[item] || {};
VectorClock.increment(clock, id);
set.add[item] = undefined;
set.rem[item] = clock;
},
value(set) {
return Object.keys(set.add).reduce((result, item) => {
var addClock = set.add[item] || {};
var remClock = set.rem[item] || {};
if (VectorClock.compare(addClock, remClock) !== -1) {
result.push(item);
}
return result;
}, []);
},
merge(existing, incoming) {
function partialMerge(a, b) {
Object.keys(b).forEach(item => {
var aclock = a[item] || {};
var bclock = b[item] || {};
VectorClock.merge(aclock, bclock);
a[item] = aclock;
});
}
partialMerge(existing.add, incoming.add);
partialMerge(existing.rem, incoming.rem);
}
};
Overhead:
Nr. of nodes * (Key size + seq. nr.)
Examples:
3 × (4 + 8) = 36 bytes
10 × (16 + 8) = 240 bytes
WALL CLOCK
TIMESTAMP
Overhead:
8 bytes
VECTOR CLOCKS
DELTAS
COMPRESSING THE PAYLOAD
COMPAR
ING
VECTOR
CLOCKS
DELTAS
A 2
B 3
C 1
State
(G-Counter)
COMPAR
ING
VECTOR
CLOCKS
DELTAS
A 2
B 3
C 1
State
(G-Counter)
INC(B)
COMPAR
ING
VECTOR
CLOCKS
DELTAS
A 2
B 3
C 1
State
(G-Counter)
INC(B)
A 2
B 4
C 1
New State
(G-Counter)
COMPAR
ING
VECTOR
CLOCKS
DELTAS
A 2
B 3
C 1
State
(G-Counter)
INC(B)
A 2
B 4
C 1
New State
(G-Counter)
B 4
Delta
(G-Counter)
DELTA
STATE CRDT
1. Propagate only change set of the state
after update.
2. Make sure that all changes have been
propagated and received.
APPENDIX #1
ENFORCING CONSISTENCY
ENFORCING
CONSISTENCY
WRITES
Alice
X1
X1
X1
X1 X1
X2
ENFORCING
CONSISTENCY
WRITES
Alice
Replicate write
to majority of
replicas
X2
X1
X1
X1 X1
ENFORCING
CONSISTENCY
WRITES
Alice
ACK
ACK
X2
X2
X1
X2 X1
ENFORCING
CONSISTENCY
WRITES
Alice
ACK
X2
X2
X1
X2 X1
ENFORCING
CONSISTENCY
READS
Bob
X2
X2
X1
X2 X1
ENFORCING
CONSISTENCY
READS
Bob
Request reads
from majority of
replicas
X2
X2
X1
X2 X1
ENFORCING
CONSISTENCY
READS
Bob
Request reads
from majority of
replicas
X2 X1
X2 X1
X1
X2
X2
ENFORCING
CONSISTENCY
READS
Bob
X2
X2
X2 X1
X2
X2
APPENDIX #2
DOTTED VERSION VECTORS
DOT
A:1REPLICA ID SEQUENCE NR.
DOTTED
VERSION
VECTORS
DOTTED
VERSION
VECTORS
REPRESENTATION
D 4
C 5
B 7
A 5
D 8
C 10
C 11
A 9
vector clock dot cloud
+
OR-SET
UNOPTIMIZED
VERSION “banana”
A
1
“apple”
A B
2 1
“carrot”
A B C
1 2 1
“pear”
A B C D
2 2 1 1
ADD
“pear”
A B C D
1 2 3 1
“strawberry”
A B C D
2 2 4 1
REM
ORSet
OR-SET
WITHOUT
TOMBSTONES
D 1
C 1
B 2
A 2
C 3
C 4
vector clock dot cloud
+
“banana”
A
1
“apple”
A
2
“carrot”
B
2
“pear”
D
1
+
active set
OR-SET
TRACKING
REMOVED VALUES
D 1
C 1
B 2
A 2
C 3
C 4
vector clock dot cloud
+
“banana”
A
1
“apple”
A
2
“carrot”
B
2
“pear”
D
1
+
active set
(C:3) DOT FROM
REMOVED OBJECT
dot context
1. JSON-like CRDTs
2. Distributed transactions
a. RAMP
b. CURE
WHAT’S NEXT?
SUMMARY
 Consistency without consensus: https://www.infoq.com/presentations/crdt-soundcloud
 CRDTs and the Quest for Distributed Consistency: https://www.youtube.com/watch?v=B5NULPSiOGw
 CRDT blog posts: https://bartoszsypytkowski.com/tag/crdt/
 CRDT examples in F#: https://github.com/Horusiath/crdt-examples/
 Azure CosmosDB custom conflict resolution: https://docs.microsoft.com/en-us/azure/cosmos-db/how-
to-manage-conflicts#create-a-custom-conflict-resolution-policy-using-a-stored-procedure
 Redis Enterprise CRDB: https://docs.redislabs.com/latest/rs/administering/database-operations/create-
crdb/
REFERENCES
THANK YOU

Contenu connexe

Similaire à Living in eventually consistent reality

Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."sjabs
 
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Dan Robinson
 
Receipt processing with Google Cloud Platform and the Google Assistant
Receipt processing with Google Cloud Platform and the Google AssistantReceipt processing with Google Cloud Platform and the Google Assistant
Receipt processing with Google Cloud Platform and the Google AssistantOrestes Carracedo
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJSKyung Yeol Kim
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Igalia
 
A head start on cloud native event driven applications - bigdatadays
A head start on cloud native event driven applications - bigdatadaysA head start on cloud native event driven applications - bigdatadays
A head start on cloud native event driven applications - bigdatadaysSriskandarajah Suhothayan
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB
 
JavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptJavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptLaurence Svekis ✔
 
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)Presto in Treasure Data (presented at db tech showcase Sapporo 2015)
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)Mitsunori Komatsu
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
 
Constance et qualité du code dans une équipe - Rémi Prévost
Constance et qualité du code dans une équipe - Rémi PrévostConstance et qualité du code dans une équipe - Rémi Prévost
Constance et qualité du code dans une équipe - Rémi PrévostWeb à Québec
 
JS Fest 2019. Anjana Vakil. Serverless Bebop
JS Fest 2019. Anjana Vakil. Serverless BebopJS Fest 2019. Anjana Vakil. Serverless Bebop
JS Fest 2019. Anjana Vakil. Serverless BebopJSFestUA
 
C Programming :- An Example
C Programming :- An Example C Programming :- An Example
C Programming :- An Example Atit Gaonkar
 
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxbbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxikirkton
 
java experiments and programs
java experiments and programsjava experiments and programs
java experiments and programsKaruppaiyaa123
 
BLoC - Be Reactive in flutter
BLoC - Be Reactive in flutterBLoC - Be Reactive in flutter
BLoC - Be Reactive in flutterGiacomo Ranieri
 
Cnam azure 2014 mobile services
Cnam azure 2014   mobile servicesCnam azure 2014   mobile services
Cnam azure 2014 mobile servicesAymeric Weinbach
 

Similaire à Living in eventually consistent reality (20)

Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
 
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
 
Receipt processing with Google Cloud Platform and the Google Assistant
Receipt processing with Google Cloud Platform and the Google AssistantReceipt processing with Google Cloud Platform and the Google Assistant
Receipt processing with Google Cloud Platform and the Google Assistant
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
Community-driven Language Design at TC39 on the JavaScript Pipeline Operator ...
 
project
projectproject
project
 
A head start on cloud native event driven applications - bigdatadays
A head start on cloud native event driven applications - bigdatadaysA head start on cloud native event driven applications - bigdatadays
A head start on cloud native event driven applications - bigdatadays
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: Keynote
 
JavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScriptJavaScript Objects and OOP Programming with JavaScript
JavaScript Objects and OOP Programming with JavaScript
 
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)Presto in Treasure Data (presented at db tech showcase Sapporo 2015)
Presto in Treasure Data (presented at db tech showcase Sapporo 2015)
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
Constance et qualité du code dans une équipe - Rémi Prévost
Constance et qualité du code dans une équipe - Rémi PrévostConstance et qualité du code dans une équipe - Rémi Prévost
Constance et qualité du code dans une équipe - Rémi Prévost
 
JS Fest 2019. Anjana Vakil. Serverless Bebop
JS Fest 2019. Anjana Vakil. Serverless BebopJS Fest 2019. Anjana Vakil. Serverless Bebop
JS Fest 2019. Anjana Vakil. Serverless Bebop
 
C Programming :- An Example
C Programming :- An Example C Programming :- An Example
C Programming :- An Example
 
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxbbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
 
java experiments and programs
java experiments and programsjava experiments and programs
java experiments and programs
 
BLoC - Be Reactive in flutter
BLoC - Be Reactive in flutterBLoC - Be Reactive in flutter
BLoC - Be Reactive in flutter
 
Cnam azure 2014 mobile services
Cnam azure 2014   mobile servicesCnam azure 2014   mobile services
Cnam azure 2014 mobile services
 

Plus de Bartosz Sypytkowski

Postgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your applicationPostgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your applicationBartosz Sypytkowski
 
How do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recoveryHow do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recoveryBartosz Sypytkowski
 
Scaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applicationsScaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applicationsBartosz Sypytkowski
 
Rich collaborative data structures for everyone
Rich collaborative data structures for everyoneRich collaborative data structures for everyone
Rich collaborative data structures for everyoneBartosz Sypytkowski
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitivesBartosz Sypytkowski
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitivesBartosz Sypytkowski
 
Virtual machines - how they work
Virtual machines - how they workVirtual machines - how they work
Virtual machines - how they workBartosz Sypytkowski
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streamsBartosz Sypytkowski
 
GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageBartosz Sypytkowski
 

Plus de Bartosz Sypytkowski (14)

Postgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your applicationPostgres indexes: how to make them work for your application
Postgres indexes: how to make them work for your application
 
How do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recoveryHow do databases perform live backups and point-in-time recovery
How do databases perform live backups and point-in-time recovery
 
Scaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applicationsScaling connections in peer-to-peer applications
Scaling connections in peer-to-peer applications
 
Rich collaborative data structures for everyone
Rich collaborative data structures for everyoneRich collaborative data structures for everyone
Rich collaborative data structures for everyone
 
Postgres indexes
Postgres indexesPostgres indexes
Postgres indexes
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
 
Collaborative eventsourcing
Collaborative eventsourcingCollaborative eventsourcing
Collaborative eventsourcing
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
 
Virtual machines - how they work
Virtual machines - how they workVirtual machines - how they work
Virtual machines - how they work
 
Short story of time
Short story of timeShort story of time
Short story of time
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streams
 
Collaborative text editing
Collaborative text editingCollaborative text editing
Collaborative text editing
 
The last mile from db to disk
The last mile from db to diskThe last mile from db to disk
The last mile from db to disk
 
GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized age
 

Dernier

Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 

Dernier (20)

Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 

Living in eventually consistent reality