Демистифицирање на репликацијата на бази на податоци: Стратегии за отпорни системи
Репликацијата на бази на податоци звучи едноставно сè додека првиот инцидент во продукција не наметне потешко прашање: што всушност значи „ажурно“? Втора копија на податоците може да ја заштити достапноста, да ги подобри перформансите при читање и да поддржи обновување. Но, може и тивко да испорачува застарени резултати, да ја умножи оперативната сложеност и да претвори краткотраен мрежен проблем во дефект на целата апликација.
Корисниот начин да се размислува за репликацијата не е како за поле за штиклирање во конзолата на базата на податоци. Таа е збир на компромиси во врска со конзистентноста, латентноста, префрлањето при дефект и видовите грешки што вашиот систем може безбедно да ги толерира.
Репликацијата има различни задачи
Пред да изберете топологија, именувајте го проблемот што таа мора да го реши. „Ни требаат реплики“ е премногу нејасно за да доведе до сигурен дизајн.
- Скалирање на читањата: распределете го сообраќајот со многу читања, така што еден примарен сервер не е одговорен за секое барање.
- Висока достапност: задржете копија што може да се промовира кога тековниот сервер за запишување станува недостапен.
- Обновување по катастрофа: чувајте ги податоците во одделен домен на дефект, често со намерно растојание или доцнење.
- Изолација за известување: заштитете ги трансакциските оптоварувања од скапи аналитички барања.
Една реплика понекогаш може да служи за повеќе од една намена, но комбинирањето улоги го зголемува влогот. Работно оптоварување за известување што го преоптоварува единствениот кандидат за префрлање при дефект не е отпорен дизајн. Каде што ризикот го оправдува тоа, одвојте ги оперативните реплики од репликите за известување или обновување.
Намерно изберете го моделот на конзистентност
Повеќето познати конфигурации примарен сервер-реплика ги реплицираат промените асинхроно. Примарниот сервер го потврдува запишувањето, му одговара на клиентот, а репликите ја применуваат таа промена подоцна. Ова ја одржува ниска латентноста на запишувањата, но создава доцнење во репликацијата: читање испратено веднаш до реплика можеби нема да види успешно запишување.
Тоа е прифатливо за многу екрани. Каталог на производи, довод на активности или контролна табла често можат да толерираат кратко доцнење. Опасно е за тек што потврдува плаќање, менува дозвола на сметка или го прикажува резултатот од ажурирање што истиот корисник штотуку го направил.
Класичниот симптом е грешка read-after-write:
$orderId = $orders->create($payload);
// A replica may not have applied the new row yet.
$order = $replicaConnection->findOrder($orderId);
Практично решение е читањата по запишување да се насочуваат кон примарниот сервер во краток, изречно дефиниран период, или додека не заврши границата на барањето. Друга опција е новосоздадениот запис да се прочита од примарниот сервер и да се врати директно. Важниот дел е правилото да биде видливо во архитектурата на апликацијата, наместо да се надевате дека никогаш нема да има доцнење.
Синхроната репликација може да го намали ризикот потврдените запишувања да отсуствуваат од реплика, но додава латентност и може да ја намали достапноста кога репликите се бавни или недостапни. Таа не е автоматски „подобра“. Соодветна е само кога деловната операција ја бара таа посилна гаранција и системот може да си ја дозволи нејзината оперативна цена.
Одржувајте ги запишувањата едноставни
Наједноставната отпорна топологија обично има еден авторитативен записувач во исто време. Апликациите испраќаат запишувања до тој примарен сервер и ги насочуваат подобните читања до реплики. Ова ги избегнува конфликтите при запишување и ја олеснува анализата на семантиката на трансакциите.
Дизајните со повеќе примарни сервери или повеќе записувачи може да бидат валидни, особено кога запишувањата мора да се прифатат на повеќе локации. Но, тие бараат изречно справување со конфликти, правила за генерирање клучеви и јасен одговор за тоа што се случува кога два јазли го менуваат истиот логички запис. Ако апликацијата нема добро дефинирана политика за спојување, топологијата на базата на податоци не може безбедно да измисли таква.
Почнете со еден записувач освен ако реално барање на производот не налага поинаку. Скалирањето на читањата е релативно едноставно; усогласувањето конфликтни запишувања не е.
Направете го насочувањето политика, а не расфрлани услови
Во PHP апликација, изборот на база на податоци треба да постои зад мала граница што може да се тестира. Контролерите и доменските услуги не треба самостојно да одлучуваат дали едно барање „изгледа безбедно“ за реплика. Тоа создава неконзистентно однесување при инциденти и ги поскапува идните промени.
final class ConnectionRouter
{
public function forRead(bool $requiresFreshData): Connection
{
return $requiresFreshData
? $this->primary
: $this->replica;
}
public function forWrite(): Connection
{
return $this->primary;
}
}
Точната интеграција со рамката ќе варира, но политиката треба да биде стабилна: запишувањата го користат примарниот сервер; читањата чувствителни на свежина го користат примарниот сервер; читањата од реплика се користат само таму каде што се прифатливи застарени податоци. Ако апликацијата користи трансакции, чувајте ги сите барања што учествуваат во трансакција на истата примарна врска. Разделувањето на трансакција меѓу јазли ја поништува причината за постоење на трансакцијата.
Планирајте за дефект на реплика
Репликата треба да биде опционална за достапноста, а не нова единствена точка на дефект. Ако реплика за читање е недостапна, многу системи треба да се вратат на примарниот сервер, со прекинување на колото или привремени промени во насочувањето за да се избегнат повторени бавни обиди за поврзување. Ова враќање жртвува капацитет за точност и континуитет, што обично е правилната размена при делумен прекин.
Не обидувајте се тивко повторно да извршите произволни запишувања на друг сервер. Истекувањето на времето не докажува дека првичното запишување не успеало. Повторувањето може да создаде дупликати, освен ако операцијата не е дизајнирана да биде идемпотентна. Користете единствени идентификатори на барања, трајни записи за идемпотентност каде што е потребно и јасно справување со грешки околу двосмислените исходи.
Префрлањето при дефект е процес, а не настан
Промовирањето реплика го менува изворот на вистина на системот. Веродостоен план за префрлање при дефект бара повеќе од команда што ги менува улогите. Потребен е начин да се запре или ограничи стариот примарен сервер, да се ажурира поврзувањето на апликацијата, да се потврди дека новиот примарен сервер прифаќа запишувања и да се спречи split brain, каде два јазли прифаќаат конфликтни запишувања.
Вашиот прирачник за постапување треба да одговори на практични прашања:
- Како се открива дефект на примарниот сервер и кому или на што му е дозволено да промовира замена?
- Како се спречуваат запишувања на поранешниот примарен сервер пред тој да се врати?
- Како апликациите ја откриваат крајната точка на новиот записувач?
- Кој прозорец на загуба на податоци е можен со асинхрона репликација?
- Како поправениот јазол повторно се приклучува и се проверува?
Автоматизацијата помага, но не ја отстранува потребата од овие одлуки. Автоматското префрлање при дефект без ограничување може побрзо да произведе неконзистентни податоци. Тестирајте го прирачникот во изолирана околина и извежбајте го однесувањето на апликацијата, не само промената на улогата во базата на податоци.
Следете ги сигналите што ги менуваат одлуките
Зелена проверка на процесот не е доволна. Следете го доцнењето на репликацијата, грешките во репликацијата, заситеноста на врските, капацитетот на дискот, латентноста на барањата и здравјето на преносот на репликацијата. Алармирањето треба да прави разлика меѓу реплика што накратко заостанува и реплика што целосно престанала да применува промени.
Доцнењето заслужува и видливост на ниво на апликација. Ако услуга ветува свежи податоци, но нејзината политика за насочување ги испраќа тие читања до реплики, само инфраструктурните метрики нема да го откријат прекршениот договор. Инструментирајте која класа на врска обработила важни барања, особено околу запишувања, автентикација, салда, залихи и дозволи.
Отпорноста произлегува од изречни граници
Репликацијата е моќна затоа што му овозможува на системот да продолжи кога поединечни машини, мрежи или работни оптоварувања откажуваат. Нејзината цена е тоа што повеќе не постои една моментално идентична копија на реалноста насекаде. Добриот backend дизајн отворено го признава тој факт.
Дефинирајте кои читања може да бидат застарени, задржете еден јасен авторитет за запишување, третирајте го префрлањето при дефект како извежбан работен тек и направете ги правилата за насочување дел од дизајнот на апликацијата. Кога тие граници се изречни, репликацијата престанува да биде магија на базата на податоци и станува тоа што треба да биде: сигурна инженерска алатка за градење системи што се виткаат под стрес без да се скршат.