{"id":56365,"date":"2020-02-11T00:00:00","date_gmt":"2020-02-10T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike"},"modified":"2020-02-18T14:04:37","modified_gmt":"2020-02-18T11:04:37","slug":"highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","title":{"rendered":"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>The next HighLoad++ conference will take place on April 6 and 7, 2020 in Saint Petersburg. <br \/>\nDetails and tickets <noindex><a rel=\"nofollow\" href=\"http:\/\/bit.ly\/2sSxgBx\">at the link<\/a><\/noindex>. HighLoad++ Siberia 2019. Hall \"Krasnoyarsk\". June 25, 12:00. Theses and <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/siberia\/2019\/abstracts\/5253\">presentation<\/a><\/noindex>.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/cded9c5434d670db7295aadf5da0a9f1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSometimes, practical requirements conflict with theory, where important aspects for a commercial product are not accounted for. This presentation outlines the process of selecting and combining various approaches to creating components of Causal consistency based on academic research while considering the requirements of a commercial product. Listeners will learn about existing theoretical approaches to logical clocks, dependency tracking, system security, clock synchronization, and why MongoDB opted for certain solutions.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><b>Mikhail Tyulenev (hereafter \u2013 MT):<\/b> \u2013 I will talk about Causal consistency \u2013 a feature we worked on at MongoDB. I work in the distributed systems group, and we developed it about two years ago.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/b8d0a5b64e715f53b033fa8c398e2eb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn the process, I had to delve into a considerable amount of academic research because this feature is quite well-studied. It turned out that no single paper fits what is required in production, a database due to the very specific demands that exist in almost any production application.<\/p>\n<p>I will discuss how we, as consumers of academic research, prepare something that we can then present to our users as a finished product that is convenient and safe to use.<\/p>\n<h3>Causal consistency. Let's clarify the concepts.<\/h3>\n<p>\nFirst, I want to briefly explain what Causal consistency is. There are two characters \u2013 Leonard and Penny (from the series \"The Big Bang Theory\"):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/ee0835b604ae5d5d6c0fa1bc369e6b18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSuppose Penny is in Europe, and Leonard wants to surprise her with some kind of gathering. And he thinks of no better idea than to remove her from the friend list, send all his friends an update on the feed: \"Let's surprise Penny!\" (she's in Europe, asleep, cannot see any of this, and cannot notice because she is not there). Eventually, he deletes this post, erases it from the feed, and restores access so that she doesn't notice anything and there is no scandal.<br \/>\nThis is all wonderful, but let's assume that the system is distributed, and things went a bit differently. For instance, it might happen that the access restriction on Penny occurred after this post appeared, if the events are not causally linked. Essentially, this is an example of when causal consistency is needed to perform a business function (in this case).<\/p>\n<p>In fact, these are quite non-trivial properties of databases\u2014very few actually support them. Let's move on to the models.<\/p>\n<h3>Consistency Models<\/h3>\n<p>\nWhat is a consistency model in databases anyway? It refers to certain guarantees that a distributed system gives regarding which data and in what sequence the client can receive.<\/p>\n<p>Essentially, all consistency models boil down to how much a distributed system resembles one that operates, for example, on a single node on a laptop. The question is how similar a system operating across thousands of geographically distributed nodes is to a laptop where all these properties are essentially fulfilled automatically.<\/p>\n<p>Therefore, consistency models only apply to distributed systems. All systems that existed before and operated on vertical scaling did not experience such problems. There was a single Buffer Cache, and everything was always read from it.<\/p>\n<h3>Strong Model<\/h3>\n<p>\nEssentially, the very first model is the Strong model (or rise ability, as it is often called). This is a consistency model that guarantees that every change, as soon as confirmation of its occurrence is received, becomes visible to all users of the system.<\/p>\n<p>This creates a global order of all events in the database. This is a very strong consistency property, and it is generally very costly. Nevertheless, it is very well supported. It\u2019s just very expensive and slow\u2014hence it is rarely used. This is called rise ability.<\/p>\n<p>There is another, even stronger property supported in Spanner, known as External Consistency. We will discuss it a bit later.<\/p>\n<h3>Causal<\/h3>\n<p>\nThe following is Causal, exactly what I was talking about. There are several sublevels between Strong and Causal that I won\u2019t discuss, but they all come down to Causal. This is an important model because it is the strongest of all models, providing the most robust consistency in the presence of a network or partitions.<\/p>\n<p>Causals refer to situations where events are connected by a cause-and-effect relationship. They are often perceived as Read your on rights from the client's perspective. If a client has observed certain values, they cannot see values from the past. They start to notice prefix reads. It all comes down to the same thing.<br \/>\nCausals as a consistency model involve a partial ordering of events on the server, where events from all clients are observed in the same sequence. In this case, it involves Leonard and Penny.<\/p>\n<h3>Eventual<\/h3>\n<p>\nThe third model is Eventual Consistency. This is what absolutely all distributed systems support; it is the minimal model that makes any sense. It means that when we make some changes to the data, they eventually become consistent.<\/p>\n<p>At that moment, it doesn\u2019t say anything; otherwise, it would turn into External Consistency\u2014 that would be a completely different story. Nevertheless, this is a very popular model, the most widespread. By default, all users of distributed systems use Eventual Consistency.<\/p>\n<p>I want to provide some comparative examples:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/c23e59b30d96de6ec456aaa76c67ad61.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWhat do these arrows mean?<\/p>\n<ul>\n<li><b>Latency.<\/b> As the strength of consistency increases, it becomes greater for obvious reasons: more writes must be made, and confirmation is needed from all hosts and nodes participating in the cluster that the data is already there. Accordingly, in Eventual Consistency, the response is the fastest because, as a rule, you can even commit in memory, and that would generally suffice.<\/li>\n<li><b>Availability.<\/b> If we understand this as the system's ability to respond in the presence of network outages, partitions, or failures\u2014fault tolerance increases as the consistency model decreases, as it is sufficient for one host to be alive and provide some data. Eventual Consistency does not guarantee anything about the data\u2014it could be anything.<\/li>\n<li><b>Anomalies.<\/b> At the same time, of course, the number of anomalies increases. In Strong Consistency, they should almost not exist, while Eventual Consistency can have any number of them. The question arises: why do people choose Eventual Consistency if it contains anomalies? The answer lies in the fact that Eventual Consistency models are applicable, and anomalies exist, for example, over a short period; there is the possibility to use a master for reading and somewhat read consistent data; often there is a chance to utilize strong consistency models. Practically, this works, and often the number of anomalies is time-limited.<\/li>\n<\/ul>\n<p><\/p>\n<h3>CAP Theorem<\/h3>\n<p>\nWhen you see the words consistency and availability, what comes to mind? Right \u2013 the CAP theorem! I want to dispel a myth\u2026 It\u2019s not me \u2013 it\u2019s Martin Kleppmann, who wrote a great article, a wonderful book.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/02a9b84585218c4e85afd65f7e88aa26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe CAP theorem is a principle formulated in the 2000s, stating that Consistency, Availability, and Partition Tolerance: take any two, and you cannot choose all three. This was a certain principle. It was proven as a theorem a few years later by Gilbert and Lynch. Then it began to be used as a mantra \u2013 systems started to be classified into CA, CP, AP, and so on.<\/p>\n<p>This theorem was actually proven for the following cases\u2026 First, Availability was not considered as a continuous value from zero to one hundred (0 \u2013 the system is 'dead', 100 \u2013 it responds quickly; we are used to viewing it this way), but as a property of the algorithm that guarantees that in all its executions it returns data.<\/p>\n<p>There is not a word about response time! There is an algorithm that returns data after 100 years \u2013 a perfectly available algorithm, which is part of the CAP theorem.<br \/>\nSecond: the theorem was proven for changes in the values of the same key, while these changes are a resizable line. This means that in reality they are hardly used because there are other models like Eventual Consistency and Strong Consistency (possibly).<\/p>\n<p>What\u2019s the point of all this? That the CAP theorem, in the form it was proven, is practically inapplicable and rarely used. In its theoretical form, it somehow limits everything. It turns out to be a principle that is intuitively correct but not really proven.<\/p>\n<h3>Causal consistency is the strongest model.<\/h3>\n<p>\nWhat is happening now allows us to achieve all three things: Consistency, Availability through Partitions. In particular, Causal consistency is the strongest consistency model that still works in the presence of Partitions (network disruptions). That's why it represents such a significant interest and why we've engaged with it.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/c4320294320261858a6d22faa97b9e23.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nFirstly, it simplifies the work of application developers. In particular, there is considerable backing from the server: when all records occurring within a single client are guaranteed to come in such an order to another client. Secondly, it withstands partitions.<\/p>\n<h3>The inner workings of MongoDB<\/h3>\n<p>\nRemembering that it\u2019s lunchtime, we move into the kitchen. I\u2019ll explain the system model, specifically what MongoDB is for those hearing about such a database for the first time.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/a1784442ff1c44403b5347f4f43a1197.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/a1f9bcb4daebb43e4fc848a5f5f07c60.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMongoDB (hereinafter referred to as 'MongoDB') is a distributed system that supports horizontal scaling, meaning sharding; and within each shard, it also supports data redundancy, that is, replication.<\/p>\n<p>Sharding in MongoDB (a non-relational DB) performs automatic balancing, which means each document collection (or 'table' in relational database terms) is divided into chunks, and the server automatically moves them between shards.<\/p>\n<p>The Query Router, which distributes requests, acts as a client for the user, through which they operate. It already knows where and what data resides and directs all requests to the correct shard.<\/p>\n<p>Another important point: MongoDB is single master. There is one Primary \u2013 it can take entries that support the keys it contains. Multi-master writes are not possible.<\/p>\n<p>We released version 4.2 \u2013 new interesting features were added. In particular, Lucene has been integrated \u2013 search \u2013 specifically executable Java directly in Mongo, and it has become possible to perform searches through Lucene, just like in Elastic.<\/p>\n<p>And we created a new product \u2013 Charts, which is also available on Atlas (Mongo\u2019s own Cloud). They have a Free Tier \u2013 you can play around with it. I really liked Charts \u2013 data visualization, very intuitive.<\/p>\n<h3>Ingredients of Causal consistency<\/h3>\n<p>\nI counted about 230 articles that have been published on this topic \u2013 by Leslie Lamport. I will now share with you some parts of these materials from memory.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/e88b34b7a724e94837b944a4ddd21a04.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIt all started with an article by Leslie Lampert, written in the 1970s. As you can see, research in this area is still ongoing. Currently, Causal consistency is gaining interest due to the development of distributed systems.<\/p>\n<h3>Restrictions<\/h3>\n<p>\nWhat limitations exist? This is actually one of the main points, as the constraints imposed by production systems differ significantly from those found in academic articles. Often, they are quite artificial.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/9583ba9ff870e4ddc7aad4ba4c59ecc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>First of all, MongoDB is a single master, as I mentioned (this simplifies things a lot).<\/li>\n<li>We believe that the system should support around 10,000 shards. We cannot make architectural decisions that would clearly limit this number.<\/li>\n<li>We have a cloud, but we assume that users should still have the option to download binaries, run them on their laptops, and everything should work perfectly.<\/li>\n<li>We assume that in research, external clients can do whatever they want: MongoDB is open source. Accordingly, clients can be smart and malicious\u2014they may want to break everything. We assume that Byzantine failures can occur.<\/li>\n<li>For external clients outside the perimeter, an important limitation is that if this feature is turned off, no performance degradation should be observed.<\/li>\n<li>Another point is quite anti-academic: compatibility of previous and future versions. Old drivers should support new updates, and the database should support old drivers.<\/li>\n<\/ul>\n<p>\nIn general, all this imposes limitations.<\/p>\n<h3>Components of Causal consistency<\/h3>\n<p>\nI will now talk about some components. If we consider Causal consistency in general, we can highlight blocks. We selected from works related to various blocks: Dependency Tracking, clock selection, how these clocks can be synchronized, and how we ensure safety\u2014this is an approximate plan of what I will discuss:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/10c2631d6e61a280139b448628db763e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Full Dependency Tracking<\/h3>\n<p>\nWhy is it needed? To ensure that when data is replicated, each record and each data change contains information about what changes it depends on. The very first and naive change is when each message containing a record also includes information about the previous messages:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/fa5d0086c3c77e33631d8a2cd5c217fa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn this example, the numbers in curly braces are record numbers. Sometimes these records are transmitted entirely with their values, and sometimes only certain versions are shared. The essence is that every change carries information about the previous change (it explicitly contains all this information).<\/p>\n<p>Why did we decide not to use this approach (full tracking)? Obviously, because this approach is impractical: any change in a social network depends on all previous changes in that social network, conveying, say, 'Facebook' or 'VK' in each update. Nevertheless, there is a lot of research on Full Dependency Tracking \u2013 it predates social networks and works in certain situations.<\/p>\n<h3>Explicit Dependency Tracking<\/h3>\n<p>\nThe next one is more limited. Here, the transmission of information is also considered, but only that which is explicitly dependent. Usually, the application determines what depends on what. When data is replicated, responses are only given when previous dependencies have been satisfied, that is, shown. This is the essence of how Causal consistency works.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/7fe101b998c1a0c922788d8d36a5243f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIt sees that record 5 depends on records 1, 2, 3, and 4 \u2013 accordingly, it waits before the client can access the changes made by Penny's access decree, when all previous changes have already been processed in the database.<\/p>\n<p>This also does not suit us because there is still too much information, and it will slow things down. There is another approach\u2026<\/p>\n<h3>Lamport Clock<\/h3>\n<p>\nThey are very old. Lamport Clock implies that these dependencies are folded into a scalar function, which is called the Lamport Clock.<\/p>\n<p>A scalar function is an abstract number. It is often referred to as logical time. With each event, this counter increases. The counter known to the process at that moment sends each message. It is clear that processes can be desynchronized, having completely different times. Nevertheless, through this message exchange, the system somehow balances the clocks. What happens in this case?<\/p>\n<p>I split that large shard in two to clarify: Friends may reside in one node that contains a piece of the collection, while Feed exists in another node that holds a different piece of that collection. How can they avoid being queued? First, Feed will say, \"Replicated,\" and then \u2013 Friends. If the system does not provide any guarantees that Feed will not be displayed until the dependencies of Friends in the Friends collection are also delivered, we will encounter the situation I mentioned.<\/p>\n<p>You can see how the logical time on the Feed counter increases:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/bae152d1890b53804f2cb28122983df6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThus, the main property of this Lamport Clock and Causal consistency (explained through Lamport Clock) is as follows: if we have events A and B, and event B depends on event A, then it follows that the LogicalTime of Event A is less than the LogicalTime of Event B.<\/p>\n<p><i>* Sometimes it is also said that A happened before B, meaning A occurred before B \u2013 this is a relationship that partially orders the whole set of events that have occurred.<\/i><\/p>\n<p>The reverse is not true. This is actually one of the main drawbacks of the Lamport Clock \u2013 partial ordering. There is a concept of simultaneous events, meaning events where neither (A happened before B) nor (B happened before A). An example could be the parallel addition of someone as a friend by Leonard (not even by Leonard, but by Sheldon, for instance).<br \/>\nThis is the property that is often used when working with Lamport clocks: they look specifically at the function and draw conclusions from that \u2013 perhaps these events are dependent. Because in one direction, it is true: if LogicalTime A is less than LogicalTime B, then B cannot have happened before A; and if it is greater, then it possibly can.<\/p>\n<h3>Vector clocks<\/h3>\n<p>\nThe logical advancement of Lamport clocks is Vector clocks. They differ in that each node here contains its own individual clocks, which are transmitted as a vector.<br \/>\nIn this case, you see that the zero index of the vector corresponds to the Feed, and the first index of the vector corresponds to Friends (each of these nodes). And now they will be increasing: the zero index of the Feed increases to \u2013 1, 2, 3:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/d89292686ed8dd41aef06090f16db1c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWhat makes Vector clocks better? They help to understand which events are simultaneous and when they occur on different nodes. This is very important for sharding systems like MongoDB. However, we did not choose this, although it is a great tool, works wonderfully, and would probably suit us...<\/p>\n<p>If we have 10,000 shards, we cannot transmit 10,000 components, even if we compress or invent something else \u2013 the payload will still be several times smaller than the total volume of this vector. Therefore, grudgingly, we gave up this approach and switched to another.<\/p>\n<h3>Spanner TrueTime. Atomic clocks.<\/h3>\n<p>\nI mentioned that there would be a talk about Spanner. It's a cool tool, straight from the 21st century: atomic clocks, GPS synchronization.<\/p>\n<p>What\u2019s the idea? Spanner is Google's system, which has recently even become available to people (they added SQL to it). Each transaction has a certain timestamp. Since the time is synchronized*, each event can be assigned a specific time \u2013 atomic clocks have a waiting time after which another time is guaranteed to 'occur'.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/707b5998fbb500d201aafffccc666f0e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThus, by simply recording in the database and waiting for some period of time, event Serializability is automatically guaranteed. They have the strongest Consistency model you can imagine \u2013 it is External Consistency.<\/p>\n<p>* This is the main problem with Lamport clocks \u2013 they are never synchronized in distributed systems. They can drift apart, and even with NTP, they still do not work very well. Spanner has atomic clocks and synchronization, apparently to the microsecond.<\/p>\n<p>Why didn\u2019t we choose this? We do not assume that our users have built-in atomic clocks. When they do become built-in in every laptop, there will be some super-cool GPS synchronization \u2013 then yes\u2026 But for now, the best available is Amazon, Base Stations \u2013 for enthusiasts\u2026 So we used other clocks.<\/p>\n<h3>Hybrid clocks.<\/h3>\n<p>\nThis is essentially what ticks in MongoDB when ensuring Causal consistency. What are they hybrid about? Hybrid is a scalar value, but it consists of two components:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/dab03a87d9f6ee2e716f75baff1736bc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>The first is the Unix epoch (the number of seconds that have passed since the 'beginning of the computer world').<\/li>\n<li>The second is an increment, also a 32-bit unsigned int.<\/li>\n<\/ul>\n<p>\nThat's essentially it. There is an approach where the part responsible for time is constantly synchronized with the clock; every time an update occurs, this part synchronizes with the clock, so the time is always more or less correct, and the increment allows distinguishing between events that occurred at the same moment in time.<\/p>\n<p>Why is this important for MongoDB? Because it allows for certain backup restores to a specific point in time, meaning the event is indexed by time. This is important when certain events are needed; for a database, events are changes in the database that occurred at specific intervals of time.<\/p>\n<p>The main reason I'll only tell you (please, don\u2019t share this with anyone)! We did this because that's how ordered, indexed data looks in MongoDB's OpLog. OpLog is a data structure that contains all changes in the database: they first go into the OpLog, and then are applied to Storage when it's a replicated data or shard.<\/p>\n<p>That was the main reason. However, there are also practical requirements for database development, which means it should be simple \u2013 minimal code, as few broken things as possible that need to be rewritten and tested. The fact that our oplogs turned out to be indexed by hybrid clocks greatly helped and allowed for the right choice. It really paid off and somehow worked like magic right on the first prototype. It was very cool!<\/p>\n<h3>Clock synchronization<\/h3>\n<p>\nThere are several methods of synchronization described in the scientific literature. I'm referring to synchronization when we have two different shards. If there is a replica set, synchronization is not needed: it's a 'single-master' setup; we have an OpLog where all changes are recorded \u2013 in this case, everything is already sequentially ordered in the OpLog itself. But when we have two different shards, time synchronization becomes important. This is where vector clocks help more! However, we don't have them.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/7d3306747490ac044b7f8130defea0c9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe second option is 'Heartbeats'. You can exchange some signals that occur at each time unit. But Heartbeats are too slow; we cannot ensure latency for our client.<\/p>\n<p>True time is, of course, a wonderful thing. But again, this is probably the future\u2026 Although in the 'Atlas' it can already be done; there are fast Amazon time synchronizers. But this won't be available for everyone.<\/p>\n<p>Gossiping is when all messages include timestamps. This is roughly what we use. Every message between nodes, drivers, router data nodes, everything for MongoDB \u2013 these are some elements, components of the database that contain flowing clocks. They all have a hybrid time value that is transmitted. 64 bits? That\u2019s possible.<\/p>\n<h3>How does all of this work together?<\/h3>\n<p>\nHere, I consider one replica set to make it a bit simpler. There is a Primary and a Secondary. The Secondary replicates and is not always fully synchronized with the Primary.<\/p>\n<p>An insert occurs in the Primary with a certain timestamp. This insert increments the internal counter by 11, if that is the maximum. Otherwise, it will check the clock values and synchronize based on those clocks if the clock values are greater. This allows for time ordering.<\/p>\n<p>After it writes, an important moment occurs. Clocks in MongoDB are incremented only when a record is made in the OpLog. This is the event that changes the state of the system. In all classical articles, an event is considered to be when a message reaches a node: when a message arrives, it means the system has changed its state.<\/p>\n<p>This is related to the fact that during the investigation, it is not entirely clear how this message will be interpreted. We know for certain that if it is not reflected in the 'Oplog', it will not be interpreted at all, and the only change in the system state is the entry in the 'Oplog'. This simplifies things for us: both the model is simplified, and it allows for ordering within a single replica set, along with many other useful aspects.<\/p>\n<p>The value that is already recorded in the 'Oplog' is returned \u2013 we know that this value is already present in the 'Oplog', and its time is 12. Now, let's say reading starts from another node (Secondary), and it passes the afterClusterTime in the message itself. It states: 'I need everything that happened at least after 12 or at twelve' (see the figure above).<\/p>\n<p>This is what is known as Causal and consistent (CAT). There is a concept in theory that this is some snapshot of time that is self-consistent. In this case, it can be said that this is the system state that was observed at the moment of time 12.<\/p>\n<p>Right now, there is nothing here because it simulates a situation where the Secondary needs to replicate data from the Primary. It is waiting... And then the data arrives \u2013 it returns these values back.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/54d9de3e2696c1e5d19f4da206be090b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThis is more or less how everything works. Almost.<\/p>\n<p>What does 'almost' mean? Let's assume there is a certain person who read and understood how all this works. They grasp that each time a ClusterTime occurs, it updates the internal logical clocks, and then the next entry increments by one. This function takes 20 lines. Let's say this person transmits the largest possible 64-bit number minus one.<\/p>\n<p>Why 'minus one'? Because the internal clocks will be substituted into this value (obviously, this is the largest possible and greater than the current time), then there will be a write to the 'Oplog', and the clocks are incremented by one more \u2013 and it will already be the absolute maximum value (there are just all ones, there\u2019s no further, unsaint ints).<\/p>\n<p>It is clear that after this, the system becomes absolutely unavailable for anything. It can only be unloaded, cleaned \u2013 a lot of manual work. Full availability:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/634b25fe0ef1e0af39181cd59c7b522f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIf this is replicated elsewhere, the entire cluster can simply crash. An absolutely unacceptable situation that anyone could easily and quickly create! Therefore, we considered this aspect as one of the most important. How to prevent it?<\/p>\n<h3>Our solution is to sign clusterTime.<\/h3>\n<p>\nThis is conveyed in the message (before the blue text). But we also started generating a signature (blue text):<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/c16e985f9610e01a61293e0d6dde459b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nThe signature is generated by a key that is stored inside the database, within a secure perimeter; it is generated and updated (users don\u2019t see any of this). A hash is generated, and each message is signed upon creation, and validated upon receipt.<br \/>\nPeople might wonder: 'How much does this slow things down?' I emphasized that it should work quickly, especially in the absence of this feature.<\/p>\n<p>What does it mean to use Causal consistency in this case? It shows the afterClusterTime parameter. Without it, it will simply pass values anyways. Gossiping, starting from version 3.6, always works.<\/p>\n<p>If we keep generating signatures constantly, it will slow down the system even when this feature is absent, which does not align with our approaches and requirements. So what did we do?<\/p>\n<h3>Do it quickly!<\/h3>\n<p>\nA fairly simple thing, but an interesting trick \u2014 I\u2019ll share it; maybe someone will find it interesting.<br \/>\nWe have a hash that stores signed data. All data goes through a cache. The cache doesn\u2019t sign a specific time, but a Range. When a certain value comes in, we generate a Range, mask the last 16 bits, and this value is what we sign:<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/f4810456f08ba1cc69730ac0079d4206.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nBy obtaining such a signature, we speed up the system (conditionally) by 65,000 times. It works perfectly: when we conducted experiments, the time for our sequential updates was really cut down by 10,000 times. Of course, when they are out of sync, it doesn't happen. But in most practical scenarios, this works. The combination of Range signing alongside the signature allowed us to solve the security issue.<\/p>\n<h3>It is clear that any service strives to avoid downtime. In our case, we believe that the recent failures helped make quay.io better. We took away several key lessons that we would like to share:<\/h3>\n<p>\nLessons we learned from this:<\/p>\n<ul>\n<li>It's important to read materials, stories, and articles because we have many interesting things to share. When we work on a feature (especially now, when we were working on transactions, etc.), we need to read and understand. This takes time, but it is actually very beneficial because it clarifies where we stand. We haven't really invented anything new \u2013 we've just taken the ingredients.\n<p>In general, there is a certain difference in thinking when there is an academic conference (like \"Sigmon\", for example) \u2013 everyone focuses on new ideas. What is the novelty of our algorithm? There isn't much novelty here. The novelty rather lies in how we blended existing approaches together. Therefore, the first thing is to read the classics, starting with Lamport.<\/li>\n<li>In production, the requirements are completely different. I'm sure many of you face not \"spherical\" databases in an abstract vacuum, but real, normal things that have issues with availability, latency, and fault tolerance.<\/li>\n<li>The last point is that we had to consider different ideas and combine several completely different articles into one approach, together. The idea of signing, for example, actually came from an article discussing the Paxos protocol, which deals with non-Byzantine failures within the authorization protocol, and for Byzantine failures \u2013 outside the authorization protocol... Overall, that\u2019s exactly what we ended up doing.\n<p>There is absolutely nothing new here! But once we mixed it all together... It's like saying the recipe for Olivier salad is nonsense because eggs, mayonnaise, and cucumbers have already been invented... It's pretty much the same story.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/2f9e5cb77079f9a0f7bdf76430c3386e.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI'll conclude here. Thank you!<\/p>\n<h3>Questions<\/h3>\n<p>\n<b>Question from the audience (Q):<\/b> \u2013 Thank you, Mikhail, for the presentation! The topic of time is interesting. You use Gossiping. You mentioned that everyone has their own time, everyone knows their local time. I understood that we have a driver \u2013 there can be many clients with drivers, also many query planners, and many shards... So what happens to the system if suddenly we have a discrepancy: someone thinks they are a minute ahead, someone \u2013 a minute behind? Where will we end up?<\/p>\n<p><b>MT:<\/b> \u2013 That's a great question! I was actually going to mention shards. If I understand your question correctly, we have this situation: there is shard 1 and shard 2, and reading occurs from these two shards \u2013 they diverge, they do not interact with each other because the time they know is different, especially the time they have in the oplogs.<br \/>\nSuppose shard 1 has made a million records, shard 2 has made none at all, and a request comes to both shards. And the first one has an afterClusterTime greater than a million. In this situation, as I explained, shard 2 will never respond.<\/p>\n<p><b>Q:<\/b> \u2013 I wanted to know how they synchronize and choose one logical time?<\/p>\n<p><b>MT:<\/b> \u2013 They synchronize very simply. When a shard receives afterClusterTime and does not find a time in the 'Oplog' \u2013 it initiates no approved. This means it manually raises its time to that value. This indicates that it does not have events corresponding to that request. It artificially creates this event and thus becomes Causal Consistent.<\/p>\n<p><b>Q:<\/b> \u2013 What if other events arrive after this that got lost somewhere in the network?<\/p>\n<p><b>MT:<\/b> \u2013 The shard is designed such that they will not arrive, as it is single master. Once it has recorded, they will not arrive but will come later. It cannot happen that something got stuck somewhere, then it does a no write, and then those events arrive\u2014violating Causal Consistency. When it performs no write, all events should come next (it will wait for them).<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/dbbc7c5c653f0c9fa449cceb88ed62ef.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>Q:<\/b> \u2013 I have a few questions regarding queues. Causal consistency assumes that there is a certain queue of actions that need to be performed. What happens if one packet is lost? For example, the 10th, 11th\u2026 the 12th is lost, while all the others are waiting for it to be executed. Suddenly our machine crashes, and we cannot do anything. Is there a maximum queue length that accumulates before execution? What fatal failure occurs when losing any single state? Moreover, if we record that there is some previous state, then we should somehow base ourselves on it? But we didn't base ourselves on it!<\/p>\n<p><b>MT:<\/b> \u2013 That's also a great question! What do we do? In MongoDB, there is the concept of quorum writes and quorum reads. In what cases can a message be lost? When the write is non-quorum or when the read is non-quorum (there may also be some garbage that gets stuck).<br \/>\nWe conducted a significant experimental verification regarding Causal consistency, which showed that when reads and writes are non-quorum, violations of Causal consistency occur. That's exactly what you are saying!<\/p>\n<p>Our advice: use at least quorum reads when implementing Causal consistency. In this way, nothing will be lost, even if the quorum write fails\u2026 This is an orthogonal situation: if a user wants to avoid data loss, they need to use quorum writes. Causal consistency does not guarantee durability. Durability is guaranteed by replication and the machinery associated with replication.<\/p>\n<p><b>Q:<\/b> \u2013 When we create an instance that performs sharding (not master, but slave accordingly), does it rely on the Unix time of its own machine or on the time of the \u2018master\u2019; is it synchronized the first time or periodically?<\/p>\n<p><b>MT:<\/b> \u2013 Let me clarify. A shard (i.e., a horizontal partition) always has a Primary. There can be a \u2018master\u2019 in a shard and there can be replicas. But the shard must always support writing, because it has to maintain some domain (the Primary is located in the shard).<\/p>\n<p><b>Q:<\/b> \u2013 So everything depends solely on the \u2018master\u2019? Is the \u2018master\u2019 time always used?<\/p>\n<p><b>MT:<\/b> \u2013 Yes. It can be metaphorically said: clocks tick when a write occurs in the \u2018master\u2019, in the \u2018OpLog\u2019.<\/p>\n<p><b>Q:<\/b> \u2013 We have a client that connects, and they need to know nothing about time?<\/p>\n<p><b>MT:<\/b> \u2013 They don\u2019t need to know anything at all! Speaking of how this works on the client side: for the client, when they want to use Causal consistency, they need to open a session. Everything is in there now: transactions in the session and retrieve rights\u2026 A session is an ordering of logical events occurring with the client.<\/p>\n<p>If they open this session and state that they want Causal consistency (if the session supports Causal consistency by default), everything works automatically. The driver remembers this time and increments it when it receives a new message. It remembers the response returned by the previous server that provided the data. The next request will include afterCluster (\u2018time greater than this\u2019).<\/p>\n<p>The client doesn't need to know anything at all! It's completely opaque to them. If people use these features, what does it allow? Firstly, it is safe to read from secondaries: you can write to Primary and read from geographically replicated secondaries, being confident that it works. At the same time, sessions recorded on Primary can even be passed to Secondary, meaning you can use not just one session, but several.<\/p>\n<p><b>Q:<\/b> \u2013 The topic of Eventual consistency is closely related to a new layer of Computer Science \u2013 CRDT (Conflict-free Replicated Data Types). Have you considered integrating these data types into the database, and what can you say about this?<\/p>\n<p><b>MT:<\/b> \u2013 Good question! CRDT makes sense for conflicts during writes: in MongoDB, there\u2019s a single master.<\/p>\n<p><b>Q:<\/b> \u2013 I have a question from the DevOps team. In the real world, there are such Jesuitical situations where Byzantine Failures occur, and malicious actors within the protected perimeter begin to poke into the protocol, sending specially crafted packets?<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/99a521d04b416e6978aa68ce7c4a4c46.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<b>MT:<\/b> \u2013 Malicious actors inside the perimeter are like a Trojan horse! They can do many bad things.<\/p>\n<p><b>Q:<\/b> \u2013 Clearly, leaving a hole in the server, so to speak, through which a whole zoo of elephants can pass and crash the entire cluster forever\u2026 It will take time for manual recovery\u2026 This is, to put it mildly, incorrect. On the other hand, here's a curious thought: in real life, do we encounter situations where such internal attacks actually occur?<\/p>\n<p><b>MT:<\/b> \u2013 Since I don\u2019t often encounter security breaches in real life, I can\u2019t say \u2013 maybe they do happen. But speaking from a development philosophy standpoint, we think this way: we have a perimeter that protects the folks who handle security \u2013 it\u2019s a lock, a wall; and within the perimeter, you can do anything you want. Of course, there are users who can only view and others who have permission to delete the directory.<\/p>\n<p>Depending on the rights, the damage that users can inflict can range from minimal to significant. Clearly, a user with full rights can do anything they want. A user with limited rights can cause considerably less harm. In particular, they cannot break the system.<\/p>\n<p><b>Q:<\/b> \u2013 Within the secured perimeter, someone is trying to create unexpected protocols for the server to compromise it, and if lucky, the entire cluster\u2026 Is it ever that 'good'?<\/p>\n<p><b>MT:<\/b> \u2013 I have never heard of such things. It's no secret that you can take down a server this way. Taking it down from within, being an authorized user that can write something in a message\u2026 In reality, you can't, because it will still need to be verified. There is a way to disable this authentication for users who don't want it \u2013 that's their problem; they essentially broke down the walls and you could stuff an elephant in there to trample everything\u2026 Actually, you can dress as a technician, come in, and pull it out!<\/p>\n<p><b>Q:<\/b> \u2013 Thank you for the report. Sergey (Yandex). In Mongo, there is a constant that limits the number of voting members in a Replica Set, and this constant is 7 (seven). Why is this a constant? Why isn't it some kind of parameter?<\/p>\n<p><b>MT:<\/b> \u2013 A Replica Set can have as many as 40 nodes. There is always a majority. I don't know which version\u2026<\/p>\n<p><b>Q:<\/b> \u2013 In a Replica Set, you can run non-voting members, but for voting members, the maximum is 7. How do we handle a shutdown in this case if our Replica Set is spread across 3 data centers? One data center can easily go down, and another machine can drop out.<\/p>\n<p><b>MT:<\/b> \u2013 That's already a bit beyond the scope of the report. It's a general question. Maybe I can talk about it later.<\/p>\n<p><img decoding=\"async\" alt=\"HighLoad++, Mikhail Tyulenev (MongoDB): Causal consistency: from theory to practice\" src=\"\/wp-content\/uploads\/2020\/02\/161966c7e77704dc619674ff0302ff57.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<center><div class=\"youtube-placeholder\" data-id=\"UnAprFMX1d4\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/UnAprFMX1d4\/hqdefault.jpg\" alt=\"Play video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<h3>A little advertisement \ud83d\ude42<\/h3>\n<p>\nThank you for staying with us. Do you enjoy our articles? Want to see more interesting content? Support us by placing an order or recommending us to your friends, <noindex><a rel=\"nofollow\" href=\"https:\/\/ua-hosting.company\/cloudvps\/nl\">cloud VPS for developers starting at $4.99<\/a><\/noindex>, <b>a unique entry-level server alternative that we have created for you:<\/b> <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/347386\/\">The whole truth about VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps from $19 or how to properly share a server?<\/a><\/noindex> (options available with RAID1 and RAID10, up to 24 cores and up to 40GB DDR4).<\/p>\n<p><b>Dell R730xd at half the price in the Equinix Tier IV data center in Amsterdam?<\/b> Only with us <b><noindex><a rel=\"nofollow\" href=\"https:\/\/ua-hosting.company\/serversnl\">2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100TB starting at $199<\/a><\/noindex> in the Netherlands! <b>Dell R420 \u2014 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB \u2014 from $99!<\/b><\/b> Read about how <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/ua-hosting\/blog\/329618\/\">To build a corporate-class infrastructure using Dell R730xd E5-2650 v4 servers costing 9000 euros for peanuts?<\/a><\/noindex><br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ua-hosting\/blog\/487638\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435. HighLoad++ Siberia 2019. \u0417\u0430\u043b \u00ab\u041a\u0440\u0430\u0441\u043d\u043e\u044f\u0440\u0441\u043a\u00bb. 25 \u0438\u044e\u043d\u044f, 12:00. \u0422\u0435\u0437\u0438\u0441\u044b \u0438 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u044f. \u0411\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0443\u044e\u0442 \u0441 \u0442\u0435\u043e\u0440\u0438\u0435\u0439, \u0433\u0434\u0435 \u043d\u0435 \u0443\u0447\u0442\u0435\u043d\u044b \u0432\u0430\u0436\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u0430\u0441\u043f\u0435\u043a\u0442\u044b. \u0412 \u044d\u0442\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u044b\u0431\u043e\u0440\u0430 \u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-56365","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47HighLoad++, \u041c\u0438\u0445\u0430\u0438\u043b \u0422\u044e\u043b\u0435\u043d\u0435\u0432 (MongoDB): Causal consistency: \u043e\u0442 \u0442\u0435\u043e\u0440\u0438\u0438 \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-02-10T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:04:37+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47HighLoad++, Mikhail Tyulenyev (MongoDB): Causal consistency: from theory to practice | ProHoster","description":"The next HighLoad++ conference will take place on April 6 and 7, 2020, in St. Petersburg. Details and tickets can be found at the link.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47HighLoad++, \u041c\u0438\u0445\u0430\u0438\u043b \u0422\u044e\u043b\u0435\u043d\u0435\u0432 (MongoDB): Causal consistency: \u043e\u0442 \u0442\u0435\u043e\u0440\u0438\u0438 \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 | ProHoster","og:description":"\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044f HighLoad++ \u043f\u0440\u043e\u0439\u0434\u0435\u0442 6 \u0438 7 \u0430\u043f\u0440\u0435\u043b\u044f 2020 \u0433\u043e\u0434\u0430 \u0432 \u0421\u0430\u043d\u043a\u0442-\u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438 \u0431\u0438\u043b\u0435\u0442\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435.","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/highload-mihail-tyulenev-mongodb-causal-consistency-ot-teorii-k-praktike","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-02-10T21:00:00+00:00","article:modified_time":"2020-02-18T11:04:37+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"56365","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:26:38","updated":"2022-09-29 16:36:31","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/56365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=56365"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/56365\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=56365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=56365"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=56365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}