Перейти к содержанию

🗄️ БАЗЫ ДАННЫХ

БД — структурированное хранилище данных. СУБД — ПО, которое создаёт БД, даёт доступ (SQL и др.), обеспечивает целостность и безопасность.

Status: Draft

1. Типы БД

Три модели, с которыми чаще всего сталкиваются в проде.

Реляционные

Данные в таблицах (строки × столбцы), связи через PK / FK, запросы на SQL.

Плюсы целостность, JOIN, транзакции (ACID), зрелые инструменты
Минусы схема жёстче; горизонтальный scale сложнее, чем у многих NoSQL
Примеры PostgreSQL, MySQL, SQL Server, Oracle, SQLite

Первичный ключ (PK) — однозначно идентифицирует строку. Внешний ключ (FK) — ссылка на PK другой таблицы; СУБД проверяет ссылочную целостность.

Key-value

Пары ключ → значение; значение — что угодно (строка, JSON, бинарь).

Плюсы скорость, простая модель, гибкие значения
Минусы слабые запросы по «содержимому»; логика часто в приложении
Примеры Redis, etcd, DynamoDB (как KV-слой)
Документоориентированные

Хранят документы (часто JSON-подобные) в коллекциях; схема гибкая — поля могут отличаться между документами.

Плюсы гибкая модель, удобно для вложенных структур
Минусы целостность и JOIN’ы слабее классического SQL
Примеры MongoDB, CouchDB
db.users.find({"name": "Daniel"}).count()
2. SQL-шпаргалка

Диалекты отличаются (MySQL, PostgreSQL/PL/pgSQL, T-SQL…), база SELECT общая.

SELECT и фильтры
SELECT col1, col2 AS alias
FROM table_name
WHERE status IN ('a', 'b')
  AND price BETWEEN 100 AND 500
  AND name IS NOT NULL
  AND email LIKE '%@example.com'
ORDER BY created_at DESC
LIMIT 100;
  • DISTINCT — уникальные строки
  • AND / OR / NOT — логика в WHERE
  • Сравнение с NULL — только IS NULL / IS NOT NULL, не =
JOIN

Связка таблиц по ключу:

SELECT u.name, o.total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.total > 100;
Тип Смысл
INNER JOIN только совпавшие строки
LEFT JOIN все слева + совпадения справа (или NULL)
RIGHT JOIN зеркало LEFT (реже)
FULL JOIN все с обеих сторон (есть в PostgreSQL)
GROUP BY, агрегаты, HAVING
SELECT home_type, AVG(price) AS avg_price, COUNT(*) AS n
FROM rooms
GROUP BY home_type
HAVING AVG(price) > 50
ORDER BY n DESC;

Агрегаты: COUNT, SUM, AVG, MIN, MAX.

Порядок выполнения (упрощённо): FROMWHEREGROUP BYHAVINGSELECTORDER BY

WHERE фильтрует строки до группировки; HAVINGгруппы после.

3. PostgreSQL: права

Практика: отдельный пользователь с минимальными правами (часто read-only для аналитики).

RO-пользователь
CREATE USER analytics WITH PASSWORD '…';

GRANT CONNECT ON DATABASE sedo TO analytics;
GRANT USAGE ON SCHEMA public TO analytics;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analytics;

ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO analytics;

Только CONNECT + USAGE + SELECT — без INSERT/UPDATE/DELETE/CREATE.

Проверка привилегий (psql)
Команда Что смотрит
\dp права на таблицы / views / sequences
\dn+ схемы и права (U = USAGE, C = CREATE)
\ddp default privileges для новых объектов

В \dp вид analytics=r/sedo — у analytics есть SELECT (r), выдал sedo. Буквы: r SELECT, w INSERT, u UPDATE, d DELETE, …

Postgres Pro (кратко)

Форк PostgreSQL (Postgres Professional): коммерческая поддержка, доп. модули, сертификация ФСТЭК — часто в контексте импортозамещения.

Для ops-базы достаточно знать: синтаксис/репликация близки к PostgreSQL; отличия — в Enterprise-фичах (бэкап, сжатие, мультимастер и т.д.), не в «другом SQL».

4. HA PostgreSQL (Patroni)

Типичный стек: Patroni (мастер/failover) + etcd (DCS) + HAProxy (точка входа) + Keepalived (VIP).

Роли компонентов
Компонент Роль
Patroni Управляет PostgreSQL, репликацией и авто-failover
etcd Хранит метаданные кластера (кто master)
HAProxy Клиенты ходят сюда; проксирует на текущего master
Keepalived Держит VIP на активном HAProxy
Patroni (фрагмент)

На каждой PG-ноде свой name / IP. Пример pg_node_1:

scope: pg_cluster
namespace: /pg_cluster/
name: pg_node_1

restapi:
  listen: 192.168.1.101:8008
  connect_address: 192.168.1.101:8008

etcd:
  hosts: 192.168.1.201:2379,192.168.1.202:2379,192.168.1.203:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    postgresql:
      use_pg_rewind: true
      parameters:
        max_connections: 200
        shared_buffers: 256MB
        synchronous_commit: "on"
  initdb:
    - encoding: UTF8
    - data-checksums

postgresql:
  listen: 192.168.1.101:5432
  connect_address: 192.168.1.101:5432
  data_dir: /var/lib/postgresql/12/main
  authentication:
    replication:
      username: replicator
      password: secret
    superuser:
      username: postgres
      password: supersecret
  parameters:
    hot_standby: "on"
etcd, HAProxy, Keepalived

etcd (пример env одной ноды):

ETCD_NAME=etcd1
ETCD_INITIAL_CLUSTER=etcd1=http://192.168.1.201:2380,etcd2=http://192.168.1.202:2380,etcd3=http://192.168.1.203:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://192.168.1.201:2380
ETCD_LISTEN_PEER_URLS=http://192.168.1.201:2380
ETCD_LISTEN_CLIENT_URLS=http://192.168.1.201:2379
ETCD_ADVERTISE_CLIENT_URLS=http://192.168.1.201:2379

HAProxy — TCP на 5432, health-check Patroni /master (порт 8008):

frontend postgresql
    bind *:5432
    default_backend postgresql_cluster

backend postgresql_cluster
    mode tcp
    option httpchk GET /master
    http-check expect status 200
    default-server inter 3s fall 3 rise 2
    server pg1 192.168.1.101:5432 check port 8008
    server pg2 192.168.1.102:5432 check port 8008
    server pg3 192.168.1.103:5432 check port 8008 backup

Keepalived — VIP 192.168.1.100 (на backup-ноде priority ниже):

vrrp_instance haproxy_vip {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass keepalive
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

Клиенты: psql -h 192.168.1.100 -U postgres -d mydb

FAQ failover
  • Кто станет master? — реплика с наибольшим LSN (прогресс WAL), по правилам Patroni
  • Кто сейчас master?curl http://<node>:8008/master
  • Кластер «завис» — проверить etcd; systemctl restart etcd; patronictl list / restart node
  • Ускорить failover — уменьшить ttl / loop_wait / retry_timeout (осторожнее с ложными срабатываниями)
  • Без Patroni? — можно, но promote/failover руками (pg_ctl promote)
Вопросы

В разработке..