Zero Downtime Deployment an Datenbanken

Zero Downtime Deployment an Datenbanken

DĂ«sen Artikel erklĂ€ert am Detail wĂ©i d'DatebankkompatibilitĂ©itsprobleemer beim Deployment lĂ©isen. Mir soen Iech wat mat Äre Produktiounsapplikatioune ka geschĂ©ien wann Dir probĂ©iert ouni virleefeg Virbereedung z'installĂ©ieren. Mir ginn dann duerch d'Uwendungsliewenszyklusstadien dĂ©i noutwenneg sinn fir null Ausdauer ze hunn (ca. Lane: weider - null Ausdauer). D'Resultat vun eisen Operatiounen wĂ€ert sinn d'RĂ©ck-inkompatibel Datebank Ă€nneren op eng zrĂ©ck-kompatibel ManĂ©ier Ă«mzesetzen.

Wann Dir de Code Beispiller aus dem Artikel wëllt verstoen, kënnt Dir se op GitHub.

Aféierung

Null Downtime Deployment

Wat eng mystesch null Ënnerbriechung? Dir kĂ«nnt soen dat ass wann Är Applikatioun esou agesat gĂ«tt datt Dir erfollegrĂ€ich eng nei Versioun vun der Applikatioun an d'Produktioun afĂ©iere kĂ«nnt, wĂ€hrend de Benotzer seng OnverfĂŒgbarkeet net bemierkt. Aus enger Benotzer- a Firmenperspektiv ass dĂ«st dee beschtmĂ©igleche Deployment Szenario well et erlaabt nei Features agefouert ze ginn an Bugs ouni Ënnerbriechung ze fixĂ©ieren.

Wéi dëst z'erreechen? Et gi verschidde Weeër, hei ass ee vun hinnen:

  • deploy Versioun Nr 1 vun Ärem Service
  • eng Datebankmigratioun ausfĂ©ieren
  • Deploy Versioun #2 vun Ärem Service parallel mat Versioun #1
  • soubal Dir gesitt datt d'Versioun Nummer 2 funktionnĂ©iert wĂ©i se soll, huelt d'Versioun Nummer 1 ewech
  • gemaach!

Einfach, ass et net? Leider ass et net sou einfach, a mir wÀerten dat spéider am Detail kucken. Loosst eis elo en aneren zimlech allgemengen Deploymentprozess iwwerpréiwen - blo gréng Deployment.

Hutt Dir jeemools héieren blo gréng Détachement? Cloud Foundry mécht dëst extrem einfach. Kuckt just un dësen Artikel, wou mir dat méi am Detail beschreiwen. Fir kuerz ze resuméieren, loosst eis Iech drun erënneren wéi Dir blo gréng Deployment maacht:

  • sĂ©cherstellen datt zwee Exemplare vun Ärem Produktiounscode ("blo" a "grĂ©ng") funktionnĂ©ieren;
  • all VerkĂ©ier an dĂ©i blo Ëmwelt riichten, d.h. sou datt d'Produktioun URLen dohinner weisen;
  • deployĂ©ieren an testen all Applikatioun Ännerungen an engem grĂ©ngen Ëmfeld;
  • schalt URLen aus blo op grĂ©ng Ëmwelt

Blo grĂ©ng Deployment ass eng Approche dĂ©i Iech erlaabt nei Features einfach z'informĂ©ieren ouni Iech Suergen iwwer d'Produktioun ze briechen. DĂ«st ass wĂ©inst der Tatsaach datt och wann eppes geschitt, Dir kĂ«nnt einfach zrĂ©ck an dat viregt Ëmfeld zrĂ©ckrollen andeems Dir einfach "e Schalter flĂ©isst."

Nodeems Dir all déi uewe gelies hutt, kënnt Dir d'Fro stellen: Wat huet Null Downtime mat Blue Green Deployment ze dinn?

Gutt, si hunn zimmlech vill gemeinsam, well zwee Exemplare vum selwechten Ëmfeld erhalen, erfuerdert duebel Effort fir se z'erhalen. Dofir behaapten e puer Equippen Martin Fowler, befollegt eng Variatioun vun dĂ«ser Approche:

Eng aner Optioun ass déi selwecht Datebank ze benotzen, blo-gréng Schalter fir de Web an Domain Schichten ze kreéieren. An dëser Approche kann d'Datebank dacks e Problem sinn, besonnesch wann Dir sÀi Schema Ànneren musst fir eng nei Versioun vun der Software z'ënnerstëtzen.

An hei komme mer zum Haaptproblem an dësem Artikel. Datebank. Loosst eis dëse Saz nach eng Kéier kucken.

eng Datebankmigratioun ausféieren.

Elo musst Dir Iech d'Fro stellen - wat wann d'DatebankÀnnerung net zréckkompatibel ass? WÀert meng éischt Versioun vun der App net briechen? TatsÀchlech ass dat genau wat wÀert geschéien ...

Also, och trotz de grousse Virdeeler vun Null Downtime / Blogréng Deployment, tendéieren Firmen de folgende méi séchere Prozess fir hir Uwendungen z'installéieren:

  • preparĂ©ieren e Pak mat enger neier Versioun vun der Applikatioun
  • eng lafend Applikatioun zoumaachen
  • Scripte lafen fir d'Datebank ze migrĂ©ieren
  • deployĂ©ieren an eng nei Versioun vun der Applikatioun starten

An dĂ«sem Artikel wĂ€erte mir detaillĂ©iert wĂ©i Dir mat Ärer Datebank a Code schaffe kĂ«nnt fir vun Null Downtime Deployment ze profitĂ©ieren.

Datebank Problemer

Wann Dir eng stateless Applikatioun hutt, dĂ©i keng Daten an der Datebank spĂ€ichert, kĂ«nnt Dir direkt Null-Downtime-Deployment krĂ©ien. Leider muss dĂ©i meescht Software Daten iergendwou spĂ€icheren. Dofir sollt Dir zweemol nodenken ier Dir Ännerungen am Circuit maacht. Ier mer an d'Detailer kommen wĂ©i een de Schema Ă€nnert, sou datt d'Deployment ouni Downtime mĂ©iglech ass, loosst eis fir d'Ă©ischt op de Versiounsschema konzentrĂ©ieren.

Versioun Schema

An dĂ«sem Artikel wĂ€erte mir benotzen Fluchwee als Versiounskontrollinstrument (ca. Iwwersetzung: mir schwĂ€tzen iwwer Datebankmigratiounen). Natierlech wĂ€erte mir och eng Spring Boot Applikatioun schreiwen dĂ©i agebaute Flyway Support huet a Schema Migratioun ausfĂ©iert wĂ€rend den Applikatiounskontext opstellt. Wann Dir Flyway benotzt, kĂ«nnt Dir Migratiounsskripter an Ärem Projeten Dossier spĂ€icheren (par dĂ©faut an classpath:db/migration). Hei kĂ«nnt Dir e Beispill vun esou Migratioun Fichieren gesinn

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

An dësem Beispill gesi mir 4 Migratiounsskripter déi, wann net virdru ausgefouert goufen, een nom aneren ausgefouert ginn wann d'Applikatioun ufÀnkt. Loosst eis ee vun de Fichieren kucken (V1__init.sql) als Beispill.

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');

Alles ass perfekt selbstĂ€nneg: Dir kĂ«nnt SQL benotze fir ze definĂ©ieren wĂ©i Är Datebank geĂ€nnert soll ginn. Fir mĂ©i Informatiounen iwwert FrĂ©ijoer Boot an Flyway, kontrollĂ©ieren aus FrĂ©ijoer Boot Docs.

Andeems Dir e Quellkontrollinstrument mat Spring Boot benotzt, kritt Dir 2 grouss Virdeeler:

  • Dir trennt Datebank Ännerungen aus Code Ännerungen
  • Datebank Migratioun geschitt zesumme mat der Ausrollung vun Ärer Applikatioun, d.h. Ären Ofbauprozess ass vereinfacht

Troubleshooting Datebank Problemer

An der nĂ€chster Sektioun vum Artikel konzentrĂ©iere mir eis op zwou Approche fir Datebank Ännerungen ze kucken.

  • rĂ©ckgĂ€ngeg InkompatibilitĂ©it
  • RĂ©ckkompatibilitĂ©it

Déi éischt gëtt als Warnung ugesinn datt Dir keng Null-Downtime-Deployment ouni virleefeg Virbereedung sollt maachen ... Déi zweet bitt eng Léisung fir wéi Dir en Deployment ouni Downtime ausféiere kënnt a glÀichzÀiteg Réckkompatibilitéit erhalen.

Eise Projet un deem mir wĂ€erte schaffen ass eng einfach Spring Boot Flyway Applikatioun dĂ©i huet Person с first_name Đž last_name an der Datebank (ca. Iwwersetzung: Person ass en DĂ«sch a first_name Đž last_name - dat sinn d'Felder dran). Mir wĂ«llen Ă«mbenennen last_name ĐČ surname.

Viraussetzungen

Ier mer an d'Detailer kommen, ginn et e puer Viraussetzungen déi mir iwwer eis Uwendungen maache mussen. Den Haaptresultat, dee mir erreechen wëllen, ass e relativ einfache Prozess.

D'Notiz. Business PRO-TIP. Vereinfachung vu Prozesser kann Iech vill Suen op ËnnerstĂ«tzung spueren (wat mĂ©i Leit Dir fir Är Firma schafft, wat Dir mĂ©i Sue kĂ«nnt spueren)!

Kee Grond fir d'Datebank zréckzekréien

DĂ«st vereinfacht den DĂ©tachement Prozess (e puer Datebank Rollbacks si bal onmĂ©iglech, wĂ©i LĂ€schen Rollback). Mir lĂ©iwer nĂ«mmen Uwendungen zrĂ©ckrollen. Op dĂ«s ManĂ©ier, och wann Dir verschidden Datenbanken hutt (zum Beispill SQL an NoSQL), wĂ€ert Är Deployment Pipeline d'selwecht ausgesinn.

Et muss ËMMER mĂ©iglech sinn d'Applikatioun eng Versioun zrĂ©ck ze rullĂ©ieren (net mĂ©i)

Rollback soll nëmme gemaach ginn wann néideg. Wann et e Feeler an der aktueller Versioun ass, deen net einfach fixéiert ass, sollte mir fÀeg sinn op déi lescht funktionnéiert Versioun zréckzekommen. Mir huelen un datt dës lescht funktionnéiert Versioun déi virdrun ass. Code an Datebank Kompatibilitéit erhalen fir méi wéi ee Rollout wier extrem schwéier an deier.

D'Notiz. Fir méi Liesbarkeet, wÀerte mir an dësem Artikel d'Haaptversioun vun der Applikatioun Ànneren.

Schrëtt 1: Ufank Staat

App Versioun: 1.0.0
DB Versioun: v1

Commentaire

Dëst wÀert den initialen Zoustand vun der Applikatioun sinn.

Datebank Ännerungen

DB enthÀlt 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');

Code Ännerungen

D'Applikatioun spÀichert Persoundaten an 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
                + "]";
    }
}

Zeréck inkompatibel Kolonn ëmbenennen

Loosst eis e Beispill kucken wéi Dir e Kolonnnumm Ànnert:

Opgepasst. Dat folgend Beispill wÀert d'Saache bewosst briechen. Mir weisen dëst fir de Problem vun der Datebankkompatibilitéit ze weisen.

App Versioun: 2.0.0.BAD

DB Versioun: v2bad

Commentaire

DĂ©i aktuell Ännerungen erlaben eis NET zwou Instanzen (al an nei) zur selwechter ZĂ€it ze lafen. Also, Null Downtime Deployment wĂ€ert schwĂ©ier z'erreechen (wann Viraussetzunge berĂŒcksichtegt ginn, ass et tatsĂ€chlech onmĂ©iglech).

A/B Test

Déi aktuell Situatioun ass datt mir eng Applikatioun Versioun hunn 1.0.0, an der Produktioun agesat, an Datebank v1. Mir mussen eng zweet Instanz vun der Applikatioun ofsetzen, Versioun 2.0.0.BAD, an update der Datebank op v2bad.

Schrëtt:

  1. eng nei Instanz vun der Versiounsapplikatioun gëtt ofgesat 2.0.0.BADdéi d'Datebank aktualiséiert v2bad
  2. an der Datebank v2bad Kolonn last_name existéiert net méi - et gouf geÀnnert surname
  3. D'Datebank an d'Applikatioun Update war erfollegrÀich an e puer Instanzen lafen 1.0.0, anerer - an 2.0.0.BAD. Alles ass mat der Datebank verbonnen v2bad
  4. all Instanzen vun der Versioun 1.0.0 wÀert ufÀnken Feeler ze geheien well se probéieren Daten an d'Kolonn ze setzen last_namedéi et net méi gëtt
  5. all Instanzen vun der Versioun 2.0.0.BAD wÀert ouni Problemer schaffen

WĂ©i Dir gesitt, wa mir rĂ©ckgĂ€ngeg inkompatibel Ännerungen un der Datebank an der Applikatioun maachen, ass A/B Testen onmĂ©iglech.

Applikatioun Réckroll

Loosst eis unhuelen datt nodeems Dir probéiert A/B Deployment ze maachen (ca. per .: den Auteur gemengt wahrscheinlech A / B Testen hei) hu mir décidéiert datt mir d'Applikatioun op d'Versioun mussen zréckrollen 1.0.0. Loosst eis soen datt mir d'Datebank net wëllen zréckrollen.

Schrëtt:

  1. mir stoppen der Versioun Applikatioun Instanz 2.0.0.BAD
  2. d'Datebank ass nach ëmmer v2bad
  3. zanter der Versioun 1.0.0 versteet net wat et ass surname, mir wÀerte Feeler gesinn
  4. D'HÀll ass gebrach, mir kënnen net méi zréck

WĂ©i Dir gesitt, wa mir rĂ©ckgĂ€ngeg inkompatibel Ännerunge vun der Datebank an der Applikatioun maachen, kĂ«nne mir net op dĂ©i viregt Versioun zrĂ©ckrollen.

Skript Ausféierung Logbicher

Backward incompatible scenario:

01) Run 1.0.0
02) Wait for the app (1.0.0) to boot
03) Generate a person by calling POST localhost:9991/person to version 1.0.0
04) Run 2.0.0.BAD
05) Wait for the app (2.0.0.BAD) to boot
06) Generate a person by calling POST localhost:9991/person to version 1.0.0 <-- this should fail
07) Generate a person by calling POST localhost:9992/person to version 2.0.0.BAD <-- this should pass

Starting app in version 1.0.0
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

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

Starting app in version 2.0.0.BAD
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

curl: (22) The requested URL returned error: 500 Internal Server Error

Generate a person in version 2.0.0.BAD
Sending a post to 127.0.0.1:9995/person. This is the response:

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

Datebank Ännerungen

Migratiounsskript dat Ă«mbenannt last_name ĐČ surname

Source Flyway Skript:

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');

Skript dat ëmbenannt last_name.

-- This change is backward incompatible - you can't do A/B testing
ALTER TABLE PERSON CHANGE last_name surname VARCHAR;

Code Ännerungen

Mir hunn den Numm vum Feld geÀnnert lastName op surname.

Eng Kolonn ëmbenennen op eng zréckkompatibel Manéier

DĂ«st ass dĂ©i heefegst Situatioun dĂ©i mir begĂ©inen. Mir mussen rĂ©ckgĂ€ngeg inkompatibel Ännerungen maachen. Mir hu scho bewisen datt fir Null-Downtime Deployment, mir sollten net einfach Datebankmigratioun ouni zousĂ€tzlech SchrĂ«tt applizĂ©ieren. An dĂ«ser Rubrik vum Artikel wĂ€erte mir 3 Deployementer vun der Applikatioun zesumme mat Datebankmigratiounen ausfĂ©ieren fir dat gewĂ«nschte Resultat z'erreechen an d'RĂ©ckkompatibilitĂ©it z'erhalen.

D'Notiz. Erënneren, datt mir eng Versioun Datebank hunn v1. Et enthÀlt Kolonnen first_name О last_name. Mir mussen Ànneren last_name op surname. Mir hunn och App Versioun 1.0.0, déi nach net benotzt gëtt surname.

Schrëtt 2: Numm derbÀi

App Versioun: 2.0.0
DB Versioun: v2

Commentaire

Andeems Dir eng nei Kolonn bĂ€idrĂ©it a sĂ€in Inhalt kopĂ©iert, kreĂ©iere mir zrĂ©ckkompatibel Datebank Ännerungen. Zur selwechter ZĂ€it, wa mir de JAR zrĂ©ckrollen oder en alen JAR lafen, brĂ©cht en net wĂ€hrend der AusfĂ©ierung.

Mir rullen eng nei Versioun aus

Schrëtt:

  1. eng Datebankmigratioun ausfĂ©ieren fir eng nei Kolonn ze kreĂ©ieren surname. Elo Är DB Versioun v2
  2. kopĂ©ieren Daten aus last_name ĐČ surname. Opgepasstdatt wann Dir vill vun dĂ«sen DonnĂ©eĂ«n hutt, sollt Dir Batchmigratioun betruechten!
  3. schreiwen de Code wou se benotzt ginn BĂ©id Đž ĐœĐŸĐČыĐčan dĂ©i al Kolonn. Elo Är App Versioun 2.0.0
  4. liesen de WĂ€ert aus der Kolonn surname, wann et net ass nulloder aus last_name, wann a surname net uginn. Dir kĂ«nnt lĂ€schen getLastName() aus dem Code, well et gĂ«tt erausginn null wann Dir Är Applikatioun zrĂ©ckrollt 3.0.0 ze 2.0.0.

Wann Dir Spring Boot Flyway benotzt, ginn dës zwee Schrëtt wÀhrend der Versioun vum Startup gemaach 2.0.0 Uwendungen. Wann Dir d'Datebankversiouns-Tool manuell leeft, musst Dir zwou verschidde Saache maachen fir dëst ze maachen (éischt d'db Versioun manuell aktualiséieren an dann déi nei Applikatioun ofsetzen).

Et ass wichteg. ErĂ«nneren, datt dĂ©i nei geschaf Kolonn SOLL NET ze sinn NET NULL. Wann Dir eng Rollback maacht, weess dĂ©i al Applikatioun net iwwer dĂ©i nei Kolonn a wĂ€ert se net wĂ€hrend der Installatioun installĂ©ieren Insert. Awer wann Dir dĂ«s AschrĂ€nkung bĂ€idrĂ©it an Är db wĂ€ert sinn v2, DĂ«st wĂ€ert erfuerderen de WĂ€ert vun der neier Kolonn ze setzen. Wat zu Violatioune vu Restriktiounen fĂ©iert.

Et ass wichteg. Dir sollt d'Method ewechhuelen getLastName(), well an der Versioun 3.0.0 Et gëtt kee Konzept vun enger Kolonn am Code last_name. Dëst bedeit datt null do gesat gëtt. Dir kënnt d'Method verloossen a Schecken derbÀi fir null, mee eng vill besser Léisung wier sécher ze stellen, datt an der Logik getSurname() Dir hutt de richtegen Net-NullwÀert gewielt.

A/B Test

Déi aktuell Situatioun ass datt mir eng Applikatioun Versioun hunn 1.0.0, op Produktioun ofgesat, an d'Datebank an v1. Mir mussen eng zweet Instanz vun der Versiounsapplikatioun ofsetzen 2.0.0déi d'Datebank aktualiséieren v2.

Schrëtt:

  1. eng nei Instanz vun der Versiounsapplikatioun gëtt ofgesat 2.0.0déi d'Datebank aktualiséiert v2
  2. an der TëschenzÀit goufen e puer Ufroe vu Versiounsinstanzen veraarbecht 1.0.0
  3. den Update war erfollegrÀich an Dir hutt verschidde Lafen Instanzen vun der Versiounsapplikatioun 1.0.0 an aner Versiounen 2.0.0. Jiddereen kommunizéiert mat der Datebank an v2
  4. Versioun 1.0.0 benotzt net den Numm Kolonn an der Datebank, mÀ d'Versioun 2.0.0 benotzt. Si stéieren net mateneen, an et sollt kee Feeler sinn.
  5. Versioun 2.0.0 spÀichert Daten an der aler an der neier Kolonn, a garantéiert Réckkompatibilitéit

Et ass wichteg. Wann Dir Ufroen hutt dĂ©i Elementer zielen basĂ©iert op WĂ€erter aus der aler / neier Kolonn, sollt Dir drun erĂ«nneren datt Dir elo duplizĂ©iert WĂ€erter hutt (wahrscheinlech si se nach Ă«mmer migrĂ©ieren). Zum Beispill, wann Dir d'Zuel vun de Benotzer ziele wĂ«llt, deenen hire Familljennumm (egal wĂ©i d'Kolonn genannt gĂ«tt) mam Buschtaf ugefaang huet A, dann bis d'Datemigratioun fĂ€erdeg ass (old → new Kolonn) Dir hutt vlĂ€icht inkonsistent DonnĂ©eĂ«n wann Dir eng nei Kolonn ufrot.

Applikatioun Réckroll

Elo hu mir App Versioun 2.0.0 an Datebank an v2.

Schrëtt:

  1. rullt Är Applikatioun op d'Versioun zrĂ©ck 1.0.0.
  2. Versioun 1.0.0 benotzt keng Kolonn an der Datebank surname, sou datt d'Rollback erfollegrÀich ass

D'Ännerung am DB

D'Datebank enthÀlt eng Kolonn mam Numm last_name.

Flyway Quell Skript:

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');

Schreift derbÀi surname.

Opgepasst. Denkt drun datt Dir NET NULL AschrÀnkungen op d'Kolonn bÀidréit, déi Dir bÀidréit. Wann Dir de JAR zréckrollt, wÀert déi al Versioun keng Ahnung iwwer déi addéiert Kolonn hunn a se automatesch op NULL setzen. Wann et esou eng Begrenzung gëtt, brécht déi al Applikatioun einfach.

-- NOTE: This field can't have the NOT NULL constraint cause if you rollback, the old version won't know about this field
-- and will always set it to NULL
ALTER TABLE PERSON ADD surname varchar(255);

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
UPDATE PERSON SET PERSON.surname = PERSON.last_name

Code Ännerungen

Mir spÀicheren Daten als last_name, a surname. GlÀichzÀiteg liesen mir aus last_name, well dës Kolonn déi relevantst ass. WÀrend dem Détachementprozess kënnen e puer Ufroe vun enger Applikatiounsinstanz veraarbecht ginn, déi nach net aktualiséiert gouf.

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

Schrëtt 3: Last_name aus dem Code lÀschen

App Versioun: 3.0.0

DB Versioun:v3

Commentaire

Note per.: Scheinbar, am Originalartikel huet den Auteur falsch den Text vun dĂ«sem Block vum SchrĂ«tt kopĂ©iert 2. Op dĂ«sem SchrĂ«tt sollten Ännerungen am Applikatiounscode gemaach ginn, fir d'FunktionalitĂ©it ze lĂ€schen, dĂ©i d'Kolonn benotzt. last_name.

Andeems Dir eng nei Kolonn bĂ€idrĂ©it a sĂ€in Inhalt kopĂ©iert, hu mir rĂ©ckgĂ€ngeg kompatibel Datebank Ännerungen erstallt. Och wa mir de JAR zrĂ©ckrollen oder en alen JAR lafen, brĂ©cht et net wĂ€hrend der AusfĂ©ierung.

Applikatioun Réckroll

Momentan hu mir App Versioun 3.0.0 an Datebank v3. Versioun 3.0.0 spÀichert net Daten un last_name. Dat heescht, datt am surname déi aktuellst Informatioun gëtt gespÀichert.

Schrëtt:

  1. rullt Är Applikatioun op d'Versioun zrĂ©ck 2.0.0.
  2. Versioun 2.0.0 benotzt an last_name Đž surname.
  3. Versioun 2.0.0 wÀert huelen surname, wann et net null ass, soss -last_name

Datebank Ännerungen

Et gi keng strukturell Ännerungen an der Datebank. De folgende Skript gĂ«tt ausgefouert fir dĂ©i lescht Migratioun vun den alen DonnĂ©eĂ«n auszefĂ©ieren:

-- WE'RE ASSUMING THAT IT'S A FAST MIGRATION - OTHERWISE WE WOULD HAVE TO MIGRATE IN BATCHES
-- ALSO WE'RE NOT CHECKING IF WE'RE NOT OVERRIDING EXISTING ENTRIES. WE WOULD HAVE TO COMPARE
-- ENTRY VERSIONS TO ENSURE THAT IF THERE IS ALREADY AN ENTRY WITH A HIGHER VERSION NUMBER
-- WE WILL NOT OVERRIDE IT.
UPDATE PERSON SET PERSON.surname = PERSON.last_name;

-- DROPPING THE NOT NULL CONSTRAINT; OTHERWISE YOU WILL TRY TO INSERT NULL VALUE OF THE LAST_NAME
-- WITH A NOT_NULL CONSTRAINT.
ALTER TABLE PERSON MODIFY COLUMN last_name varchar(255) NULL DEFAULT NULL;

Code Ännerungen

Note per .: D'Beschreiwung vun dĂ«sem Block gouf och falsch vum Auteur vum SchrĂ«tt kopĂ©iert 2. Am Aklang mat der Logik vum Artikel, Ännerunge vum Code an dĂ«sem SchrĂ«tt solle zielt fir Elementer ze lĂ€schen dĂ©i mat der Kolonn funktionnĂ©ieren last_name.

Mir spÀicheren Daten als last_name, a surname. ZousÀtzlech liesen mir aus der Kolonn last_name, well et am meeschte relevant ass. WÀrend dem Détachementprozess kënnen e puer Ufroe vun enger Instanz veraarbecht ginn, déi nach net aktualiséiert gouf.

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

Schrëtt 4: Last_name aus der Datebank erofhuelen

App Versioun: 4.0.0

DB Versioun: v4

Commentaire

Wéinst der Tatsaach, datt d'Versioun Code 3.0.0 hunn d'Kolonn net benotzt last_name, nÀischt Schlechtes wÀert wÀhrend der Ausféierung geschéien wa mir zréck op 3.0.0 nodeems Dir eng Kolonn aus der Datebank ewechgeholl huet.

Skript Ausféierung Logbicher

We will do it in the following way:

01) Run 1.0.0
02) Wait for the app (1.0.0) to boot
03) Generate a person by calling POST localhost:9991/person to version 1.0.0
04) Run 2.0.0
05) Wait for the app (2.0.0) to boot
06) Generate a person by calling POST localhost:9991/person to version 1.0.0
07) Generate a person by calling POST localhost:9992/person to version 2.0.0
08) Kill app (1.0.0)
09) Run 3.0.0
10) Wait for the app (3.0.0) to boot
11) Generate a person by calling POST localhost:9992/person to version 2.0.0
12) Generate a person by calling POST localhost:9993/person to version 3.0.0
13) Kill app (3.0.0)
14) Run 4.0.0
15) Wait for the app (4.0.0) to boot
16) Generate a person by calling POST localhost:9993/person to version 3.0.0
17) Generate a person by calling POST localhost:9994/person to version 4.0.0

Starting app in version 1.0.0
Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

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

Starting app in version 2.0.0

Generate a person in version 1.0.0
Sending a post to 127.0.0.1:9991/person. This is the response:

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

Generate a person in version 2.0.0
Sending a post to 127.0.0.1:9992/person. This is the response:

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

Killing app 1.0.0

Starting app in version 3.0.0

Generate a person in version 2.0.0
Sending a post to 127.0.0.1:9992/person. This is the response:
{"firstName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","lastName":"74d84a9e-5f44-43b8-907c-148c6d26a71b","surname":"74d84a9e-5f44-43b8-907c-148c6d26a71b"}

Generate a person in version 3.0.0
Sending a post to 127.0.0.1:9993/person. This is the response:
{"firstName":"c6564dbe-9ab5-40ae-9077-8ae6668d5862","surname":"c6564dbe-9ab5-40ae-9077-8ae6668d5862"}

Killing app 2.0.0

Starting app in version 4.0.0

Generate a person in version 3.0.0
Sending a post to 127.0.0.1:9993/person. This is the response:

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

Generate a person in version 4.0.0
Sending a post to 127.0.0.1:9994/person. This is the response:

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

D'Ännerung am DB

Relativ v3 mir lÀschen just d'Kolonn last_name an dobÀi vermësst Restriktiounen.

-- REMOVE THE COLUMN
ALTER TABLE PERSON DROP last_name;

-- ADD CONSTRAINTS
UPDATE PERSON SET surname='' WHERE surname IS NULL;
ALTER TABLE PERSON ALTER COLUMN surname VARCHAR NOT NULL;

Code Ännerungen

Et gi keng Ännerungen un de Code.

Konklusioun

Mir hunn erfollegrĂ€ich e RĂ©ck-inkompatibel Spaltennumm Ännerung applizĂ©iert andeems mir e puer zrĂ©ckkompatibel Deployementer ausfĂ©ieren. DrĂ«nner ass e ResumĂ© vun den Aktiounen dĂ©i gemaach goufen:

  1. Détachement vun der Applikatioun Versioun 1.0.0 с v1 Datebank Schema (Kolonnnumm = last_name)
  2. Détachement vun der Applikatioun Versioun 2.0.0, déi Daten spÀichert an last_name О surname. D'Applikatioun liest aus last_name. D'Datebank ass an der Versioun v2enthÀlt Spalten wéi last_namean surname. surname ass eng Kopie vum last_name. (OPGEPASST: Dës Kolonn dÀerf keng net null Constraint hunn)
  3. DĂ©tachement vun der Applikatioun Versioun 3.0.0, dĂ©i nĂ«mmen Daten spĂ€ichert an surname a liest aus Familljennumm. Wat d'Datebank ugeet, fĂ«nnt dĂ©i lescht Migratioun statt last_name ĐČ surname. Och eng Begrenzung NET NULL zrĂ©ckgezunn aus last_name. D'Datebank ass elo an der Versioun v3
  4. DĂ©tachement vun der Applikatioun Versioun 4.0.0 - keng Ännerungen am Code gemaach. Datebank Deployment v4, dĂ©i lĂ€scht last_name. Hei kĂ«nnt Dir all fehlend AschrĂ€nkungen an d'Datebank derbĂ€isetzen.

Andeems Dir dës Approche verfollegt, kënnt Dir ëmmer eng Versioun zréckrollen ouni d'Datebank-/Uwendungskompatibilitéit ze briechen.

Code

All Code an dësem Artikel benotzt ass sinn op Github. Drënner ass eng zousÀtzlech Beschreiwung.

Projeten

Nodeems Dir de Repository klonen, gesitt Dir déi folgend Dossierstruktur.

├── boot-flyway-v1              - 1.0.0 version of the app with v1 of the schema
├── boot-flyway-v2              - 2.0.0 version of the app with v2 of the schema (backward-compatible - app can be rolled back)
├── boot-flyway-v2-bad          - 2.0.0.BAD version of the app with v2bad of the schema (backward-incompatible - app cannot be rolled back)
├── boot-flyway-v3              - 3.0.0 version of the app with v3 of the schema (app can be rolled back)
└── boot-flyway-v4              - 4.0.0 version of the app with v4 of the schema (app can be rolled back)

Scripten

Dir kĂ«nnt d'Skripte lafen, dĂ©i an de Scripten hei Ă«nnen beschriwwe ginn, dĂ©i zrĂ©ckkompatibel an inkompatibel Ännerungen an der Datebank weisen.

Fir ze kucken de Fall mat RĂ©ckkompatibel Ännerungen, lafen:

./scripts/scenario_backward_compatible.sh

An ze gesinn Fall mat rĂ©ckgĂ€ngeg inkompatibel Ännerungen, lafen:

./scripts/scenario_backward_incompatible.sh

Fréijoer Boot Sample Flyway

All Beispiller sinn aus Spring Boot Sample Flyway.

Dir kënnt e Bléck op http://localhost:8080/flyway, et gëtt eng Lëscht vu Scripten.

Dëst Beispill enthÀlt och d'H2 Konsol (at http://localhost:8080/h2-console) sou datt Dir den Datebankstatus kuckt (Standard jdbc URL ass jdbc:h2:mem:testdb).

ZousÀtzlech

Liest och aner Artikelen op eisem Blog:

Source: will.com

Kaaft zouverlĂ€sseg Hosting fir Site mat DDoS Schutz, VPS VDS Server đŸ”„ Kaaft zouverlĂ©issegt WebsĂ€ithosting mat DDoS-Schutz, VPS VDS Server | ProHoster