3. Распределённые системы
• Много общающихся машин
• Общее состояние
• Бывает разное
• CAP теорема
• Consistency, Availability, Partitioning – выберите любые два
• CALM теорема
• Consistency as logical monotonicity – система может быть распределённой,
если она не удаляет исторические факты
4.
5. CRDT
• Тип структур данных для eventually consistent систем
• Формально доказано: состояние системы сходится
• CAP теорема: выкидываем строгую consistency
• CALM теорема: строгая гарантия eventual consistency
6. CRDT: State-based
• Множество <A, combine>
• a combine (b combine c) == (a combine b) combine c
• a combine b == b combine a
• a combine a == a
• Необходимо есть нулевой элемент
• Ограниченная полурешетка AKA коммутативный идемпотентный моноид
• Частичный порядок
7. G-Counter
• Можно только увеличивать счётчик
case class GCounter[R, E](state: Map[R, E])(implicit num: Numeric[E])
import com.machinomy.crdt.state._
import cats.syntax.all._
import cats._
val counter = Monoid[GCounter[Int, Int]].empty // empty G-Counter
val firstReplica = counter + (1 -> 1) // increment replica 1
val secondReplica = counter + (2 -> 2) // increment replica 2
val firstReplicacombined = firstReplica |+| secondReplica // combine
val secondReplicacombined = secondReplica |+| firstReplica // combine
firstReplicacombined == secondReplicacombined // the result is independent of combine order
8. PN-Counter
• Можно делать инкремент и декремент
class PNCounter[K, E: Numeric](increments: GCounter[K, E], decrements: GCounter[K, E])
import com.machinomy.crdt.state._
import cats.syntax.all._
import cats._
val counter = Monoid[PNCounter[Int, Int]].empty
val firstReplica = counter + (1 -> 1) // increment replica 1
val secondReplica = counter + (2 -> -2) // decrement replica 2
val firstReplicacombined = firstReplica |+| secondReplica // combine
val secondReplicacombined = secondReplica |+| firstReplica // combine
firstReplicacombined == secondReplicacombined // the result is independent of combine
order
9. G-Set
• Только добавление, `combine` объединяет множества
• class GSet[E](val state: Set[E])
import com.machinomy.crdt.state._
import cats.syntax.all._
import cats._
val counter = Monoid[GSet[Int]].empty // empty G-Set
val firstReplica = counter + 1 // add element
val secondReplica = counter + 2 // add element
val firstReplicacombined = firstReplica |+| secondReplica // combine
val secondReplicacombined = secondReplica |+| firstReplica // combine
firstReplicacombined == secondReplicacombined // the result is independent of
combine order
14. 2P2P-Graph
case class TPTPGraph[A, V <: VertexLike[A], E <: EdgeLike[A, V]]
(va: Set[V], vr: Set[V], ea: Set[E], er: Set[E])
• Можно добавлять и удалять элементы
• Но никаких гарантий!
16. Monotonic DAG
case class MonotonicDag[V, E[X] <: DiEdgeLikeIn[X], G <: Graph[V, E]](graph: G)
type UpdateResult[V, E[X] <: DiEdgeLikeIn[X], G <: Graph[V, E]] = (MonotonicDag[V, E, G],
Option[Update[V, E, G]])
def add(e: E[V] with OuterEdge[V, E]): MonotonicDag.UpdateResult[V, E, G] = {
val from = graphLike.fromVertex(graph, e)
val to = graphLike.toVertex(value, e)
val containsSource = graphLike.contains(value, from)
val containsDestination = graphLike.contains(value, to)
val effective = graphLike.addEdge(value, e)
if (containsSource && containsDestination && graphLike.existsPath(effective, from, to)) {
(MonotonicDag[V, E, G](effective), Some(MonotonicDag.AddEdge[V, E, G](e)))
} else {
(this, None)
}
}
17. Pro et Contra
• Простая логика
• Стабильное теоретическое
обоснование
• Лучше, чем OT
• Социальное доказательство
• Непонятно, что делать с BFT
• Необходимо обеспечить
стабильный канал
• Сложно найти подходящую
реализацию
https://github.com/machinomy/crdt
https://www.mendeley.com/groups/9275881/crdt/papers/
sergey.ukustov@machinomy.com