Zero Downtime Deployment és adatbázisok

Zero Downtime Deployment és adatbázisok

Ez a cikk részletesen bemutatja, hogyan lehet megoldani az adatbázisok kompatibilitási problémáit a telepítés során. Megmutatjuk, mi történhet a termelési alkalmazásaival, ha megpróbál telepíteni előkészítés nélkül. Ezután végigvezetjük az alkalmazás életszakaszain, amelyek szükségesek a nullás leállási idő eléréséhez (megjegyzés: a továbbiakban – zero downtime). Műveleteink eredményeként a visszafelé inkompatibilis adatbázis-változtatásokat visszafelé kompatibilis módon alkalmazzuk.

Ha szeretne elmélyedni a cikk kódtöredékeiben, azokat itt találja: GitHub.

Bevezetés

Zero downtime deployment

Mi ez a misztikus zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.

Hogyan érhetjük el ezt? Több módszer is létezik, íme az egyik:

  • telepítse az Ön szolgáltatásának 1. verzióját
  • végezze el az adatbázis migrációját
  • telepítse a szolgáltatása 2. verzióját párhuzamosan az 1. verzióval
  • amint látja, hogy a 2. verzió megfelelően működik, távolítsa el az 1. verziót
  • kész!

Egyszerű, ugye? Sajnos nem ennyire egyszerű, és ezt később részletesen is megvizsgáljuk. Most nézzük meg egy elég elterjedt telepítési folyamatot – a blue green deployment-et.

Hallott már a blue green deployment-ról? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на erre a cikkre, ahol ezt részletesebben kifejtjük. Röviden összefoglalva, emlékezzünk, hogyan kell végezni a blue green deployment-et:

  • biztosítani kell, hogy két példányban fusson a production kód ("blue" és "green");
  • az összes forgalmat a blue környezetbe kell irányítani, azaz a production URL-jeinek oda kell mutatniuk;
  • az összes alkalmazásváltoztatást a green környezetben kell telepíteni és tesztelni;
  • az URL-eket a blue-ról a green környezetre kell váltani

A Blue green deployment egy olyan megközelítés, amely lehetővé teszi, hogy új funkciókat vezessen be anélkül, hogy aggódnia kellene, hogy a production megsérül. Ennek oka, hogy ha bármi történik, könnyen visszaállhat az előző környezetbe, csak egy "kapcsoló kipöccintésével".

Az összes korábbi tudnivaló után felmerülhet a kérdés: Mi köze a zero downtime-nak a Blue green telepítéshez?

Nos, sok közö van, mivel két példány fenntartása ugyanazon környezetből dupla erőfeszítést igényel a karbantartásukhoz. Ezért van, hogy egyes csapatok, ahogyan azt Martin Fowler, ezt a megközelítést követik:

A másik lehetőség az, hogy ugyanazt az adatbázist használjuk, kék-zöld váltókat létrehozva a web- és domain rétegek számára. Ebben a megközelítésben az adatbázisok gyakran problémát okozhatnak, különösen, amikor meg kell változtatni a sémát egy új szoftververzió támogatásához.

Itt elérkeztünk a cikk fő problémájához. Adatbázis. Nézzük meg újra ezt a mondatot.

végezze el az adatbázis migrációját.

Most fel kell tennie magának a kérdést — mi van, ha az adatbázis visszafordíthatatlan változása történik? Nem fog-e eltörni az első verzióm? Valójában pontosan ez fog történni...

Így, még ha a zero downtime / kék-zöld telepítés óriási előnyökkel is jár, a cégek hajlamosak a következő biztonságosabb telepítési folyamatot követni alkalmazásaik esetében:

  • készítsen egy csomagot az új alkalmazásverzióval
  • zárja le a futó alkalmazást
  • futtassa az adatbázis migrációs szkriptjeit
  • telepítse és indítsa el az új alkalmazásverziót

Ebben a cikkben részletesen ismertetjük, hogyan dolgozhat az adatbázissal és a kóddal, hogy kihasználhassa a zero downtime telepítés előnyeit.

Adatbázis problémák

Ha van egy állapotmentes alkalmazása, amely nem tárol adatokat az adatbázisban, akkor azonnal elérheti a zero downtime telepítést. Sajnos a szoftverek nagy része kénytelen valahol tárolni az adatokat. Ezért érdemes alaposan átgondolnia, mielőtt bármilyen változtatást végez a sémán. Mielőtt elmerülnénk a sémaváltoztatás olyan részleteiben, amelyek lehetővé teszik a leállás nélküli telepítést, először a verziókezelési sémára kell összpontosítanunk.

Verziókezelési séma

Ebben a cikkben használni fogjuk Flyway mint eszközt a verziókezeléshez (megjegyzés: adatbázis migrációkról van szó). Természetesen írni fogunk egy Spring Boot alkalmazást is, amely beépített támogatást nyújt a Flyway számára, és a séma migrálását a projekt kontextusának beállítása során végzi. A Flyway használatakor tárolhatja a migrációs szkripteket a projektjei mappájában (alapértelmezés szerint a classpath:db/migration). Itt láthat egy példát az ilyen migrációs fájlokra

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

Ebben a példában 4 migrációs forgatókönyvet látunk, amelyek, ha korábban nem hajtották végre őket, egymás után fognak végrehajtódni az alkalmazás indításakor. Nézzük meg az egyik fájlt (V1__init.sql) példaként.

CREATE TABLE PERSON (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
first_name varchar(255) not null,
last_name varchar(255) not null
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Minden világos, ami önmagáért beszél: használhat SQL-t arra, hogy meghatározza, hogyan kell módosítani az adatbázisát. További információk a Spring Boot és a Flyway témájában találhatók a Spring Boot Docs.

A Spring Boot verziókezelő eszköz használatával 2 nagy előnyt kap:

  • elválasztja az adatbázis-változásokat a kódváltozásoktól
  • az adatbázis-migráció együtt történik az alkalmazás telepítésével, azaz egyszerűsíti a telepítési folyamatot

Adatbázis problémák megoldása

A cikk következő részében a két megközelítés áttekintésére fogunk összpontosítani az adatbázis-változásokkal kapcsolatban.

  • visszafelé inkompatibilitás
  • visszafelé kompatibilitás

Az első figyelmeztetésként kerül bemutatásra, hogy nem érdemes zero downtime telepítést végezni előkészítés nélkül... A második megoldást kínál arra, hogyan lehet a telepítést megszakítás nélkül végrehajtani, miközben fenntartjuk a visszafelé kompatibilitást.

A projekt, amin dolgozni fogunk, egy egyszerű Spring Boot Flyway alkalmazás lesz, amely tartalmazza a entitásokra ne figyeljetek, azok a domainhez tartoznak és a teszt keretében nem kerülnek figyelembe vételre. Tehát, egy ilyen gráf struktúrához a láncok keresési kérdése így nézne ki: a first_name és last_name az adatbázisban (megj.: entitásokra ne figyeljetek, azok a domainhez tartoznak és a teszt keretében nem kerülnek figyelembe vételre. Tehát, egy ilyen gráf struktúrához a láncok keresési kérdése így nézne ki: ez egy táblázat, és a first_name és last_name ez pedig egy mező benne). Azt szeretnénk, ha átneveznénk last_name be. surname.

Feltételezések

Mielőtt mélyebbre ásnánk a részletekbe, fontos néhány feltételezést megállapítani a projektjeinkkel kapcsolatban. A fő eredmény, amit el szeretnénk érni, egy viszonylag egyszerű folyamat lesz.

Megjegyzés. Business PRO-TIP: A folyamatok egyszerűsítése sok pénzt takaríthat meg a karbantartás során (minél több ember dolgozik a cégedben, annál több pénzt spórolhatsz)!

Nem szabad adatbázis visszaállítást végezni

Ez egyszerűsíti a telepítési folyamatot (bizonyos adatbázis-visszaállítások gyakorlatilag lehetetlenek, például egy törlés visszaállítása). Csak az alkalmazásokat szeretnénk visszaállítani. Így még ha különböző adatbázisok vannak is (például SQL és NoSQL), a telepítési pipelined ugyanúgy fog kinézni.

Mindig legyen lehetőség az alkalmazás visszaállítására egy verzióval korábbi állapotba (legfeljebb egyet).

A visszaállítást csak akkor kell végrehajtani, ha szükséges. Ha a jelenlegi verzióban van egy hiba, amelyet nehéz kijavítani, lehetőségünk kell, hogy legyen visszatérni az utolsó működő verzióhoz. Feltételezzük, hogy ez az utolsó működő verzió az előző. A kód és az adatbázis kompatibilitásának fenntartása több kiadáshoz rendkívül bonyolult és költséges lenne.

Megjegyzés. A nagyobb olvashatóság érdekében a cikk keretein belül a főverziót fogjuk módosítani.

1. lépés: Kiinduló állapot

Alkalmazás verzió: 1.0.0
DB verzió: v1

Megjegyzés

Ez lesz az alkalmazás kiinduló állapota.

DB változások

A DB tartalmazza last_name.

CREATE TABLE PERSON (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Kód változások

Az alkalmazás a Person adatokat tárolja a 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
                + "]";
    }
}

Visszafelé nem kompatibilis oszlop átnevezés

Nézzük meg a példát arra, hogyan lehet átnevezni egy oszlopot:

Figyelem. A következő példa szándékosan hibát fog okozni. Ezt az adatbázis kompatibilitásának problémájának bemutatására mutatjuk be.

Alkalmazás verzió: 2.0.0.BAD

DB verzió: v2bad

Megjegyzés

A jelenlegi változások NEM teszik lehetővé, hogy két példányt (a régit és az újat) párhuzamosan futtassunk. Így a zero downtime telepítés nehezen elérhető (figyelembe véve a feltételezéseket, ez gyakorlatilag lehetetlen).

A/B tesztelés

A jelenlegi helyzet az, hogy van egy alkalmazásunk, amelynek verziója 1.0.0, az éles rendszerben van telepítve, és a DB v1. Telepítenünk kell egy második példányt az alkalmazásból, amelynek verziója 2.0.0.BAD, és frissítenünk kell az adatbázist a v2bad.

Lépések:

  1. telepített új példány az alkalmazás verziójával 2.0.0.BAD, amely frissíti az adatbázist a v2bad
  2. az adatbázisban v2bad oszlop last_name többé nem létezik — átnevezték surname
  3. az adatbázis és az alkalmazás frissítése sikeresen megtörtént, és néhány példány működik a 1.0.0, mások pedig a 2.0.0.BAD. Mindezek kapcsolódnak a DB-hez v2bad
  4. minden példány verziója 1.0.0 hibákat kezd el dobni, mert próbálnak adatokat beszúrni az oszlopba last_name, amely már nem létezik
  5. minden példány verziója 2.0.0.BAD problémamentesen fognak működni

Ahogy látható, ha visszafelé nem kompatibilis változtatásokat végzünk az adatbázison és az alkalmazáson, akkor az A/B tesztelés lehetetlenné válik.

Alkalmazás visszaállítása

Tegyük fel, hogy az A/B telepítési kísérlet után (megjegyzés: valószínűleg itt az író A/B tesztelésre gondolt) azt döntöttük, hogy vissza kell állítanunk az alkalmazást a verzióra 1.0.0. Tegyük fel, hogy nem akarjuk visszaállítani az adatbázist.

Lépések:

  1. leállítjuk az alkalmazás példányát, a verziója 2.0.0.BAD
  2. az adatbázis még mindig v2bad
  3. mivel a verzió 1.0.0 nem érti, mi az surname, hibákat fogunk látni
  4. a pokol kiszabadult, már nem tudunk visszatérni

Ahogy látja, ha visszafelé inkompatibilis változtatásokat hajtunk végre az adatbázison és az alkalmazáson, nem tudunk visszatérni a korábbi verzióhoz.

A script futtatási naplója

Visszafelé inkompatibilis forgatókönyv:

01) Futtassa a 1.0.0-t
02) Várjon, amíg az alkalmazás (1.0.0) elindul
03) Generáljon egy személyt a POST localhost:9991/person hívással a 1.0.0 verzión
04) Futtassa a 2.0.0.BAD-t
05) Várjon, amíg az alkalmazás (2.0.0.BAD) elindul
06) Generáljon egy személyt a POST localhost:9991/person hívással a 1.0.0 verzión <-- ennek meg kellene buknia
07) Generáljon egy személyt a POST localhost:9992/person hívással a 2.0.0.BAD verzión <-- ennek át kellene mennie

Alkalmazás indítása 1.0.0 verzióban
Személy generálása 1.0.0 verzióban
POST küldése a 127.0.0.1:9991/person-ra. Ez a válasz:

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

Alkalmazás indítása 2.0.0.BAD verzióban
Személy generálása 1.0.0 verzióban
POST küldése a 127.0.0.1:9991/person-ra. Ez a válasz:

curl: (22) A kért URL hibaüzenetet adott vissza: 500 Belső Szolgáltatás Hiba

Személy generálása a 2.0.0.BAD verzióban
POST küldése a 127.0.0.1:9995/person-ra. Ez a válasz:

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

DB változások

A migrációs script, amely átnevezi last_name be. surname

Eredeti Flyway script:

CREATE TABLE PERSON (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

A script, amely átnevezi last_name.

-- Ez a változtatás visszafelé inkompatibilis - nem lehet A/B tesztelni
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Kód változások

Megváltoztattuk a mező nevét lastName Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata surname.

Az oszlop visszafelé kompatibilis módon történő átnevezése

Ez a leggyakoribb helyzet, amelybe beleütközhetünk. Visszafelé inkompatibilis változtatásokat kell végrehajtanunk. Már bizonyítottuk, hogy a leállás nélküli telepítésekhez nem alkalmazhatunk csak úgy adatbázis-migrációt, további lépések nélkül. Ebben a cikkben három alkalmazás telepítést fogunk végezni az adatbázis-migrációkkal együtt, hogy elérjük a kívánt eredményt, miközben megőrizzük a visszafelé kompatibilitást.

Megjegyzés. Emlékeztetünk, hogy van egy adatbázisunk a verzióval v1. Ez tartalmazza az oszlopokat first_name és last_name. Meg kell változtatnunk last_name Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata surname. Van egy alkalmazásunk a verzióval 1.0.0, , amely még nem használja surname.

2. lépés: Hozzáadjuk a surname-t

Alkalmazás verzió: 2.0.0
DB verzió: v2

Megjegyzés

Új oszlop hozzáadásával és annak tartalmának másolásával visszafelé kompatibilis adatbázis-változtatásokat végzünk. Ugyanakkor, ha vissza kell állítanunk a JAR-t, vagy van egy működő régi JAR-unk, az futás közben nem fog meghibásodni.

Új verzió kiadása

Lépések:

  1. végezze el az adatbázis-migrációt az új oszlop létrehozásához surname. Most az Ön adatbázisa a verzióval v2
  2. másolja az adatokat a last_name be. surname. Figyeljünk arra, hogy, és ha sok ilyen adat van, érdemes fontolóra venni a tömeges migrációt!
  3. írja meg a kódot, ahol használják BÁRMILYEN és új, és a régi oszlop. Most az alkalmazásod verziója 2.0.0
  4. olvassa az értéket az oszlopból surname, ha az nem null, vagy a last_name, ha surname nincs megadva. Eltávolíthatod a getLastName() metódust a kódból, mivel az hibát fog adni null ha visszaállítod az alkalmazásodat 3.0.0 tól 2.0.0.

Ha a Spring Boot Flyway-t használod, ezek a lépések az alkalmazás verziójának indításakor történnek. Ha manuálisan futtatod az adatbázis-kezelő eszközt, akkor két különböző lépést kell végrehajtanod (először manuálisan frissítened kell az adatbázis verzióját, majd telepítened kell az új alkalmazást). 2.0.0 Ne feledd, hogy az újonnan létrehozott oszlop

Fontos. NEM LEHET NOT NULL lenni . Ha visszaállítod, a régi alkalmazás nem tud az új oszlopról, és nem állítja be azt aBeszúrásakor. De ha ezt a korlátozást hozzáadod, és az adatbázisod , akkor az megköveteli az új oszlop értékének beállítását. Ez korlátozási hibákhoz vezet. v2El kell távolítanod a metódust

Fontos. , mivel a verzióban getLastName()a kódban nincs oszlop fogalom 3.0.0 . Ez azt jelenti, hogy null értéket állítanak be. Meghagyhatod a metódust, és hozzáadhatsz ellenőrzéseket a last_name, de sokkal jobb megoldás megbizonyosodni arról, hogy a logikában nullgetSurname() a helyes nem-null értéket választottad. , amely éles környezetben van telepítve, és az adatbázisban

A/B tesztelés

A jelenlegi helyzet az, hogy van egy alkalmazásunk, amelynek verziója 1.0.0. Telepítenünk kell a második példányt a verzióból v1, amely frissíti az adatbázist 2.0.0eközben néhány kérdést a verzió példányai kezeltek v2.

Lépések:

  1. telepített új példány az alkalmazás verziójával 2.0.0, amely frissíti az adatbázist a v2
  2. a frissítés sikeresen megtörtént, és több működő verziópéldányod van az alkalmazásból 1.0.0
  3. és a többi verzióból 1.0.0 Mind újra kommunikálnak az adatbázissal 2.0.0. nem használja az adatbázisban a surname oszlopot, míg a verzió v2
  4. verzió 1.0.0 használja. Ezek nem zavarják egymást, és nem kellene hibáknak lenniük. 2.0.0 megőrzi az adatokat mind a régi, mind az új oszlopban, ami biztosítja a visszafelé kompatibilitást
  5. verzió 2.0.0 Ha vannak bármilyen kérdéseid, amelyek elemeket számítanak a régi / új oszlop értékei alapján, ne feledd, hogy most adatduplikációk lesznek (valószínűleg még mindig migrálnak). Például, ha meg szeretnéd számolni a felhasználók számát, akiknek a vezetékneve (bármilyen néven is hívják az oszlopot) 'b'-vel kezdődik, akkor az adatmigrálás befejezése előtt

Fontos. a 'old' oszlopnál ellentmondásos adatokkal találkozhatsz, ha a új oszlopra kérdezel. AJelenleg van egy alkalmazásod a verzióbólés az adatbázis → new vissza kell állítani az alkalmazásodat a verzióhoz

Alkalmazás visszaállítása

nem használja az adatbázisban az oszlopot 2.0.0 és az adatbázisban v2.

Lépések:

  1. visszaállíthatja az alkalmazását egy korábbi verzióra 1.0.0.
  2. verzió 1.0.0 nem használja az adatbázisban az oszlopot surname, ezért a visszaállításnak sikeresnek kell lennie

DB módosítások

Az adatbázis oszlopot tartalmaz a következő névvel last_name.

Eredeti Flyway szkript:

CREATE TABLE PERSON (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY,
    first_name varchar(255) NOT NULL,
    last_name varchar(255) NOT NULL
);

insert into PERSON (first_name, last_name) values ('Dave', 'Syer');

Hozzáadási szkript surname.

Figyelem. Ne felejtsd el, hogy NEM ADDHATSZ SEMMILYEN NOT NULL megszorítást a hozzáadott oszlophoz. Ha visszaállítod a JAR-t, a régi verzió nem tud a hozzáadott oszlopról, és automatikusan NULL értéket ad neki. Ha van ilyen megszorítás, a régi alkalmazás egyszerűen hibát fog okozni.

-- MEGJEGYZÉS: Ez a mező nem lehet NOT NULL megszorítással, mert ha visszaállítod, a régi verzió nem tud a mezőről
-- és mindig NULL-ra állítja
ALTER TABLE PERSON ADD surname varchar(255);

-- FELTÉTELEZZÜK, HOGY EZ EGY GYORS MIGRÁCIÓ - KÜLÖNBEN CÉLSZERŰ BATCH-EBEN MIGRÁLNI
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Kód változások

Az adatokat úgy tároljuk, mint a last_name-ban, valamint a surname. Eközben olvasunk a last_name-ból, mivel ez az oszlop a legaktuálisabb. A telepítés során egyes lekérdezéseket lehet, hogy olyan alkalmazáspéldány kezelte, amely még nem volt frissítve.

/*
 * 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
                + "]";
    }
}

3. lépés: last_name eltávolítása a kódból

Alkalmazás verzió: 3.0.0

DB verzió:v3

Megjegyzés

Megjegyzés: Nyilvánvalóan az eredeti cikkben a szerző tévesen másolta ezt a blokk szöveget a 2. lépésből. Ezen a lépésen a kód módosításait kell végrehajtani az oszlopot használó funkciók eltávolítására. last_name.

Új oszlop hozzáadásával és tartalmának másolásával hátra kompatibilis változásokat hoztunk létre az adatbázisban. Emellett, ha visszaállítjuk a JAR-t vagy van egy működő régi JAR, az nem fog hibát okozni a futás során.

Alkalmazás visszaállítása

Jelenleg az alkalmazásunk a következő verziójú: 3.0.0 és az adatbázis v3. Verzió: 3.0.0 nem tárolja az adatokat a last_name. Ez azt jelenti, hogy a surname tartalmazza a legaktuálisabb információt.

Lépések:

  1. visszaállíthatja az alkalmazását egy korábbi verzióra 2.0.0.
  2. verzió 2.0.0 használ és last_name és surname.
  3. verzió 2.0.0 meg fogja kapni surname, ha nem null, különben —last_name

DB változások

Az adatbázisban nincsenek strukturális módosítások. A következő szkript fut, amely végrehajtja a régi adatok végső migrálását:

-- FELTÉTELEZZÜK, HOGY EZ EGY GYORS MIGRÁCIÓ - KÜLÖNBEN CÉLSZERŰ BATCH-EBEN MIGRÁLNI
-- Azt SEM állítjuk, hogy nem felülírjuk a meglévő bejegyzéseket. Össze kellene hasonlítanunk
-- a bejegyzések verzióit, hogy biztosak legyünk abban, hogy ha van már egy bejegyzés
-- magasabb verziószámmal, azt nem írjuk felül.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- A NOT NULL megszorítás eltávolítása; különben NULL értéket próbálsz beszúrni a last_name-ra
-- NOT_NULL megszorítással.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Kód változások

Megjegyzés: Ennek a blokknak a leírását is tévesen másolta a szerző a 2. lépésből. A cikk narratív logikájának megfelelően a kód módosításainak ezen a lépésen a az oszlopot kezelő elemek eltávolítására kell irányulnia. last_name.

Az adatokat úgy tároljuk, mint a last_name-ban, valamint a surname. Ezen kívül olvasunk az oszlopból last_name, mivel ez a legaktuálisabb. A telepítés során néhány lekérdezést olyan példány kezelhet, amely még nem frissült.

/*
 * 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
                + "]";
    }
}

4. lépés: last_name eltávolítása az adatbázisból

Alkalmazás verzió: 4.0.0

DB verzió: v4

Megjegyzés

A verzió kód miatt 3.0.0 nem használtuk az oszlopot last_name, a végrehajtás során nem történik semmi rossz, ha visszalépünk 3.0.0 az adatbázisból az oszlop eltávolítása után.

A script futtatási naplója

Ezt az alábbi módon fogjuk megtenni:

01) Futtassuk a 1.0.0-át
02) Várjunk az alkalmazás (1.0.0) elindulására
03) Generáljunk egy személyt a 1.0.0 verzióra a POST localhost:9991/person hívással
04) Futtassuk a 2.0.0-át
05) Várjunk az alkalmazás (2.0.0) elindulására
06) Generáljunk egy személyt a 1.0.0 verzióra a POST localhost:9991/person hívással
07) Generáljunk egy személyt a 2.0.0 verzióra a POST localhost:9992/person hívással
08) Öljük meg az alkalmazást (1.0.0)
09) Futtassuk a 3.0.0-át
10) Várjunk az alkalmazás (3.0.0) elindulására
11) Generáljunk egy személyt a 2.0.0 verzióra a POST localhost:9992/person hívással
12) Generáljunk egy személyt a 3.0.0 verzióra a POST localhost:9993/person hívással
13) Öljük meg az alkalmazást (3.0.0)
14) Futtassuk a 4.0.0-át
15) Várjunk az alkalmazás (4.0.0) elindulására
16) Generáljunk egy személyt a 3.0.0 verzióra a POST localhost:9993/person hívással
17) Generáljunk egy személyt a 4.0.0 verzióra a POST localhost:9994/person hívással

Alkalmazás indítása a 1.0.0-ás verzióban
Személy generálása az 1.0.0-ás verzióban
 POST küldése a 127.0.0.1:9991/person címre. Ez a válasz:

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

Alkalmazás indítása a 2.0.0-ás verzióban

Személy generálása az 1.0.0-ás verzióban
 POST küldése a 127.0.0.1:9991/person címre. Ez a válasz:

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

Személy generálása a 2.0.0-ás verzióban
 POST küldése a 127.0.0.1:9992/person címre. Ez a válasz:

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

1.0.0 alkalmazás leállítása

Alkalmazás indítása a 3.0.0-ás verzióban

Személy generálása a 2.0.0-ás verzióban
 POST küldése a 127.0.0.1:9992/person címre. Ez a válasz:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Személy generálása a 3.0.0-ás verzióban
 POST küldése a 127.0.0.1:9993/person címre. Ez a válasz:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

2.0.0 alkalmazás leállítása

Alkalmazás indítása a 4.0.0-ás verzióban

Személy generálása a 3.0.0-ás verzióban
 POST küldése a 127.0.0.1:9993/person címre. Ez a válasz:

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

Személy generálása a 4.0.0-ás verzióban
 POST küldése a 127.0.0.1:9994/person címre. Ez a válasz:

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

Adatbázis változások

Kapcsolatban v3 egyszerűen eltávolítjuk az oszlopot last_name és hozzáadjuk a hiányzó korlátozásokat.

-- ELMETETT OSZLOP
ALTER TABLE PERSON DROP last_name;

-- KORLÁTOZÁSOK HOZZÁADÁSA
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Kód változások

Nincs változás a kódban.

Következtetés

Sikeresen alkalmaztuk a nem hátra kompatibilis oszlopnév-változást több hátra kompatibilis telepítéssel. Az elvégzett lépések összefoglalása:

  1. alkalmazás telepítése a 1.0.0 a v1 adatbázis séma (oszlop neve = last_name)
  2. alkalmazás telepítése a 2.0.0, amely adatokat tárol last_name és surname. Az alkalmazás olvas a last_name. Az adatbázis a verzióban található v2, amely oszlopokat tartalmaz, mint például last_name, valamint vezetéknév. vezetéknév a l másolatát jelentiast_name. (MEGJEGYZÉS: ez az oszlop nem rendelkezhet not null megszorítással)
  3. alkalmazás telepítése a 3.0.0, amely csak adatokat tárol surname és olvas a vezetéknévből. Ami az adatbázist illeti, a legutolsó migráció zajlik. last_name be. surname. A megszorítás szintén . Ha visszaállítod, a régi alkalmazás nem tud az új oszlopról, és nem állítja be azt a levonásra kerül a last_name. Az adatbázis most a verzióban található v3
  4. alkalmazás telepítése a 4.0.0 — a kódban nincsenek változtatások. Az adatbázis telepítése v4, amely eltávolítja last_name. Itt bármilyen hiányzó megszorítást hozzáadhat az adatbázishoz.

E megközelítés követésével mindig visszaléphet egy verziót anélkül, hogy megsértené az adatbázis / alkalmazás kompatibilitását.

Kód

A cikkben használt összes kód elérhető a Githubot. További leírás következik.

Projektek

A tároló klónozása után a következő mappastruktúrát fogja látni.

├── boot-flyway-v1              - az alkalmazás 1.0.0 verziója v1 séma szerint
├── boot-flyway-v2              - az alkalmazás 2.0.0 verziója v2 séma szerint (visszafelé kompatibilis - az alkalmazás visszaállítható)
├── boot-flyway-v2-bad          - az alkalmazás 2.0.0.BAD verziója v2bad séma szerint (visszafelé nem kompatibilis - az alkalmazás nem állítható vissza)
├── boot-flyway-v3              - az alkalmazás 3.0.0 verziója v3 séma szerint (az alkalmazás visszaállítható)
└── boot-flyway-v4              - az alkalmazás 4.0.0 verziója v4 séma szerint (az alkalmazás visszaállítható)

Szkriptek

Futtathatja az alábbi scriptben leírt szkripteket, amelyek bemutatják a visszafelé kompatibilis és nem kompatibilis változásokat az adatbázisban.

Ahhoz, hogy lássa a visszafelé kompatibilis változások esetét,futtassa:

. /scripts/scenario_backward_compatible.sh

És ahhoz, hogy lássa a visszafelé nem kompatibilis változások esetét,futtassa:

. /scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

Minden példa a Spring Boot Sample Flyway-ból származik.

Megnézheti a http://localhost:8080/flyway, ott van a szkriptek listája.

Ez a példa tartalmaz egy H2 konzolt is (cím: http://localhost:8080/h2-console), hogy megtekinthesse az adatbázis állapotát (az alapértelmezett jdbc URL — jdbc:h2:mem:testdb).

További információ

Olvasd el többi cikkünket a blogunkban:

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster