Zero Downtime Deployment a databázy

Zero Downtime Deployment a databázy

V tomto článku podrobne vysvetlíme, ako riešiť problémy súvisiace s kompatibilitou databáz pri nasadzovaní. Povieme vám, čo sa môže stať s vašimi aplikáciami na produkcii, ak sa pokúsite vykonať nasadenie bez predchádzajúcej prípravy. Potom prejdeme fázami životného cyklu aplikácie, ktoré sú potrebné na zabezpečenie nulového času výpadku (pozn. prekl.: ďalej — zero downtime). Výsledkom našich operácií bude aplikácia spätne nekompatibilnej zmeny databázy spätné kompatibilným spôsobom.

Ak chcete preskúmať príklady kódu z článku, nájdete ich na GitHub.

Úvod

Zero downtime deployment

Čo je to za mystický zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.

Ako toho dosiahnuť? Existuje niekoľko spôsobov, tu je jeden z nich:

  • nasadte verziu č. 1 vášho servisu
  • vykonajte migráciu DB
  • nasadte verziu č. 2 vášho servisu paralelne s verziou č. 1
  • keď uvidíte, že verzia č. 2 funguje tak, ako má, odstráňte verziu č. 1
  • hotovo!

Jednoduché, nie? Bohužiaľ, nie je to také jednoduché, a to neskôr podrobne preskúmame. Teraz sa pozrime na ďalší pomerne bežný proces nasadenia — blue green deployment.

Počuli ste už o blue green deployment? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на tento článok, kde o tom podrobne hovoríme. Stručne zhrnieme, ako robiť blue green deployment:

  • zaistiť funkčnosť dvoch kópií vášho production kódu (“blue” a “green”);
  • nasmerovať celý prenos do modrej oblasti, t.j. aby URL adresy produkcie ukazovali tam;
  • nasádzať a testovať všetky zmeny aplikácie v zelenej oblasti;
  • prepínať URL adresy z modrej na zelenú oblasť

Blue green deployment je prístup, ktorý vám umožňuje ľahko zavádzať nové funkcie, bez obáv, že produkcia sa rozbije. Je to spôsobené tým, že aj keď sa niečo stane, môžete sa jednoducho vrátiť k predchádzajúcej oblasti, jednoducho „prepnutím spínača“.

Prečítali ste všetko vyššie uvedené, môžete sa opýtať: Aký vzťah má zero downtime s Blue green nasadením?

Nuže, majú toho dosť veľa spoločného, keďže podpora dvoch kópií tej istej oblasti si vyžaduje dvojnásobné úsilie na ich údržbu. Preto niektoré tímy, ako tvrdí Martin Fowler, dodržiavajú variantu tohto prístupu:

Ďalšou možnosťou je použiť tú istú databázu, vytvoriť modro-zelené prepínače pre web a doménové vrstvy. V takom prístupe môžu byť databázy často problémom, najmä keď potrebujete zmeniť jej schému na podporu novej verzie softvéru.

A tu sa dostávame k hlavnej problematike tohto článku. Databáza. Pozrime sa opäť na túto vetu.

vykonajte migráciu DB.

Teraz by ste si mali položiť otázku - čo ak je zmena databázy spätná nekompatibilná? Nebude moja prvá verzia aplikácie zlomená? V skutočnosti sa to presne stane...

Takže aj napriek obrovským výhodám zero downtime / blue green deployment, firmy majú tendenciu nasledovať bezpečnejší proces nasadenia svojich aplikácií:

  • pripravte balík s novou verziou aplikácie
  • vypnite spustenú aplikáciu
  • spustite skripty na migrovanie databázy
  • nasadte a spustite novú verziu aplikácie

V tomto článku podrobne popíšeme, ako môžete pracovať s databázou a kódom, aby ste využili výhody zero downtime deployment.

Problémy s databázou

Ak máte stateless aplikáciu, ktorá neukladá žiadne údaje do DB, môžete okamžite získať zero downtime deployment. Bohužiaľ, veľká časť softvéru musí niekde uchovávať údaje. Preto by ste mali dvakrát rozmýšľať predtým, než vykonáte akékoľvek zmeny v schéme. Predtým, než sa ponoríme do detailov, ako zmeniť schému tak, aby sa dosiahol deployment bez prestojov, zamerajme sa najskôr na schému správy verzií.

Schéma správy verzií

V tomto článku budeme používať Flyway ako nástroj na správu verzií (pozn. prekl.: jedná sa o migrácie DB). Prírodzene, napíšeme aj aplikáciu Spring Boot, ktorá má zabudovanú podporu Flyway a vykoná migráciu schémy počas inicializácie kontextu aplikácie. Pri použití Flyway môžete uchovávať migračné skripty v priečinku vašich projektov (predvolene v classpath:db/migration). Tu môžete vidieť príklad takýchto migračných súborov

└── db
 └── migration
     ├── V1__init.sql
     ├── V2__Add_surname.sql
     ├── V3__Final_migration.sql
     └── V4__Remove_lastname.sql

V tomto príklade vidíme 4 scenáre migrácie, ktoré, ak neboli vykonané predtým, sa budú vykonávať jeden za druhým pri spustení aplikácie. Pozrime sa na jeden z týchto súborov (V1__init.sql) ako na príklad.

VYTVORIŤ TABUĽKU PERSON (
id BIGINT GENEROVANÉ PODĽA PREDVOĽBY AKO IDENTITA,
first_name varchar(255) NOT NULL,
last_name varchar(255) NOT NULL
);

vložiť do PERSON (first_name, last_name) hodnoty ('Dave', 'Syer');

Všetko hovorí samo za seba: môžete použiť SQL na to, aby ste určili, ako by mala byť vaša databáza zmenená. Pre viac informácií o Spring Boote a Flyway si prečítajte Dokumentácia Spring Boot.

Použitím nástroja na správu verzií so Spring Boot získavate 2 veľké výhody:

  • oddělujete zmeny databázy od zmien kódu
  • migrácia databázy prebieha spolu s nasadením vašej aplikácie, t.j. váš proces nasadenia je zjednodušený

Riešenie problémov s databázou

V nasledujúcej časti článku sa zameriame na preskúmanie dvoch prístupov k zmenám databázy.

  • spätná nekompatibilita
  • spätná kompatibilita

Prvý bude posúdený ako varovanie, že by sme nemali vykonávať nasadenie bez prestojov bez predchádzajúcej prípravy... Druhý ponúka riešenie, ako možno realizovať nasadenie bez prestojov a súčasne zachovať spätnú kompatibilitu.

Náš projekt, na ktorom budeme pracovať, bude jednoduchou aplikáciou Spring Boot Flyway, v ktorej je Person s first_name a last_name v databáze (pozn. prekl.: Person je tabuľka, a first_name a last_name — to sú polia v nej). Chceme premenovať last_name v priezvisko.

Predpoklady

Predtým, než sa ponoríme do podrobností, je potrebné určiť niekoľko predpokladov týkajúcich sa našich aplikácií. Hlavným výsledkom, ktorý chceme dosiahnuť, bude pomerne jednoduchý proces.

Poznámka. Business PRO-TIP. Zjednodušenie procesov vám môže ušetriť veľa peňazí na údržbe (čím viac ľudí pracuje vo vašej spoločnosti, tým viac peňazí môžete ušetriť)!

Nie je potrebné robiť návrat databázy

To zjednodušuje proces nasadenia (niektoré návraty databázy sú prakticky nemožné, napr. návrat zmazania). Uprednostňujeme vracanie iba aplikácií. Takto aj keď máte rôzne databázy (napr. SQL a NoSQL), váš proces nasadenia bude vyzerať rovnako.

Musí existovať vždy možnosť vrátiť aplikáciu o jednu verziu späť (nie viac)

Rollback should only be performed when necessary. If there is an error in the current version that is difficult to fix, we must be able to revert to the last working version. We assume that this last working version is the previous one. Supporting code and database compatibility for more than one release would be extremely difficult and costly.

Poznámka. For better readability, in this article we will change the major version of the application.

Krok 1: Počiatočný stav

Verzia aplikácie: 1.0.0
Verzia DB: v1

Komentár

Toto bude počiatočný stav aplikácie.

Zmeny DB

DB obsahuje last_name.

VYTVORIŤ TABUĽKU OSOBA (
    id BIGINT VYGENEROVANÉ PODĽA SÚČASNOSTI AKO IDENTITA,
    first_name varchar(255) nie null,
    last_name varchar(255) nie null
);

vložiť do OSOBA (first_name, last_name) hodnoty ('Dave', 'Syer');

Zmeny kódu

Aplikácia uchováva údaje Person v last_name:

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastname) {
        this.lastName = lastname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName
                + "]";
    }
}

Spätná nekompatibilná zmena názvu stĺpca

Pozrime sa na príklad, ako zmeniť názov stĺpca:

Pozor. Nasledujúci príklad zámerne spôsobí poruchu. Ukazujeme to s cieľom demonštrovať problém s kompatibilitou databázy.

Verzia aplikácie: 2.0.0.BAD

Verzia DB: v2bad

Komentár

Aktuálne zmeny NEMOŽNÝCH nám umožňujú spustiť dva inštancie (starú a novú) zároveň. Tým pádom, zero downtime deployment bude ťažko dosiahnuteľný (ak vezmeme do úvahy predpoklady, je to prakticky nemožné).

A/B testovanie

Aktuálna situácia je taká, že máme aplikáciu verzie 1.0.0, nasadenú v produkcii, a DB v1. Musíme nasadiť druhú inštanciu aplikácie, verzie 2.0.0.BAD, a aktualizovať databázu na v2bad.

Kroky:

  1. bol nasadený nový inštancia aplikácie verzie 2.0.0.BAD, ktorá aktualizuje databázu na v2bad
  2. v databáze v2bad stĺpec last_name už neexistuje — bol zmenený na priezvisko
  3. aktualizácia databázy a aplikácie prebehla úspešne, a niektoré inštancie bežia v 1.0.0, iné — v 2.0.0.BAD. Všetky sú pripojené k DB v2bad
  4. všetky inštancie verzie 1.0.0 začnú vyhadzovať chyby, pretože sa pokúsia vložiť dáta do stĺpca last_name, ktorý už neexistuje
  5. všetky inštancie verzie 2.0.0.BAD budú fungovať bez problémov

Ako vidíte, ak urobíme spätné nekompatibilné zmeny DB a aplikácie, A/B testovanie nie je možné.

Rollback aplikácie

Povedzme, že po pokuse o A/B nasadenie (pozn. prekl.: pravdepodobne mal autor na mysli A/B testovanie) sme sa rozhodli, že potrebujeme vrátiť aplikáciu na verziu 1.0.0. Povedzme, že nechceme vykonať obnovenie databázy.

Kroky:

  1. Zastavujeme inštanciu aplikácie verzie 2.0.0.BAD
  2. databáza je stále v2bad
  3. keďže verzia 1.0.0 nechápe, čo je priezvisko, uvidíme chyby
  4. peklo sa uvoľnilo, už sa nemôžeme vrátiť späť

Ako vidíte, ak urobíme spätné nekompatibilné zmeny v DB a aplikácii, nemôžeme sa vrátiť na predchádzajúcu verziu.

Logy vykonávania skriptu

Scenár spätných kompatibilít:

01) Spustiť 1.0.0
02) Čakať, kým sa aplikácia (1.0.0) spustí
03) Vygenerovať osobu volaním POST localhost:9991/person na verziu 1.0.0
04) Spustiť 2.0.0.BAD
05) Čakať, kým sa aplikácia (2.0.0.BAD) spustí
06) Vygenerovať osobu volaním POST localhost:9991/person na verziu 1.0.0 <-- toto by malo zlyhať
07) Vygenerovať osobu volaním POST localhost:9992/person na verziu 2.0.0.BAD <-- toto by malo prebehnúť

Spúšťam aplikáciu vo verzii 1.0.0
Vygenerovať osobu vo verzii 1.0.0
Posielam POST na 127.0.0.1:9991/person. Toto je odpoveď:

{"firstName":"b73f639f-e176-4463-bf26-1135aace2f57","lastName":"b73f639f-e176-4463-bf26-1135aace2f57"}

Spúšťam aplikáciu vo verzii 2.0.0.BAD
Vygenerovať osobu vo verzii 1.0.0
Posielam POST na 127.0.0.1:9991/person. Toto je odpoveď:

curl: (22) Požadovaná adresa URL vrátila chybu: 500 Interná serverová chyba

Vygenerovať osobu vo verzii 2.0.0.BAD
Posielam POST na 127.0.0.1:9995/person. Toto je odpoveď:

{"firstName":"e156be2e-06b6-4730-9c43-6e14cfcda125","surname":"e156be2e-06b6-4730-9c43-6e14cfcda125"}

Zmeny DB

Skript migrácie, ktorý prepája last_name v priezvisko

Pôvodný Flyway skript:

VYTVORIŤ TABUĽKU OSOBA (
    id BIGINT VYGENEROVANÉ PODĽA SÚČASNOSTI AKO IDENTITA,
    first_name varchar(255) nie null,
    last_name varchar(255) nie null
);

vložiť do OSOBA (first_name, last_name) hodnoty ('Dave', 'Syer');

Skript, ktorý prepája last_name.

-- Táto zmena je spätná nekompatibilná - nemôžete vykonávať A/B testovanie
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Zmeny kódu

Zmenili sme názov poľa lastName na priezvisko.

Prepojovanie stĺpca spätnou kompatibilitou

Toto je najbežnejšia situácia, s ktorou sa môžeme stretnúť. Musíme uskutočniť spätné nekompatibilné zmeny. Už sme preukázali, že na nasadenie bez prestojov nemôžeme jednoducho vykonať migráciu databázy bez dodatočných opatrení. V tejto časti článku uskutočníme 3 nasadenia aplikácie spolu s migráciami databáz s cieľom dosiahnuť požadovaný výsledok a zároveň zachovať spätnú kompatibilitu.

Poznámka. Pripomeňme, že máme databázu verzie v1. Obsahuje stĺpce first_name a last_name. Musíme zmeniť last_name na priezvisko. Máme tiež aplikáciu verzie 1.0.0, ktorá zatiaľ nepoužíva priezvisko.

Krok 2: Pridáva sa priezvisko

Verzia aplikácie: 2.0.0
Verzia DB: v2

Komentár

Pridaním nového stĺpca a kopírovaním jeho obsahu vytvárame spätné kompatibilné zmeny DB. Zároveň, ak vrátime JAR alebo máme funkčný starý JAR, nebude to počas vykonávania zlyhávať.

Nasadzujeme novú verziu

Kroky:

  1. vykonajte migráciu DB na vytvorenie nového stĺpca priezvisko. Teraz je vaša databáza verzie v2
  2. skopírujte dáta z last_name v priezvisko. Všimnite si, čo ak máte veľa týchto údajov, mali by ste zvážiť hromadnú migráciu!
  3. napíšte kód, kde sa používajú OBE a nový, a stará stĺpec. Teraz vaša verzia aplikácie 2.0.0
  4. prečítajte hodnotu zo stĺpca priezvisko, ak nie je null, alebo z last_name, ak priezvisko nie je zadané. Môžete odstrániť getLastName() z kódu, pretože bude vracať null pri spätnej verzii vašej aplikácie z 3.0.0 do 2.0.0.

Ak používate Spring Boot Flyway, tieto dva kroky budú vykonané počas spustenia verzie 2.0.0 aplikácie. Ak spúšťate nástroj na správu verzií databázy ručne, budete musieť urobiť dva rôzne kroky (najprv manuálne aktualizujte verziu db a potom nasadíte novú aplikáciu).

Dôležité. Pamätajte, že novo vytvorený stĺpec NIE JE POVOLENÝ byť NOT NULL. Ak robíte spätnú verziu, stará aplikácia nevie o novom stĺpci a nenastaví ho počas Vložiť. Ale ak pridáte toto obmedzenie, a vaša DB bude v2, to si bude vyžadovať nastavenie hodnoty nového stĺpca. Čo povedie k porušeniam obmedzení.

Dôležité. Mali by ste odstrániť metódu getLastName(), pretože v verzii 3.0.0 v kóde neexistuje pojem stĺpec last_name. To znamená, že tam budú nastavené null. Môžete nechať metódu a pridať kontroly na null, ale oveľa lepším riešením bude zabezpečiť, že v logike getSurname() ste vybrali správnu nenulovú hodnotu.

A/B testovanie

Aktuálna situácia je taká, že máme aplikáciu verzie 1.0.0, nasadenú na produ, a DB v v1. Musíme nasadiť druhý instance aplikácie verzie 2.0.0, ktorá aktualizuje databázu na v2.

Kroky:

  1. bol nasadený nový inštancia aplikácie verzie 2.0.0, ktorá aktualizuje databázu na v2
  2. medzitým niektoré požiadavky spracovávali instance verzie 1.0.0
  3. aktualizácia prebehla úspešne, a máte niekoľko fungujúcich instance aplikácie verzie 1.0.0 a ostatné verzie 2.0.0. Všetky komunikujú s DB v v2
  4. verzia 1.0.0 nepoužíva v DB stĺpec surname, zatiaľ čo verzia 2.0.0 používa. Nezavadzajú si navzájom a chyby by nemali byť.
  5. verzia 2.0.0 uchováva údaje ako v starom, tak aj v novom stĺpci, čo zabezpečuje spätnú kompatibilitu.

Dôležité. Ak máte akékoľvek požiadavky, ktoré počítajú položky na základe hodnôt zo starého / nového stĺpca, mali by ste pamätať, že teraz máte duplikácie hodnôt (pravdepodobne sa stále migrujú). Napríklad, ak chcete spočítať počet používateľov, ktorých priezvisko (ako by sa stĺpec volal) začínalo písmenom A, tak do dokončenia migrácie údajov (old → new stĺpec) môžete mať nekonzistentné údaje, ak vykonávate dotaz na nový stĺpec.

Rollback aplikácie

Teraz máme aplikáciu verzie 2.0.0 a databázu v v2.

Kroky:

  1. vráťte vašu aplikáciu na verziu 1.0.0.
  2. verzia 1.0.0 nepoužíva v DB stĺpec priezvisko, preto by vrátenie malo byť úspešné

Zmeny DB

DB obsahuje stĺpec s názvom last_name.

Pôvodný skript Flyway:

VYTVORIŤ TABUĽKU OSOBA (
    id BIGINT VYGENEROVANÉ PODĽA SÚČASNOSTI AKO IDENTITA,
    first_name varchar(255) nie null,
    last_name varchar(255) nie null
);

vložiť do OSOBA (first_name, last_name) hodnoty ('Dave', 'Syer');

Skript pridania priezvisko.

Pozor. Pamätajte, že NEMÔŽETE PRIDAŤ žiadne obmedzenia NOT NULL do pridaného stĺpca. Ak vrátite JAR, staršia verzia nebude mať vedomosť o pridanom stĺpci a automaticky mu priradí hodnotu NULL. V prípade existencie takého obmedzenia sa stará aplikácia jednoducho rozpadne.

-- POZNÁMKA: Toto pole nemôže mať obmedzenie NOT NULL, pretože ak sa vrátite, staršia verzia nebude vedieť o tomto poli
-- a vždy ho nastaví na NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- PREDPOKLADÁME, ŽE IDE O RÝCHLU MIGRÁCIU - INAK BY SME MUSILI MIGROVAŤ V PARTIACH
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Zmeny kódu

Uchovávame údaje ako v last_name, tak aj v priezvisko. Pri tom čítame z last_name, pretože tento stĺpec je najaktuálnejší. Počas nasadzovania niektoré dotazy mohli byť spracované inštanciou aplikácie, ktorá ešte nebola aktualizovaná.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * Reading from the new column if it's set. If not the from the old one.
     *
     * When migrating from version 1.0.0 -> 2.0.0 this can lead to a possibility that some data in
     * the surname column is not up to date (during the migration process lastName could have been updated).
     * In this case one can run yet another migration script after all applications have been deployed in the
     * new version to ensure that the surname field is updated.
     *
     * However it makes sense since when looking at the migration from 2.0.0 -> 3.0.0. In 3.0.0 we no longer
     * have a notion of lastName at all - so we don't update that column. If we rollback from 3.0.0 -> 2.0.0 if we
     * would be reading from lastName, then we would have very old data (since not a single datum was inserted
     * to lastName in version 3.0.0).
     */
    public String getSurname() {
        return this.surname != null ? this.surname : this.lastName;
    }

    /**
     * Storing both FIRST_NAME and SURNAME entries
     */
    public void setSurname(String surname) {
        this.lastName = surname;
        this.surname = surname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName + ", surname=" + this.surname
                + "]";
    }
}

Krok 3: Odstránenie last_name zo zdrojového kódu

Verzia aplikácie: 3.0.0

Verzia DB:v3

Komentár

Pozn. prekl.: Zrejme, v pôvodnom článku bol autorom chybne skopírovaný text tohto bloku z kroku 2. V tomto kroku by mali byť vykonané zmeny v kóde aplikácie, ktoré sú zamerané na odstránenie funkcií, ktoré používajú stĺpec last_name.

Pridaním nového stĺpca a kopírovaním jeho obsahu sme vytvorili spätnú kompatibilitu zmien DB. Taktiež, ak vrátime JAR alebo budeme mať funkčný starý JAR, počas vykonávania sa nerozpadne.

Rollback aplikácie

V súčasnosti máme aplikáciu verzie 3.0.0 a databázu v3. Verzia 3.0.0 neuchováva údaje v last_name. To znamená, že v priezvisko sa uchováva najaktuálnejšia informácia.

Kroky:

  1. vráťte vašu aplikáciu na verziu 2.0.0.
  2. verzia 2.0.0 používa a last_name a priezvisko.
  3. verzia 2.0.0 vezme priezvisko, ak nie je nulový, inak —last_name

Zmeny DB

V DB nie sú štrukturálne zmeny. Vykonáva sa nasledujúci skript, ktorý vykonáva konečnú migráciu starých údajov:

-- PREDPOKLADÁME, ŽE IDE O RÝCHLU MIGRÁCIU - INAK BY SME MUSILI MIGROVAŤ V PARTIACH
-- TIEŽ NEKONTROLUJEME, ČI NEPREPÍŠEME EXISTUJÚCE VSTUPY. MUSILI BY SME POROVNAŤ
-- VERZIE VSTUPOV, ABY SME ZAISTILI, ŽE AK UŽ EXISTUJE VSTUP S VYŠŠÍM ČÍSLOM VERZIE
-- NEPREPÍŠEME HO.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- ODSTRÁNENIE OBLÍBENIA NOT NULL; INAK SA POKÚSITE VNÚTIŤ NULL HODNOTU LAST_NAME
-- S OBLÍBENÍM NOT NULL.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Zmeny kódu

Pozn. prekl.: Opis tohto bloku bol nesprávne skopírovaný autorom zo kroku 2. V súlade s logikou naratívu článku by zmeny v kóde v tomto kroku mali byť zamerané na odstránenie prvkov, ktoré manipulujú so stĺpcom last_name.

Ukladáme dáta ako v last_name, tak aj v priezvisko. Okrem toho čítame zo stĺpca last_name, pretože je to najaktuálnejšie. Počas nasadzovania môžu niektoré požiadavky spracovať inštancia, ktorá ešte nebola aktualizovaná.

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.flyway;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String surname;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getSurname() {
        return this.surname;
    }

    public void setSurname(String lastname) {
        this.surname = lastname;
    }

    @Override
    public String toString() {
        return "Person [firstName=" + this.firstName + ", surname=" + this.surname
                + "]";
    }
}

Krok 4: Odstránenie last_name z DB

Verzia aplikácie: 4.0.0

Verzia DB: v4

Komentár

Vzhľadom na to, že kód verzie 3.0.0 nepoužíval stĺpec last_name, počas vykonávania sa nič zlé nestane, ak sa vrátime späť k 3.0.0 po odstránení stĺpca z databázy.

Logy vykonávania skriptu

Urobíme to nasledovne:

01) Spustite verziu 1.0.0
02) Počkajte, kým sa aplikácia (1.0.0) spustí
03) Vytvorte osobu zavolaním POST localhost:9991/person pre verziu 1.0.0
04) Spustite verziu 2.0.0
05) Počkajte, kým sa aplikácia (2.0.0) spustí
06) Vytvorte osobu zavolaním POST localhost:9991/person pre verziu 1.0.0
07) Vytvorte osobu zavolaním POST localhost:9992/person pre verziu 2.0.0
08) Zrušte aplikáciu (1.0.0)
09) Spustite verziu 3.0.0
10) Počkajte, kým sa aplikácia (3.0.0) spustí
11) Vytvorte osobu zavolaním POST localhost:9992/person pre verziu 2.0.0
12) Vytvorte osobu zavolaním POST localhost:9993/person pre verziu 3.0.0
13) Zrušte aplikáciu (3.0.0)
14) Spustite verziu 4.0.0
15) Počkajte, kým sa aplikácia (4.0.0) spustí
16) Vytvorte osobu zavolaním POST localhost:9993/person pre verziu 3.0.0
17) Vytvorte osobu zavolaním POST localhost:9994/person pre verziu 4.0.0

Spúšťanie aplikácie vo verzii 1.0.0
Vytváranie osoby vo verzii 1.0.0
Posielanie POST na 127.0.0.1:9991/person. Toto je odpoveď:

{"firstName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2","lastName":"52b6e125-4a5c-429b-a47a-ef18bbc639d2"}

Spúšťanie aplikácie vo verzii 2.0.0

Vytváranie osoby vo verzii 1.0.0
Posielanie POST na 127.0.0.1:9991/person. Toto je odpoveď:

{"firstName":"e41ee756-4fa7-4737-b832-e28827a00deb","lastName":"e41ee756-4fa7-4737-b832-e28827a00deb"}

Vytváranie osoby vo verzii 2.0.0
Posielanie POST na 127.0.0.1:9992/person. Toto je odpoveď:

{"firstName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","lastName":"0c1240f5-649a-4bc5-8aa9-cff855f3927f","surname":"0c1240f5-649a-4bc5-8aa9-cff855f3927f"}

Zrušenie aplikácie 1.0.0

Spúšťanie aplikácie vo verzii 3.0.0

Vytváranie osoby vo verzii 2.0.0
Posielanie POST na 127.0.0.1:9992/person. Toto je odpoveď:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Vytváranie osoby vo verzii 3.0.0
Posielanie POST na 127.0.0.1:9993/person. Toto je odpoveď:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

Zrušenie aplikácie 2.0.0

Spúšťanie aplikácie vo verzii 4.0.0

Vytváranie osoby vo verzii 3.0.0
Posielanie POST na 127.0.0.1:9993/person. Toto je odpoveď:

{"firstName":"cbe942fc-832e-45e9-a838-0fae25c10a51","surname":"cbe942fc-832e-45e9-a838-0fae25c10a51"}

Vytváranie osoby vo verzii 4.0.0
Posielanie POST na 127.0.0.1:9994/person. Toto je odpoveď:

{"firstName":"ff6857ce-9c41-413a-863e-358e2719bf88","surname":"ff6857ce-9c41-413a-863e-358e2719bf88"}

Zmeny DB

Pokiaľ ide o v3 jednoducho odstraňujeme stĺpec last_name a pridávame chýbajúce obmedzenia.

-- ODSTRÁNIŤ STĹPEC
ALTER TABLE PERSON DROP last_name;

-- PRIDAŤ OBMEDZENIA
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Zmeny kódu

Zmeny v kóde chýbajú.

Záver

Úspešne sme vrátili nekompatibilnú zmenu názvu stĺpca vykonaním niekoľkých spätných kompatibilných nasadení. Nižšie uvádzame súhrn vykonaných akcií:

  1. nasadenie aplikácie verzie 1.0.0 s v1 schémy DB (názov stĺpca = last_name)
  2. nasadenie aplikácie verzie 2.0.0, ktorá uchováva údaje v last_name a priezvisko. Aplikácia číta z last_name. DB je vo verzii v2, ktorá obsahuje stĺpce ako last_name, tak aj surname. surname je kópiou last_name. (POZNÁMKA: tento stĺpec by nemal mať obmedzenie not null)
  3. nasadenie aplikácie verzie 3.0.0, ktorá uchováva údaje iba v priezvisko a číta zo surname. Pokiaľ ide o DB, prebieha posledná migrácia last_name v priezvisko. Taktiež sa obmedzenie NOT NULL odstraňuje z last_name. DB je teraz vo verzii v3
  4. nasadenie aplikácie verzie 4.0.0 — v kóde sa nevykonávajú žiadne zmeny. Nasadenie databázy v4, ktoré odstraňuje last_name. Tu môžete pridať akékoľvek chýbajúce obmedzenia v DB.

Dodržiavaním tohto prístupu sa vždy môžete vrátiť o jednu verziu späť bez poškodenia kompatibility databázy / aplikácie.

Kód

Celý kód použitý v tomto článku je dostupný na Github. Nižšie sú ďalšie informácie.

Projekt

Po sklonovaní repozitára uvidíte nasledujúcu štruktúru priečinkov.

├── boot-flyway-v1              - 1.0.0 verzia aplikácie s v1 schémou
├── boot-flyway-v2              - 2.0.0 verzia aplikácie s v2 schémou (spätná kompatibilita - aplikáciu je možné vrátiť)
├── boot-flyway-v2-bad          - 2.0.0.BAD verzia aplikácie s v2bad schémou (nekompatibilná - aplikáciu nie je možné vrátiť)
├── boot-flyway-v3              - 3.0.0 verzia aplikácie s v3 schémou (aplikáciu je možné vrátiť)
└── boot-flyway-v4              - 4.0.0 verzia aplikácie s v4 schémou (aplikáciu je možné vrátiť)

Skripty

Môžete spustiť skripty popísané nižšie, ktoré predvedú spätné kompatibilné a nekompatibilné zmeny v DB.

Aby ste videli prípad so spätnými kompatibilnými zmenami, spustite:

./scripts/scenario_backward_compatible.sh

Aby ste videli prípad s nekompatibilnými zmenami, spustite:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Všetky príklady sú prevzaté z Spring Boot Sample Flyway.

Môžete si pozrieť http://localhost:8080/flyway, tam je zoznam skriptov.

Tento príklad tiež obsahuje konzolu H2 (na adrese http://localhost:8080/h2-console), aby ste mohli sledovať stav databázy (URL jdbc predvolene — jdbc:h2:mem:testdb).

Ďalšie

Čítajte tiež ďalšie články na našom blogu:

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster