Mamy aplikację, która łączy w sobie zarówno szybką (<1 sekundę), jak i powolną migrację bazy danych (> 30 sekund). W tej chwili przeprowadzamy migracje baz danych jako część CI, ale nasze narzędzie CI musi znać wszystkie parametry połączenia z bazą danych dla naszej aplikacji (w wielu środowiskach), co nie jest idealne. Chcemy zmienić ten proces, aby aplikacja uruchamiała własne migracje baz danych podczas uruchamiania.
Oto sytuacja:
Mamy wiele wystąpień tej aplikacji - około 5 w produkcji. Zadzwońmy do nich node1, ..., node5
. Każda aplikacja łączy się z pojedynczą instancją SQL Server, a my nie używamy wdrożeń kroczących (o ile wiem, wszystkie aplikacje są wdrażane jednocześnie)
Problem: powiedzmy, że mamy długą migrację. W takim przypadku node1
rozpoczyna się, a następnie rozpoczyna migrację. Teraz node4
zaczyna się, a migracja długoterminowa jeszcze się nie zakończyła, więc node4
zaczyna się także migracja -> możliwe uszkodzenie danych? Jak zapobiegniesz temu problemowi, czy problem jest wystarczająco ważny, aby się o niego martwić?
Myślałem o rozwiązaniu tego problemu za pomocą zamka rozproszonego (za pomocą etcd
lub czegoś podobnego). Zasadniczo wszystkie aplikacje próbują uzyskać blokadę, tylko jedna z nich ją pobiera i uruchamia migracje, a następnie odblokowuje. Gdy reszta aplikacji uruchomi się i przejdzie do sekcji krytycznej, wszystkie migracje zostały już uruchomione, więc skrypt migracji właśnie kończy działanie.
Jednak mam przeczucie, że „to przesada, musi być prostsze rozwiązanie”, więc pomyślałem, że poproszę tutaj, aby sprawdzić, czy ktoś ma jakieś lepsze pomysły.
Odpowiedzi:
Ponieważ wspomniałeś o serwerze SQL: zgodnie z poprzednim postem DBA.SE zmiany schematu można (i należy) wprowadzać do transakcji. Daje to możliwość zaprojektowania migracji tak, jak każdej innej formy równoczesnych zapisów w bazie danych - zaczynasz transakcję, a gdy się nie powiedzie, wycofujesz ją. Zapobiega to co najmniej niektórym najgorszym scenariuszom uszkodzenia bazy danych (chociaż same transakcje nie zapobiegną utracie danych, gdy występują destrukcyjne kroki migracji, takie jak usunięcie kolumny lub tabeli).
Jak dotąd jestem pewien, że będziesz potrzebować również
migrations
tabeli, w której są już zarejestrowane migracje, więc proces aplikacji może sprawdzić, czy konkretna migracja została już zastosowana, czy nie. Następnie użyj „WYBIERZ DO AKTUALIZACJI”, aby zaimplementować swoje migracje w ten sposób (pseudo kod):SELECT FROM Migrations FOR UPDATE WHERE MigrationLabel='MyMigration42'
INSERT 'MyMigration42' INTO Migrations(MigrationLabel)
To buduje mechanizm blokujący bezpośrednio w teście „była już zastosowana migracja” .
Zauważ, że ten projekt - teoretycznie - pozwoli nieświadomym krokom migracji, która aplikacja faktycznie je zastosuje - możliwe, że krok 1 zostanie zastosowany przez app1, krok 2 przez app2, krok 3 przez app 3, krok 4 przez app1 znowu i tak dalej. Dobrym pomysłem jest jednak nie stosowanie migracji, dopóki używane są inne instancje aplikacji. Równoległe wdrożenie, jak wspomniano w pytaniu, może już dotyczyć tego ograniczenia.
źródło
Może znajdziesz bibliotekę obsługującą migrację bazy danych z wieloma węzłami.
Wiem o dwóch bibliotekach w świecie Java, obie obsługują to, czego potrzebujesz:
Prawdopodobnie istnieją także inne narzędzia dla Java i innych języków.
Jeśli nie możesz (lub nie chcesz) korzystać z takiego narzędzia, tabelę można wykorzystać jako blokadę lub nawet jako dziennik migracji, patrz przykład odpowiedzi Doc Browna .
źródło