Conflict-free replicated data type

Last updated

In distributed computing, a conflict-free replicated data type (CRDT) is a data structure that is replicated across multiple computers in a network, with the following features: [1] [2] [3] [4] [5] [6] [7] [8]

Contents

  1. The application can update any replica independently, concurrently and without coordinating with other replicas.
  2. An algorithm (itself part of the data type) automatically resolves any inconsistencies that might occur.
  3. Although replicas may have different state at any particular point in time, they are guaranteed to eventually converge.

The CRDT concept was formally defined in 2011 by Marc Shapiro, Nuno Preguiça, Carlos Baquero and Marek Zawirski. [9] Development was initially motivated by collaborative text editing and mobile computing. CRDTs have also been used in online chat systems, online gambling, and in the SoundCloud audio distribution platform. The NoSQL distributed databases Redis, Riak and Cosmos DB have CRDT data types.

Background

Concurrent updates to multiple replicas of the same data, without coordination between the computers hosting the replicas, can result in inconsistencies between the replicas, which in the general case may not be resolvable. Restoring consistency and data integrity when there are conflicts between updates may require some or all of the updates to be entirely or partially dropped.

Accordingly, much of distributed computing focuses on the problem of how to prevent concurrent updates to replicated data. But another possible approach is optimistic replication, where all concurrent updates are allowed to go through, with inconsistencies possibly created, and the results are merged or "resolved" later. In this approach, consistency between the replicas is eventually re-established via "merges" of differing replicas. While optimistic replication might not work in the general case, there is a significant and practically useful class of data structures, CRDTs, where it does work where it is always possible to merge or resolve concurrent updates on different replicas of the data structure without conflicts. This makes CRDTs ideal for optimistic replication.

As an example, a one-way Boolean event flag is a trivial CRDT: one bit, with a value of true or false. True means some particular event has occurred at least once. False means the event has not occurred. Once set to true, the flag cannot be set back to false (an event having occurred cannot un-occur). The resolution method is "true wins": when merging a replica where the flag is true (that replica has observed the event), and another one where the flag is false (that replica hasn't observed the event), the resolved result is true the event has been observed.

Types of CRDTs

There are two approaches to CRDTs, both of which can provide strong eventual consistency: operation-based CRDTs [10] [11] and state-based CRDTs. [12] [13]

The two alternatives are theoretically equivalent, as each can emulate the other. [1] However, there are practical differences. State-based CRDTs are often simpler to design and to implement; their only requirement from the communication substrate is some kind of gossip protocol. Their drawback is that the entire state of every CRDT must be transmitted eventually to every other replica, which may be costly. In contrast, operation-based CRDTs transmit only the update operations, which are typically small. However, operation-based CRDTs require guarantees from the communication middleware; that the operations are not dropped or duplicated when transmitted to the other replicas, and that they are delivered in causal order. [1]

Operation-based CRDTs

Operation-based CRDTs are also called commutative replicated data types, or CmRDTs. CmRDT replicas propagate state by transmitting only the update operation. For example, a CmRDT of a single integer might broadcast the operations (+10) or (−20). Replicas receive the updates and apply them locally. The operations are commutative. However, they are not necessarily idempotent. The communications infrastructure must therefore ensure that all operations on a replica are delivered to the other replicas, without duplication, but in any order.

Pure operation-based CRDTs [11] are a variant of operation-based CRDTs that reduces the metadata size.

State-based CRDTs

State-based CRDTs are called convergent replicated data types, or CvRDTs. In contrast to CmRDTs, CvRDTs send their full local state to other replicas, where the states are merged by a function which must be commutative, associative, and idempotent. The merge function provides a join for any pair of replica states, so the set of all states forms a semilattice. The update function must monotonically increase the internal state, according to the same partial order rules as the semilattice.

Delta state CRDTs [13] [14] (or simply Delta CRDTs) are optimized state-based CRDTs where only recently applied changes to a state are disseminated instead of the entire state.

Comparison

While CmRDTs place more requirements on the protocol for transmitting operations between replicas, they use less bandwidth than CvRDTs when the number of transactions is small in comparison to the size of internal state. However, since the CvRDT merge function is associative, merging with the state of some replica yields all previous updates to that replica. Gossip protocols work well for propagating CvRDT state to other replicas while reducing network use and handling topology changes.

Some lower bounds [15] on the storage complexity of state-based CRDTs are known.

Known CRDTs

G-Counter (Grow-only Counter)

payloadinteger[n]Pinitial[0,0,...,0]updateincrement()letg=myId()P[g]:=P[g]+1queryvalue():integervletv=ΣiP[i]compare(X,Y):booleanbletb=(∀i[0,n-1]:X.P[i]Y.P[i])merge(X,Y):payloadZlet∀i[0,n-1]:Z.P[i]=max(X.P[i],Y.P[i])

This CvRDT implements a counter for a cluster of n nodes. Each node in the cluster is assigned an ID from 0 to n - 1, which is retrieved with a call to myId(). Thus each node is assigned its own slot in the array P, which it increments locally. Updates are propagated in the background, and merged by taking the max() of every element in P. The compare function is included to illustrate a partial order on the states. The merge function is commutative, associative, and idempotent. The update function monotonically increases the internal state according to the compare function. This is thus a correctly-defined CvRDT and will provide strong eventual consistency. The CmRDT equivalent broadcasts increment operations as they are received. [2]

PN-Counter (Positive-Negative Counter)

payloadinteger[n]P,integer[n]Ninitial[0,0,...,0],[0,0,...,0]updateincrement()letg=myId()P[g]:=P[g]+1updatedecrement()letg=myId()N[g]:=N[g]+1queryvalue():integervletv=ΣiP[i]-ΣiN[i]compare(X,Y):booleanbletb=(∀i[0,n-1]:X.P[i]Y.P[i]∀i[0,n-1]:X.N[i]Y.N[i])merge(X,Y):payloadZlet∀i[0,n-1]:Z.P[i]=max(X.P[i],Y.P[i])let∀i[0,n-1]:Z.N[i]=max(X.N[i],Y.N[i])

A common strategy in CRDT development is to combine multiple CRDTs to make a more complex CRDT. In this case, two G-Counters are combined to create a data type supporting both increment and decrement operations. The "P" G-Counter counts increments; and the "N" G-Counter counts decrements. The value of the PN-Counter is the value of the P counter minus the value of the N counter. Merge is handled by letting the merged P counter be the merge of the two P G-Counters, and similarly for N counters. Note that the CRDT's internal state must increase monotonically, even though its external state as exposed through query can return to previous values. [2]

G-Set (Grow-only Set)

payloadsetAinitialupdateadd(elemente)A:=A{e}querylookup(elemente):booleanbletb=(eA)compare(S,T):booleanbletb=(S.AT.A)merge(S,T):payloadUletU.A=S.AT.A

The G-Set (grow-only set) is a set which only allows adds. An element, once added, cannot be removed. The merger of two G-Sets is their union. [2]

2P-Set (Two-Phase Set)

payloadsetA,setRinitial,querylookup(elemente):booleanbletb=(eAeR)updateadd(elemente)A:=A{e}updateremove(elemente)prelookup(e)R:=R{e}compare(S,T):booleanbletb=(S.AT.AS.RT.R)merge(S,T):payloadUletU.A=S.AT.AletU.R=S.RT.R

Two G-Sets (grow-only sets) are combined to create the 2P-set. With the addition of a remove set (called the "tombstone" set), elements can be added and also removed. Once removed, an element cannot be re-added; that is, once an element e is in the tombstone set, query will never again return True for that element. The 2P-set uses "remove-wins" semantics, so remove(e) takes precedence over add(e). [2]

LWW-Element-Set (Last-Write-Wins-Element-Set)

LWW-Element-Set is similar to 2P-Set in that it consists of an "add set" and a "remove set", with a timestamp for each element. Elements are added to an LWW-Element-Set by inserting the element into the add set, with a timestamp. Elements are removed from the LWW-Element-Set by being added to the remove set, again with a timestamp. An element is a member of the LWW-Element-Set if it is in the add set, and either not in the remove set, or in the remove set but with an earlier timestamp than the latest timestamp in the add set. Merging two replicas of the LWW-Element-Set consists of taking the union of the add sets and the union of the remove sets. When timestamps are equal, the "bias" of the LWW-Element-Set comes into play. A LWW-Element-Set can be biased towards adds or removals. The advantage of LWW-Element-Set over 2P-Set is that, unlike 2P-Set, LWW-Element-Set allows an element to be reinserted after having been removed. [2]

OR-Set (Observed-Remove Set)

OR-Set resembles LWW-Element-Set, but using unique tags instead of timestamps. For each element in the set, a list of add-tags and a list of remove-tags are maintained. An element is inserted into the OR-Set by having a new unique tag generated and added to the add-tag list for the element. Elements are removed from the OR-Set by having all the tags in the element's add-tag list added to the element's remove-tag (tombstone) list. To merge two OR-Sets, for each element, let its add-tag list be the union of the two add-tag lists, and likewise for the two remove-tag lists. An element is a member of the set if and only if the add-tag list less the remove-tag list is nonempty. [2] An optimization that eliminates the need for maintaining a tombstone set is possible; this avoids the potentially unbounded growth of the tombstone set. The optimization is achieved by maintaining a vector of timestamps for each replica. [16]

Sequence CRDTs

A sequence, list, or ordered set CRDT can be used to build a collaborative real-time editor, as an alternative to operational transformation (OT).

Some known Sequence CRDTs are Treedoc, [5] RGA, [17] Woot, [4] Logoot, [18] and LSEQ. [19] CRATE [20] is a decentralized real-time editor built on top of LSEQSplit (an extension of LSEQ) and runnable on a network of browsers using WebRTC. LogootSplit [21] was proposed as an extension of Logoot in order to reduce the metadata for sequence CRDTs. MUTE [22] [23] is an online web-based peer-to-peer real-time collaborative editor relying on the LogootSplit algorithm.

Industrial sequence CRDTs, including open-source ones, are known to out-perform academic implementations due to optimizations and a more realistic testing methodology. [24] The main popular example is Yjs CRDT, a pioneer in using a plainlist instead of a tree (ala Kleppmann's automerge). [25]

Industry use

Related Research Articles

In information technology and computer science, especially in the fields of computer programming, operating systems, multiprocessors, and databases, concurrency control ensures that correct results for concurrent operations are generated, while getting those results as quickly as possible.

In computer science, a consistency model specifies a contract between the programmer and a system, wherein the system guarantees that if the programmer follows the rules for operations on memory, memory will be consistent and the results of reading, writing, or updating memory will be predictable. Consistency models are used in distributed systems like distributed shared memory systems or distributed data stores. Consistency is different from coherence, which occurs in systems that are cached or cache-less, and is consistency of data with respect to all processors. Coherence deals with maintaining a global order in which writes to a single location or single variable are seen by all processors. Consistency deals with the ordering of operations to multiple locations with respect to all processors.

Eventual consistency is a consistency model used in distributed computing to achieve high availability that informally guarantees that, if no new updates are made to a given data item, eventually all accesses to that item will return the last updated value. Eventual consistency, also called optimistic replication, is widely deployed in distributed systems and has origins in early mobile computing projects. A system that has achieved eventual consistency is often said to have converged, or achieved replica convergence. Eventual consistency is a weak guarantee – most stronger models, like linearizability, are trivially eventually consistent.

Multi-master replication is a method of database replication which allows data to be stored by a group of computers, and updated by any member of the group. All members are responsive to client data queries. The multi-master replication system is responsible for propagating the data modifications made by each member to the rest of the group and resolving any conflicts that might arise between concurrent changes made by different members.

Replication in computing involves sharing information so as to ensure consistency between redundant resources, such as software or hardware components, to improve reliability, fault-tolerance, or accessibility.

Causal consistency is one of the major memory consistency models. In concurrent programming, where concurrent processes are accessing a shared memory, a consistency model restricts which accesses are legal. This is useful for defining correct data structures in distributed shared memory or distributed transactions.

Operational transformation (OT) is a technology for supporting a range of collaboration functionalities in advanced collaborative software systems. OT was originally invented for consistency maintenance and concurrency control in collaborative editing of plain text documents. Its capabilities have been extended and its applications expanded to include group undo, locking, conflict resolution, operation notification and compression, group-awareness, HTML/XML and tree-structured document editing, collaborative office productivity tools, application-sharing, and collaborative computer-aided media design tools. In 2009 OT was adopted as a core technique behind the collaboration features in Apache Wave and Google Docs.

In concurrency control of databases, transaction processing, and other transactional distributed applications, global serializability is a property of a global schedule of transactions. A global schedule is the unified schedule of all the individual database schedules in a multidatabase environment. Complying with global serializability means that the global schedule is serializable, has the serializability property, while each component database (module) has a serializable schedule as well. In other words, a collection of serializable components provides overall system serializability, which is usually incorrect. A need in correctness across databases in multidatabase systems makes global serializability a major goal for global concurrency control. With the proliferation of the Internet, Cloud computing, Grid computing, and small, portable, powerful computing devices, as well as increase in systems management sophistication, the need for atomic distributed transactions and thus effective global serializability techniques, to ensure correctness in and among distributed transactional applications, seems to increase.

Microsoft Sync Framework is a data synchronization platform from Microsoft that can be used to synchronize data across multiple data stores. Sync Framework includes a transport-agnostic architecture, into which data store-specific synchronization providers, modelled on the ADO.NET data provider API, can be plugged in. Sync Framework can be used for offline access to data, by working against a cached set of data and submitting the changes to a master database in a batch, as well as to synchronize changes to a data source across all consumers and peer-to-peer synchronization of multiple data sources. Sync Framework features built-in capabilities for conflict detection – whether data to be changed has already been updated – and can flag them for manual inspection or use defined policies to try to resolve the conflict. Sync Services includes an embedded SQL Server Compact database to store metadata about the synchronization relationships as well as about each sync attempt. The Sync Framework API is surfaced both in managed code, for use with .NET Framework applications, as well as unmanaged code, for use with COM applications. It was scheduled to ship with Visual Studio 2008 in late November 2007.

Optimistic replication, also known as lazy replication, is a strategy for replication, in which replicas are allowed to diverge.

<span class="mw-page-title-main">Apache CouchDB</span> Document-oriented NoSQL database

Apache CouchDB is an open-source document-oriented NoSQL database, implemented in Erlang.

<span class="mw-page-title-main">Collaborative virtual environment</span> Applications of distributed computing

Collaborative virtual environments are used for collaboration and interaction of possibly many participants that may be spread over large distances. Typical examples are distributed simulations, 3D multiplayer games, collaborative engineering software, collaborative learning applications, and others. The applications are usually based on the shared virtual environment. Because of the spreading of participants and the communication latency, some data consistency model have to be used to keep the data consistent.

<span class="mw-page-title-main">Apache Cassandra</span> Free and open-source database management system

Cassandra is a free and open-source, distributed, wide-column store, NoSQL database management system designed to handle large amounts of data across many commodity servers, providing high availability with no single point of failure. Cassandra offers support for clusters spanning multiple data centers, with asynchronous masterless replication allowing low latency operations for all clients. Cassandra was designed to implement a combination of Amazon's Dynamo distributed storage and replication techniques combined with Google's Bigtable data and storage engine model.

A version vector is a mechanism for tracking changes to data in a distributed system, where multiple agents might update the data at different times. The version vector allows the participants to determine if one update preceded another (happened-before), followed it, or if the two updates happened concurrently. In this way, version vectors enable causality tracking among data replicas and are a basic mechanism for optimistic replication. In mathematical terms, the version vector generates a preorder that tracks the events that precede, and may therefore influence, later updates.

Riak is a distributed NoSQL key-value data store that offers high availability, fault tolerance, operational simplicity, and scalability. Riak moved to an entirely open-source project in August 2017, with many of the licensed Enterprise Edition features being incorporated. Riak implements the principles from Amazon's Dynamo paper with heavy influence from the CAP theorem. Written in Erlang, Riak has fault-tolerant data replication and automatic data distribution across the cluster for performance and resilience.

<span class="mw-page-title-main">Column (data store)</span> NoSQL object of the lowest level in a keyspace

A column of a distributed data store is a NoSQL object of the lowest level in a keyspace. It is a tuple consisting of three elements:

<span class="mw-page-title-main">Basho Technologies</span>

Basho Technologies was a distributed systems' company that developed a key-value NoSQL database technology, Riak, and an object storage system built upon the Riak platform, called Riak CS.

Elliptics is a distributed key–value data storage with open source code. By default it is a classic distributed hash table (DHT) with multiple replicas put in different groups. Elliptics was created to meet requirements of multi-datacenter and physically distributed storage locations when storing huge amount of medium and large files.

Azure Cosmos DB is a globally distributed, multi-model database service offered by Microsoft. It is designed to provide high availability, scalability, and low-latency access to data for modern applications. Unlike traditional relational databases, Cosmos DB is a NoSQL and vector database, which means it can handle unstructured, semi-structured, structured, and vector data types.

<span class="mw-page-title-main">PACELC theorem</span> Theorem in theoretical computer science

In theoretical computer science, the PACELC theorem is an extension to the CAP theorem. It states that in case of network partitioning (P) in a distributed computer system, one has to choose between availability (A) and consistency (C), but else (E), even when the system is running normally in the absence of partitions, one has to choose between latency (L) and loss of consistency (C).

References

  1. 1 2 3 Shapiro, Marc; Preguiça, Nuno; Baquero, Carlos; Zawirski, Marek (2011). "Conflict-Free Replicated Data Types". Stabilization, Safety, and Security of Distributed Systems (PDF). Lecture Notes in Computer Science. Vol. 6976. Grenoble, France: Springer Berlin Heidelberg. pp. 386–400. doi:10.1007/978-3-642-24550-3_29. ISBN   978-3-642-24549-7. S2CID   51995307.
  2. 1 2 3 4 5 6 7 Shapiro, Marc; Preguiça, Nuno; Baquero, Carlos; Zawirski, Marek (13 January 2011). "A Comprehensive Study of Convergent and Commutative Replicated Data Types". Rr-7506.
  3. Shapiro, Marc; Preguiça, Nuno (2007). "Designing a Commutative Replicated Data Type". arXiv: 0710.1784 [cs.DC].
  4. 1 2 Oster, Gérald; Urso, Pascal; Molli, Pascal; Imine, Abdessamad (2006). Proceedings of the 2006 20th anniversary conference on Computer supported cooperative work - CSCW '06. p. 259. CiteSeerX   10.1.1.554.3168 . doi:10.1145/1180875.1180916. ISBN   978-1595932495. S2CID   14596943.
  5. 1 2 Letia, Mihai; Preguiça, Nuno; Shapiro, Marc (2009). "CRDTs: Consistency without Concurrency Control". Computing Research Repository. arXiv: 0907.0929 .
  6. Preguiça, Nuno; Marques, Joan Manuel; Shapiro, Marc; Letia, Mihai (June 2009), "A Commutative Replicated Data Type for Cooperative Editing" (PDF), Proc 29th IEEE International Conference on Distributed Computing Systems, Montreal, Quebec, Canada: IEEE Computer Society, pp. 395–403, doi:10.1109/ICDCS.2009.20, ISBN   978-0-7695-3659-0, S2CID   8956372
  7. Baquero, Carlos; Moura, Francisco (1997), Specification of Convergent Abstract Data Types for Autonomous Mobile Computing, Universidade do Minho
  8. Schneider, Fred (December 1990). "Implementing Fault-Tolerant Services Using the State Machine Approach: A Tutorial". ACM Computing Surveys. 22 (4): 299–319. doi: 10.1145/98163.98167 . S2CID   678818.
  9. "Conflict-free Replicated Data Types" (PDF). inria.fr. July 19, 2011.
  10. Letia, Mihai; Preguiça, Nuno; Shapiro, Marc (1 April 2010). "Consistency without Concurrency Control in Large, Dynamic Systems" (PDF). SIGOPS Oper. Syst. Rev. 44 (2): 29–34. doi:10.1145/1773912.1773921. S2CID   6255174.
  11. 1 2 Baquero, Carlos; Almeida, Paulo Sérgio; Shoker, Ali (2014-06-03). "Making Operation-Based CRDTS Operation-Based". In Magoutis, Kostas; Pietzuch, Peter (eds.). Distributed Applications and Interoperable Systems. Lecture Notes in Computer Science. Vol. 8460. Springer Berlin Heidelberg. pp. 126–140. CiteSeerX   10.1.1.492.8742 . doi:10.1007/978-3-662-43352-2_11. ISBN   9783662433515.
  12. Baquero, Carlos; Moura, Francisco (1 October 1999). "Using Structural Characteristics for Autonomous Operation". SIGOPS Oper. Syst. Rev. 33 (4): 90–96. doi:10.1145/334598.334614. hdl: 1822/34984 . S2CID   13882850.
  13. 1 2 Almeida, Paulo Sérgio; Shoker, Ali; Baquero, Carlos (2015-05-13). "Efficient State-Based CRDTS by Delta-Mutation". In Bouajjani, Ahmed; Fauconnier, Hugues (eds.). Networked Systems. Lecture Notes in Computer Science. Vol. 9466. Springer International Publishing. pp. 62–76. arXiv: 1410.2803 . doi:10.1007/978-3-319-26850-7_5. ISBN   9783319268491. S2CID   7852769.
  14. Almeida, Paulo Sérgio; Shoker, Ali; Baquero, Carlos (2016-03-04). "Delta State Replicated Data Types". Journal of Parallel and Distributed Computing. 111: 162–173. arXiv: 1603.01529 . doi:10.1016/j.jpdc.2017.08.003. S2CID   7990602.
  15. Burckhardt, Sebastian; Gotsman, Alexey; Yang, Hongseok; Zawirski, Marek (23 January 2014). "Replicated Data Types: Specification, Verification, Optimality". Proceedings of the 41st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (PDF). pp. 271–284. doi:10.1145/2535838.2535848. ISBN   9781450325448. S2CID   15023909.
  16. Bieniusa, Annette; Zawirski, Marek; Preguiça, Nuno; Shapiro, Marc; Baquero, Carlos; Balegas, Valter; Duarte, Sérgio (2012). "An optimized conflict-free replicated set". arXiv: 1210.3368 [cs.DC].
  17. Roh, Huyn-Gul; Jeon, Myeongjae; Kim, Jin-Soo; Lee, Joonwon (2011). "Replicated Abstract Data Types: Building Blocks for Collaborative Applications". Journal of Parallel and Distributed Computing. 71 (2): 354–368. doi:10.1016/j.jpdc.2010.12.006.
  18. Weiss, Stephane; Urso, Pascal; Molli, Pascal (2010). "Logoot-Undo: Distributed Collaborative Editing System on P2P Networks". IEEE Transactions on Parallel and Distributed Systems. 21 (8): 1162–1174. doi:10.1109/TPDS.2009.173. ISSN   1045-9219. S2CID   14172605.
  19. Nédelec, Brice; Molli, Pascal; Mostefaoui, Achour; Desmontils, Emmanuel (2013). "LSEQ: An adaptive structure for sequences in distributed collaborative editing". Proceedings of the 2013 ACM symposium on Document engineering (PDF). pp. 37–46. doi:10.1145/2494266.2494278. ISBN   9781450317894. S2CID   9215663.
  20. Nédelec, Brice; Molli, Pascal; Mostefaoui, Achour (2016). "CRATE: Writing Stories Together with our Browsers". Proceedings of the 25th International Conference Companion on World Wide Web. p. 231. doi:10.1145/2872518.2890539. S2CID   5096789. Archived from the original on 2020-01-01. Retrieved 2020-01-01.
  21. André, Luc; Martin, Stéphane; Oster, Gérald; Ignat, Claudia-Lavinia (2013). "Supporting Adaptable Granularity of Changes for Massive-scale Collaborative Editing". Proceedings of the International Conference on Collaborative Computing: Networking, Applications and Worksharing – CollaborateCom 2013. pp. 50–59. doi: 10.4108/icst.collaboratecom.2013.254123 . ISBN   978-1-936968-92-3.
  22. "MUTE". Coast Team. March 24, 2016.
  23. Nicolas, Matthieu; Elvinger, Victorien; Oster, Gérald; Ignat, Claudia-Lavinia; Charoy, François (2017). "MUTE: A Peer-to-Peer Web-based Real-time Collaborative Editor". Proceedings of ECSCW Panels, Demos and Posters 2017. doi:10.18420/ecscw2017_p5. S2CID   43984228.
  24. Gentle, Seph. "Faster CRDTs: An Adventure in Optimization". josephg.com. Retrieved 1 August 2021.
  25. "yjs/yjs: Shared data types for building collaborative software". GitHub.
  26. "About CRDTs" . Retrieved 2020-06-18.
  27. Bourgon, Peter (9 May 2014). "Roshi: a CRDT system for timestamped events". SoundCloud.
  28. "Introducing Riak 2.0: Data Types, Strong Consistency, Full-Text Search, and Much More". Basho Technologies, Inc. 29 October 2013.
  29. Hoff, Todd (13 October 2014). "How League of Legends Scaled Chat to 70 Million Players - It Takes Lots of Minions". High Scalability.
  30. Macklin, Dan. "bet365: Why bet365 chose Riak". Basho.
  31. Ivanov, Dmitry. "Practical Demystification of CRDTs".
  32. McCord, Chris (25 March 2016). "What makes Phoenix Presence Special".
  33. Mak, Sander. "Facebook Announces Apollo at QCon NY 2014".
  34. "FlightTracker: Consistency across Read-Optimized Online Stores at Facebook". research.facebook.com. Retrieved 8 December 2022.
  35. "Code together in real time with Teletype for Atom". Atom.io. November 15, 2017.
  36. "OrbitDB/ipfs-log on Github". GitHub . Retrieved 2018-09-07.
  37. "IOS Objective-C headers as derived from runtime introspection: NST/IOS-Runtime-Headers". GitHub . 2019-07-25.