У більшості вебзастосунків читань у десятки разів більше, ніж записів. Репліки дають змогу розподілити читання між кількома серверами бази, а всі записи лишити на основному (primary).
У Laravel - розділення з'єднань:
'mysql' => [
'read' => ['host' => ['10.0.0.11', '10.0.0.12']],
'write' => ['host' => ['10.0.0.10']],
'sticky' => true,
// ...
],
SELECT ідуть на репліки, усе інше - на основний сервер.
Затримка реплікації - репліка отримує зміни з запізненням: зазвичай мілісекунди, під навантаженням чи при важких запитах - секунди й більше.
Типові наслідки:
- «не бачу свого запису»: користувач зберіг профіль, сторінка після редиректу читає з репліки - і показує старі дані;
- джоба в черзі не знаходить запис: модель щойно створено на основному сервері, воркер читає з репліки, де її ще немає, -
ModelNotFoundException; - неправильні рішення: перевірка «чи вистачає залишку на складі» на застарілій репліці.
Як з цим жити:
sticky => true- якщо в поточному запиті був запис, наступні читання цього ж запиту йдуть на основний сервер;- читання з основного сервера там, де важлива свіжість: після запису, при перевірках перед зміною даних, у критичних джобах (
->useWritePdo(), окреме з'єднання); - «читати свої записи» - кілька секунд після запису користувача направляти його читання на основний сервер (позначка в сесії);
- моніторинг затримки реплікації зі сповіщеннями - і автоматичне виключення відсталої репліки з пулу.
Що репліки не вирішують:
- масштабування записів - усі записи все одно на одному сервері;
- повільні запити - запит, що займає 10 секунд, займе їх і на репліці. Спершу індекси й оптимізація.
Корисне застосування окремої репліки: важкі звіти, аналітика, бекапи - щоб вони не впливали на основний трафік.
Докладніше в документації: Laravel: з'єднання для читання й запису