Osiągnięcie zerowego czasu przestoju

40

Usiłuję osiągnąć zerowe czasy przestoju, aby móc wdrażać mniej podczas wolnych godzin i więcej podczas „wolniejszych” godzin - lub teoretycznie w dowolnym momencie.

Moja obecna konfiguracja, nieco uproszczona:

  • Serwer WWW A (aplikacja .NET)
  • Serwer WWW B (aplikacja .NET)
  • Serwer bazy danych (SQL Server)

Mój obecny proces wdrażania:

  1. „Zatrzymaj” witryny zarówno na serwerze sieciowym A, jak i B
  2. Zaktualizuj schemat bazy danych dla wdrażanej wersji aplikacji
  3. Zaktualizuj serwer WWW A
  4. Zaktualizuj serwer WWW B
  5. Przywróć wszystko do sieci

Aktualny problem

Prowadzi to do niewielkiej ilości przestojów każdego miesiąca - około 30 minut. Robię to poza godzinami pracy, więc nie jest to duży problem - ale chciałbym uciec od tego.

Ponadto - nie ma sposobu, aby naprawdę wrócić. Generalnie nie tworzę wycofanych skryptów DB - tylko skrypty aktualizacji.

Wykorzystanie modułu równoważenia obciążenia

Chciałbym móc aktualizować jeden serwer WWW na raz. Wyjmij serwer sieci Web A z modułu równoważenia obciążenia, zaktualizuj go, przełącz z powrotem w tryb online, a następnie powtórz dla serwera sieci Web B.

Problemem jest baza danych. Każda wersja mojego oprogramowania będzie musiała zostać uruchomiona z inną wersją bazy danych - więc jestem trochę „utknięty”.

Możliwe rozwiązanie

Obecne rozwiązanie, które rozważam, przyjmuje następujące zasady:

  • Nigdy nie usuwaj tabeli bazy danych.
  • Nigdy nie usuwaj kolumny bazy danych.
  • Nigdy nie zmieniaj nazwy kolumny bazy danych.
  • Nigdy nie zmieniaj kolejności kolumny.
  • Każda procedura składowana musi być wersjonowana.
    • Znaczenie - „spFindAllThings” zmieni się w „spFindAllThings_2” podczas edycji.
    • Po ponownej edycji staje się „spFindAllThings_3”.
    • Ta sama zasada dotyczy widoków.

Chociaż wydaje się to nieco ekstremalne - myślę, że rozwiązuje problem. Każda wersja aplikacji będzie uderzać w DB w sposób niezniszczalny. Kod oczekuje pewnych wyników od widoków / procedur przechowywanych - i to zachowuje ważność „umowy”. Problem w tym, że po prostu jest niechlujny. Wiem, że mogę wyczyścić stare procedury przechowywane po wdrożeniu aplikacji na jakiś czas, ale po prostu czuję się brudny. Ponadto - zależy to od wszystkich programistów przestrzegających tej reguły, co w większości się zdarzy, ale wyobrażam sobie, że ktoś popełni błąd.

Wreszcie - moje pytanie

  • Czy to jest niechlujne czy hacky?
  • Czy ktoś robi to w ten sposób?
  • Jak inni ludzie rozwiązują ten problem?
MattW
źródło
2
Gdzie jest twój plan wycofania się? Jak sprawdzasz, czy wszystko działa i czy nie ma regresji?
Deer Hunter
3
Nie potrzebujesz „nigdy”: „tylko” musisz upewnić się, że każda dwie sąsiednie wersje mogą działać jednocześnie. Ogranicza to ścieżki aktualizacji, ale nie jest tak poważne, jak to, że nigdy nie jest w stanie znacząco zmienić schematu DB.
Joachim Sauer
Dzięki Joachim ... Lubię mówić absolutnie, aby podstawowa idea była jasna - ale masz rację, moglibyśmy mieć zasadę wstecznej kompatybilności z wydaniami N, w którym to momencie możemy usunąć niepotrzebne obiekty DB.
MattW,
2
Będziesz chciał mieć plan wycofania. Pewnego dnia będziesz go potrzebować.
Thorbjørn Ravn Andersen
1
Z mojego doświadczenia wynika, że ​​w przypadku większości stron internetowych możliwe rozwiązanie jest gorsze niż problem, który rozwiązuje. Złożoność, którą doda, będzie droższa, niż można się teraz spodziewać. Być może wiele razy więcej czasu / wysiłku na wprowadzanie zmian i dodawanie funkcji. Chciałbym tylko uważają, że na stronach internetowych, które absolutnie nie można dowolny mają przestoje, kiedykolwiek .
MGOwen

Odpowiedzi:

14

Jest to bardzo pragmatyczne podejście do aktualizacji oprogramowania z bazą danych. Zostało to opisane przez Martina Fowlera i Pramoda Sadalage w 2003 roku, a następnie zapisane w Refactoring Databases: Evolutionary Database Design .

Rozumiem, co masz na myśli, gdy mówisz, że wydaje się niechlujny, ale gdy zrobiono to celowo i z wyprzedzeniem, i poświęcając czas na refaktoryzację nieużywanych struktur z bazy kodu i bazy danych, gdy są one wyraźnie nieużywane, jest o wiele bardziej solidny niż prostsze rozwiązania oparte na skryptach aktualizacji i wycofywania.

Mike Partridge
źródło
5

„Zero przestojów” to tylko jeden z wielu możliwych powodów tego rodzaju podejścia. Utrzymanie wstecznej kompatybilności modelu danych pomaga w radzeniu sobie z wieloma różnymi problemami:

  • jeśli masz wiele pakietów oprogramowania uzyskujących dostęp do bazy danych, nie będziesz musiał sprawdzać ich wszystkich, jeśli dotyczy ich zmiana schematu (w większych organizacjach z wieloma zespołami piszącymi programy korzystające z tej samej bazy danych zmiany schematu mogą być bardzo trudne)

  • jeśli musisz, możesz wypróbować starszą wersję jednego ze swoich programów i najprawdopodobniej uruchomi się ponownie w nowszej bazie danych (o ile nie spodziewasz się, że stary program poprawnie obsłuży nowe kolumny)

  • import / eksport zarchiwizowanych danych do bieżącej wersji bazy danych jest znacznie łatwiejszy

Oto dodatkowa reguła dla Twojej listy

  • każda nowa kolumna powinna mieć wartość NULLable lub zawierać znaczącą wartość domyślną

(gwarantuje to, że nawet starsze programy, które nie znają nowych kolumn, niczego nie zniszczą podczas tworzenia nowych rekordów w bazie danych).

Oczywiście to podejście ma jedną prawdziwą wadę: jakość modelu danych może z czasem ulec pogorszeniu. A jeśli masz pełną kontrolę nad wszystkimi aplikacjami uzyskującymi dostęp do bazy danych i możesz łatwo refaktoryzować wszystkie te aplikacje, na przykład, gdy zamierzasz zmienić nazwę kolumny, możesz rozważyć refaktoryzację rzeczy w czystszy sposób.

Doktor Brown
źródło
4

Różni się w zależności od wdrożenia.

Jasne, nigdy nie można usunąć tabeli ani kolumny. Nigdy nie można zmienić niczego, co złamałoby kompatybilność interfejsu. Zawsze możesz dodać warstwę abstrakcji. Ale potem musisz zaktualizować tę abstrakcję i wersję.

Pytanie, które musisz sobie zadać, brzmi: czy każde wydanie zmienia schemat w taki sposób, że nie jest kompatybilny wstecz?

Jeśli bardzo niewiele wersji zmienia schemat w ten sposób, problem bazy danych jest wyciszony. Po prostu wykonaj ciągłe wdrażanie serwerów aplikacji.

Dwie rzeczy, które widziałem najbardziej pomagają przy minimalnym czasie przestoju:

  1. Dąż do kompatybilności wstecznej - przynajmniej w jednym wydaniu. Nie zawsze to osiągniesz, ale mogę się założyć, że możesz to osiągnąć na 90% lub więcej swoich wydań, szczególnie jeśli każde wydanie jest małe.
  2. Przygotuj skrypt bazy danych przed i po wydaniu. Umożliwia to obsługę zmian nazw lub zmian interfejsu poprzez utworzenie nowego obiektu przed wdrożeniem kodu aplikacji, a następnie usunięcie starego po wdrożeniu kodu aplikacji. Jeśli dodasz nową kolumnę, która nie ma wartości null, możesz dodać ją jako null w skrypcie przedpremierowym za pomocą wyzwalacza, który wypełnia wartość domyślną. Następnie w wersji po wydaniu możesz upuścić spust.

Mamy nadzieję, że resztę wdrożeń można zapisać na okna obsługi.

Inne pomysły, które mogą pomóc poradzić sobie z kilkoma wdrożeniami, które wymagają przestoju:

  • Czy potrafisz wbudować kompatybilność wsteczną w swój kod? Na przykład, czy jest jakiś sposób, aby Twój kod obsługiwał wiele typów zestawów wyników? Jeśli chcesz zmienić kolumnę z int na double, kod aplikacji może odczytać ją jako ciąg i przeanalizować. Trochę hacky, ale jeśli jest to tymczasowy kod, aby przejść przez proces wydania, może to nie być koniec świata.
  • Procedury przechowywane mogą pomóc w izolacji kodu aplikacji przed zmianami schematu. To może pójść tylko do tej pory, ale trochę pomaga.
Brandon
źródło
2

Możesz potencjalnie zrobić to w ten sposób dla dodatkowego wysiłku.

  1. Utwórz kopię zapasową bazy danych, eksportując
  2. Zaimportuj kopię zapasową, ale zmień jej nazwę w wersji Release np. MyDb_2_1
  3. Uruchom wydanie bazy danych na myDB_2_1
  4. „Zatrzymaj” pulę aplikacji na serwerze sieci Web A lub wyjmij ją z modułu równoważenia obciążenia
  5. Zaktualizuj serwer WWW A, uruchom testy po implementacji i w razie potrzeby wycofaj
  6. Sesja wykrwawia serwer sieciowy B i ponownie włącza serwer sieciowy A.
  7. Zaktualizuj serwer sieciowy B, a następnie przywróć moduł równoważenia obciążenia

Oczywiście aktualizacje internetowe będą wymagały nowych wpisów konfiguracji, aby wskazać nowy schemat Db. Chodzi o to, że jeśli robisz wydania raz w miesiącu i to mały zespół, ile naprawdę wprowadzasz zmian w DB, które nie są kompatybilne wstecz? Jeśli możesz to kontrolować, testując, możesz przejść do automatycznego wdrożenia bez przestojów, a w najgorszym przypadku tylko 5 minut przestoju.

LeoLambrettra
źródło
1
Co jeśli (kiedy) aplikacja na serwerze A zapisuje w swojej bazie danych po zapisaniu kopii zapasowej, ale przed zatrzymaniem serwera A? Zawsze istnieje „okno podatności”. Te zapisy zostaną utracone, co może być nie do zaakceptowania.
sleske