Ответ
Да, это стандартный и очень распространенный паттерн в распределенных системах, который называется Primary-Replica (или Master-Slave). Он позволяет масштабировать нагрузку и повысить отказоустойчивость.
Основной принцип:
- Запись (Write): Все операции записи (
INSERT
,UPDATE
,DELETE
) направляются на один узел — Primary (мастер). Это гарантирует консистентность данных. - Репликация: Primary асинхронно или синхронно копирует (реплицирует) изменения на один или несколько других узлов — Реплики (slaves/secondaries).
- Чтение (Read): Операции чтения (
SELECT
) могут быть распределены между репликами. Это снимает нагрузку с Primary и позволяет обрабатывать гораздо больше запросов на чтение.
Ключевой компромисс: Производительность vs. Консистентность
Из-за того, что репликация занимает время (даже миллисекунды), возникает лаг репликации. Это означает, что данные, только что записанные в Primary, могут быть еще не доступны на реплике. Этот эффект называется Eventual Consistency (согласованность в конечном счёте).
Пример реализации на Go с MongoDB:
В MongoDB можно указать Read Preference
(предпочтение чтения), чтобы направить запрос на реплику.
import (
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
// Запись всегда идет в Primary шард по умолчанию
_, err := client.Database("test").Collection("users").InsertOne(ctx, user)
if err != nil { /* обработка ошибки */ }
// Чтение можно направить на Secondary (реплику)
// Это снизит нагрузку на основной узел
opts := options.Find().SetReadPreference(readpref.SecondaryPreferred())
cursor, err := client.Database("test").Collection("users").Find(ctx, bson.M{}, opts)
Что необходимо учитывать:
- Лаг репликации: Критически важные данные сразу после записи лучше читать с Primary, чтобы избежать получения устаревшей информации (проблема
read-your-writes
). - Балансировка нагрузки: Нужен механизм (часто встроенный в драйвер или прокси) для распределения запросов на чтение между доступными репликами.
- Отказоустойчивость: Система должна уметь обрабатывать отказ Primary (выбрать новую Primary из реплик) или отказ реплики (исключить ее из ротации).