# Migracja z Oracle na PostgreSQL bez przestoju: analiza techniczna
Przeniesienie z Oracle na PostgreSQL bez zatrzymywania serwisu to zadanie trudne, ale wykonalne. W tym artykule omawiamy krok po kroku strategię migracji opartą na rzeczywistym projekcie z mikrousługami na Spring Boot, gdzie kluczowym wymaganiem było zerowe wpływu na użytkowników. Użycie CDC poprzez Debezium pozwoliło synchronizować dane w czasie rzeczywistym, unikając przestojów i minimalizując ryzyka.
Przygotowanie: analiza struktury i danych
Pierwszy etap to głęboki audyt istniejącej bazy danych. Należy zrozumieć rozmiar danych, rozkład typów pól, obecność nieaktualnych rekordów oraz specyficznych konstrukcji Oracle, które nie mają bezpośrednich odpowiedników w PostgreSQL. Oczyszczenie nieaktualnych danych zmniejsza objętość migracji i przyspiesza proces.
Kluczowy aspekt to zgodność typów danych. Na przykład:
NUMBER(1,0)→BOOLEANVARCHAR2→TEXTlubVARCHARDATE→TIMESTAMP WITHOUT TIME ZONECLOB→TEXT
Do analizy użyto zapytania SQL:
select distinct DATA_TYPE
from ALL_TAB_COLUMNS
where owner = 'schemat'
order by DATA_TYPE
Na podstawie wyników przygotowano tabelę mapowania typów, która stała się podstawą wszystkich dalszych transformacji. Ważne jest też uwzględnienie różnic w obsłudze NULL i pustych ciągów: w Oracle pusty ciąg jest traktowany jako NULL, w PostgreSQL — nie. To wymaga dostosowania logiki biznesowej i zapytań.
Dostosowanie schematu i Liquibase
Prosta zmiana sterownika bazy danych doprowadzi do błędów. Skrypty migracyjne muszą być dostosowane do PostgreSQL. W tym celu:
- Operacje DDL i DML rozdzielono za pomocą kontekstów Liquibase — DML tymczasowo wyłączono.
- Skrypty testowano iteracyjnie: po każdej zmianie uruchamiano changelog, czyszczono i przeprowadzano smoke-testy.
- Sprawdzano poprawność preconditions oraz spójność schematu z Oracle.
Szczególną uwagę zwrócono na sequence. Bez ich synchronizacji nowe ID mogą kolidować z danymi historycznymi. Rozwiązanie:
- Przy starcie aplikacji sprawdzane jest aktualne wartość sequence w PostgreSQL.
- Jeśli jest mniejsze niż w Oracle — następuje przesunięcie z zapasem.
- Logika jest idempotentna: wielokrotne uruchomienia nie powodują błędów.
W rezultacie docelowy schemat PostgreSQL został zebrany w jednym pull request, gotowy do załadowania danych.
Poprawki w kodzie aplikacji
Po udanym uruchomieniu aplikacji na pustym PostgreSQL ujawniają się błędy na poziomie kodu Java. Główne zmiany:
- Zamiana adnotacji
@Lobna@Column(columnDefinition = "text"). - Obsługa NULL w natywnych zapytaniach SQL, zwłaszcza w konstrukcjach
IN (...). - Przejście z numerycznych flag (0/1) na
boolean. - Dostosowanie logiki porównywania ciągów z uwzględnieniem różnic Oracle/PostgreSQL.
- Przepisanie natywnych zapytań z uwzględnieniem dialektu PostgreSQL.
Testowanie odbywało się na poziomie testów jednostkowych i integracyjnych. Szczególną uwagę zwrócono na przypadki brzegowe: puste ciągi, wartości NULL, duże pola tekstowe.
Implementacja CDC poprzez Debezium i Kafka Connect
Wybrano klasyczny stos: Debezium + Kafka Connect. Architektura:
- Source-konnektor (Debezium Oracle) odczytuje redo log i generuje zdarzenia CDC.
- Zdarzenia trafiają do Kafka (jeden topik na tabelę).
- Sink-konnektor (JDBC Sink) stosuje zmiany w PostgreSQL w tej samej kolejności.
Etapy konfiguracji:
- Initial Snapshot — pełne skopiowanie danych na moment startu.
- Streaming Changes — ciągła replikacja INSERT/UPDATE/DELETE z redo log.
- Order Preservation — gwarancja kolejności zmian dzięki LogMiner.
Użyte obrazy:
quay.io/debezium/kafka:3.0quay.io/debezium/zookeeper:3.0quay.io/debezium/connect:3.0provectuslabs/kafka-ui:0.7.2(do monitorowania)
Konfiguracja odbywa się poprzez REST API za pomocą curl. Interfejs Debezium w czasie migracji był niestabilny, dlatego konfiguracje przekazywano ręcznie w formacie JSON.
Przykładowa konfiguracja source-konnektora:
{
"name": "oracle-connector",
"config": {
"connector.class": "io.debezium.connector.oracle.OracleConnector",
"database.hostname": "oracle-host",
"database.port": "1521",
"database.user": "user",
"database.password": "password",
"database.dbname": "ORCLCDB",
"database.server.name": "server1",
"table.include.list": "schema.table1,schema.table2",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes"
}
}
Przykładowa konfiguracja sink-konnektora:
{
"name": "postgres-sink",
"config": {
"connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",
"connection.url": "jdbc:postgresql://postgres:5432/db",
"connection.user": "user",
"connection.password": "password",
"topics": "server1.schema.table1,server1.schema.table2",
"auto.create": "false",
"auto.evolve": "false",
"insert.mode": "upsert",
"pk.mode": "record_key",
"pk.fields": "id"
}
}
Niektóre tabele (np. z kluczami kompozytowymi) wymagają oddzielnej konfiguracji. Testowanie każdego konektora odbywa się izolowanie.
Ostateczne przełączenie i kontrola jakości
Po zakończeniu initial snapshot i ustabilizowaniu streamingu:
- Uruchamiane są instancje testowe serwisów podłączone do PostgreSQL.
- Przeprowadzane jest testowanie end-to-end: API, UI, procesy tła.
- Wykonywane jest testowanie obciążeniowe na danych zbliżonych do produkcyjnych.
- W momencie minimalnego obciążenia — przełączenie DNS lub tras ingress na nowe instancje.
- Monitorowanie logów, metryk i alertów przez 24–48 godzin.
Rollback przewidziano tylko do momentu przełączenia. Potem system działa wyłącznie na PostgreSQL. Kopie zapasowe Oracle zachowano na wypadek awaryjnego odzyskiwania danych.
Co ważne
- Brak uniwersalnego rozwiązania — każdy projekt wymaga indywidualnego dostosowania.
- CDC bez podwójnego zapisu — akceptowalny kompromis przy dopuszczalnym opóźnieniu rzędu kilku sekund.
- Synchronizacja sequence — obowiązkowa dla uniknięcia konfliktów ID.
- Testowanie na każdym etapie — klucz do stabilnej migracji.
- Debezium + Kafka Connect — elastyczny i niezawodny stos do migracji online.
Migracja trwała 18 godzin łącznie z przygotowaniami, ale faktyczny przestój dla użytkowników wyniósł 0 sekund. Projekt działa na PostgreSQL od ponad roku bez regresji.
— Editorial Team
Brak komentarzy.