Налаштування Serverless Database (DynamoDB / PlanetScale / Neon)
Serverless база даних — це керована база, яка масштабується автоматично (включаючи до нуля), тарифікується за споживанням, а не час роботи. Оптимальний вибір залежить від моделі даних та паттернів доступу.
Порівняння варіантів
| БД | Тип | Масштаб | Найкраще для |
|---|---|---|---|
| DynamoDB | Key-value / Document | Безлімітний | Висока пропускна здатність, передбачувані запити |
| PlanetScale | MySQL-совместимий | До терабайта | Реляційні дані, GitHub-стильне розгалуження |
| Neon | PostgreSQL | Малий-середній | Повний SQL, dev окремення |
| FaunaDB | Document / Relational | Середній | Мультирегіональна консистентність |
| Upstash | Redis | Малий-середній | Кеш, черги, rate limiting |
DynamoDB: Проектування для Serverless
DynamoDB потребує думання про доступ до даних перед проектуванням схеми. Погано спроектована таблиця DynamoDB — дорога та повільна.
Single-Table Design — весь домен в одній таблиці, PK/SK кодують тип сутності:
# Схема e-commerce
# PK | SK | Дані
# USER#u123 | PROFILE | {name, email}
# USER#u123 | ORDER#o456 | {status, total, items}
# USER#u123 | ORDER#o789 | {status, total, items}
# ORDER#o456 | ITEM#i001 | {product_id, qty, price}
# PRODUCT#p001 | METADATA | {title, description}
import boto3
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('ecommerce')
def get_user_with_orders(user_id: str) -> dict:
response = table.query(
KeyConditionExpression=Key('PK').eq(f'USER#{user_id}') &
Key('SK').begins_with('ORDER#')
)
return response['Items']
def put_order(user_id: str, order: dict):
with table.batch_writer() as batch:
# Запис для user → order зв'язку
batch.put_item(Item={
'PK': f'USER#{user_id}',
'SK': f'ORDER#{order["id"]}',
**order
})
# Запис для прямого доступу по order_id
batch.put_item(Item={
'PK': f'ORDER#{order["id"]}',
'SK': 'METADATA',
'GSI1PK': f'STATUS#{order["status"]}',
'GSI1SK': order['created_at'],
**order
})
GSI (Global Secondary Index) — для альтернативних паттернів доступу (отримати всі замовлення по статусу).
DynamoDB On-Demand vs Provisioned
On-Demand: платиш за кожен read/write. Немає планування потужності. Ідеально для непередбачуваного трафіку або нових програм.
Provisioned + Auto Scaling: задаєш baseline RCU/WCU, автомасштабування при піках. Дешевше при передбачуваному навантаженню.
resource "aws_dynamodb_table" "ecommerce" {
name = "ecommerce"
billing_mode = "PAY_PER_REQUEST" # On-demand
hash_key = "PK"
range_key = "SK"
attribute {
name = "PK"
type = "S"
}
attribute {
name = "SK"
type = "S"
}
attribute {
name = "GSI1PK"
type = "S"
}
attribute {
name = "GSI1SK"
type = "S"
}
global_secondary_index {
name = "GSI1"
hash_key = "GSI1PK"
range_key = "GSI1SK"
projection_type = "ALL"
}
ttl {
attribute_name = "expires_at"
enabled = true
}
}
Neon: Serverless PostgreSQL
Neon розділяє compute та storage. Compute масштабується до нуля при неактивності, storage тарифікується за обсягом.
import psycopg2
import os
# Connection string з Neon dashboard
conn = psycopg2.connect(
os.environ['DATABASE_URL'],
# Neon рекомендує connection pooling через pgBouncer
# DATABASE_URL вже містить pooler endpoint
)
# Стандартний PostgreSQL — без специфіки SDK
with conn.cursor() as cur:
cur.execute("SELECT * FROM orders WHERE user_id = %s", (user_id,))
orders = cur.fetchall()
Branching у Neon — створити гілку БД як git гілка за секунди:
neon branches create --name feature/new-schema --parent main
# Тестувати міграцію на гілці
neon connection-string feature/new-schema
# → postgresql://user:[email protected]/neondb
# Після успішного тесту — merge в main (через стандартні міграції)
PlanetScale
MySQL-совместимий, branching database workflow, без foreign key constraints (Vitess-based):
import { connect } from '@planetscale/database'
const conn = connect({
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD
})
// HTTP-based protocol — працює з Lambda без overhead з'єднання
const results = await conn.execute(
'SELECT * FROM orders WHERE user_id = ?',
[userId]
)
PlanetScale використовує HTTP протокол замість TCP — особливо добре для Lambda без постійних з'єднань.
Connection Pooling для Lambda
Lambda створює нове з'єднання з БД при кожному cold start. При 100 паралельних Lambdas — 100 з'єднань. Це вбиває PostgreSQL/MySQL.
Рішення:
- RDS Proxy (AWS) — connection pooler перед RDS, прозорий для програми
- PgBouncer — self-hosted, перед PostgreSQL
- Neon/PlanetScale — вбудований pooling у керованому сервісі
- Prisma Accelerate — connection pooler + query cache для Prisma ORM
Графік налаштування
- DynamoDB single-table design + базові операції — 3-5 днів
- Neon / PlanetScale підключення + pooling — 1-2 дні
- Міграція існуючої БД на serverless — 5-14 днів







