50 years later, is two-phase locking the best we can do?
concurrencyfreaks.blogspot.com
concurrencyfreaks.blogspot.com
If I have a distributed microservice architecture and I want to keep multiple datastores in synchronization or "consistent" what's the industry best practice?
A few days ago I was trying to solve the inconsistency problem with "settled timestamps" which is a kind of multiversioning idea except that timestamps elapsed with the absence of reported error represent a valid save/commit. Kind of like two phase commit with the second phase being time. The idea is that we watch the clocks of other servers and if they don't update then we know we cannot trust their settled timestamps. (My intent was to allow scaling consistency across many servers, because we don't need to wait for response for every update, we only need to wait for the next timestamp interval)
Here's my Multithreaded multiprocessing Python code to test indeterminancy. 10 threads all send eachother random updates. They also broadcast their own timestamp and the timestamps of their own perspective of the timestamps every other server.
https://replit.com/@Chronological/InconsistencySimulation#ma... (click Run and watch the output, you'll have to wait 10 seconds)
A read in this simulation is the MIN of all timestamps of all servers reported timestamps.
10 seconds into the simulation, we ask every thread for its own perspective of what the counter value is. Sometimes they will all report the same value, a lot of the time they shall be split brained.
I am aware that wall clock timestamps are not suitable for ordering in a distributed system and that logical or vector clocks should be used for ordering.
If you can get the simulation to all report the same number at any point in time, then that would be great :-)
Ordering in distributed systems is significant, as the eventual consistency of the simulation means that some values can arrive late but affect the value, meaning it is not linearizable. Bloomlang tries to solve this.
I'm specifically interested in scaling WITH consistency but I think this is quite difficult.
Multiple systems write sequentially to the central journal. The journal is simply taking requests like a key value store. The journal is replicated to all the nodes. The nodes read from the journal and performs the complex logic requested.
If you need strict order, that order should happen in strictly one place. (The universe itself does not support strict order at a distance, as Special Relativity shows.)
Everyone: yes.
Nope. Not for real-time gaming which is the topic at hand. Certainly not at scale. Certainly not at the kind of volume of events that gaming produces.
But its price may be prohibitive.
(Kubernetes uses etcd so it scales pretty well for a strongly-consistent k/v store.)
You said “multiple datastores” so I’m assuming you have heterogenous data and something like CockroachDB isn’t an option.
> I'm a beginner in this topic and I find this topic interesting.
Not trying to gatekeepe but rolling your own is dangerous. See https://aphyr.com/ for the gold standard in testing (great educational material). You can use Jepsen to test your distributed systems. But better to just use datastores that Kyle has shown are solid.
I've experimented with a toy Raft implementation but I haven't Jepsen tested that and it's incomplete
I did write a Jepsen test for a different eventually consistent protocol which understandably fails the linearizability test because I'm still learning - eventually consistent is not linearizable.
https://GitHub.com/samsquire/eventually-consistent-mesh
I want to have my cake and eat it too. Scalability and consistency.
Not to use a distributed microservice architecture.
I was part of an engineering team that built a payments switch from scratch in the early oughts.
We built it in Java, on commodity hardware and OS, on top of our own replicated, stateful, distributed computing platform.
This was a bonkers thing to do then, pre-cloud. It’s probably still a bonkers thing to do _today_.
Anyway, we did a lot of work with 2PC and other consensus mechanisms and came to the conclusion they 2PC wasn’t up to scratch for what we needed (it’s actually provably less than ideal).
We ended up building (again, from scratch) one of the earliest (that I know of) implementations of the Virtual Synchrony protocol. VS has some robust maths behind it that you can use to make some stronger consistency claims than you can with 2PC. These are important when you’re dealing with interbank settlements for payments switching.
If we started again today I’d say that we might use something like Raft, but I’ve been away from the space for ~20 years now so I’m not entirely sure.
However, one thing I do know is this: distributed consensus is Very Hard™ to get right.
If the answer to your question involves any kind of multiple master implementation using distributed consensus I can unequivocally guarantee that (other than in a few very specific circumstances that you almost certainly do not have) you’re asking the wrong question.
I'm not familiar with these technologies, but when I was studying databases, SSI was touted as the "better" 2PL on the horizon. I wonder how SSI compares to 2PLSF, and why it wasn't mentioned here?
Often, you can batch the requests and hit the external resource with less concurrency, but larger payloads. If the resource handles well batches, you'll need far less concurrency and locking. For example, if you're working with Postgres, you'll need fewer connections, and you may be able to forego adding PgBouncer, which makes things more complicated.
Granted, batching requests is not something most programming languages are well suited to do. Those that are optimized for high concurrency like Go (channels) and Elixir (processes) can do it well, but for languages that do everything with threads it can be painful.
It doesn't make sense to link to HTTP when the site works fine over HTTPS, which is the case here. I'm not sure I'd want to completely ban all HTTP though.
The privacy issue is that your local WiFi provider, direct isp, and all the intermediate isps can see not only which site you visit, but all your activity within that site (like which pages you visit or things you download).
The security part is that any of those who can view can also do a “man in the middle” attack. Comcast could decide to send you a different version of the website that was more favorable to their company, or inject ads (ISPs have been known to inject ads on sites they don’t own before https was big).
A hacker could send you a version that gets you to download malware by replacing content or links. They can see and effect everything you do and see in such a site if they can intercept your request.
You'll get a warning for any site that CAN'T be upgraded to HTTPS, but any site that supports both you'll just go straight to the HTTPS version.
Also, no if an http link is about a good concurrent algorithm, I will read it anyways.
While it’s not mentioned, I suppose you want to prioritize older transactions in order to prevent long-running transactions from being starved by shorter-running transactions. (If one long transaction conflicts with an average of, say, three short transactions, and on each conflict it’s effectively random who wins, then each long transaction has only a 1/8 chance of winning all three conflicts and being able to commit.)
But preventing starvation only requires older transactions to be prioritized most of the time, not every single time, especially not if the transaction is only slightly older. So some kind of timestamp / cycle counter should work fine, even if there’s skew between threads or other sources of inaccuracy. Ties could be broken by thread ID, or again by having both sides abort.
They (and others) are great for this kind of case - and many others.
There is also a draft to make a new uuid variant – uuid v7 – that will be very similar to how ulid works.
https://www.ietf.org/archive/id/draft-peabody-dispatch-new-u...
How? UUID is a structured format so the only options I can see is ulid creating their own unregistered uuid variant (probably a terrible idea) or adding ulid support to postgres (nothing to do with uuid).
https://lamport.azurewebsites.net/video/consensus-on-transac...
Two-phase locking is a concurrency control mechanism.
2PC: An algorithm used in the context of distributed transactions where each machine handles a different part of the transaction. This means that nothing is redundant - the success of each and every participant is required for the transaction to be committed.
Paxos/Raft/consensus: An algorithm usually used in the context of distributed replication. Since every participant is doing the same thing, it's tolerable if a few fail or give outputs that diverge from the majority.
2PL: A method of acquiring multiple locks such that first you acquire all the required locks (first phase), then you do what you need to do, and then you release all the locks (second phase). This is in contrast to a locking scheme where lock acquisitions and releases are interspersed. This isn't strictly limited to distributed systems, although it's common to see 2PC with 2PL.
If this piques your interest, read the Spanner paper! Spanner uses all three - 2PC with 2PL for distributed read-write transactions, and Paxos for replication.
PS: "Distributed" just means there's more than one machine involved, any of which may fail independently, and communication among these machines happens over unreliable wire.
Locks (computer science) > Disadvantages: https://en.wikipedia.org/wiki/Lock_(computer_science)#Disadv...
Two-phase locking (2PL) https://en.wikipedia.org/wiki/Two-phase_locking
Two-phase commit protocol (2PC) https://en.wikipedia.org/wiki/Two-phase_commit_protocol
Paxos: https://en.wikipedia.org/wiki/Paxos_(computer_science)
Raft: https://en.wikipedia.org/wiki/Raft_(algorithm)
Consensus (computer science) https://en.wikipedia.org/wiki/Consensus_(computer_science)
Spanner: https://en.wikipedia.org/wiki/Spanner_(database)
Non-blocking algorithm; "lock-free concurrency", "wait-free" https://en.wikipedia.org/wiki/Non-blocking_algorithm
"Ask HN: Why don't PCs have better entropy sources?" [for generating txids/uuids] https://news.ycombinator.com/item?id=30877296
"100-Gbit/s Integrated Quantum Random Number Generator Based on Vacuum Fluctuations" https://link.aps.org/doi/10.1103/PRXQuantum.4.010330
Re: tests of randomness: https://mail.python.org/archives/list/python-ideas@python.or...
TIL there's a regular heartbeat in the quantum foam; there's a regular monotonic heartbeat in the quantum Rydberg wave packet interference; and that should be useful for distributed applications with and without vector clocks and an initial time synchronization service (WhiteRabbit > PTP > NTP Network Time Protocol) https://journals.aps.org/prresearch/abstract/10.1103/PhysRev... :
> The [quantum time-keeping application of this research] relies on the unique fingerprint that is created by the time-dependent photoionization of these complex wave packets. These fingerprints determine how much time has passed since the wave packet was formed and provide an assurance that the measured time is correct. Unlike any other clock, this quantum watch does not utilize a counter and is fully quantum mechanical in its nature. The quantum watch has the potential to become an invaluable tool in pump-probe spectroscopy due to its simplicity, assurance of accuracy, and ability to provide an absolute timestamp, i.e., there is no need to find time zero.
IIUC a Rydberg antenna can read and/or write such noise?
"Patterns of Distributed Systems (2022)" https://news.ycombinator.com/item?id=36504073
The issue is if your first locking message gone how do you know it is not the reply message that is lost. For simple one just go ahead and deal with conflict later like GitHub and Dropbox etc. for database good luck. For bank.
however, i do think the tl2 implementation as described in the paper is memory based, as is TinySTM so every read needs to do a hash to locate the corresponding lock / meta data. the read-only transactions for tl2 and TinySTM seem identical to me which is why i am so confused.
looking at other figures from the 2PLSF paper, the TL2 for 100% lookup on hash set and skip list it looks like such a dog compared to the other algos.
Example, typically have 1000 tasks and 10..100 hardware threads.
So, make one ordered list of 1000 tasks, and than make copy of it for each thread, each time randomize order of copy.
Than, each thread will just read it's list and execute task and subscribe to one list implemented as non-blocking multi-thread queue.
In worst case, few threads will do some task repeatedly.
And atomic operations this way will scale up to 1000 times.
All my incoming and outgoing “transactions” are over loosely-coupled API calls.
Is there a point I’m missing?
Usually there are multiple writes to complete a business process. In each step stale data is read to create a write request similar to how you place your order with the wait staff at the restaurant. The wait staff will orchestrate your request. First the chef prepares your meal according to the order ticket. Second the wait staff delivers your meal based on the chef’s internal work order. Lastly they take your payment based on the original order ticket. Notice there are at least three microtransactions based on stale data. No one is holding locks until the diner finishes eating.
What happens if the chef can’t fulfill the meal, the customer leaves cause the order is taking long … etc Most real life will not charge the customer is the chef can’t make the meal and cancel the cooking if the customer leaves
The analogy maybe going far ;)
That (possibly brief) moment where you hold all the necessary locks is your point of linearizability: it's as if everything happened at that exact moment.
Sometimes, we find a good solution, and it's the best possible one and we found it early on. We think we can do better, but we can't. A classic example of this is Euclid's fifth axiom. It wasn't proven until the 19th century that this axiom was necessary but everyone from Euclid to Gauss tried to get rid of it. Foolish.
I think it's a testament to the human condition there are those of us willing to entertain the folly of pushing the boundaries, or of being foolish as you put it.
[1] https://www.cs.utexas.edu/~EWD/transcriptions/EWD09xx/EWD975...
It is a delight to read.