Initial commit: interview prep repo (resume, legend, stack cases, Kubernetes course)
This commit is contained in:
90
stack/databases/CASE.md
Normal file
90
stack/databases/CASE.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Кейс: PostgreSQL (репликация и базовые запросы)
|
||||
|
||||
Связь с легендой: [../../legend/LEGEND.md](../../legend/LEGEND.md) — раздел «Домашняя лаборатория / pet-проект». SQL как язык запросов уже вписан в легенду как сквозной инструмент (работа с данными сопровождаемых сервисов в АО ТНИИС), но отдельного опыта администрирования/репликации самой СУБД в рабочей практике не было — это тоже честный pet-кейс поверх рабочего опыта с запросами.
|
||||
|
||||
## Что нужно реально сделать (домашний стенд)
|
||||
|
||||
Поднять master + одну streaming-реплику PostgreSQL в Docker Compose, попробовать синхронный и асинхронный режим репликации, прогнать `pgbench` для базовых цифр производительности и потренировать SQL-запросы на простой учебной схеме.
|
||||
|
||||
### 1. docker-compose.yml — master + replica
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
pg-master:
|
||||
image: postgres:16
|
||||
container_name: pg-master
|
||||
environment:
|
||||
POSTGRES_PASSWORD: labpass
|
||||
POSTGRES_USER: labuser
|
||||
POSTGRES_DB: labdb
|
||||
command: >
|
||||
postgres
|
||||
-c wal_level=replica
|
||||
-c max_wal_senders=5
|
||||
-c max_replication_slots=5
|
||||
-c synchronous_commit=on
|
||||
-c synchronous_standby_names='FIRST 1 (replica1)'
|
||||
volumes:
|
||||
- ./master-init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
pg-replica:
|
||||
image: postgres:16
|
||||
container_name: pg-replica
|
||||
environment:
|
||||
POSTGRES_PASSWORD: labpass
|
||||
PGUSER: labuser
|
||||
depends_on:
|
||||
- pg-master
|
||||
ports:
|
||||
- "5433:5432"
|
||||
entrypoint: >
|
||||
bash -c "
|
||||
until pg_basebackup -h pg-master -D /var/lib/postgresql/data -U labuser -Fp -Xs -P -R --slot=replica1 --create-slot;
|
||||
do echo waiting for master; sleep 2; done;
|
||||
echo \"primary_conninfo = 'host=pg-master port=5432 user=labuser application_name=replica1'\" >> /var/lib/postgresql/data/postgresql.auto.conf;
|
||||
exec postgres"
|
||||
```
|
||||
|
||||
### 2. master-init.sql — учебная схема
|
||||
|
||||
```sql
|
||||
CREATE TABLE customers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id SERIAL PRIMARY KEY,
|
||||
customer_id INT REFERENCES customers(id),
|
||||
amount NUMERIC(10,2),
|
||||
status TEXT
|
||||
);
|
||||
|
||||
INSERT INTO customers (name) VALUES ('Иванов'), ('Петров'), ('Сидоров');
|
||||
INSERT INTO orders (customer_id, amount, status)
|
||||
VALUES (1, 1500.00, 'paid'), (1, 300.00, 'pending'), (2, 4200.00, 'paid');
|
||||
```
|
||||
|
||||
### 3. Шаги воспроизведения
|
||||
|
||||
1. `docker compose up -d` — поднять master, дождаться, пока replica пройдёт `pg_basebackup` и подключится (`docker compose logs -f pg-replica`).
|
||||
2. Проверить репликацию: `psql -h localhost -p 5432 -U labuser labdb -c "INSERT INTO customers (name) VALUES ('Новый клиент')"`, затем `psql -h localhost -p 5433 -U labuser labdb -c "SELECT * FROM customers"` — строка должна появиться на реплике.
|
||||
3. Проверить статус на master: `SELECT * FROM pg_stat_replication;` — увидеть `replica1`, `state = streaming`, `sync_state = sync` (при заданном `synchronous_standby_names`).
|
||||
4. Переключить на асинхронный режим: убрать `synchronous_standby_names` из command, перезапустить master, повторить `pg_stat_replication` — `sync_state` сменится на `async`. Разница на практике: при `sync` транзакция на master не считается закоммиченной, пока реплика не подтвердила запись (гарантия нуля потерянных данных при падении master ценой задержки commit); при `async` master коммитит сразу, не дожидаясь реплики (быстрее, но при падении master возможна потеря последних транзакций).
|
||||
5. Погонять `pgbench` для базовых цифр: `pgbench -h localhost -p 5432 -U labuser -i labdb` (инициализация), `pgbench -h localhost -p 5432 -U labuser -c 10 -j 2 -T 30 labdb` (10 клиентов, 30 секунд) — записать TPS в [../../legend/CAPACITY.md](../../legend/CAPACITY.md).
|
||||
6. Потренировать запросы на схеме `customers`/`orders`: JOIN, агрегации, `WHERE id = N` — см. [QUESTIONS.md](QUESTIONS.md).
|
||||
|
||||
## Что это даёт в разговоре с интервьюером
|
||||
|
||||
- Практическое понимание разницы sync/async репликации не как определения, а как наблюдаемого поведения (`pg_stat_replication`, разная задержка commit).
|
||||
- Понимание streaming-репликации через WAL и `pg_basebackup` — как реплика вообще получает данные.
|
||||
- Базовые цифры TPS со своей лабы — честная отправная точка для разговора про производительность (см. [../../legend/CAPACITY.md](../../legend/CAPACITY.md)).
|
||||
- Уверенное владение основными типами JOIN и агрегатными запросами на конкретной схеме.
|
||||
|
||||
## Как это ложится в легенду
|
||||
|
||||
PostgreSQL как СУБД — pet-кейс, не приписанный к опыту в компаниях. SQL как язык запросов к данным сопровождаемых сервисов остаётся в легенде как рабочий навык (см. [../../legend/LEGEND.md](../../legend/LEGEND.md)); этот кейс добавляет к нему более глубокое, честно обозначенное pet-понимание того, как устроена сама СУБД под капотом.
|
||||
43
stack/databases/QUESTIONS.md
Normal file
43
stack/databases/QUESTIONS.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Вопросы: PostgreSQL / базы данных
|
||||
|
||||
Опираются на кейс: [CASE.md](CASE.md). Источники реальных вопросов — [Реалист банк.md](../../interview/Реалист%20банк.md), [Alfa-Bank.md](../../interview/Alfa-Bank.md), [VK Cloud.md](../../interview/VK%20Cloud.md).
|
||||
|
||||
### Расскажи про синхронный и асинхронный режим работы PostgreSQL — в чём разница?
|
||||
|
||||
При синхронной репликации (`synchronous_commit=on` + `synchronous_standby_names`) master не подтверждает клиенту commit транзакции, пока хотя бы одна указанная реплика не подтвердила запись WAL — это гарантирует нулевую потерю данных при падении master ценой более медленного commit. При асинхронной репликации master коммитит сразу и отправляет WAL реплике фоном — быстрее, но при падении master прямо перед репликацией последние транзакции можно потерять. У себя в стенде я явно переключал этот параметр и видел разницу в `pg_stat_replication.sync_state` (`sync` → `async`), а не просто читал про это.
|
||||
|
||||
### Как будешь разворачивать PostgreSQL на две ноды?
|
||||
|
||||
Классическая схема — master + streaming replica: реплика инициализируется через `pg_basebackup` с master и дальше получает изменения через WAL-стриминг по replication slot. Дальше поверх этого нужен failover-механизм (например, Patroni + etcd/Consul для автоматического переключения при падении master) — сам failover-контроллер я не поднимал, но принцип базовой репликации прогнал в Docker Compose на две ноды (master + replica) и вижу, из каких частей состоит более сложная HA-схема поверх этого.
|
||||
|
||||
### Какие виды JOIN существуют и как они работают?
|
||||
|
||||
`INNER JOIN` — только строки, где есть совпадение в обеих таблицах. `LEFT JOIN` — все строки левой таблицы + совпадения справа (NULL, если совпадения нет). `RIGHT JOIN` — зеркально, все строки правой таблицы. `FULL OUTER JOIN` — все строки из обеих таблиц, с NULL там, где нет совпадения. На своей учебной схеме `customers`/`orders`: `SELECT c.name, o.amount FROM customers c LEFT JOIN orders o ON o.customer_id = c.id` покажет всех клиентов, включая тех, у кого нет заказов (у меня в примере таких не было, но проверял именно так, добавляя клиента без заказов).
|
||||
|
||||
### Что такое кластер (в контексте баз данных)?
|
||||
|
||||
В контексте PostgreSQL термин многозначный: (1) «кластер БД» на уровне процесса — это весь набор баз данных, которыми управляет один экземпляр `postgres` (директория данных, `initdb`); (2) в контексте отказоустойчивости — группа из нескольких инстансов (master + реплики), обеспечивающая доступность и/или масштабирование чтения. У себя в лабе я поднял именно второй случай — master + reплика как единый логический кластер с общими данными.
|
||||
|
||||
### Как происходит репликация базы данных?
|
||||
|
||||
Master пишет все изменения в WAL (write-ahead log) до применения к данным. Реплика подключается к master через replication slot, получает поток WAL-записей (streaming replication) и применяет их у себя, воспроизводя то же состояние с небольшой задержкой (или без задержки — при sync-режиме). Начальное состояние реплика получает через `pg_basebackup` — полную копию данных на момент старта, дальше — только дельты через WAL.
|
||||
|
||||
### Что такое quorum в конфигурации master-master (или в отказоустойчивом кластере вообще)?
|
||||
|
||||
Кворум — минимальное количество узлов, которое должно быть согласно/доступно, чтобы кластер считал своё решение валидным (обычно больше половины от общего числа узлов). Нужен, чтобы избежать одновременного принятия противоречащих решений разными частями кластера при разрыве сети — при потере кворума меньшая часть кластера не имеет права принимать решения (например, выбирать нового master), что и предотвращает split brain.
|
||||
|
||||
### Расскажи про split brain и почему кворум помогает?
|
||||
|
||||
Split brain — ситуация, когда из-за разрыва сети кластер разделяется на две части, и обе считают себя главными/рабочими одновременно (например, две ноды одновременно думают, что они master и принимают записи) — это ведёт к расхождению данных. Кворум решает эту проблему: только та часть кластера, где узлов больше половины от общего числа, имеет право принимать решения (выбирать нового лидера, подтверждать транзакции); меньшая часть автоматически переходит в read-only или отказывает в обслуживании, не считая себя валидным большинством.
|
||||
|
||||
### Есть таблица orders — какая команда выведет количество записей, где id = 15?
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM orders WHERE id = 15;
|
||||
```
|
||||
|
||||
Так как `id` — первичный ключ, результат либо 0, либо 1; если бы вопрос был про количество заказов конкретного клиента, это было бы `SELECT COUNT(*) FROM orders WHERE customer_id = 15;`.
|
||||
|
||||
### Что такое скоринг и кредитный конвейер? (контекст банковских вакансий)
|
||||
|
||||
Скоринг — процесс автоматической оценки кредитоспособности клиента по набору параметров (доход, кредитная история и т.д.), результат — числовой балл или решение одобрить/отклонить. Кредитный конвейер — сквозной автоматизированный процесс обработки заявки на кредит от подачи до решения: сбор данных → проверки (антифрод, скоринг, внешние бюро) → решение → оформление. Для инженера сопровождения/DevOps практический смысл в том, что это высоконагруженный и критичный по SLA процесс — отсюда повышенные требования к мониторингу и отказоустойчивости систем, которые его обслуживают.
|
||||
Reference in New Issue
Block a user