From 75154e0892a396e0a80a8dce0aa5d2323d38475f Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Wed, 18 Feb 2015 14:42:27 +0900 Subject: [PATCH] Initial documentation import --- .gitignore | 3 +- doc/chain-self-management-sketch.Diagram1.dia | Bin 0 -> 6836 bytes doc/chain-self-management-sketch.Diagram1.pdf | Bin 0 -> 45367 bytes doc/chain-self-management-sketch.org | 672 ++++++++++++++++++ 4 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 doc/chain-self-management-sketch.Diagram1.dia create mode 100644 doc/chain-self-management-sketch.Diagram1.pdf create mode 100644 doc/chain-self-management-sketch.org diff --git a/.gitignore b/.gitignore index 8e46d5a..2693865 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,9 @@ .eunit deps *.o -*.beam +ebin/*.beam *.plt erl_crash.dump -ebin rel/example_project .concrete/DEV_MODE .rebar diff --git a/doc/chain-self-management-sketch.Diagram1.dia b/doc/chain-self-management-sketch.Diagram1.dia new file mode 100644 index 0000000000000000000000000000000000000000..6e42b7e53e51f24b12245bd92d9f45ed2f3c9694 GIT binary patch literal 6836 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

Z7xxrKBR!*&_Zf?%A}| zoyI9Ll`5hOtLWMi?)ho}2Yq#$ZD`yTqj6YMPmlY>GbR`3$-V%sP(?zb=Zx85XXMqY zU;C=36ak5r#;7va21-vg-ecJE+#UcA)tL$aSQ$_;RbYWG5;-t)iA-uQP}aaeNw6nw zzRvkQ>IavXa>M9%N#v+Dptx;lX#3RUC6$anK;{{x3|mUV2N~xAni+;GRVajIhgdG* z3lm9jE2x{$NB_luOg*9QwddP2B8xyL;_)BvmO}JHi63ZbfDiPX5!y&>;&&LBb^~qG zeF-0e`*Rnskn3@0M3myC%`jDNRu5VIbCXCn&AlmI*9dFF&sQv5u4(LIk7$Kf=FUTp zn1{B9)-**#&L}-S_Y(Fn`2BGtBa0a6@3FJiO@MSxXikze+57h4MSeEO1-eQxzg0MA zGq-)Qt#cXRn7^E{SP8mzZX6toj-r(jo~q zOY~uMJl7XKTh{_UZ6_BRFojme@4LP%E-%)D6iv=1q8(4v$8?qy9d;jMiugU6@{g`K zAth7oM46N~@oYBich1?R+*BRAE94=i3w89T;A5rsbDVq(GqpK=UDg}INIP_M0!$9~ za>r1-ijyWR^7Zzv_f{3WpI%#1a;&E2Ndwq38-8q9Gj&hqq4)%h$a^zp-^;$HyN1E2 zsf1Zf3|v5- z?rsgJ&QvUS;M$CHoqcMq?6KK3`aUJqUieP$Ti2CPb+I{MA&vG%Jl1qnHg9s)`x8&U z%!6dkfNE~vS(N+h;0NciU||T!SC*&z9h73pahL|(I;?5YHF#EiXAEfW!{Mg@|SzeH^fbhR*-;m$hg1=E#b*MRm z=5q#p23`<1;si5jc|cv=Uo$+FQ;>CXbhq?&XZz2je=FdznnP_}ofvqzdHJ|O3`VRr z?(WVaJUstGtzDtcHn!$&+)l36Mr{9``|qj>Ryh$ch?gG(0f9k$5HOg}00er1IR9h$ zo9+E?j_*@fCkqdAOIL<}#ruqbN7mI6>h6RX|BpJ~|BP*&9OapRpV24viQHp z|CR9bcD1y^L6E(La6tb#7zFtF5#FsB{s-gZgYY9L@xKoS$N$AZ2-Y>i^*=FT0U<<@ z#Xm6+2tm>Q0}~M7|7)&*pfDoKf6f&aK+u-|#DsVe6zG50fx$w&h=PxQU=UtG(BEqa zgZ|1xSOEN|KajAXz@Hc|h@bzj+=PV@^z?tOi?I7$Qt*#hctL^!e_jJ#UJ&Tdn0XOO ziGSt`1`7)Rxds@*_xr#8#~NU;u;8CDBkXwpvV#a9)ENJm3lS9lYh6CX-S~$cgjYc5 zPk#{b-?2b=h5pJHVfR-o5b)ozK)^zOuL0rxEnWJLeEIlzh5p9Cpg*qxA0HS|vhe3z zL?-{m++CrzuPj}0ers4hw|$M+GYGlLXHHJ;48QL*L|qY&vZEDZXaDbSIfTrp7}(s5 z*UB7mn+TafAy!Zj$jlsp2!SDB3qC#}ehUel|Gx>MU;(iW-P{q6mVa$RKExr6^XQSh IrUK6Y0c|9^AOHXW literal 0 HcmV?d00001 diff --git a/doc/chain-self-management-sketch.org b/doc/chain-self-management-sketch.org new file mode 100644 index 0000000..07cfd41 --- /dev/null +++ b/doc/chain-self-management-sketch.org @@ -0,0 +1,672 @@ +-*- mode: org; -*- +#+TITLE: Machi Chain Self-Management Sketch +#+AUTHOR: Scott +#+STARTUP: lognotedone hidestars indent showall inlineimages +#+SEQ_TODO: TODO WORKING WAITING DONE + +* Abstract +Yo, this is the first draft of a document that attempts to describe a +proposed self-management algorithm for Machi's chain replication. +Welcome! Sit back and enjoy the disjointed prose. + +We attempt to describe first the self-management and self-reliance +goals of the algorithm. Then we make a side trip to talk about +write-once registers and how they're used by Machi, but we don't +really fully explain exactly why write-once is so critical (why not +general purpose registers?) ... but they are indeed critical. Then we +sketch the algorithm by providing detailed annotation of a flowchart, +then let the flowchart speak for itself, because writing good prose is +prose is damn hard, but flowcharts are very specific and concise. + +Finally, we try to discuss the network partition simulator that the +algorithm runs in and how the algorithm behaves in both symmetric and +asymmetric network partition scenarios. The symmetric partition cases +are all working well (surprising in a good way), and the asymmetric +partition cases are working well (in a damn mystifying kind of way). +It'd be really, *really* great to get more review of the algorithm and +the simulator. + +* Copyright +%% Copyright (c) 2015 Basho Technologies, Inc. All Rights Reserved. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. + +* TODO Naming: possible ideas +** Humming consensus? + +See [[https://tools.ietf.org/html/rfc7282][On Consensus and Humming in the IETF]], RFC 7282. + +** Tunesmith? + +A mix of orchestral conducting, music composition, humming? + +** Foggy consensus? + +CORFU-like consensus between mist-shrouded islands of network +partitions + +** Rough consensus + +This is my favorite, but it might be too close to handwavy/vagueness +of English language, even with a precise definition and proof +sketching? + +** Let the bikeshed continue! + +I agree with Chris: there may already be a definition that's close +enough to "rough consensus" to continue using that existing tag than +to invent a new one. TODO: more research required + +* What does "self-management" mean in this context? + +For the purposes of this document, chain replication self-management +is the ability for the N nodes in an N-length chain replication chain +to manage the state of the chain without requiring an external party +to participate. Chain state includes: + +1. Preserve data integrity of all data stored within the chain. Data + loss is not an option. +2. Stably preserve knowledge of chain membership (i.e. all nodes in + the chain, regardless of operational status). A systems + administrators is expected to make "permanent" decisions about + chain membership. +3. Use passive and/or active techniques to track operational + state/status, e.g., up, down, restarting, full data sync, partial + data sync, etc. +4. Choose the run-time replica ordering/state of the chain, based on + current member status and past operational history. All chain + state transitions must be done safely and without data loss or + corruption. +5. As a new node is added to the chain administratively or old node is + restarted, add the node to the chain safely and perform any data + synchronization/"repair" required to bring the node's data into + full synchronization with the other nodes. + +* Goals +** Better than state-of-the-art: Chain Replication self-management + +We hope/believe that this new self-management algorithem can improve +the current state-of-the-art by eliminating all external management +entities. Current state-of-the-art for management of chain +replication chains is discussed below, to provide historical context. + +*** "Leveraging Sharding in the Design of Scalable Replication Protocols" by Abu-Libdeh, van Renesse, and Vigfusson. + +Multiple chains are arranged in a ring (called a "band" in the paper). +The responsibility for managing the chain at position N is delegated +to chain N-1. As long as at least one chain is running, that is +sufficient to start/bootstrap the next chain, and so on until all +chains are running. (The paper then estimates mean-time-to-failure +(MTTF) and suggests a "band of bands" topology to handle very large +clusters while maintaining an MTTF that is as good or better than +other management techniques.) + +If the chain self-management method proposed for Machi does not +succeed, this paper's technique is our best fallback recommendation. + +*** An external management oracle, implemented by ZooKeeper + +This is not a recommendation for Machi: we wish to avoid using ZooKeeper. +However, many other open and closed source software products use +ZooKeeper for exactly this kind of data replica management problem. + +*** An external management oracle, implemented by Riak Ensemble + +This is a much more palatable choice than option #2 above. We also +wish to avoid an external dependency on something as big as Riak +Ensemble. However, if it comes between choosing Riak Ensemble or +choosing ZooKeeper, the choice feels quite clear: Riak Ensemble will +win, unless there is some critical feature missing from Riak +Ensemble. If such an unforseen missing feature is discovered, it +would probably be preferable to add the feature to Riak Ensemble +rather than to use ZooKeeper (and document it and provide product +support for it and so on...). + +** Support both eventually consistent & strongly consistent modes of operation + +Machi's first use case is for Riak CS, as an eventually consistent +store for CS's "block" storage. Today, Riak KV is used for "block" +storage. Riak KV is an AP-style key-value store; using Machi in an +AP-style mode would match CS's current behavior from points of view of +both code/execution and human administrator exectations. + +Later, we wish the option of using CP support to replace other data +store services that Riak KV provides today. (Scope and timing of such +replacement TBD.) + +We believe this algorithm allows a Machi cluster to fragment into +arbitrary islands of network partition, all the way down to 100% of +members running in complete network isolation from each other. +Furthermore, it provides enough agreement to allow +formerly-partitioned members to coordinate the reintegration & +reconciliation of their data when partitions are healed. + +** Preserve data integrity of Chain Replicated data + +While listed last in this section, preservation of data integrity is +paramount to any chain state management technique for Machi. + +** Anti-goal: minimize churn + +This algorithm's focus is data safety and not availability. If +participants have differing notions of time, e.g., running on +extremely fast or extremely slow hardware, then this algorithm will +"churn" in different states where the chain's data would be +effectively unavailable. + +In practice, however, any series of network partition changes that +case this algorithm to churn will cause other management techniques +(such as an external "oracle") similar problems. [Proof by handwaving +assertion.] See also: "time model" assumptions (below). + +* Assumptions +** Introduction to assumptions, why they differ from other consensus algorithms + +Given a long history of consensus algorithms (viewstamped replication, +Paxos, Raft, et al.), why bother with a slightly different set of +assumptions and a slightly different protocol? + +The answer lies in one of our explicit goals: to have an option of +running in an "eventually consistent" manner. We wish to be able to +make progress, i.e., remain available in the CAP sense, even if we are +partitioned down to a single isolated node. VR, Paxos, and Raft +alone are not sufficient to coordinate service availability at such +small scale. + +** The CORFU protocol is correct + +This work relies tremendously on the correctness of the CORFU +protocol, a cousin of the Paxos protocol. If the implementation of +this self-management protocol breaks an assumption or prerequisite of +CORFU, then we expect that the implementation will be flawed. + +** Communication model: Asyncronous message passing +*** Unreliable network: messages may be arbitrarily dropped and/or reordered +**** Network partitions may occur at any time +**** Network partitions may be asymmetric: msg A->B is ok but B->A fails +*** Messages may be corrupted in-transit +**** Assume that message MAC/checksums are sufficient to detect corruption +**** Receiver informs sender of message corruption +**** Sender may resend, if/when desired +*** System particpants may be buggy but not actively malicious/Byzantine +** Time model: per-node clocks, loosely synchronized (e.g. NTP) + +The protocol & algorithm presented here do not specify or require any +timestamps, physical or logical. Any mention of time inside of data +structures are for human/historic/diagnostic purposes only. + +Having said that, some notion of physical time is suggested for +purposes of efficiency. It's recommended that there be some "sleep +time" between iterations of the algorithm: there is no need to "busy +wait" by executing the algorithm as quickly as possible. See below, +"sleep intervals between executions". + +** Failure detector model: weak, fallible, boolean + +We assume that the failure detector that the algorithm uses is weak, +it's fallible, and it informs the algorithm in boolean status +updates/toggles as a node becomes available or not. + +If the failure detector is fallible and tells us a mistaken status +change, then the algorithm will "churn" the operational state of the +chain, e.g. by removing the failed node from the chain or adding a +(re)started node (that may not be alive) to the end of the chain. +Such extra churn is regrettable and will cause periods of delay as the +"rough consensus" (decribed below) decision is made. However, the +churn cannot (we assert/believe) cause data loss. + +** The "wedge state", as described by the Machi RFC & CORFU + +A chain member enters "wedge state" when it receives information that +a newer projection (i.e., run-time chain state reconfiguration) is +available. The new projection may be created by a system +administrator or calculated by the self-management algorithm. +Notification may arrive via the projection store API or via the file +I/O API. + +When in wedge state, the server/FLU will refuse all file write I/O API +requests until the self-management algorithm has determined that +"rough consensus" has been decided (see next bullet item). The server +may also refuse file read I/O API requests, depending on its CP/AP +operation mode. + +See the Machi RFC for more detail of the wedge state and also the +CORFU papers. + +** "Rough consensus": consensus built upon data that is *visible now* + +CS literature uses the word "consensus" in the context of the problem +description at +[[http://en.wikipedia.org/wiki/Consensus_(computer_science)#Problem_description]]. +This traditional definition differs from what is described in this +document. + +The phrase "rough consensus" will be used to describe +consensus derived only from data that is visible/known at the current +time. This implies that a network partition may be in effect and that +not all chain members are reachable. The algorithm will calculate +"rough consensus" despite not having input from all/majority/minority +of chain members. "Rough consensus" may proceed to make a +decision based on data from only a single participant, i.e., the local +node alone. + +When operating in AP mode, i.e., in eventual consistency mode, "rough +consensus" could mean that an chain of length N could split into N +independent chains of length 1. When a network partition heals, the +rough consensus is sufficient to manage the chain so that each +replica's data can be repaired/merged/reconciled safely. +(Other features of the Machi system are designed to assist such +repair safely.) + +When operating in CP mode, i.e., in strong consistency mode, "rough +consensus" would require additional supplements. For example, any +chain that didn't have a minimum length of the quorum majority size of +all members would be invalid and therefore would not move itself out +of wedged state. In very general terms, this requirement for a quorum +majority of surviving participants is also a requirement for Paxos, +Raft, and ZAB. + +(Aside: The Machi RFC also proposes using "witness" chain members to +make service more available, e.g. quorum majority of "real" plus +"witness" nodes *and* at least one member must be a "real" node. See +the Machi RFC for more details.) + +** Heavy reliance on a key-value store that maps write-once registers + +The projection store is implemented using "write-once registers" +inside a key-value store: for every key in the store, the value must +be either of: + +- The special 'unwritten' value +- An application-specific binary blob that is immutable thereafter + +* The projection store, built with write-once registers + +- NOTE to the reader: The notion of "public" vs. "private" projection + stores does not appear in the Machi RFC. + +Each participating chain node has its own "projection store", which is +a specialized key-value store. As a whole, a node's projection store +is implemented using two different key-value stores: + +- A publicly-writable KV store of write-once registers +- A privately-writable KV store of write-once registers + +Both stores may be read by any cluster member. + +The store's key is a positive integer; the integer represents the +epoch number of the projection. The store's value is an opaque +binary blob whose meaning is meaningful only to the store's clients. + +See the Machi RFC for more detail on projections and epoch numbers. + +** The publicly-writable half of the projection store + +The publicly-writable projection store is used to share information +during the first half of the self-management algorithm. Any chain +member may write a projection to this store. + +** The privately-writable half of the projection store + +The privately-writable projection store is used to store the "rough +consensus" result that has been calculated by the local node. Only +the local server/FLU may write values into this store. + +The private projection store serves multiple purposes, including: + +- remove/clear the local server from "wedge state" +- act as the store of record for chain state transitions +- communicate to remote nodes the past states and current operational + state of the local node + +* Modification of CORFU-style epoch numbering and "wedge state" triggers + +According to the CORFU research papers, if a server node N or client +node C believes that epoch E is the latest epoch, then any information +that N or C receives from any source that an epoch E+delta (where +delta > 0) exists will push N into the "wedge" state and C into a mode +of searching for the projection definition for the newest epoch. + +In the algorithm sketch below, it should become clear that it's +possible to have a race where two nodes may attempt to make proposals +for a single epoch number. In the simplest case, assume a chain of +nodes A & B. Assume that a symmetric network partition between A & B +happens, and assume we're operating in AP/eventually consistent mode. + +On A's network partitioned island, A can choose a UPI list of `[A]'. +Similarly B can choose a UPI list of `[B]'. Both might choose the +epoch for their proposal to be #42. Because each are separated by +network partition, neither can realize the conflict. However, when +the network partition heals, it can become obvious that there are +conflicting values for epoch #42 ... but if we use CORFU's protocol +design, which identifies the epoch identifier as an integer only, then +the integer 42 alone is not sufficient to discern the differences +between the two projections. + +The proposal modifies all use of CORFU's projection identifier +to use the identifier below instead. (A later section of this +document presents a detailed example.) + +#+BEGIN_SRC +{epoch #, hash of the entire projection (minus hash field itself)} +#+END_SRC + +* Sketch of the self-management algorithm +** Introduction +See also, the diagram (((Diagram1.eps))), a flowchart of the +algorithm. The code is structured as a state machine where function +executing for the flowchart's state is named by the approximate +location of the state within the flowchart. The flowchart has three +columns: + +1. Column A: Any reason to change? +2. Column B: Do I act? +3. Column C: How do I act? + +States in each column are numbered in increasing order, top-to-bottom. + +** Flowchart notation +- Author: a function that returns the author of a projection, i.e., + the node name of the server that proposed the projection. + +- Rank: assigns a numeric score to a projection. Rank is based on the + epoch number (higher wins), chain length (larger wins), number & + state of any repairing members of the chain (larger wins), and node + name of the author server (as a tie-breaking criteria). + +- E: the epoch number of a projection. + +- UPI: "Update Propagation Invariant". The UPI part of the projection + is the ordered list of chain members where the UPI is preserved, + i.e., all UPI list members have their data fully synchronized + (except for updates in-process at the current instant in time). + +- Repairing: the ordered list of nodes that are in "repair mode", + i.e., synchronizing their data with the UPI members of the chain. + +- Down: the list of chain members believed to be down, from the + perspective of the author. This list may be constructed from + information from the failure detector and/or by status of recent + attempts to read/write to other nodes' public projection store(s). + +- P_current: local node's projection that is actively used. By + definition, P_current is the latest projection (i.e. with largest + epoch #) in the local node's private projection store. + +- P_newprop: the new projection proposal that is calculated locally, + based on local failure detector info & other data (e.g., + success/failure status when reading from/writing to remote nodes' + projection stores). + +- P_latest: this is the highest-ranked projection with the largest + single epoch # that has been read from all available public + projection stores, including the local node's public store. + +- Unanimous: The P_latest projections are unanimous if they are + effectively identical. Minor differences such as creation time may + be ignored, but elements such as the UPI list must not be ignored. + NOTE: "unanimous" has nothing to do with the number of projections + compared, "unanimous" is *not* the same as a "quorum majority". + +- P_current -> P_latest transition safe?: A predicate function to + check the sanity & safety of the transition from the local node's + P_current to the P_newprop, which must be unanimous at state C100. + +- Stop state: one iteration of the self-management algorithm has + finished on the local node. The local node may execute a new + iteration at any time. + +** Column A: Any reason to change? +*** A10: Set retry counter to 0 +*** A20: Create a new proposed projection based on the current projection +*** A30: Read copies of the latest/largest epoch # from all nodes +*** A40: Decide if the local proposal P_newprop is "better" than P_latest +** Column B: Do I act? +*** B10: 1. Is the latest proposal unanimous for the largest epoch #? +*** B10: 2. Is the retry counter too big? +*** B10: 3. Is another node's proposal "ranked" equal or higher to mine? +** Column C: How to act? +*** C1xx: Save latest proposal to local private store, unwedge, stop. +*** C2xx: Ping author of latest to try again, then wait, then repeat alg. +*** C3xx: My new proposal appears best: write @ all public stores, repeat alg + +** Flowchart notes +*** Algorithm execution rates / sleep intervals between executions + +Due to the ranking algorithm's preference for author node names that +are small (lexicographically), nodes with smaller node names should +execute the algorithm more frequently than other nodes. The reason +for this is to try to avoid churn: a proposal by a "big" node may +propose a UPI list of L at epoch 10, and a few moments later a "small" +node may propose the same UPI list L at epoch 11. In this case, there +would be two chain state transitions: the epoch 11 projection would be +ranked higher than epoch 10's projeciton. If the "small" node +executed more frequently than the "big" node, then it's more likely +that epoch 10 would be written by the "small" node, which would then +cause the "big" node to stop at state A40 and avoid any +externally-visible action. + +*** Transition safety checking + +In state C100, the transition from P_current -> P_latest is checked +for safety and sanity. The conditions used for the check include: + +1. The Erlang data types of all record members are correct. +2. UPI, down, & repairing lists contain no duplicates and are in fact + mutually disjoint. +3. The author node is not down (as far as we can tell). +4. Any additions in P_latest in the UPI list must appear in the tail + of the UPI list and were formerly in P_current's repairing list. +5. No re-ordering of the UPI list members: P_latest's UPI list prefix + must be exactly equal to P_current's UPI prefix, and any P_latest's + UPI list suffix must in the same order as they appeared in + P_current's repairing list. + +The safety check may be performed pair-wise once or pair-wise across +the entire history sequence of a server/FLU's private projection +store. + +*** A simple example race between two participants noting a 3rd's failure + +Assume a chain of three nodes, A, B, and C. In a projection at epoch +E. For all nodes, the P_current projection at epoch E is: + +#+BEGIN_QUOTE +UPI=[A,B,C], Repairing=[], Down=[] +#+END_QUOTE + +Now assume that C crashes during epoch E. The failure detector +running locally at both A & B eventually notice C's death. The new +information triggers a new iteration of the self-management algorithm. +A calculates its P_newprop (call it P_newprop_a) and writes it to its +own public projection store. Meanwhile, B does the same and wins the +race to write P_newprop_b to its own public projection store. + +At this instant in time, the public projection stores of each node +looks something like this: + +|-------+--------------+--------------+--------------| +| Epoch | Node A | Node B | Node C | +|-------+--------------+--------------+--------------| +| E | UPI=[A,B,C] | UPI=[A,B,C] | UPI=[A,B,C] | +| | Repairing=[] | Repairing=[] | Repairing=[] | +| | Down=[] | Down=[] | Down=[] | +| | Author=A | Author=A | Author=A | +|-------+--------------+--------------+--------------| +| E+1 | UPI=[A,B] | UPI=[A,B] | C is dead, | +| | Repairing=[] | Repairing=[] | unwritten | +| | Down=[C] | Down=[C] | | +| | Author=A | Author=B | | +|-------+--------------+--------------+--------------| + +If we use the CORFU-style projection naming convention, where a +projection's name is exactly equal to the epoch number, then all +participants cannot tell the difference between the projection at +epoch E+1 authored by node A from the projection at epoch E+1 authored +by node B: the names are the same, i.e., E+1. + +Machi must extend the original CORFU protocols by changing the name of +the projection. In Machi's case, the projection is named by this +2-tuple: +#+BEGIN_SRC +{epoch #, hash of the entire projection (minus hash field itself)} +#+END_SRC + +This name is used in all relevant APIs where the name is required to +make a wedge state transition. In the case of the example & table +above, all of the UPI & Repairing & Down lists are equal. However, A +& B's unanimity is due to the symmetric nature of C's partition: C is +dead. In the case of an asymmetric partition of C, it is indeed +possible for A's version of epoch E+1's UPI list to be different from +B's UPI list in the same epoch E+1. + +*** A second example, building on the first example + +Building on the first example, let's assume that A & B have reconciled +their proposals for epoch E+2. Nodes A & B are running under a +unanimous proposal at E+2. + +|-------+--------------+--------------+--------------| +| E+2 | UPI=[A,B] | UPI=[A,B] | C is dead, | +| | Repairing=[] | Repairing=[] | unwritten | +| | Down=[C] | Down=[C] | | +| | Author=A | Author=A | | +|-------+--------------+--------------+--------------| + +Now assume that C restarts. It was dead for a little while, and its +code is slightly buggy. Node C decides to make a proposal without +first consulting its failure detector: let's assume that C believes +that only C is alive. Also, C knows that epoch E was the last epoch +valid before it crashed, so it decides that it will write its new +proposal at E+2. The result is a set of public projection stores that +look like this: + +|-----+--------------+--------------+--------------| +| E+2 | UPI=[A,B] | UPI=[A,B] | UPI=[C] | +| | Repairing=[] | Repairing=[] | Repairing=[] | +| | Down=[C] | Down=[C] | Down=[A,B] | +| | Author=A | Author=A | | +|-----+--------------+--------------+--------------| + +Now we're in a pickle where a client C could read the latest +projection from node C and get a different view of the world than if +it had read the latest projection from nodes A or B. + +If running in AP mode, this wouldn't be a big problem: a write to node +C only (or a write to nodes A & B only) would be reconciled +eventually. Also, eventually, one of the nodes would realize that C +was no longer partitioned and would make a new proposal at epoch E+3. + +If running in CP mode, then any client that attempted to use C's +version of the E+2 projection would fail: the UPI list does not +contain a quorum majority of nodes. (Other discussion of CP mode's +use of quorum majority for UPI members is out of scope of this +document. Also out of scope is the use of "witness servers" to +augment the quorum majority UPI scheme.) + +* The Simulator +** Overview +The function machi_chain_manager1_test:convergence_demo_test() +executes the following in a simulated network environment within a +single Erlang VM: + +#+BEGIN_QUOTE +Test the convergence behavior of the chain self-management algorithm +for Machi. + + 1. Set up 4 FLUs and chain manager pairs. + + 2. Create a number of different network partition scenarios, where + (simulated) partitions may be symmetric or asymmetric. (At the + Seattle 2015 meet-up, I called this the "shaking the snow globe" + phase, where asymmetric network partitions are simulated and are + calculated at random differently for each simulated node. During + this time, the simulated network is wildly unstable.) + + 3. Then halt changing the partitions and keep the simulated network + stable. The simulated may remain broken (i.e. at least one + asymmetric partition remains in effect), but at least it's + stable. + + 4. Run a number of iterations of the algorithm in parallel by poking + each of the manager processes on a random'ish basis to simulate + the passage of time. + + 5. Afterward, fetch the chain transition histories made by each FLU + and verify that no transition was ever unsafe. +#+END_QUOTE + + +** Behavior in symmetric network partitions + +The simulator has yet to find an error. This is both really cool and +really terrifying: is this *really* working? No, seriously, where are +the bugs? Good question. Both the algorithm and the simulator need +review and futher study. + +In fact, it'd be awesome if I could work with someone who has more +TLA+ experience than I do to work on a formal specification of the +self-management algorithm and verify its correctness. + +** Behavior in asymmetric network partitions + +The simulator's behavior during stable periods where at least one node +is the victim of an asymmetric network partition is ... weird, +wonderful, and something I don't completely understand yet. This is +another place where we need more eyes reviewing and trying to poke +holes in the algorithm. + +In cases where any node is a victim of an asymmetric network +partition, the algorithm oscillates in a very predictable way: each +node X makes the same P_newprop projection at epoch E that X made +during a previous recent epoch E-delta (where delta is small, usually +much less than 10). However, at least one node makes a proposal that +makes unanimous results impossible. When any epoch E is not +unanimous, the result is one or more new rounds of proposals. +However, because any node N's proposal doesn't change, the system +spirals into an infinite loop of never-fully-unanimous proposals. + +From the sole perspective of any single participant node, the pattern +of this infinite loop is easy to detect. When detected, the local +node moves to a slightly different mode of operation: it starts +suspecting that a "proposal flapping" series of events is happening. +(The name "flap" is taken from IP network routing, where a "flapping +route" is an oscillating state of churn within the routing fabric +where one or more routes change, usually in a rapid & very disruptive +manner.) + +If flapping is suspected, then the count of number of flap cycles is +counted. If the local node sees all participants (including itself) +flappign with the same relative proposed projection for 5 times in a +row, then the local node has firm evidence that there is an asymmetric +network partition somewhere in the system. The pattern of proposals +is analyzed, and the local node makes a decision: + +1. The local node is directly affected by the network partition. The + result: stop making new projection proposals until the failure + detector belives that a new status change has taken place. + +2. The local node is not directly affected by the network partition. + The result: continue participating in the system by continuing new + self-management algorithm iterations. + +After the asymmetric partition victims have "taken themselves out of +the game" temporarily, then the remaining participants rapidly +converge to rough consensus and then a visibly unanimous proposal. +For as long as the network remains partitioned but stable, any new +iteration of the self-management algorithm stops without +externally-visible effects. (I.e., it stops at the bottom of the +flowchart's Column A.) +