2. Коротко про мульти-мастер
Что такое транзакция и уровень изоляции транзакций
Как делают транзакции в версионных БД (MVCC)
Как делают транзакции в распределенных БД
Как мы сделали распределенные транзакции в Postgres.
Как мы сделали мульти-мастер репликацию поверх таких
транзакций
О чем расскажем
2
3. Мультимастер:
Репликация. Одинаковые данные (*)
Распределенные транзакции
OLTP нагрузка
Кластер доступен пока работает большинство нод
Ноду можно добавлять на лету
Совместимо с постгресом
Мульти-мастер, быстро
3
7. Обычно в книгах пишут два определения:
Атомарное действие над несколькими объектами
Атомарность + Сериализуемость – результат выполнения
нескольких параллельных транзакций равносилен
некоторому последовательному (серийному) их
выполнению.
Концепция транзакций
7
8. // Пишем программу, которая во много процессов/потоков
делает такие действия
// x – переменная в общей памяти, my_id – локальный номер
процесса/потока
while(true){
x = my_id
if (x != my_id) print("Wow!")
}
Пример: race condition
8
9. x += 1 – ?
x = 4294967297 – ?
Еще примеры race condition
9
10. x += 1 – может быть атомарно если процессор умеет
делать инструкции память-память. И если он один.
x = 4294967297 – две инструкции на x32
Еще примеры race condition
10
11. Atomicity – Visibility, CLOG
Consistency – просто нужна была буква
Isolation – locks, MVCC
Durability – WAL
ACID
11
14. Consistency (Linearizability = Serializability)
Availability
Partition tolerance
Нюансы:
Внутри стойки P – не проблема (Stonebraker)
Consistency в БД это не Linearizability
CAP теорема
14
17. Хотим присвоить двум объектам одинаковое значение.
T1
wa(12)
wb(12)
Comm
T2
wa(10)
wb(10)
Comm
−→
T1
wa(12)
wb(12)
Comm
T2
↓
↓
↓
↓
wa(10)
wb(10)
Comma = 10, b = 12 a = 10, b = 10
Кто видит проблему? =)
Изоляция: dirty write
17
18. T1
wa(10)
wb(10)
↓
↓
T2
wb(20)
↓
↓
↓
↓
Deadlock detection: если процесс проспал время T на локе,
то строим граф блокировок и ищем циклы. Нашли циклы
– принудительно завершаем одну из транзакций в цикле.
Борьба: упорядочить изменения внутри транзакций.
Выбрать более строгий уровень изоляции.
Изоляция: dead lock
18
19. Делаем интерфейс для просмотра состояния счетов.
uid
1
1
acc
1
2
amount
500
500
T1
wa(600)
wb(400)
Comm
T2
ra(500)
rb(400)
Comm
Бэкапы
Аналитика
Изоляция: non-repeatable read
19
21. STM чаще всего делают так же.
Нужен vacuum (сборка мусора).
MVCC или snapshot isolation,
замечания
21
22. Repeateble read:
Запомнить список активных транзакций на момент старта
новой
Видим строки с xmax <= xid
Если строка видима в нашей транзакции, то еще проверяем
в CLOG (для игнорирования абортированных транзакций)
Замечание №1: если брать список активных на каждое
выражение в транзакции, то получим RC. Замечание №2: такие
правила видимости специфичны для постгреса.
Правила видимости
22
23. Кроме последовательности стартов транзакций можно
вести еще последовательность завершений (CSN)
Тогда список активных не нужен
Правила видимости, альтернативно
23
24. Со списками активных:
Xid-ы получаем сквозные на кластер
Списки активных объединяем со всех нод
Коммит по 2PC (Как на свадьбе)
Новое состояние в CLOG: in doubt. Ставим между Prepare
и Commit.
С CSN:
CSN-ы получаем сквозные на кластер
Коммит по 2PC
Новое состояние в CLOG: in doubt.
+: Eсть теория децентрализации такого подхода
+: для CSN можно использовать физическое время
(георепликация)
Распределенные транзакции
24
25. Slide by Sameh Elnikety
Snapshot isolation, традиционно
25
26. Slide by Sameh Elnikety
Snapshot isolation, начало
транзакции
26
27. Slide by Sameh Elnikety
Snapshot isolation, выполнение
транзакции
27
28. Slide by Sameh Elnikety
Snapshot isolation, коммит
транзакции
28
42. Replication:
Identical replicated data on all nodes
Possibility to have local tables
Writes allowed to any node
=> Easy to use
=> We need to take care about proper isolation
Design objectives: replication
42
43. Transaction manager. We want:
Avoid single point of failure.
+: Spanner, Cockroach, Clock-SI
—: Snapshot sharing, GTM, ...
Avoid network communication for Read-Only transactions
+: Snapshot sharing (HANA), Spanner, Cockroach, Clock-SI
—: GTM, ...
Design objectives: transaction manager
43
44. Fault tolerance.
Paxos. Distributed consensus, low level.
Raft. Complete state-machine replication solution with failure
detector on timeouts and autorecovery. But all writes are
proxied to one node.
2PC. Blocks in case of node and coordinator failure. Postgres
already support 2pc.
3PC-like. Extra message between "P"and "C". 3PC, Paxos
commit, E3PC.
Design objectives: liveness
44
45. Summary.
No or small performance penalty for reads.
Tx can be issued to any node.
No special actions required in case of failure.
Design objectives
45
46. github.com/postgrespro/postgres_cluster
Patched version of Postgres 9.6
Transaction Manager API + Deadlock detection API.
Logical decoding of 2PC transactions.
Mmts extension.
Transaction Manager implementation (Clock-SI)
Logical replication protocol/client
Hooks on transaction commit and transforms it into 2PC.
Bunch of bgworkers.
Implementation
46
47. Mmts uses logical replication/decoding.
In-core support and extension by 2ndQuadrant.
Very flexible:
Can skip tables
Replication between different versions
Logical messages
Implementation
47
49. Transaction Manager.
Clock-SI algorithm (MS research)
Make use of CSN instead of running lists. (we track xid-csn
correspondence in extension, but there is ongoing work to have
CSN in-core by Heikki and Alexander)
Implementation
49
50. DDL replication.
Statement-based.
Happily, postgres support 2PC for almost all DDL (alter enum
already fixed in -master)
CREATE TABLE AS, CREATE MATVIEW, etc – tricky, mixes
DDL and DML.
Temp tables are tricky – shouldn’t be replicted.
Depends on environment (search_path, auth, etc.)
Implementation
50
51. Postgres compatibility.
almost FULLY compatible with pg.
162 of 166 regressions tests pass as is.
1 test is using prepared statement inside CREATE TABLE AS
(CTA).
3 tests are using CTA(CTA(TEMP TABLE)).
Some obvious way to abuse statement based replication, e.g.
write function that create table with name based on current
timestamp.
Also sequences can add pain.
Implementation
51
57. We want:
Test cluster liveness against network problems, restarts,
timeshifts, etc.
Sound like Jepsen. But unfortunately it uses ssh on precreated
vm’s/servers. That’s okay for single test, but painful for CI.
No sane way of testing network split with processes, i.e.
postgres TAP test framework is not helpful with that.
Testing
57
58. So we are using python unittest with docker.
3-5 containers is _way_ faster to start than vm’s.
takes 10 seconds to compile mmts extension, init and start
cluster.
failure injection via docker.exec (iptables, shift time, etc).
compatible with Travis-CI.
Testing
58
59. Testing itself: attach clients to each node of cluster and start
abusing nodes.
Client: bank-like test case. Transfer money between accounts
with concurrent total balance calculation.
Testing
59
60. Failures injected:
Node stop-start
Node kill-start
Node in network partition
Edge network split (a.k.a. majority rings)
Shift time
Change clock speed on nodes with libfaketime *
* – not yet implemented.
Testing
60
61. Performance.
Read-only tx speed is the same as in standalone postgres.
Commit takes more time (two net roundtrips).
Logical decoding slows down big transactions – but that
should be fixed, patch on commitfest.
Testing
61