-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3288a59
commit d28be26
Showing
2 changed files
with
94 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"* **Replication** is one of the strategies for distributing data processes across multiple nodes (the other is **partitioning**, the subject of a later chapter).\n", | ||
"* The difference between replication and partitioning is that whilst replication has you keep multiple copies of the data in several different places, partioning has you split that one dataset amongst multiple partitions.\n", | ||
"* Both strategies are useful, but obviously there are tradeoffs either way.\n", | ||
"\n", | ||
"\n", | ||
"* Replication strategies fall into three categories:\n", | ||
" * **Single-leader** — one service is deemed the leader. All other replicas follow.\n", | ||
" * **Multi-leader** — multiple services are deemed leaders. All other replicas follow.\n", | ||
" * **Client-driver** — not sure.\n", | ||
" \n", | ||
"## Single-leader replication\n", | ||
"\n", | ||
"* The first important choice that needs to be made is whether replication is synchronous or asynchronous.\n", | ||
"* Almost all replication is done asynchronously, because synchronous replication introduces unbounded latency to the application.\n", | ||
"* User-facing applications generally want to maintain the illusion of being synchronous, even when the underlying infrastructure is not.\n", | ||
"* Asynchronous replication introduces a huge range of problems that you have to contend with if you try to maintain this illusion.\n", | ||
"* (personal note) GFS is an interesting example. GFS was explicitly designed to be weakly consistent. That unlocked huge system power, and the additional application layer work that was required to deal with the architecture was deemed \"worth it\" because it was on the engineer's hands.\n", | ||
"\n", | ||
"\n", | ||
"* The precise configuration of concerns with a single-leader replication strategy differs. At a minimum the leader handles writes, and communicates those writes to the follower, and then the followers provide reads.\n", | ||
"\n", | ||
"\n", | ||
"* If a follower fails, you perform catch-up recovery. This is relatively easy (example, Redis).\n", | ||
"* If a leader fails you have to perform a **failover**. This is very hard:\n", | ||
" * If asynchronous replication is used the replica that is elected the leader may be \"missing\" some transaction history which occurred in the leader. Totally ordered consistency goes wrong.\n", | ||
" * You can discard writes in this case, but this introduces additional complexity onto any coordinating services that are also aware of those writes (such as cache invalidation).\n", | ||
" * It is possible for multiple nodes to believe they are the leader (Byzantine generals). This is dangerous as it allows concurrent writes to different parts of the system. E.g. **split brain**.\n", | ||
" * Care must be taken in setting the timeout. Timeouts that are too long will result in application delay for users. Timeouts that are too short will cause unnecessary failovers during high load periods.\n", | ||
"* Every solution to these problems requires making trade-offs!\n", | ||
"\n", | ||
"\n", | ||
"## Replication streams\n", | ||
"\n", | ||
"* How do you implement the replication streams?\n", | ||
"\n", | ||
"\n", | ||
"* The immediately obvious solution is **statement-based replication**. Every write request results in a follower update.\n", | ||
"* This is a conceptually simple architecture and likely the most compact and human-readable one. But it's one that's fallen out of favor due to problems with edge cases.\n", | ||
"* Statement-based replication requires pure functions. Non-deterministic functions (`RAND`, `NOW`), auto-incrementation (`UPDATE WHERE`), and side effects (triggers and so on) create difficulties.\n", | ||
"\n", | ||
"\n", | ||
"* **Write-ahead log shipping** is an alternative where you ship your write-ahead log (if you're a database or something else with a WAL).\n", | ||
"* This is nice because it doesn't require any additional work by the service. A WAL already exists.\n", | ||
"* This deals with the statement-based replication problems because WALs contain record dumps by design. To update a follower, push that record dump to it.\n", | ||
"* The tradeoff is that record dumps are a data storage implementation detail. Data storage may change at any times, and so the logical contents of the WAL may differ between service versions.\n", | ||
"* The write-ahead logs of different versions of a service are generally incompatible! But your system will contain many different versions.\n", | ||
"* Generally WALs are not designed to be version-portable, so upgrading distributed services using WAL shipping for replication requires application downtime.\n", | ||
"\n", | ||
"\n", | ||
"* **Logical log replication** is the use of an alternative log format for replication. E.g. replication is handled by its own distinct logs that are only used for that one specific purpose.\n", | ||
"* This is more system that you have to maintain, but it's naturally backwards and forward compatible if you design it right (using e.g. a data interchange format like Protobufs) and works well in practice.\n", | ||
"\n", | ||
"\n", | ||
"* Post-script: you may want partial replication. In that case you generally need to have application-level replication. You can do this in databases, for example, by using triggers and stored procedures to move data that fits your criteria in specific ways." | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.6.5" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |