← Назад к вопросам
Для чего используют сразу несколько баз данных?
2.0 Middle🔥 191 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Использование нескольких БД в приложении
Да, я встречал проекты с несколькими БД. Это практика для оптимизации производительности, надёжности и масштабируемости. Важно понять зачем это делают.
1. Разные типы БД для разных задач
PostgreSQL + Redis:
┌─────────────────────────────────┐
│ Frontend Application │
└──────┬──────────────────────────┘
│
├──> PostgreSQL (основная БД)
│ - Пользователи
│ - Посты
│ - Комментарии
│ - ACID транзакции
│
└──> Redis (кэш)
- Sessions
- Rate limiting
- Real-time notifications
- Быстрый доступ (in-memory)
Практический пример:
# Backend (FastAPI)
from fastapi import FastAPI
import redis
import asyncpg
app = FastAPI()
# PostgreSQL для постоянного хранения
db_pool: asyncpg.Pool
# Redis для кэша и сессий
redis_client: redis.Redis
@app.get('/api/users/{user_id}')
async def get_user(user_id: int):
# 1. Проверяем Redis (кэш)
cached_user = await redis_client.get(f'user:{user_id}')
if cached_user:
return json.loads(cached_user)
# 2. Если нет в кэше — берём из PostgreSQL
user = await db_pool.fetchrow(
'SELECT * FROM users WHERE id = $1',
user_id
)
# 3. Сохраняем в Redis на 1 час
await redis_client.setex(
f'user:{user_id}',
3600,
json.dumps(dict(user))
)
return dict(user)
Frontend не видит различия:
const fetchUser = async (userId) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
};
// Для frontend это просто API, БД скрыта за backend
2. Sharding — распределение данных по БД
Когда одна БД не вмещает данные:
Пользователи распределены по ID:
┌─────────────────┬─────────────────┬─────────────────┐
│ DB Shard 1 │ DB Shard 2 │ DB Shard 3 │
├─────────────────┼─────────────────┼─────────────────┤
│ user_id: 1-1000 │ user_id: 1001- │ user_id: 2001- │
│ (PostgreSQL) │ 2000 (PG) │ 3000 (PG) │
└─────────────────┴─────────────────┴─────────────────┘
│ │ │
└───────────────┼───────────────┘
│
Backend (Router)
Определяет какой shard
Backend логика:
def get_shard_for_user(user_id: int) -> str:
# Используем хеширование
shard_num = hash(user_id) % 3
return f'db_shard_{shard_num}'
async def get_user(user_id: int):
shard = get_shard_for_user(user_id)
db = get_db_connection(shard)
user = await db.fetchrow(
'SELECT * FROM users WHERE id = $1',
user_id
)
return user
3. Read Replicas — оптимизация читается
Backend
│
┌──────┴──────┐
│ │
▼ ▼
Write Read Replicas
PostgreSQL
(Primary) ┌─────────────┐
(5432) │ Replica 1 │
│ (5433) │
├─────────────┤
│ Replica 2 │
│ (5434) │
└─────────────┘
Использование:
# Пишем в основную БД
async def create_post(title: str, content: str):
post_id = await primary_db.execute(
'INSERT INTO posts (title, content) VALUES ($1, $2)',
title, content
)
return post_id
# Читаем с реплик (load balancing)
async def get_feed():
replica = select_random_replica() # Random read replica
posts = await replica.fetch(
'SELECT * FROM posts ORDER BY created_at DESC LIMIT 20'
)
return posts
4. Polyglot Persistence — разные БД для разных данных
┌──────────────────────────────────┐
│ Backend Application │
└──┬──┬──┬──┬────────────┬─────────┘
│ │ │ │ │
│ │ │ │ ▼
│ │ │ │ MongoDB
│ │ │ │ (гибкая
│ │ │ │ схема)
│ │ │ │
│ │ │ └──> Elasticsearch
│ │ │ (полнотекстовый
│ │ │ поиск)
│ │ │
│ │ └──> Redis
│ │ (кэш/очереди)
│ │
│ └──> PostgreSQL
│ (основные данные)
│
└──> Neo4j
(графовая БД
для связей)
Практический пример:
# Пост
post = {
'id': 1,
'title': 'Hello',
'content': 'World'
}
# Где хранить?
# - id, title → PostgreSQL (обязательно)
# - полный text → Elasticsearch (для поиска)
# - структурированные данные → MongoDB (гибко)
# - связи user->post→comment → Neo4j (граф)
@app.post('/api/posts')
async def create_post(post: PostCreate):
# 1. PostgreSQL (основное хранилище)
post_id = await pg_db.execute(
'INSERT INTO posts (title, user_id) VALUES ($1, $2)',
post.title, post.user_id
)
# 2. Elasticsearch (индексирование для поиска)
await es.index(
index='posts',
id=post_id,
body={'title': post.title, 'content': post.content}
)
# 3. Neo4j (граф связей)
await neo4j.run(
'CREATE (p:Post {id: $id, title: $title}) '
'CREATE (u:User {id: $user_id}) '
'CREATE (u)-[:WROTE]->(p)',
id=post_id, title=post.title, user_id=post.user_id
)
# 4. Redis (кэш последних постов)
await redis.lpush('recent_posts', post_id)
await redis.ltrim('recent_posts', 0, 99)
return {'id': post_id}
5. Event Sourcing — разные хранилища событий
┌──────────────────┐
│ User Action │
│ (Button click) │
└────────┬─────────┘
│
▼
┌──────────────────────────────┐
│ Event Log (Append-only) │
│ Kafka или Event Store │
│ - user_created_event │
│ - user_updated_event │
│ - post_liked_event │
└────────┬─────────────────────┘
│
├──> PostgreSQL (Current state)
│ для быстрых запросов
│
├──> Elasticsearch (Projections)
│ для аналитики
│
└──> Redis (Cache)
для real-time
6. Выбор БД в frontend (индиректно)
Frontend видит это в API ответах:
// Быстро — данные из Redis
const cachedUser = await fetch('/api/users/1'); // <1ms
// Медленнее — данные из PostgreSQL
const user = await fetch('/api/users/complex-query'); // 50-100ms
// Поиск — из Elasticsearch
const searchResults = await fetch('/api/search?q=react'); // 10-50ms
Frontend может заметить разницу:
const loadPostsNormalWay = async () => {
// Читает с реплик или кэша
const response = await fetch('/api/posts'); // Быстро
return response.json();
};
const loadPostsComplexQuery = async () => {
// Сложный запрос к основной БД
const response = await fetch('/api/posts/analytics'); // Медленнее
return response.json();
};
Почему это важно для frontend разработчика
1. Понимание performance bottlenecks:
Если API медленный, возможно:
- Нет кэша (Redis)
- Запрос идёт на основную БД вместо реплики
- Нет индекса (Elasticsearch)
2. Правильное кэширование на клиенте:
// Часто меняется → кэшируем на 1 сек
const recentPosts = useQuery(['posts'], fetchPosts, {
staleTime: 1000
});
// Редко меняется → кэшируем на 1 час
const user = useQuery(['user'], fetchUser, {
staleTime: 3600000
});
3. Выбор инструментов для frontend:
// Если backend использует Redis для real-time:
const subscribe = () => {
const ws = new WebSocket('wss://api.example.com/ws');
ws.onmessage = handleUpdate;
};
// Если backend использует Event Sourcing:
const [optimisticUpdate, setOptimisticUpdate] = useState(null);
// Нужен optimistic update т.к. обработка может занять время
Вывод
Frontend разработчику нужно понимать, что:
- Несколько БД в backend = оптимизация, но не меняет API
- API скрывает сложность — frontend просто вызывает endpoints
- Понимание архитектуры помогает оптимизировать frontend — кэширование, debouncing, request batching
- Performance зависит от backend выбора БД — frontend не может влиять, но может компенсировать задержки
Важно знать почему backend выбирает несколько БД, но реально работать с ними не нужно.