Перейти к содержимому

NoSQL и поисковые движки в Go

Зачем знать: Не все данные подходят под реляционную модель. Документы, time-series, full-text search, analytics — для каждого свой инструмент. На уровне Middle 2 ты должен знать, когда выбрать MongoDB вместо Postgres, чем Cassandra отличается от ScyllaDB, для чего нужен ClickHouse и Elasticsearch, и иметь представление о российской экосистеме: Tarantool, YDB. Это знание определяет, придёшь ты в команду с правильным выбором БД или будешь воевать с неподходящим инструментом.

  1. Когда NoSQL вместо SQL
  2. MongoDB
  3. Cassandra и ScyllaDB
  4. ClickHouse
  5. Elasticsearch / OpenSearch
  6. Tarantool
  7. YDB (Yandex Database)
  8. Gotchas
  9. Production-практики
  10. Вопросы для собеседования
  11. Practice
  12. Источники

  1. Schema flexibility — данные имеют разную структуру, schema эволюционирует часто.
  2. Scale-out — горизонтальное масштабирование через sharding из коробки.
  3. High throughput — миллионы writes/sec.
  4. Specialized workloads — analytics, search, time-series.
  5. Low latency reads — key-value, in-memory.
  • Бизнес-логика с транзакциями (банк, ERP) — Postgres.
  • ACID требуется — Postgres.
  • Сложные ad-hoc queries и JOIN’ы — Postgres.
  • Маленький проект (≤10M записей) — Postgres хватит.
  • “Хочу хайпово” — Postgres.

Postgres 2026 поддерживает почти всё: JSONB (документы), pgvector (вектора), TimescaleDB extension (time-series), Citus (sharding), FTS (поиск). Часто это лучше отдельной БД.

Use caseЛучший инструмент
Гибкая схема, документыMongoDB
Write-heavy, time-series, IoTCassandra / ScyllaDB
Analytics OLAP, observability backendClickHouse
Full-text search, log searchElasticsearch / OpenSearch
In-memory + scriptingTarantool / Redis
Russian cloud, distributed SQLYDB
Vector search (AI/RAG)pgvector / Weaviate / Qdrant
Graph dataNeo4j / Dgraph
CacheRedis / Memcached / Tarantool
GeoPostGIS / MongoDB geo / Elasticsearch geo

Document-oriented: данные хранятся как JSON-подобные BSON документы.

{
"_id": ObjectId("..."),
"username": "alice",
"email": "alice@example.com",
"preferences": {
"theme": "dark",
"language": "ru"
},
"tags": ["admin", "power-user"],
"lastLogin": ISODate("2026-05-21T10:30:00Z")
}
  • DatabaseCollection (≈ table) → Document (≈ row).
  • No schema enforced (но можно с validator).
  • Sharding и replica sets — native.

Официальный драйвер: go.mongodb.org/mongo-driver/v2.

import (
"context"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/bson"
)
ctx := context.Background()
client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
coll := client.Database("shop").Collection("users")
// Insert
type User struct {
ID bson.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
Email string `bson:"email"`
Tags []string `bson:"tags"`
}
u := User{Name: "Alice", Email: "alice@x.com", Tags: []string{"admin"}}
res, err := coll.InsertOne(ctx, u)
// Find by filter
filter := bson.M{"tags": "admin"}
cursor, err := coll.Find(ctx, filter)
defer cursor.Close(ctx)
var users []User
if err := cursor.All(ctx, &users); err != nil {
log.Fatal(err)
}
// Update
_, err = coll.UpdateOne(ctx,
bson.M{"_id": id},
bson.M{"$set": bson.M{"tags": []string{"admin", "vip"}}},
)

bson.M vs bson.D:

  • bson.M — map (unordered).
  • bson.D — ordered slice. Нужно, когда порядок важен (aggregation pipeline, sort).

Mongo-specific query language:

pipeline := bson.A{
bson.D{{"$match", bson.M{"status": "active"}}},
bson.D{{"$group", bson.M{
"_id": "$country",
"total": bson.M{"$sum": 1},
}}},
bson.D{{"$sort", bson.M{"total": -1}}},
bson.D{{"$limit", 10}},
}
cursor, err := coll.Aggregate(ctx, pipeline)

Похоже на SQL:

SELECT country, COUNT(*) AS total
FROM users WHERE status = 'active'
GROUP BY country ORDER BY total DESC LIMIT 10;
import "go.mongodb.org/mongo-driver/v2/mongo"
// Single field
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"email", 1}},
Options: options.Index().SetUnique(true),
})
// Compound
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"country", 1}, {"createdAt", -1}},
})
// Text
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"name", "text"}, {"description", "text"}},
})
// Geo (2dsphere)
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"location", "2dsphere"}},
})
// Partial
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"email", 1}},
Options: options.Index().SetPartialFilterExpression(bson.M{"verified": true}),
})
// TTL
coll.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{"createdAt", 1}},
Options: options.Index().SetExpireAfterSeconds(86400), // 1 day
})

Sharding key — выбирается per-collection. Документы распределяются по шардам по key.

Виды:

  • Range sharding — диапазоны (lastName A-D, E-K, L-R, S-Z).
  • Hashed sharding — хеш от key. Равномерное распределение.
  • Zone sharding — данные привязаны к локациям (например, EU users в EU shards).

⚠️ Sharding key выбирается раз и навсегда. Поменять — болезненно (export/import).

Стандартный setup: 3 узла (1 primary + 2 secondary).

Primary ←─ writes
├─── replication ───► Secondary 1
└─── replication ───► Secondary 2

Read preferences:

  • primary (default) — strong consistency.
  • secondary — eventual.
  • nearest — ближайший.

В Go:

opts := options.Client().ApplyURI("mongodb://r1,r2,r3/?replicaSet=rs0").
SetReadPreference(readpref.SecondaryPreferred())

MongoDB 4.0+ поддерживает multi-document транзакции.

sess, err := client.StartSession()
defer sess.EndSession(ctx)
err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
if err := sess.StartTransaction(); err != nil {
return err
}
if _, err := coll1.InsertOne(ctx, doc1); err != nil {
sess.AbortTransaction(ctx)
return err
}
if _, err := coll2.UpdateOne(ctx, filter, update); err != nil {
sess.AbortTransaction(ctx)
return err
}
return sess.CommitTransaction(ctx)
})

⚠️ Транзакции в Mongo — медленные (overhead replica set coordination). Используй только когда реально нужно. Часто можно перепроектировать (denormalize в один документ).

Каталог товаров — каждый product имеет разные attributes. ✓ Профили пользователей — гибкая структура. ✓ CMS — статьи с разным набором полей. ✓ Logs (если не Elastic) — JSON-ish структура. ✗ Финансовые транзакции (medium fit; лучше Postgres). ✗ Heavy analytics (использовать ClickHouse).


Wide-column store (Bigtable-style). Данные хранятся в “wide rows” с миллионами колонок.

Cassandra — open source (Facebook → Apache). ScyllaDB — rewrite на C++, drop-in replacement, в разы быстрее.

Особенности:

  • No master: peer-to-peer (кольцо узлов).
  • Tunable consistency на уровне запроса.
  • High write throughput (LSM-tree).
  • Linear scaling — добавил узлы → пропорционально больше throughput.
Node 1
/ \
Node 4 Node 2
\ /
Node 3

Каждый узел отвечает за диапазон hash значений (token range). Данные реплицируются на N узлов (replication factor).

Уровни:

  • ONE — записать на 1 replica, ответить.
  • QUORUM — большинство ((RF/2) + 1).
  • LOCAL_QUORUM — большинство в локальном DC.
  • ALL — все replicas.

Strong consistency при чтении: R + W > RF.

  • RF=3, W=QUORUM=2, R=QUORUM=2 → strong.
  • RF=3, W=1, R=1 → eventual (быстро, но stale).
import "github.com/gocql/gocql"
cluster := gocql.NewCluster("node1", "node2", "node3")
cluster.Keyspace = "myks"
cluster.Consistency = gocql.Quorum
cluster.ProtoVersion = 4
session, err := cluster.CreateSession()
defer session.Close()
// Insert
err := session.Query(
`INSERT INTO users (id, name, email) VALUES (?, ?, ?)`,
gocql.TimeUUID(), "Alice", "alice@x.com",
).Exec()
// Select
var name string
err := session.Query(
`SELECT name FROM users WHERE id = ?`, id,
).Scan(&name)
// Iterate
iter := session.Query(`SELECT id, name FROM users WHERE country = ?`, "KZ").Iter()
defer iter.Close()
var id gocql.UUID
var n string
for iter.Scan(&id, &n) {
log.Println(id, n)
}

Похож на SQL, но с ограничениями:

  • Нет JOIN.
  • Нет subquery.
  • WHERE только по primary key (или indexed columns с warnings).
CREATE KEYSPACE myks WITH REPLICATION = {
'class': 'NetworkTopologyStrategy',
'dc1': 3
};
CREATE TABLE users (
country TEXT,
user_id UUID,
name TEXT,
email TEXT,
created_at TIMESTAMP,
PRIMARY KEY ((country), user_id)
);
CREATE TABLE user_events (
user_id UUID,
event_time TIMESTAMP,
event_type TEXT,
data TEXT,
PRIMARY KEY ((user_id), event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);
PRIMARY KEY ((partition_key), clustering_col1, clustering_col2)
  • Partition key — определяет, в какой shard едут данные.
  • Clustering columns — порядок внутри partition.

Запросы должны всегда включать partition key (иначе ALLOW FILTERING — медленно и опасно).

В отличие от RDBMS, в Cassandra схема дизайнится под query. Денормализация — норма.

Пример: для запроса “все orders пользователя по дате” и “все orders в стране” — нужны две таблицы:

CREATE TABLE orders_by_user (
user_id UUID,
order_id UUID,
created_at TIMESTAMP,
total DECIMAL,
PRIMARY KEY ((user_id), created_at, order_id)
);
CREATE TABLE orders_by_country (
country TEXT,
order_date DATE,
order_id UUID,
user_id UUID,
total DECIMAL,
PRIMARY KEY ((country, order_date), order_id)
);

Дублирование данных = ОК.

DELETE в Cassandra = записать tombstone (маркер удаления). Реальное удаление — при compaction.

⚠️ Проблема tombstones: если много DELETE → много tombstones → медленные SELECT (нужно их фильтровать). Особенно в очередях/queues.

Антипаттерн: использовать Cassandra как очередь.

АспектCassandraScyllaDB
ЯзыкJavaC++
ThroughputБазовый5-10x выше
LatencyБазовыйСтабильнее (нет GC pauses)
СовместимостьAPI compatible (CQL, drivers)
Resource usageВысокий (JVM)Низкий

ScyllaDB — drop-in замена. Если у тебя есть Cassandra — переход относительно прямолинейный.

Time-series (метрики, логи) — IoT, monitoring. ✓ Write-heavy workloads — events, audit logs. ✓ Global apps с DC-aware replication. ✓ Big data (петабайты). ✗ Сложные queries — нет JOIN, GROUP BY. ✗ Очередь / queue. ✗ Финансовая ACID-логика.


Column-oriented analytical OLAP database. Создан Яндексом, open source.

  • Данные хранятся по колонкам (а не по строкам как в OLTP).
  • Compression — отличный (10-100x).
  • Aggregations — очень быстрые (миллиарды строк за секунды).
  • Vector engine (SIMD).
  • Не для OLTP: одиночные INSERT медленные, нет ACID транзакций, плохо с UPDATE/DELETE.

MergeTree — главный engine family.

  • Данные пишутся в parts (отдельные файлы).
  • Background — merge parts (а-ля LSM).
  • Каждая колонка — отдельный файл (column-oriented).
CREATE TABLE events (
ts DateTime,
user_id UInt64,
event_type LowCardinality(String),
properties String,
revenue Decimal(10, 2)
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(ts)
ORDER BY (user_id, ts);

PARTITION BY — обычно по дате (месяц/день). Старые partitions можно DROP PARTITION. ORDER BY — primary key (data sorted on disk). Влияет на запросы (диапазоны быстры по prefix).

Два варианта:

  • github.com/ClickHouse/clickhouse-go (v2) — официальный, native protocol.
  • github.com/mailru/go-clickhouse — HTTP, проще.
import "github.com/ClickHouse/clickhouse-go/v2"
conn, err := clickhouse.Open(&clickhouse.Options{
Addr: []string{"localhost:9000"},
Auth: clickhouse.Auth{Database: "default"},
})
// Batch insert (NEVER одиночные INSERT!)
batch, err := conn.PrepareBatch(ctx, "INSERT INTO events")
for _, e := range events {
batch.Append(e.Ts, e.UserID, e.EventType, e.Props, e.Revenue)
}
batch.Send()
// Query
rows, _ := conn.Query(ctx, `
SELECT toStartOfHour(ts) AS hour, count() AS n
FROM events
WHERE ts >= now() - INTERVAL 1 DAY
GROUP BY hour ORDER BY hour
`)

ClickHouse оптимизирован для больших батчей (10K-1M rows per insert).

⚠️ Антипаттерн: вставлять по 1 row в INSERT. Каждый INSERT создаёт parts → merge не справляется.

Решение: накапливать batch’ами (Kafka → consumer → batched insert каждые 10 сек или 100K rows).

Pre-computed aggregations. Обновляются на каждый INSERT (incremental).

CREATE MATERIALIZED VIEW events_daily
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, event_type)
AS
SELECT
toDate(ts) AS date,
event_type,
count() AS events_count,
sum(revenue) AS total_revenue
FROM events
GROUP BY date, event_type;

Запросы к events_daily — мгновенные.

Sharding через несколько ClickHouse узлов:

-- На каждом узле — local table
CREATE TABLE events_local ON CLUSTER mycluster (
...
) ENGINE = MergeTree() ...;
-- Distributed table — view над local'ами
CREATE TABLE events ON CLUSTER mycluster AS events_local
ENGINE = Distributed(mycluster, default, events_local, rand());

INSERT в events — распределяется по узлам. SELECT — выполняется на всех и aggregates.

Analytics (BI, dashboards). ✓ Observability backend (metrics, traces, logs) — see Quickwit, SigNoz. ✓ Time-series. ✓ Real-time analytics. ✗ OLTP (не для transactional). ✗ Frequent updates.

В России — стандартный выбор для аналитики (Яндекс, VK, Tinkoff).


Full-text search engine на основе Lucene. Хранит документы, индексирует по терминам, ищет по relevance.

OpenSearch — fork от Amazon после ES license change. API-совместим.

  • Index ≈ table (collection of documents).
  • Document — JSON.
  • Shard — горизонтальное partitioning (primary + replicas).
  • Node — узел кластера.
  • Mapping — schema (типы полей, analyzers).
PUT /products
{
"mappings": {
"properties": {
"name": { "type": "text", "analyzer": "russian" },
"description": { "type": "text" },
"price": { "type": "double" },
"tags": { "type": "keyword" },
"created_at": { "type": "date" }
}
}
}
  • text — full-text indexed.
  • keyword — exact match (для фильтров, sort, agg).
  • date, integer, double — типизированы.
import "github.com/elastic/go-elasticsearch/v8"
es, err := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{"http://localhost:9200"},
})
// Index document
doc := map[string]interface{}{
"name": "iPhone 15",
"price": 999,
"tags": []string{"electronics", "phone"},
}
body, _ := json.Marshal(doc)
res, err := es.Index(
"products",
bytes.NewReader(body),
es.Index.WithDocumentID("1"),
)
// Search
query := `{
"query": {
"bool": {
"must": [
{"match": {"name": "iPhone"}},
{"range": {"price": {"lte": 1500}}}
]
}
}
}`
res, err = es.Search(
es.Search.WithIndex("products"),
es.Search.WithBody(strings.NewReader(query)),
)

Альтернатива: olivere/elastic (typed API, более популярная).

{
"query": {
"bool": {
"must": [
{"match": {"description": "smartphone"}},
{"range": {"price": {"gte": 100, "lte": 1000}}}
],
"filter": [
{"term": {"category": "electronics"}}
],
"should": [
{"match": {"tags": "new"}}
]
}
},
"sort": [
{"price": "asc"}
],
"from": 0,
"size": 20
}
  • must — обязательное условие (влияет на score).
  • filter — фильтр (без score, кэшируется).
  • should — optional, boost score.
{
"aggs": {
"by_category": {
"terms": {"field": "category", "size": 10},
"aggs": {
"avg_price": {"avg": {"field": "price"}}
}
}
}
}
{
"settings": {
"analysis": {
"analyzer": {
"russian_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "russian_morphology", "russian_stop"]
}
}
}
},
"mappings": {
"properties": {
"title": {"type": "text", "analyzer": "russian_analyzer"}
}
}
}

Plugin analysis-morphology для русской морфологии.

Site search (e-commerce, content). ✓ Logs (ELK / Elastic stack). ✓ APM / observability. ✓ Geo search. ✓ Vector search (с 8.x). ✗ Не для primary storage (нет ACID, всё в JSON).

  • Кушает RAM (off-heap для Lucene + heap для JVM).
  • Тяжёлые updates (re-index segment).
  • Не CP — eventual consistency.
  • Сложные ops (cluster recovery, shard balancing).

In-memory DB + application server + queue + cache в одном. Российская разработка (Mail.ru/VK).

  • Lua-based scripting (можно писать функции и хранимые процедуры в Lua).
  • Async network I/O (fiber-based).
  • Replication, sharding (vshard).
  • Disk-based mode для durability.

Tarantool аналог table = space.

box.schema.space.create('users')
box.space.users:format({
{name='id', type='unsigned'},
{name='name', type='string'},
{name='email', type='string'},
})
box.space.users:create_index('primary', {parts={'id'}})
box.space.users:create_index('email', {parts={'email'}, unique=true})
-- Insert
box.space.users:insert{1, 'Alice', 'alice@x.com'}
-- Select
local u = box.space.users:get(1)
import "github.com/tarantool/go-tarantool/v2"
conn, err := tarantool.Connect("localhost:3301", tarantool.Opts{
User: "guest",
})
// Insert
_, err = conn.Insert("users", []interface{}{1, "Alice", "alice@x.com"})
// Select
resp, err := conn.Select("users", "primary", 0, 1, tarantool.IterEq, []interface{}{1})
// Call stored procedure
resp, err := conn.Call("myproc", []interface{}{"arg1", 42})

Cartridge — framework для кластера. TDG (Tarantool Data Grid) — enterprise решение для микросервисов.

Кэш + storage (вместо Redis + Postgres). ✓ Сессии. ✓ Высоконагруженные сервисы в финтехе (Tinkoff, VK, Mail.ru, Sber). ✓ Queue (через queue модуль). ✗ Сложные queries. ✗ Big data analytics.


Distributed SQL database от Yandex. Open source.

  • Сильная consistency (Multi-Raft consensus).
  • Distributed transactions across shards (Calvin-like).
  • SQL (YQL — variant), API близок к Postgres.
  • Используется в Yandex Cloud, Yandex Search, Yandex.Metrica.
  • Tablet-based (single-shard primitives).
  • Distributed coordinator.
  • Auto-sharding по primary key.
  • Replication factor 3.
CREATE TABLE users (
id Uint64,
email Utf8,
name Utf8,
PRIMARY KEY (id)
);
UPSERT INTO users (id, email, name) VALUES
(1, 'alice@x.com', 'Alice'),
(2, 'bob@x.com', 'Bob');
SELECT * FROM users WHERE id BETWEEN 1 AND 100;
import "github.com/ydb-platform/ydb-go-sdk/v3"
db, err := ydb.Open(ctx, "grpcs://endpoint/?database=/ru-central1/db", ydb.WithAccessTokenCredentials(token))
defer db.Close(ctx)
err = db.Table().Do(ctx, func(ctx context.Context, s table.Session) error {
_, _, err := s.Execute(ctx, table.DefaultTxControl(),
"SELECT * FROM users WHERE id = $id",
table.NewQueryParameters(
table.ValueParam("$id", types.Uint64Value(1)),
),
)
return err
})

Yandex Cloud managed services. ✓ High-scale OLTP в РФ. ✓ Когда нужен distributed SQL с strong consistency.

В 2026 — конкурирует с CockroachDB и Spanner.


BSON shop поддерживает больше типов (ObjectID, Decimal128, Date). При marshalling/unmarshalling в Go — использовать bson tag, а не json.

type User struct {
ID bson.ObjectID `bson:"_id,omitempty" json:"id"`
Email string `bson:"email" json:"email"`
}

Выбран неправильно — миграция через export/import. Поэтому 10x подумать.

Если ты дизайнишь как RDBMS — нормализуешь — будет тормозить. Денормализация + одна таблица на запрос.

Если запрос без partition key — Cassandra ругается. Можно ALLOW FILTERING — но это значит full scan. Никогда в production.

Используешь Cassandra как очередь? DELETE → tombstones → читать всё медленнее. Не делай.

INSERT INTO ... VALUES (...) по 1 row — убивает performance. Батчи 10K+. Использовать buffer engines или kafka engine.

ALTER TABLE ... DELETE WHERE ... — медленный (mutation). Использовать только в редких случаях. Дизайн без updates.

Изменить mapping существующего поля — почти нельзя. Создать новый index → reindex → swap alias.

JVM heap не > 32 GB (compressed OOPs). Остальное — для off-heap (Lucene). Memory tuning — сложная тема.

При network partition — несколько nodes могут думать, что они master. Quorum-based master election (discovery.zen.minimum_master_nodes — устарело, теперь автоматически).

Avoid $where queries — выполняются JS engine. Лучше — aggregation pipeline.

Если данных больше RAM — vinyl engine (LSM, на диске). Memtx (in-memory) — fastest, но capacity limited.

Stored procedures на Lua. Команда должна это знать. Иначе — лимит логики на клиенте.

Документация мейнли русская. Сообщество меньше, чем у Postgres. Tooling (мониторинг, миграции) — exists but newer.

В большинстве случаев — приложение должно делать “JOIN” в коде. Денормализация — стандартный подход.

После INSERT не сразу видно в reads с другого реплики. UI должен это учитывать (optimistic update, retry).

Если sharding key плохой → один shard перегружен.

Пример Cassandra:

PARTITION KEY ((day)) -- сегодняшний день = все на одном узле!

Решение: composite partition key — (day, hour) или hash bucketing.

Очень болезненно. Лучше выбрать правильно с начала.

Иногда возможно через dual-write phase:

  • Сейчас все читают из Postgres.
  • Начинаем писать в Postgres + Mongo.
  • Backfill старых данных.
  • Постепенно переключаем reads на Mongo.
  • Останавливаем write в Postgres.

  • MongoDB: mongodump / Ops Manager. Continuous backup через oplog tailing.
  • Cassandra: nodetool snapshot + filesystem copy. Опять snapshots + incremental.
  • ClickHouse: BACKUP TABLE (с 22.4+) или filesystem snapshots.
  • Elasticsearch: snapshots в S3 / GCS через snapshot API.
  • Tarantool: snapshots (.snap files) + xlogs.
БДTool
MongoDBmongo-exporter + Prometheus, Atlas (managed)
Cassandrajmx_exporter + Prometheus, Datastax tools
ClickHouseclickhouse_exporter, system.metrics
Elasticsearchelasticsearch_exporter, X-Pack
Tarantoolmetrics module

Cassandra: RF=3, 70% disk usage — пора добавлять узлы.

ClickHouse: партиция > 1 TB — пора шардировать.

MongoDB: working set должен помещаться в RAM (для hot data).

Elasticsearch: 20-40 GB на shard. Heap = 50% RAM, max 32 GB.

  • Cassandra: NetworkTopologyStrategy с DC-aware. LOCAL_QUORUM для writes.
  • MongoDB: Replica set across DCs + read preferences. Atlas — managed cross-region.
  • ClickHouse: replicated tables + ZooKeeper.
  • YDB: cross-region — natively (если регионы поддерживают).
  • TLS in transit (ВСЕГДА в production).
  • Authentication: SCRAM, x509, LDAP/Kerberos integration.
  • Authorization: roles, fine-grained permissions.
  • Encryption at rest (FDE, или встроенный TDE в Enterprise).
  • Network: VPC, IP whitelist, firewall.
  • Audit log.

⚠️ Известный антипаттерн: MongoDB/Elastic без auth на публичном IP → ransomware. Регулярно появляется в новостях.

PairWhen AWhen B
MongoDB vs Postgres JSONBHeavy denormalized docs, high write QPSНужен ACID, joins, mixed workload
Cassandra vs ScyllaDBСуществующий ecosystem, дешевле hostingLatency critical, throughput
Elasticsearch vs OpenSearchEnterprise features, MLOpen source без vendor lock-in (Amazon)
ClickHouse vs Druid/PinotRealtime + ad-hoc queryOLAP-only realtime
Tarantool vs RedisСтейтфул логика + persistencePure cache
YDB vs CockroachDBYandex CloudGlobal ecosystem, AWS/GCP
  1. Identify use case fit (use right tool).
  2. Dual-write phase: писать в обе.
  3. Backfill historic data.
  4. Verify consistency.
  5. Switch reads gradually (canary).
  6. Switch writes.
  7. Decommission old.

Не делать “big bang” миграцию.

  • Cold storage tiering: старые данные в S3 / archive.
  • Compression: ZSTD в ClickHouse — экономия места.
  • TTL: автоматическое удаление (MongoDB TTL index, Cassandra TTL).
  • Right-sizing: managed services часто overprovision.

В Go все драйверы имеют встроенный пул:

  • mongo-go-drivermaxPoolSize в URI.
  • gocqlNumConns.
  • clickhouse-goMaxOpenConns.
  • elastic — http client pool.

Не создавать клиента на запрос! Создавать раз и переиспользовать.

MongoDB: documents эволюционируют в коде. Версионирование через schemaVersion field. При load: если старая версия → upgrade in-place.

Cassandra: ALTER TABLE ADD COLUMN. Не удалять колонки! (старые tombstones).

Elasticsearch: re-index с alias swap.

ClickHouse: ALTER TABLE + mutations (slow).


  1. Когда NoSQL лучше SQL? Schema flexibility, scale-out требуется, specific workloads (analytics, search, time-series). НЕ для transactional CRUD с ACID.

  2. Чем MongoDB отличается от Postgres JSONB? MongoDB: native document store, sharding. Postgres JSONB: ACID, joins возможны, mixed workload. Postgres JSONB достаточен для большинства случаев.

  3. Что такое sharding key в MongoDB? Поле(я), по которому документы распределяются по shards. Выбор раз и навсегда. Bad choice = hot shard / scatter-gather queries.

  4. Какие индексы в MongoDB? Single field, compound, multikey (для arrays), text, geo (2d, 2dsphere), partial, TTL.

  5. Чем bson.M отличается от bson.D в Go? bson.M — unordered map. bson.D — ordered slice (нужно когда порядок важен: aggregation pipeline, sort).

  6. Что такое replica set в MongoDB? Кластер из primary + secondaries. Writes → primary, reads → primary или secondaries (с read preference). Auto failover.

  7. Что такое Cassandra и где её использовать? Wide-column distributed DB. Write-heavy workloads, time-series, IoT, global apps. Linear scaling.

  8. Чем ScyllaDB отличается от Cassandra? Rewrite на C++ (vs Java). 5-10x faster, lower latency (no GC). Drop-in replacement (CQL compatible).

  9. Что такое tunable consistency в Cassandra? Уровни consistency per query: ONE, QUORUM, LOCAL_QUORUM, ALL. R+W > RF → strong.

  10. Что такое partition key в Cassandra? Часть primary key, по которой строки распределяются по nodes. Все запросы должны включать partition key.

  11. Что такое tombstones и в чём проблема? DELETE = записать tombstone. При большом числе tombstones — SELECT замедляется (нужно фильтровать). Антипаттерн — Cassandra как queue.

  12. Что такое ClickHouse и где использовать? Column-oriented analytical OLAP DB. Аналитика, observability, time-series. Не OLTP.

  13. Почему ClickHouse быстрый для analytics? Column storage, compression, vector engine (SIMD), parallel execution. Aggregations миллиардов строк за секунды.

  14. Что такое MergeTree? Engine family в ClickHouse. Данные в parts, merge в background (LSM-like). PARTITION BY (обычно по дате), ORDER BY (primary key).

  15. Почему нельзя одиночные INSERT в ClickHouse? Каждый INSERT — новый part. Merge не успевает → деградация. Батчить (10K+ rows).

  16. Что такое Materialized View в ClickHouse? Pre-computed aggregation, обновляется на каждый INSERT. Запросы к ней — мгновенные.

  17. Что такое Elasticsearch? Full-text search engine на Lucene. Indices, shards, mappings, query DSL.

  18. Чем OpenSearch отличается от Elasticsearch? Fork от Amazon. API-compatible. Open source без vendor lock-in (после ES license change).

  19. Какие типы полей в Elasticsearch? text (full-text indexed), keyword (exact match), date, integer, double, geo_point, nested.

  20. Какие use cases для Elasticsearch? Site search, logs (ELK), APM, geo search, vector search. Не primary storage.

  21. Что такое Tarantool? In-memory DB + app server + queue, российская разработка. Lua scripting, fiber-based. Использует VK, Tinkoff, Mail.ru.

  22. Зачем нужен Tarantool, если есть Redis? Tarantool — full DB (с indexes, transactions, durability). Lua stored procedures. Persistent. Redis — больше cache.

  23. Что такое YDB? Distributed SQL от Яндекса. Strong consistency, auto-sharding. Yandex Cloud стандарт.

  24. Сравните YDB и CockroachDB. Оба — distributed SQL. CockroachDB — PG-compatible, global ecosystem. YDB — Yandex Cloud, российская экосистема.

  25. Как выбрать NoSQL под use case? По matrix: документы → MongoDB; write-heavy → Cassandra; analytics → ClickHouse; search → Elasticsearch; in-memory → Tarantool; Russian cloud → YDB.


Создать каталог товаров (Mongo). Endpoints: создать товар, search по name/category/price range, aggregation by category. Индексы.

ETL pipeline: events из Kafka → batched insert в ClickHouse. Materialized view: events_per_hour. Dashboard SQL queries.

Index 1M статей. Реализовать full-text search с русским анализатором. Highlight matching terms. Pagination.

Метрики (server_id, metric_name, ts, value). Partition by (server_id, day), clustering by ts. Запросы: latest N points, по диапазону.

Хранение сессий: key=session_id, value=user_data, TTL=24h. CRUD через Go.

Реализовать money transfer в MongoDB transaction. Сравнить latency с Postgres. Понять trade-offs.

В Cassandra сделать partition key = current_day. Заметить, что все writes идут на один node. Перепроектировать с composite key.

Залить 100M event’ов. Запустить SELECT COUNT, GROUP BY на обеих. Сравнить.


  1. MongoDB Documentationhttps://www.mongodb.com/docs/ (актуально для 7.0+ в 2026).
  2. Designing Data-Intensive Applications by Martin Kleppmann — главы 2-3 (data models, storage).
  3. Cassandra: The Definitive Guide by Jeff Carpenter, Eben Hewitt (3rd edition).
  4. ScyllaDB Documentationhttps://docs.scylladb.com/
  5. ClickHouse Documentationhttps://clickhouse.com/docs (русская версия отличная).
  6. Elasticsearch: The Definitive Guide + новые версии docs.
  7. Tarantool Documentationhttps://www.tarantool.io/en/doc/latest/ (есть на русском).
  8. YDB Documentationhttps://ydb.tech/docs/ru/
  9. Habr / Postgres Pro / Yandex blog — реальные production opyt на русском.
  10. Use The Index, Luke + специфичные NoSQL гайды по индексированию.