Zero Downtime Deployment dhe databaza

Zero Downtime Deployment dhe databaza

Në këtë artikull, do të shpjegojmë se si të zgjidhni problemet e përputhshmërisë së bazave të të dhënave gjatë procesit të deplojes. Do të tregojmë se çfarë mund të ndodhi me aplikacionet tuaja në prodhim nëse provoni të kryeni deplojnë pa përgatitje të mëparshme. Pastaj, do të kalojmë përmes fazave të ciklit të jetës së aplikacionit, të cilat janë të nevojshme për të pasur kohë të mirë për zero (shënim: vazhdimi — zero downtime). Rezultati i operacioneve tona do të jetë aplikimi i modifikimit të papërshtatshëm të bazës së të dhënave në një mënyrë që është përshtatshme për prapavijën.

Nëse dëshironi të merrni një pasqyrë të shembujve të kodit nga artikulli, mund t'i gjeni në GitHub.

Hyrje

Zero downtime deployment

Çfarë është kjo mistere zero downtime deployment? Можно сказать, это когда ваше приложение развернуто так, что вы можете успешно вводить новую версию приложения на продакшн, в то время как пользователь не замечает его недоступности. С точки зрения пользователя и компании, это наилучший из возможных сценариев деплоя, поскольку таким образом можно вводить новые функции и устранять ошибки без перебоев в работе.

Si ta arrijmë këtë? Ka disa mënyra, ja një prej tyre:

  • deployoni versionin nr. 1 të shërbimit tuaj
  • kryeni migrimin e bazës së të dhënave
  • deployoni versionin nr. 2 të shërbimit tuaj paralelisht me versionin nr. 1
  • sa herë që të shihni se versioni nr. 2 funksionon siç duhet, hiqni versionin nr. 1
  • kaluar!

E lehtë, apo jo? Fatkeqësisht, nuk është aq e thjeshtë, dhe ne do ta shqyrtojmë më vonë. Tani, le të shqyrtojmë një proces tjetër të zakonshëm të deplojes — redhen blu jeshile.

A keni dëgjuar ndonjëherë për blue green deployment? С Cloud Foundry это чрезвычайно легко сделать. Просто гляньте на këtë artikull, ku e përshkruajmë këtë më në detaje. Duke bërë një përmbledhje të shkurtër, le të përmbledhim se si të kryejmë blue green deployment:

  • sigurohuni që të keni dy kopje të kodit tuaj produksion (“blu” dhe “jeshile”);
  • drejtoni gjithë trafikun në ambientin blu, dmth. që adresat URL të produksionit të tregojnë aty;
  • deployoni dhe testoni të gjitha ndryshimet e aplikacionit në ambientin jeshil;
  • kini adresat URL nga blu në ambientin jeshil

Blue green deployment — është një qasje që ju lejon të introduktoni lehtësisht funksionalitete të reja, pa u shqetësuar që prodhimi do të dështojë. Kjo lidhet me faktin se edhe nëse diçka ndodh, mund ta riktheheni lehtësisht në ambientin e mëparshëm, thjesht duke ‘ndryshuar ndriçimin’.

Pas leximit të gjithë më sipër, mund të pyesni: Çfarë lidhjeje ka zero downtime me blue green deployment?

Epo, kanë shumë të përbashkëta, pasi mbështetjeja e dy kopjeve të të njëjtit ambient kërkon përpjekje të dyfishta për mirëmbajtjen e tyre. Kjo është arsyeja pse disa ekipe, siç thotë Martin Fowler, ndjekin një variacion të këtij qasjes:

një variant tjetër është përdorimi i të njëjtës bazë të të dhënave, duke e krijuar kalimin blu-jeshil për shtresat web dhe domain. Në një qasje të tillë, bazat e të dhënave shpesh mund të bëhen problem, veçanërisht kur duhet të ndryshoni skemën e saj për të mbështetur një version të ri të softuerit.

Dhe këtu arrijmë në problemin kryesor të këtij artikulli. Baza e të dhënave. Le të heqim një herë tjetër një vështrim në këtë frazë.

kryeni migrimin e bazës së të dhënave.

Tani duhet t’i bëni vetes pyetjen — çfarë ndodh nëse ndryshimi i bazës së të dhënave është përshtatshëm? A nuk do të prishë versionin tim të parë të aplikacionit? Në fakt, pikërisht kjo do të ndodhte...

Prandaj, edhe pse ka përfitime të mëdha zero downtime / blue green deployment, kompanitë tendencojnë të ndjekin procesin më të sigurt për deplojen e aplikacioneve të tyre:

  • përgatitni një paketë me versionin e ri të aplikacionit
  • ndaloni aplikacionin që është duke funksionuar
  • në të njëjtën kohë ekzekutoni skriptet për migrimin e bazës së të dhënave
  • depononi dhe ç aktivizoni versionin e ri të aplikacionit

Në këtë artikull, do të përshkruajmë në detaje se si mund të punoni me bazën e të dhënave dhe kodin për të shfrytëzuar përfitimet e zero downtime deployment.

Problemet me bazën e të dhënave

Nëse keni një aplikacion pa gjendje, i cili nuk ruan asnjë të dhënë në bazën e të dhënave, mund të merrni zero downtime deployment menjëherë. Fatkeqësisht, shumica e softuerëve duhet të ruajnë të dhëna diku. Kjo është arsyeja pse duhet të mendoni mirë para se të bëni një ndryshim në skemë. Para se të thellohemi në detaje se si të ndryshoni skemën në mënyrë që të mund të kryhet deploy pa ndërprerje, le të përqendrohemi së pari në skemën e menaxhimit të versioneve.

Skema e menaxhimit të versioneve

Në këtë artikull, do të përdorim Flyway si një mjet për menaxhimin e versioneve (shënim: flasim për migrime të bazës së të dhënave). Natyrisht, gjithashtu do të shkruajmë një aplikacion Spring Boot, i cili ka mbështetje të integruar për Flyway dhe do të kryejë migrimin e skemës gjatë konfigurimit të kontekstit të aplikacionit. Duke përdorur Flyway, mund të ruani skriptet e migrimit në dosjen e projekteve tuaja (me default në classpath:db/migration). Këtu mund të shihni një shembull të tillë të skedarëve të migrimit

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

Në këtë shembull, ne shohim 4 skenare migrimi, të cilat, nëse nuk janë përfunduar më parë, do të kryhen një pas një kur të nisni aplikacionin. Le të shqyrtojmë një nga skedarët (V1__init.sql) si një shembull.

KRIJO TABELËN PERSON (
id BIGINT GJENERUAR NGA DEFAULT SI IDENTITET,
first_name varchar(255) not null,
last_name varchar(255) not null
);

futo në PERSON (first_name, last_name) vlera ('Dave', 'Syer');

E gjithë kjo flet për vete: mund ta përdorni SQL për të përcaktuar se si duhet të ndryshojë baza juaj e të dhënave. Për më shumë informacion në lidhje me Spring Boot dhe Flyway, shihni Dokumentat e Spring Boot.

Duke përdorur mjetin e menaxhimit të versioneve me Spring Boot, ju merrni 2 përfitime të mëdha:

  • ndani ndryshimet e bazës së të dhënave nga ndryshimet në kod
  • migroni bazën e të dhënave së bashku me lëshimin e aplikacionit tuaj, dmth. procesi juaj i deployment-it është i lehtësuar

Zgjidhja e problemeve me bazën e të dhënave

Në seksionin e ardhshëm të artikullit ne do të përqendrohemi në shqyrtimin e dy qasjeve për ndryshimet e bazës së të dhënave.

  • përputhshmëria e prapme
  • përputhshmëria përpara

E para do të shqyrtohet si një paralajmërim, se nuk duhet të bëni nxjerrje të papërgjegjshme pa përgatitje... E dyta ofron një zgjidhje, se si mund të bëni deployment pa ndalesa dhe njëkohësisht të ruani përputhshmërinë përpara.

Projekti ynë, mbi të cilin do të punojmë, do të jetë një aplikacion i thjeshtë Spring Boot Flyway, në të cilin ka Person me first_name dhe last_name në bazën e të dhënave (shënim: Person është tabela, dhe first_name dhe last_name është fusha në të). Ne duam të riemërtojmë last_namesurname.

Supozime

Para se të thellohemi në detaje, është e nevojshme të përcaktojmë disa supozime në lidhje me aplikacionet tona. Rezultati kryesor, që duam të arrijmë, do të jetë një proces mjaft i thjeshtë.

Shënim. Këshillë profesionale. Thjeshtimi i proceseve mund t'ju kursejë shumë para në mbështetje (sa më shumë njerëz të punojnë në kompaninë tuaj, aq më shumë keni mundësi të kurseni)!

Nuk duhet të bëni kthimin e bazës së të dhënave

Kjo e lehtëson procesin e lëshimit (disa kthime të bazës së të dhënave janë praktikisht të pamundura, për shembull kthimi i fshirjes). Ne preferojmë të rikthejmë vetëm aplikacionet. Në këtë mënyrë, edhe nëse keni baza të të dhënash të ndryshme (p.sh., SQL dhe NoSQL), pipeline juaj i lëshimit do të duket i njëjtë.

Duhet të ketë GJITHMONË mundësinë për të kthyer aplikacionin një version mbrapa (jo më shumë)

Kthimi duhet të bëhet vetëm në rast nevoje. Nëse në versionin aktual ka një gabim, i cili nuk është i lehtë për tu rregulluar, ne duhet të jemi në gjendje të kthehemi në versionin më të fundit funksional. Ne supozojmë se ky version më i fundit funksional është ai paraardhës. Mbështetja e përputhshmërisë midis kodit dhe bazës së të dhënave për më shumë se një lëshim do të ishte jashtëzakonisht e vështirë dhe e shtrenjtë.

Shënim. Për lexueshmëri më të madhe, brenda këtij artikulli ne do të ndryshojmë versionin e mërthit të aplikacionit.

Hapi 1: Shtimi i bazës

Versioni i aplikacionit: 1.0.0
Versioni i DB: v1

Komentari

Ky do të jetë gjendja fillestare e aplikacionit.

Ndryshimet në DB

DB përmban last_name.

KRIJO TABELËN PERSON (
    id BIGINT GJENERUAR NGA DEFAULT SI IDENTITET,
    first_name varchar(255) not null,
    last_name varchar(255) not null
);

futo në PERSON (first_name, last_name) vlera ('Dave', 'Syer');

Ndryshimet në kod

Aplikacioni ruan të dhënat Person në 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
                + "]";
    }
}

Ri-emërti i kolonës që nuk është i përputhshëm

Le të shohim një shembull, se si të ndryshoni emrin e kolonës:

Kujdes. Shembulli në vazhdim do të çojë qëllimisht në thyerjen e funksionalitetit. Ne e shfaqim këtë për të demonstruar problemin e përputhshmërisë së bazës së të dhënave.

Versioni i aplikacionit: 2.0.0.BAD

Versioni i DB: v2bad

Komentari

Ndryshimet aktuale NUK na lejojnë të drejtojmë dy ekzemplarë (të vjetër dhe të ri) njëkohësisht. Pra, lëshimi pa ndalesa do të jetë i vështirë për t'u arritur (nëse merret parasysh supozimet, në fakt është e pamundur).

Testimi A/B

Situata aktuale është se kemi një aplikacion versioni 1.0.0, të instaluar në prodhimin, dhe DB v1. Ne duhet të lëshojmë një ekzemplar të dytë të aplikacionit, versioni 2.0.0.BAD, dhe të azhurnojmë bazën e të dhënave në v2bad.

Hapat:

  1. u lëshua një ekzemplar i ri i aplikacionit versioni 2.0.0.BAD, i cili azhurnon bazën e të dhënave në v2bad
  2. në bazën e të dhënave v2bad kolona last_name nuk ekziston më - është ndryshuar në surname
  3. azhurimi i bazës së të dhënave dhe aplikacionit kaloi me sukses, dhe disa ekzemplarë funksionojnë në 1.0.0, të tjerë në 2.0.0.BAD. Të gjitha lidheshin me DB v2bad
  4. të gjithë ekzemplarët e versionit 1.0.0 do të fillojnë të japin gabime, sepse do të përpiqen të fusin të dhëna në kolonën last_nameqë nuk ekziston më
  5. të gjithë ekzemplarët e versionit 2.0.0.BAD do të funksionojnë pa probleme

Siç e shihni, nëse bëjmë ndryshime që nuk janë të përputhshme për bazën e të dhënave dhe aplikacionin, testimi A/B nuk është i mundur.

Kthimi aplikacionit

Le të supozojmë, se pas përpjekjes për të realizuar lëshimin A/B (shënim: ndoshta këtu autori kishte parasysh testimin A/B) ne vendosëm që na nevojitej të kthejmë aplikacionin në versionin 1.0.0. Supozoni se nuk duam të bëjmë kthimin e bazës së të dhënave.

Hapat:

  1. ndalem eksperimentin e aplikacionit versioni 2.0.0.BAD
  2. baza e të dhënave është akoma v2bad
  3. për shkak se versioni 1.0.0 nuk kupton se çfarë është surname, ne do të shohim gabime
  4. ka mësuar të shpëtojë, ne nuk mund të kthehemi më

Si e keni parë, nëse bëjmë ndryshime të pakompatueshme mbrapa në DB dhe aplikacion, nuk mund të kthehemi në versionin e mëparshëm.

Logs të ekzekutimit të skriptit

Scenario i pakompatueshëm mbrapa:

01) Ekzekutoni 1.0.0
02) Prisni që aplikacioni (1.0.0) të ngarkohet
03) Gjeneroni një person duke thirrur POST localhost:9991/person për versionin 1.0.0
04) Ekzekutoni 2.0.0.BAD
05) Prisni që aplikacioni (2.0.0.BAD) të ngarkohet
06) Gjeneroni një person duke thirrur POST localhost:9991/person për versionin 1.0.0 <-- kjo duhet të dështojë
07) Gjeneroni një person duke thirrur POST localhost:9992/person për versionin 2.0.0.BAD <-- kjo duhet të kalojë

Duke nisur aplikacionin në versionin 1.0.0
Gjeneroni një person në versionin 1.0.0
Duke dërguar një post në 127.0.0.1:9991/person. Kjo është përgjigjja:

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

Duke nisur aplikacionin në versionin 2.0.0.BAD
Gjeneroni një person në versionin 1.0.0
Duke dërguar një post në 127.0.0.1:9991/person. Kjo është përgjigjja:

curl: (22) URL-ja e kërkuar ktheu gabim: 500 Gabim Ndërmjetës

Ndryshimet në DB

Skripti i migrimit, i cili riemëron last_namesurname

Skripti origjinal Flyway:

KRIJO TABELËN PERSON (
    id BIGINT GJENERUAR NGA DEFAULT SI IDENTITET,
    first_name varchar(255) not null,
    last_name varchar(255) not null
);

futo në PERSON (first_name, last_name) vlera ('Dave', 'Syer');

Skripti, i cili riemëron last_name.

-- Ky ndryshim është në mënyrë pakompatibile mbrapa - nuk mund të bëni testim A/B
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Ndryshimet në kod

Ne kemi ndryshuar emrin e fushës lastNamesurname.

Riemërimi i kolonës në një mënyrë pakompatibile

Kjo është situata më e zakonshme me të cilën mund të përballemi. Na nevojitet të bëjmë ndryshime të pakompatueshme mbrapa. Ne e kemi provuar tashmë se për të bërë deploy pa ndërprerje, nuk duhet të aplikojmë thjesht migrimin e bazës së të dhënave pa hapa të tjerë. Në këtë pjesë të artikullit, ne do të kryejmë 3 deploy-e të aplikacionit së bashku me migrimet e bazës së të dhënave për të arritur rezultatin e dëshiruar dhe njëkohësisht të ruajmë pasqyrimin e prapavijës.

Shënim. Kujtojmë se kemi DB versioni v1. Ajo përmban kolonat first_name dhe last_name. Ne duhet të ndryshojmë last_namesurname. Ne gjithashtu kemi aplikacionin versioni 1.0.0, i cili ende nuk përdor surname.

Hapi 2: Shtoni surname

Versioni i aplikacionit: 2.0.0
Versioni i DB: v2

Komentari

Duke shtuar një kolonë të re dhe duke kopjuar përmbajtjen e saj, ne krijojmë ndryshime të pakompatueshme mbrapa në DB. Në të njëjtën kohë, nëse kthejmë JAR-in ose kemi një JAR të vjetër në punë, ai nuk do të dështojë gjatë ekzekutimit.

Lëshoni versionin e ri

Hapat:

  1. mënyra për të migruar DB, për të krijuar kolonën e re surname. Tani DB juaj versioni v2
  2. kopjoni të dhënat nga last_namesurname. Kërkojmë vëmendje, që nëse keni shumë nga këto të dhëna, duhet të shqyrtoni migimin në grupe!
  3. shkruani kodin, ku përdoren TË DY dhe e re, dhe kolona e vjetër. Tani aplikacioni juaj versioni lexoni vlerën nga kolona 2.0.0
  4. , nëse nuk është surname, ose nga l nullast_name, nësenuk është përcaktuar. Mund të hiqni surname getLastName() nga Kodi, pasi ai do të kthejë në kthimin e aplikacionit tuaj me null Nëse përdorni Spring Boot Flyway, këto dy hapa do të kryhen gjatë fillimit të versionit të aplikacionit. 3.0.0 deri në 2.0.0.

Nëse ekzekutoni mjetin për menaxhimin e versioneve të bazës së të dhënave manualisht, do t'ju duhet të bëni këtë për dy veprime të ndryshme (së pari azhurnoni versionin e db manualisht, pastaj lëshoni aplikacionin e ri). 2.0.0 Kujtoni që kolonat e sapo krijuara

Është e rëndësishme. NUK DUHET Nuk duhet të jetë NOT NULL. Nëse bëni kthimin prapa, aplikacioni i vjetër nuk e di për kolonën e re dhe nuk do ta vendosë gjatë Futni. Por nëse e shtoni këtë kufizim, dhe DB juaj është v2, do të kërkohet vendosja e vlerës së kolonës së re. Kjo do të çon në shkelje të kufizimeve.

Është e rëndësishme. Duhet të hiqni metodën nga Kodi, pasi ai do të kthejë, pasi në versionin 3.0.0 në kod nuk ka konceptin e kolonës last_name. Kjo do të thotë që do të vendosen null. Ju mund ta lini metodën dhe të shtoni kontrolle për null, por zgjidhja më e mirë do të ishte të siguroheni që në logjikën getSurname() zgjodhët vlerën e duhur të padëshirueshme.

Testimi A/B

Situata aktuale është se kemi një aplikacion versioni 1.0.0, e stanndardizuar në prodhim, dhe DB në v1. Duhet të lëshojmë një ekzemplar të dytë të aplikacionit versioni 2.0.0, i cili do të azhurnojë bazën e të dhënave në v2.

Hapat:

  1. u lëshua një ekzemplar i ri i aplikacionit versioni 2.0.0, i cili azhurnon bazën e të dhënave në v2
  2. ndërkohë disa kërkesa u përpunuan nga ekzemplarët e versionit 1.0.0
  3. azhurimi kaloi me sukses, dhe tani keni disa ekzemplarë funksionues të aplikacionit versioni 1.0.0 dhe versionet e tjera 2.0.0. Të gjitha komunikojnë me DB në v2
  4. versioni 1.0.0 nuk përdor kolonën surname në DB, ndërsa versioni 2.0.0 e përdor. Ato nuk pengojnë njëra-tjetrën, dhe nuk duhet të ketë gabime.
  5. versioni 2.0.0 ruan të dhënat si në kolonën e vjetër ashtu edhe në atë të re, duke siguruar pasqyrimin mbrapa

Është e rëndësishme. Nëse keni ndonjë kërkesë që numëron elemente në bazë të vlerave nga kolona e vjetër / e re, duhet të kujtoni se tani keni dublim vlerash (për shkak të migrimit në vazhdim). Për shembull, nëse dëshironi të numëroni përdoruesit, emri i të cilëve (pavarësisht se si quhet kolona) fillon me letrën A, atëherë deri në përfundimin e migrimit të të dhënave (kolona e vjetër) mund të keni të dhëna të paqëndrueshme, nëse ekzekutoni një kërkesë për kolonën e re.e re Tani kemi aplikacionin versioni

Kthimi aplikacionit

dhe bazën e të dhënave në 2.0.0 kthejeni aplikacionin tuaj në versionin v2.

Hapat:

  1. nuk përdor kolonën 1.0.0.
  2. versioni 1.0.0 në DB, prandaj kthimi duhet të jetë i suksesshëm. surnameNdryshimet e DB

DB përmban një kolonë me emrin

Skripti origjinal Flyway: last_name.

Skripti i shtimit

KRIJO TABELËN PERSON (
    id BIGINT GJENERUAR NGA DEFAULT SI IDENTITET,
    first_name varchar(255) not null,
    last_name varchar(255) not null
);

futo në PERSON (first_name, last_name) vlera ('Dave', 'Syer');

Skript për shtimin surname.

Kujdes. Kujtoni se nuk duhet të shtoni asnjë kufizim NOT NULL në kolonën që po shtohet. Nëse riktheni JAR-in, versioni i vjetër nuk do të dijë për kolonën e shtuar dhe automatikisht do t'i caktuar asaj vlerën NULL. Nëse ka një kufizim të tillë, aplikacioni i vjetër do të thyehet.

-- VËREJTJE: Ky fushë nuk mund të ketë kufizimin NOT NULL sepse nëse rikthehemi, versioni i vjetër nuk do ta dijë për këtë fushë
-- dhe gjithmonë do ta caktojë atë në NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- NË KËTË RAST MENDOJMË SE ËSHTË NJË MIGRIM I SHPEJTË - ND otherwise DO TË KISHE NEVOJË PËR TË MIGRUAR NË GRUPA
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Ndryshimet në kod

Ne ruajmë të dhënat si në last_name, si dhe në surname. Ndërkohë lexojmë nga last_name, pasi kjo kolonë është më e rëndësishmja. Në procesin e deploimit, disa kërkesa mund të jenë përpunuar nga një instancë e aplikacionit që ende nuk është përditësuar.

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

Hapi 3: Fshirja e last_name nga kodi

Versioni i aplikacionit: 3.0.0

Versioni i DB:v3

Komentari

Shënim përkthe: Duket se në artikullin origjinal autori ka kopjuar gabimisht tekstin nga ky bllok nga hapi 2. Në këtë hap duhet të bëhen ndryshime në kodin e aplikacionit, të orientuara drejt heqjes së funksionalitetit që përdor kolonën last_name.

Duke shtuar një kolonë të re dhe duke kopjuar përmbajtjen e saj, krijuam ndryshime të përshtatshme të BD-së. Nëse do të rikthejmë JAR-in ose kemi një JAR të vjetër që funksionon, ai nuk do të dështojë gjatë ekzekutimit.

Kthimi aplikacionit

Aktualisht kemi aplikacionin version 3.0.0 dhe bazën e të dhënave v3. Versioni 3.0.0 nuk ruan të dhënat në last_name. Kjo do të thotë se në surname ruhet informata më aktuale.

Hapat:

  1. nuk përdor kolonën 2.0.0.
  2. versioni 2.0.0 përdor dhe last_name dhe surname.
  3. versioni 2.0.0 do të marrë surname, nëse ai nuk është null, përndryshe —last_name

Ndryshimet në DB

Nuk ka ndryshime strukturore në BD. Skripti në vijim ekzekuton migrimin përfundimtar të të dhënave të vjetra:

-- NË KËTË RAST MENDOJMË SE ËSHTË NJË MIGRIM I SHPEJTË - NË ND otherwise DO TË KISHE NEVOJË PËR TË MIGRUAR NË GRUPA
-- PO ASHTU NUK PO KONTROLLONI Nëse NUK PO SHTONI ENTRIT TË EKZISTUAR. DUHEMI TË KRAHASOJME
-- VERSIONET E ENTRIVE PËR TË SIGURUAR QË NËSE KA NJË ENTRI ME NJË NUMËR TË LART VERSIONI
-- NE NUK DO TË SHTOJMË ATË.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- HEQJA E KUFIZIMIT NOT NULL; NDI otherwise DO TË PROVOJME TË SHTOJME VLERË NULL TË LAST_NAME
-- ME KUFIZIM NOT_NULL.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Ndryshimet në kod

Shënim përkthe: Përshkrimi i këtij blloku gjithashtu ka qenë gabimisht i kopjuar nga autori nga hapi 2. Sipas logjikës së tregimit të artikullit, ndryshimet në kodin në këtë hap duhet të jenë të orientuara drejt heqjes së elementeve që punojnë me kolonën last_name.

Ne ruajmë të dhënat si në last_name, si dhe në surname. Për më tepër, ne lexojmë nga kolona last_name, pasi ajo është më e rëndësishmja. Në procesin e shpërndarjes, disa kërkesa mund të përpunohen nga një instancë që ende nuk është përditësuar.

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

Hapi 4: Fshirja e last_name nga BD

Versioni i aplikacionit: 4.0.0

Versioni i DB: v4

Komentari

Pasi versioni 3.0.0 nuk përdori kolonën last_name, gjatë ekzekutimit nuk do të ndodhë ndonjë gjë e keqe nëse rikthehemi në 3.0.0 pas heqjes së kolonës nga baza e të dhënave.

Logs të ekzekutimit të skriptit

Do ta bëjmë në këtë mënyrë:

01) Ekzekuto 1.0.0
02) Prit për aplikacionin (1.0.0) që të ngrihet
03) Gjenero një person duke thirrur POST localhost:9991/person në versionin 1.0.0
04) Ekzekuto 2.0.0
05) Prit për aplikacionin (2.0.0) që të ngrihet
06) Gjenero një person duke thirrur POST localhost:9991/person në versionin 1.0.0
07) Gjenero një person duke thirrur POST localhost:9992/person në versionin 2.0.0
08) Vrit aplikacionin (1.0.0)
09) Ekzekuto 3.0.0
10) Prit për aplikacionin (3.0.0) që të ngrihet
11) Gjenero një person duke thirrur POST localhost:9992/person në versionin 2.0.0
12) Gjenero një person duke thirrur POST localhost:9993/person në versionin 3.0.0
13) Vrit aplikacionin (3.0.0)
14) Ekzekuto 4.0.0
15) Prit për aplikacionin (4.0.0) që të ngrihet
16) Gjenero një person duke thirrur POST localhost:9993/person në versionin 3.0.0
17) Gjenero një person duke thirrur POST localhost:9994/person në versionin 4.0.0

Duke filluar aplikacionin në versionin 1.0.0
Gjeneroni një person në versionin 1.0.0
Dërgimi i një postimi në 127.0.0.1:9991/person. Kjo është përgjigjja:

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

Duke filluar aplikacionin në versionin 2.0.0

Gjeneroni një person në versionin 1.0.0
Dërgimi i një postimi në 127.0.0.1:9991/person. Kjo është përgjigjja:

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

Gjeneroni një person në versionin 2.0.0
Dërgimi i një postimi në 127.0.0.1:9992/person. Kjo është përgjigjja:

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

Vrit aplikacionin 1.0.0

Duke filluar aplikacionin në versionin 3.0.0

Gjeneroni një person në versionin 2.0.0
Dërgimi i një postimi në 127.0.0.1:9992/person. Kjo është përgjigjja:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Gjeneroni një person në versionin 3.0.0
Dërgimi i një postimi në 127.0.0.1:9993/person. Kjo është përgjigjja:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

Vrit aplikacionin 2.0.0

Duke filluar aplikacionin në versionin 4.0.0

Gjeneroni një person në versionin 3.0.0
Dërgimi i një postimi në 127.0.0.1:9993/person. Kjo është përgjigjja:

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

Gjeneroni një person në versionin 4.0.0
Dërgimi i një postimi në 127.0.0.1:9994/person. Kjo është përgjigjja:

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

Ndryshimet e BD

Sa për v3 ne thjesht heqim kolonën last_name dhe shtojmë kufizimet që mungojnë.

-- HEQJA E KOLONËS
ALTER TABLE PERSON DROP last_name;

-- SHTIMI I KUFIZIMEVE
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Ndryshimet në kod

Nuk ka ndryshime në kod.

Përfundim

Ne e kemi realizuar me sukses një ndryshim të prapë të emrit të kolonës, duke realizuar disa shpërndarje të përshtatshme. Më poshtë është një përmbledhje e veprimeve të kryera:

  1. depoja e aplikacionit version 1.0.0 me v1 skemat e BD (emri i kolonës = last_name)
  2. depoja e aplikacionit version 2.0.0, që ruan të dhënat në last_name dhe surname. Aplikacioni lexon nga last_name. BD-ja është në versionin v2, duke përfshirë kolonat si last_name, ashtu edhe surname. surname është një kopje e l, nëse. (VËREJTJE: kjo kolona nuk duhet të ketë kufizimin not null)
  3. depoja e aplikacionit version 3.0.0, e cila ruan të dhënat vetëm në surname dhe lexon nga surname. Sa i përket DB, ndodhi migrimi i fundit last_namesurname. Po ashtu, kufizimi NOT NULL heqet nga last_name. DB tani është në versionin v3
  4. depoja e aplikacionit version 4.0.0 — nuk bëhen asnjë ndryshim në kod. Dërgimi i bazës së të dhënave v4, e cila fshin last_name. Këtu mund të shtoni çdo kufizim të munguar në DB.

Duke ndjekur këtë qasje, gjithmonë mund të ktheheni një version prapa, pa e prishur kompatibilitetin e DB / aplikacionit.

Kodi

Të gjithë kodin e përdorur në këtë artikull e gjeni në Github. Më poshtë përshkrim shtesë.

Projektet

Pas klonimit të repositorit, do të shihni strukturën e mëposhtme të dosjeve.

├── boot-flyway-v1              - 1.0.0 version e aplikacionit me v1 të skemës
├── boot-flyway-v2              - 2.0.0 version e aplikacionit me v2 të skemës (e përputhshme me prapa - aplikacioni mund të rikthehet)
├── boot-flyway-v2-bad          - 2.0.0.BAD version e aplikacionit me v2bad të skemës (e pa përputhshme - aplikacioni nuk mund të rikthehet)
├── boot-flyway-v3              - 3.0.0 version e aplikacionit me v3 të skemës (aplikacioni mund të rikthehet)
└── boot-flyway-v4              - 4.0.0 version e aplikacionit me v4 të skemës (aplikacioni mund të rikthehet)

Skripte

Mund të ekzekutoni skriptet e përshkruara në skriptet më poshtë, të cilat demonstrojnë ndryshimet e përputhshme dhe të pa përputhshme në DB.

Për të parë rastin me ndryshimet e përputhshme, ekzekutoni:

./scripts/scenario_backward_compatible.sh

Dhe për të parë rastin me ndryshimet e pa përputhshme, ekzekutoni:

./scripts/scenario_backward_incompatible.sh

Sample Flyway Spring Boot

Të gjitha shembujt janë marrë nga Spring Boot Sample Flyway.

Mund të shikoni në http://localhost:8080/flyway, aty është lista e skripteve.

Ky shembull gjithashtu përfshin konsolën H2 (në adresën http://localhost:8080/h2-console), që ju mundëson të shihni gjendjen e bazës së të dhënave (URL jdbc për default — jdbc:h2:mem:testdb).

Shtesë

Shihni gjithashtu artikuj të tjerë në blogun tonë:

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster