Osiągnięcie zerowego czasu przestoju dotknęło tego samego problemu, ale potrzebuję porady na temat strategii, którą rozważam.
Kontekst
Aplikacja internetowa z Apache / PHP do przetwarzania po stronie serwera i MySQL DB / system plików do utrwalania.
Obecnie budujemy infrastrukturę. Cały sprzęt sieciowy będzie miał nadmiarowość, a wszystkie kable głównej sieci będą używane w połączonych parach w celu zapewnienia odporności na uszkodzenia. Serwery są konfigurowane jako pary wysokiej dostępności dla sprzętowej odporności na awarie i będą zrównoważone pod względem zarówno odporności na awarie maszyn wirtualnych, jak i ogólnej wydajności.
Moim zamiarem jest, abyśmy byli w stanie zastosować aktualizacje aplikacji bez żadnych przestojów. Bardzo się starałem, projektując infrastrukturę, aby zapewnić 100% czasu sprawności; byłoby bardzo rozczarowujące mieć 10-15 minut przestoju za każdym razem, gdy zastosowano aktualizację. Jest to szczególnie istotne, ponieważ zamierzamy mieć bardzo szybki cykl wydawania (czasami może osiągnąć jedno lub więcej wydań dziennie.
Topologia sieci
To jest podsumowanie sieci:
Load Balancer
|----------------------------|
/ / \ \
/ / \ \
| Web Server | DB Server | Web Server | DB Server |
|-------------------------|-------------------------|
| Host-1 | Host-2 | Host-1 | Host-2 |
|-------------------------|-------------------------|
Node A \ / Node B
| / |
| / \ |
|---------------------| |---------------------|
Switch 1 Switch 2
And onward to VRRP enabled routers and the internet
Uwaga: serwery DB używają replikacji master-master
Sugerowana strategia
Aby to osiągnąć, obecnie myślę o podzieleniu skryptów aktualizacji schematu DB na dwie części. Aktualizacja wyglądałaby następująco:
- Serwer WWW w węźle A jest wyłączony; ruch jest nadal przetwarzany przez serwer sieciowy w węźle B.
- Zmiany schematu przejściowego są stosowane do serwerów DB
- Serwer WWW Baza kodu jest aktualizowana, pamięci podręczne są czyszczone i podejmowane są wszelkie inne działania aktualizacji.
- Serwer WWW A zostaje przełączony do trybu online, a serwer B zostaje wyłączony.
- Baza kodu serwera WWW B jest aktualizowana, pamięci podręczne są czyszczone i podejmowane są wszelkie inne działania aktualizacji.
- Serwer WWW B jest włączony do sieci.
- Ostateczne zmiany schematu są stosowane do DB
„Schemat przejściowy” zostałby zaprojektowany w celu ustanowienia bazy danych kompatybilnej z wieloma wersjami. Wykorzystałoby to głównie widoki tabel, które symulują schemat starej wersji, a sama tabela zostałaby zmieniona na nowy schemat. To pozwala starej wersji na normalną interakcję z bazą danych. Nazwy tabel zawierają numery wersji schematu, aby zapewnić, że nie będzie żadnych wątpliwości co do tego, do której tabeli pisać.
„Ostateczny schemat” usunąłby kompatybilność wsteczną i uporządkował schemat.
Pytanie
Krótko mówiąc, czy to zadziała?
dokładniej:
Czy pojawią się problemy z powodu możliwości równoczesnego zapisu w konkretnym punkcie zmiany schematu przejściowego? Czy istnieje sposób, aby upewnić się, że grupa zapytań modyfikujących tabelę i tworzących widok kompatybilny wstecz jest wykonywana kolejno? tzn. z wszelkimi innymi zapytaniami przechowywanymi w buforze, dopóki zmiany schematu nie zostaną zakończone, co zwykle będzie trwało tylko milisekundy.
Czy istnieją prostsze metody, które zapewniają taki stopień stabilności, a jednocześnie umożliwiają aktualizacje bez przestojów? Preferowane jest także unikanie strategii „ewolucyjnej”, ponieważ nie chcę się ograniczać do zgodności ze schematem wstecznym.
źródło
Twoja strategia jest dobra. Chciałbym jedynie rozważyć rozszerzenie „Schematu przejściowego” na pełny zestaw „tabel transakcji”.
W przypadku tabel transakcji SELECT (zapytania) są wykonywane względem znormalizowanych tabel w celu zapewnienia poprawności. Ale wszystkie WSTAWKI, AKTUALIZACJE i USUWANIA bazy danych są zawsze zapisywane w zdenormalizowanych tabelach transakcji.
Następnie osobny, równoległy proces stosuje te zmiany (być może przy użyciu procedur przechowywanych) do znormalizowanych tabel zgodnie z ustalonymi regułami biznesowymi i wymaganiami schematu.
Przez większość czasu byłoby to praktycznie natychmiastowe. Ale rozdzielenie działań pozwala systemowi na uwzględnienie nadmiernej aktywności i opóźnień aktualizacji schematu.
Podczas zmian schematu w bazie danych (B) aktualizacje danych w aktywnej bazie danych (A) trafiałyby do jej tabel transakcji i byłyby natychmiast stosowane do tabel znormalizowanych.
Po przywróceniu bazy danych (B) transakcje z (A) zostaną do niej zastosowane poprzez zapisanie ich w tabelach transakcji (B). Po zakończeniu tej części (A) można obniżyć i zastosować tam zmiany schematu. (B) zakończyłby stosowanie transakcji z punktu (A), jednocześnie obsługując swoje transakcje na żywo, które byłyby w kolejce tak samo jak (A), a „transakcje na żywo” byłyby stosowane w ten sam sposób, gdy wrócił (A).
Wiersz tabeli transakcji może wyglądać podobnie do ...
„Tabele” transakcji mogą faktycznie być wierszami w osobnej bazie danych NoSQL lub nawet sekwencyjnymi plikami, w zależności od wymagań wydajnościowych. Dodatkową zaletą jest to, że kodowanie aplikacji (w tym przypadku strony internetowej) jest nieco prostsze, ponieważ zapisuje tylko w tabelach transakcji.
Pomysł opiera się na tych samych zasadach co księgowość podwójnego zapisu i z podobnych powodów.
Tabele transakcji są analogiczne do „dziennika” księgowości. W pełni znormalizowane tabele są analogiczne do „księgi rachunkowej”, przy czym każda tabela jest nieco podobna do „konta” księgowego.
W księgowości każda transakcja otrzymuje dwa wpisy do dziennika. Jeden dla „księgowego” konta księgowego, a drugi dla „uznanego” konta.
W RDBMS „dziennik” (tabela transakcji) otrzymuje wpis dla każdej znormalizowanej tabeli, która ma zostać zmieniona przez tę transakcję.
Kolumna DB na powyższej ilustracji tabeli wskazuje, z której bazy danych pochodzi transakcja, umożliwiając w ten sposób odfiltrowanie wierszy z drugiej bazy danych w kolejce i ponowne ich zastosowanie po przywróceniu drugiej bazy danych.
źródło