Zero Downtime Deployment ΠΈ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…

Zero Downtime Deployment ΠΈ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΎΠ±ΡŠΡΡΠ½ΡΠ΅Ρ‚ΡΡ, ΠΊΠ°ΠΊ Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹, связанныС с ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ Π±Π°Π· Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΡ€ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠ΅. ΠœΡ‹ расскаТСм, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΡ‚ΠΈ с вашими прилоТСниями Π½Π° ΠΏΡ€ΠΎΠ΄Π΅, Ссли Π²Ρ‹ ΠΏΠΎΠΏΡ‹Ρ‚Π°Π΅Ρ‚Π΅ΡΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π±Π΅Π· ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠΈ. Π—Π°Ρ‚Π΅ΠΌ ΠΌΡ‹ пройдСмся ΠΏΠΎ этапам ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π° прилоТСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ врСмя простоя (ΠΏΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: Π΄Π°Π»Π΅Π΅ β€” zero downtime). Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ Π½Π°ΡˆΠΈΡ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимого измСнСния Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимым способом.

Если Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒΡΡ с ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°ΠΌΠΈ ΠΊΠΎΠ΄Π° ΠΈΠ· ΡΡ‚Π°Ρ‚ΡŒΠΈ, Π²Ρ‹ ΠΈΡ… Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° GitHub.

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅

Zero downtime deployment

Π§Ρ‚ΠΎ Π·Π° мистичСский zero downtime deployment? МоТно ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, это ΠΊΠΎΠ³Π΄Π° вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΠΎ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ прилоТСния Π½Π° ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½, Π² Ρ‚ΠΎ врСмя ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π·Π°ΠΌΠ΅Ρ‡Π°Π΅Ρ‚ Π΅Π³ΠΎ нСдоступности. Π‘ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, это Π½Π°ΠΈΠ»ΡƒΡ‡ΡˆΠΈΠΉ ΠΈΠ· Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Ρ… сцСнариСв дСплоя, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΠΎΠΆΠ½ΠΎ Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ ΡƒΡΡ‚Ρ€Π°Π½ΡΡ‚ΡŒ ошибки Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π±ΠΎΠ΅Π² Π² Ρ€Π°Π±ΠΎΡ‚Π΅.

Как этого Π΄ΠΎΡΡ‚ΠΈΡ‡ΡŒ? Π•ΡΡ‚ΡŒ нСсколько способов, Π²ΠΎΡ‚ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π½ΠΈΡ…:

  • Ρ€Π°Π·Π²Π΅Ρ€Π½ΠΈΡ‚Π΅ Π²Π΅Ρ€ΡΠΈΡŽ β„–1 вашСго сСрвиса
  • ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ Π‘Π”
  • Ρ€Π°Π·Π²Π΅Ρ€Π½ΠΈΡ‚Π΅ Π²Π΅Ρ€ΡΠΈΡŽ β„– 2 вашСго сСрвиса ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ с вСрсиСй β„– 1
  • ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Ρ‹ ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ вСрсия β„– 2 Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ Π½Π°Π΄ΠΎ, ΡƒΠ±ΠΈΡ€Π°ΠΉΡ‚Π΅ Π²Π΅Ρ€ΡΠΈΡŽ β„– 1
  • Π³ΠΎΡ‚ΠΎΠ²ΠΎ!

Π›Π΅Π³ΠΊΠΎ, Π½Π΅ ΠΏΡ€Π°Π²Π΄Π° Π»ΠΈ? К соТалСнию, это Π½Π΅ Ρ‚Π°ΠΊ просто, ΠΈ ΠΌΡ‹ ΠΏΠΎΠ·ΠΆΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ это рассмотрим. А сСйчас Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ довольно распространСнный процСсс дСплоя β€” blue green deployment.

Π’Ρ‹ ΠΊΠΎΠ³Π΄Π°-Π½ΠΈΠ±ΡƒΠ΄ΡŒ ΡΠ»Ρ‹ΡˆΠ°Π»ΠΈ ΠΎ blue green deployment? Π‘ Cloud Foundry это Ρ‡Ρ€Π΅Π·Π²Ρ‹Ρ‡Π°ΠΉΠ½ΠΎ Π»Π΅Π³ΠΊΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ. ΠŸΡ€ΠΎΡΡ‚ΠΎ Π³Π»ΡΠ½ΡŒΡ‚Π΅ Π½Π° эту ΡΡ‚Π°Ρ‚ΡŒΡŽ, Π³Π΄Π΅ ΠΌΡ‹ описываСм это Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ. ΠšΡ€Π°Ρ‚ΠΊΠΎ Ρ€Π΅Π·ΡŽΠΌΠΈΡ€ΡƒΡ, Π½Π°ΠΏΠΎΠΌΠ½ΠΈΠΌ, ΠΊΠ°ΠΊ Π΄Π΅Π»Π°Ρ‚ΡŒ blue green deployment:

  • ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ Π΄Π²ΡƒΡ… ΠΊΠΎΠΏΠΈΠΉ вашСго production ΠΊΠΎΠ΄Π° (β€œblue” ΠΈ β€œgreen”);
  • Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ вСсь Ρ‚Ρ€Π°Ρ„ΠΈΠΊ Π² blue срСду, Ρ‚.Π΅. Ρ‡Ρ‚ΠΎΠ±Ρ‹ URL-адрСса ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π° ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π»ΠΈ Ρ‚ΡƒΠ΄Π°;
  • Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Ρ‚ΡŒ ΠΈ Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ всС измСнСния прилоТСния Π² green срСдС;
  • ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ URL-адрСса с blue Π½Π° green срСду

Blue green deployment β€” это ΠΏΠΎΠ΄Ρ…ΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт Π²Π°ΠΌ Π»Π΅Π³ΠΊΠΎ Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π½Π΅ пСрСТивая, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½ сломаСтся. Π­Ρ‚ΠΎ связано с Ρ‚Π΅ΠΌ Ρ„Π°ΠΊΡ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π΄Π°ΠΆΠ΅ Ссли Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ случится, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π»Π΅Π³ΠΊΠΎ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒΡΡ Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΡƒΡŽ срСду, просто Β«Ρ‰Π΅Π»ΠΊΠ½ΡƒΠ² ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»Π΅ΠΌΒ».

ΠŸΡ€ΠΎΡ‡ΠΈΡ‚Π°Π² всС Π²Ρ‹ΡˆΠ΅ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»Π΅Π½Π½ΠΎΠ΅, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°Π΄Π°Ρ‚ΡŒ вопрос: КакоС ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ zero downtime ΠΈΠΌΠ΅Π΅Ρ‚ ΠΊ Blue green дСплою?

Π§Ρ‚ΠΎ ΠΆ, Ρƒ Π½ΠΈΡ… довольно ΠΌΠ½ΠΎΠ³ΠΎ ΠΎΠ±Ρ‰Π΅Π³ΠΎ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Π΄Π²ΡƒΡ… ΠΊΠΎΠΏΠΈΠΉ ΠΎΠ΄Π½ΠΎΠΉ ΠΈ Ρ‚ΠΎΠΉ ΠΆΠ΅ срСды Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π΄Π²ΠΎΠΉΠ½Ρ‹Ρ… усилий для ΠΈΡ… обслуТивания. Π’ΠΎΡ‚ ΠΏΠΎΡ‡Π΅ΠΌΡƒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹, ΠΊΠ°ΠΊ ΡƒΡ‚Π²Π΅Ρ€ΠΆΠ΄Π°Π΅Ρ‚ Martin Fowler, ΠΏΡ€ΠΈΠ΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ Π²Π°Ρ€ΠΈΠ°Ρ†ΠΈΠΈ этого ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°:

Π΄Ρ€ΡƒΠ³ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² использовании Ρ‚ΠΎΠΉ ΠΆΠ΅ Π‘Π”, создавая синС-Π·Π΅Π»Π΅Π½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»ΠΈ для web ΠΈ domain layers. Π’ Ρ‚Π°ΠΊΠΎΠΌ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π΅ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… часто ΠΌΠΎΠ³ΡƒΡ‚ ΡΠ²Π»ΡΡ‚ΡŒΡΡ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΠΉ, особСнно ΠΊΠΎΠ³Π΄Π° Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Ρ‘ схСму для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ Π½ΠΎΠ²ΠΎΠΉ вСрсии ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ обСспСчСния.

И здСсь ΠΌΡ‹ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊ Π³Π»Π°Π²Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ΅ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅. Π‘Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ…. Π”Π°Π²Π°ΠΉΡ‚Π΅ Π΅Ρ‰Π΅ Ρ€Π°Π· взглянСм Π½Π° эту Ρ„Ρ€Π°Π·Ρƒ.

ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ Π‘Π”.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π·Π°Π΄Π°Ρ‚ΡŒ сСбС вопрос β€” Ρ‡Ρ‚ΠΎ, Ссли ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимо? Π Π°Π·Π²Π΅ моя пСрвая вСрсия прилоТСния Π½Π΅ сломаСтся? На самом Π΄Π΅Π»Π΅, ΠΈΠΌΠ΅Π½Π½ΠΎ это ΠΈ случится…

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π΄Π°ΠΆΠ΅ нСсмотря Π½Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½Ρ‹Π΅ прСимущСства zero downtime / blue green deployment, ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ склонны ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌΡƒ Π±ΠΎΠ»Π΅Π΅ бСзопасному процСссу дСплоя своих ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ:

  • ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ с Π½ΠΎΠ²ΠΎΠΉ вСрсиСй прилоТСния
  • Π²Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
  • Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ скрипты для ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…
  • Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ прилоТСния

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ опишСм, ΠΊΠ°ΠΊ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΠΊΠΎΠ΄ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ прСимущСствами zero downtime deployment.

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ…

Если Ρƒ вас Π΅ΡΡ‚ΡŒ stateless ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ Π½ΠΈΠΊΠ°ΠΊΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ… Π² Π‘Π”, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ zero downtime deployment сразу. К соТалСнию, большая Ρ‡Π°ΡΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ обСспСчСния Π΄ΠΎΠ»ΠΆΠ½Π° Π³Π΄Π΅-Ρ‚ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅. Π’ΠΎΡ‚ ΠΏΠΎΡ‡Π΅ΠΌΡƒ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π΄Π²Π°ΠΆΠ΄Ρ‹ ΠΏΠΎΠ΄ΡƒΠΌΠ°Ρ‚ΡŒ, ΠΏΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Π²Π½ΠΎΡΠΈΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Π»ΠΈΠ±ΠΎ измСнСния Π² схСму. ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΠΌΡ‹ углубимся Π² Π΄Π΅Ρ‚Π°Π»ΠΈ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ схСму Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ стал Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΌ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π±Π΅Π· простоя, Π΄Π°Π²Π°ΠΉΡ‚Π΅ сначала сосрСдоточимся Π½Π° схСмС управлСния вСрсиями.

Π‘Ρ…Π΅ΠΌΠ° управлСния вСрсиями

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Flyway Π² качСствС инструмСнта для управлСния вСрсиями (ΠΏΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: Ρ€Π΅Ρ‡ΡŒ ΠΈΠ΄Ρ‘Ρ‚ ΠΏΡ€ΠΎ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ Π‘Π”). ЕстСствСнно, ΠΌΡ‹ Ρ‚Π°ΠΊΠΆΠ΅ напишСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Spring Boot, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ Π²ΡΡ‚Ρ€ΠΎΠ΅Π½Π½ΡƒΡŽ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ Flyway ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ схСмы Π²ΠΎ врСмя настройки контСкста прилоТСния. ΠŸΡ€ΠΈ использовании Flyway Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ скрипты ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ Π² ΠΏΠ°ΠΏΠΊΠ΅ Π²Π°ΡˆΠΈΡ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² (ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² classpath:db/migration). Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Π°ΠΊΠΈΡ… Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ

└── db
 └── migration
     β”œβ”€β”€ V1__init.sql
     β”œβ”€β”€ V2__Add_surname.sql
     β”œβ”€β”€ V3__Final_migration.sql
     └── V4__Remove_lastname.sql

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ 4 сцСнария ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅, Ссли ΠΎΠ½ΠΈ Π½Π΅ Π±Ρ‹Π»ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ Ρ€Π°Π½Π΅Π΅, Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ ΠΎΠ΄ΠΈΠ½ Π·Π° Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡ€ΠΈ запускС прилоТСния. Π”Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Ρ„Π°ΠΉΠ»ΠΎΠ² (V1__init.sql) Π² качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°.

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

ВсС прСкрасно Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ само Π·Π° сСбя: Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ SQL, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊ ваша Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Π°. Для получСния Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ Spring Boot ΠΈ Flyway ΠΎΠ·Π½Π°ΠΊΠΎΠΌΡŒΡ‚Π΅ΡΡŒ с Spring Boot Docs.

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ инструмСнт управлСния вСрсиями со Spring Boot, Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚Π΅ 2 Π±ΠΎΠ»ΡŒΡˆΠΈΡ… прСимущСства:

  • Π²Ρ‹ отдСляСтС измСнСния Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΡ‚ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΊΠΎΠ΄Π°
  • миграция Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… происходит вмСстС с Π²Ρ‹ΠΊΠ°Ρ‚ΠΊΠΎΠΉ вашСго прилоТСния, Ρ‚.Π΅. ваш процСсс дСплоя упрощаСтся

РСшСниС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ…

Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΌΡ‹ сосрСдоточимся Π½Π° рассмотрСнии Π΄Π²ΡƒΡ… ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠ² ΠΊ измСнСниям Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ….

  • обратная Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ
  • обратная ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ рассмотрСн ΠΊΠ°ΠΊ прСдостСрСТСниС, Ρ‡Ρ‚ΠΎ Π½Π΅ стоит ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ΡŒ zero downtime deployment Π±Π΅Π· ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ подготовки… Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π±Π΅Π· простоСв ΠΈ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ.

Наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π½Π°Π΄ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, Π±ΡƒΠ΄Π΅Ρ‚ простым ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Spring Boot Flyway, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π΅ΡΡ‚ΡŒ Person с first_name ΠΈ last_name Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… (ΠΏΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: Person являСтся Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ, Π° first_name ΠΈ last_name β€” это поля Π² Π½Π΅ΠΉ). ΠœΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ last_name Π² surname.

ДопущСния

ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΠΌΡ‹ углубимся Π² Π΄Π΅Ρ‚Π°Π»ΠΈ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Ρƒ Π΄ΠΎΠΏΡƒΡ‰Π΅Π½ΠΈΠΉ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π°ΡˆΠΈΡ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. Π“Π»Π°Π²Π½Ρ‹ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π΄ΠΎΡΡ‚ΠΈΡ‡ΡŒ, Π±ΡƒΠ΄Π΅Ρ‚ довольно простой процСсс.

Π—Π°ΠΌΠ΅Ρ‚ΠΊΠ°. Business PRO-TIP. Π£ΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΠ΅ процСссов ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ‚ΡŒ Π²Π°ΠΌ ΠΌΠ½ΠΎΠ³ΠΎ Π΄Π΅Π½Π΅Π³ Π½Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ΅ (Ρ‡Π΅ΠΌ большС людСй Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π² вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, Ρ‚Π΅ΠΌ большС Π΄Π΅Π½Π΅Π³ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ‚ΡŒ)!

НС Π½Π°Π΄ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΡ‚ΠΊΠ°Ρ‚ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…

Π­Ρ‚ΠΎ ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ процСсс дСплоя (Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΡ‚ΠΊΠ°Ρ‚Ρ‹ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… практичСски Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΡ‚ΠΊΠ°Ρ‚ удалСния). ΠœΡ‹ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌ ΠΎΡ‚ΠΊΠ°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ прилоТСния. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π΄Π°ΠΆΠ΅ Ссли Ρƒ вас Ρ€Π°Π·Π½Ρ‹Π΅ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, SQL ΠΈ NoSQL), ваш deployment pipeline Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ.

Надо, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ВБЕГДА Π±Ρ‹Π»Π° Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° ΠΎΠ΄Π½Ρƒ Π²Π΅Ρ€ΡΠΈΡŽ Π½Π°Π·Π°Π΄ (Π½Π΅ Π±ΠΎΠ»Π΅Π΅)

ΠžΡ‚ΠΊΠ°Ρ‚ стоит ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎ нСобходимости. Если Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ вСрсии Π΅ΡΡ‚ΡŒ ошибка, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π½Π΅Π»Π΅Π³ΠΊΠΎ ΡƒΡΡ‚Ρ€Π°Π½ΠΈΡ‚ΡŒ, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ послСднюю Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ. ΠœΡ‹ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ эта послСдняя рабочая вСрсия являСтся ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ. ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° совмСстимости ΠΊΠΎΠ΄Π° ΠΈ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ для ΠΎΠ΄Π½ΠΎΠΉ Π²Ρ‹ΠΊΠ°Ρ‚ΠΊΠΈ Π±Ρ‹Π»ΠΎ Π±Ρ‹ Ρ‡Ρ€Π΅Π·Π²Ρ‹Ρ‡Π°ΠΉΠ½ΠΎ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎΠΉ ΠΈ дорогостоящСй.

Π—Π°ΠΌΠ΅Ρ‚ΠΊΠ°. Для большСй Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΌΠ°ΠΆΠΎΡ€Π½ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ прилоТСния.

Π¨Π°Π³ 1: Π˜ΡΡ…ΠΎΠ΄Π½ΠΎΠ΅ состояниС

ВСрсия прилоТСния: 1.0.0
ВСрсия Π‘Π”: v1

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Π­Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ исходноС состояниС прилоТСния.

ИзмСнСния Π‘Π”

Π‘Π” содСрТит 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');

ИзмСнСния кода

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ сохраняСт Π΄Π°Π½Π½Ρ‹Π΅ Person Π² 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
                + "]";
    }
}

ΠžΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимоС ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ столбца

Π”Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠ°ΠΊ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ имя столбца:

Π’Π½ΠΈΠΌΠ°Π½ΠΈΠ΅. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½Π°ΠΌΠ΅Ρ€Π΅Π½Π½ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ ΠΏΠΎΠ»ΠΎΠΌΠΊΠ΅. ΠœΡ‹ это ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ с Ρ†Π΅Π»ΡŒΡŽ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ совмСстимости Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ….

ВСрсия прилоТСния: 2.0.0.BAD

ВСрсия Π”Π‘: v2bad

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Π’Π΅ΠΊΡƒΡ‰ΠΈΠ΅ измСнСния НЕ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Π½Π°ΠΌ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π΄Π²Π° экзСмпляра (старый ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ) ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, zero downtime deployment Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ достиТим (Ссли ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ Π²ΠΎ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ допущСния, это фактичСски Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ).

A/B-тСстированиС

ВСкущая ситуация Ρ‚Π°ΠΊΠΎΠ²Π°, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 1.0.0, Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΠΎΠ΅ Π² ΠΏΡ€ΠΎΠ΄Π΅, ΠΈ Π‘Π” v1. ΠœΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π²Ρ‚ΠΎΡ€ΠΎΠΉ экзСмпляр прилоТСния, вСрсии 2.0.0.BAD, ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎ v2bad.

Π¨Π°Π³ΠΈ:

  1. Ρ€Π°Π·Π²Ρ‘Ρ€Π½ΡƒΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр прилоТСния вСрсии 2.0.0.BAD, которая обновляСт Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎ v2bad
  2. Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… v2bad столбСц last_name большС Π½Π΅ сущСствуСт β€” Π΅Π³ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ»ΠΈ Π½Π° surname
  3. ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ прилоТСния ΠΏΡ€ΠΎΡˆΠ»ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, ΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ экзСмпляры Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π² 1.0.0, Π΄Ρ€ΡƒΠ³ΠΈΠ΅ β€” Π² 2.0.0.BAD. ВсС связаны с Π‘Π” v2bad
  4. всС экзСмпляры вСрсии 1.0.0 Π½Π°Ρ‡Π½ΡƒΡ‚ Π²Ρ‹Π΄Π°Π²Π°Ρ‚ΡŒ ошибки, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ ΠΏΠΎΠΏΡ‹Ρ‚Π°ΡŽΡ‚ΡΡ Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² столбСц last_name, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ большС Π½Π΅Ρ‚
  5. всС экзСмпляры вСрсии 2.0.0.BAD Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π±Π΅Π· ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ

Как Π²Ρ‹ Π²ΠΈΠ΄ΠΈΡ‚Π΅, Ссли ΠΌΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимыС измСнСния Π‘Π” ΠΈ прилоТСния, A/B тСстированиС Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.

ΠžΡ‚ΠΊΠ°Ρ‚ прилоТСния

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ послС ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ A/B deployment (ΠΏΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: вСроятно, Ρ‚ΡƒΡ‚ Π°Π²Ρ‚ΠΎΡ€ ΠΈΠΌΠ΅Π» Π² Π²ΠΈΠ΄Ρƒ A/B тСстированиС) ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎ вСрсии 1.0.0. Допустим, ΠΌΡ‹ Π½Π΅ Ρ…ΠΎΡ‚ΠΈΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΡ‚ΠΊΠ°Ρ‚ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ….

Π¨Π°Π³ΠΈ:

  1. ΠΌΡ‹ останавливаСм экзСмпляр прилоТСния вСрсии 2.0.0.BAD
  2. Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… всС Π΅Ρ‰Π΅ v2bad
  3. Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ вСрсия 1.0.0 Π½Π΅ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ surname, ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ ошибки
  4. Π°Π΄ вырвался Π½Π° свободу, ΠΌΡ‹ большС Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ

Как Π²Ρ‹ Π²ΠΈΠ΄ΠΈΡ‚Π΅, Ссли ΠΌΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимыС измСнСния Π‘Π” ΠΈ прилоТСния, ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ вСрсии.

Π›ΠΎΠ³ΠΈ исполнСния скрипта

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"}

ИзмСнСния Π‘Π”

Π‘ΠΊΡ€ΠΈΠΏΡ‚ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Ρ‹Π²Π°Π΅Ρ‚ last_name Π² surname

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ Flyway скрипт:

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

Π‘ΠΊΡ€ΠΈΠΏΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Ρ‹Π²Π°Π΅Ρ‚ last_name.

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

ИзмСнСния кода

ΠœΡ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ»ΠΈ имя поля lastName Π½Π° surname.

ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ столбца ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ-совмСстимым способом

Π­Ρ‚ΠΎ самая частая ситуация, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΡ‚ΡŒΡΡ. Нам Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимыС измСнСния. ΠœΡ‹ ΡƒΠΆΠ΅ Π΄ΠΎΠΊΠ°Π·Π°Π»ΠΈ, Ρ‡Ρ‚ΠΎ для дСплоя Π±Π΅Π· простоСв ΠΌΡ‹ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ просто ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π±Π΅Π· Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… дСйствий. Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΌΡ‹ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅ΠΌ 3 дСплоя прилоТСния вмСстС с миграциями Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΡΡ‚ΠΈΡ‡ΡŒ ΠΆΠ΅Π»Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΠΈ ΠΏΡ€ΠΈ этом ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ.

Π—Π°ΠΌΠ΅Ρ‚ΠΊΠ°. Напомним, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ Π‘Π” вСрсии v1. Она содСрТит столбцы first_name ΠΈ last_name. ΠœΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ last_name Π½Π° surname. Π£ нас Ρ‚Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 1.0.0, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΏΠΎΠΊΠ° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ surname.

Π¨Π°Π³ 2: ДобавляСм surname

ВСрсия прилоТСния: 2.0.0
ВСрсия Π‘Π”: v2

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Добавляя Π½ΠΎΠ²Ρ‹ΠΉ столбСц ΠΈ копируя Π΅Π³ΠΎ содСрТимоС, ΠΌΡ‹ создаСм ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимыС измСнСния Π‘Π”. Π’ Ρ‚ΠΎ ΠΆΠ΅ врСмя, Ссли ΠΌΡ‹ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΠΌ JAR ΠΈΠ»ΠΈ Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠΉ старый JAR, ΠΎΠ½ Π½Π΅ сломаСтся Π²ΠΎ врСмя исполнСния.

Π’Ρ‹ΠΊΠ°Ρ‚Ρ‹Π²Π°Π΅ΠΌ Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ

Π¨Π°Π³ΠΈ:

  1. ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ Π‘Π”, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ столбСц surname. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ваша Π‘Π” вСрсии v2
  2. скопируйтС Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· last_name Π² surname. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Ссли Ρƒ вас ΠΌΠ½ΠΎΠ³ΠΎ этих Π΄Π°Π½Π½Ρ‹Ρ…, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°ΡΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚Π½ΠΎΠΉ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ!
  3. Π½Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ΄, Π³Π΄Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ ΠžΠ‘Π ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ, ΠΈ старый столбСц. Π’Π΅ΠΏΠ΅Ρ€ΡŒ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 2.0.0
  4. ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· столбца surname, Ссли ΠΎΠ½ΠΎ Π½Π΅ null, ΠΈΠ»ΠΈ ΠΈΠ· last_name, Ссли surname Π½Π΅ Π·Π°Π΄Π°Π½ΠΎ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ getLastName() ΠΈΠ· ΠΊΠΎΠ΄Π°, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π΄Π°Π²Π°Ρ‚ΡŒ null ΠΏΡ€ΠΈ ΠΎΡ‚ΠΊΠ°Ρ‚Π΅ вашСго прилоТСния с 3.0.0 Π΄ΠΎ 2.0.0.

Если Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ Spring Boot Flyway, эти Π΄Π²Π° шага Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ Π²ΠΎ врСмя старта вСрсии 2.0.0 прилоТСния. Если Π²Ρ‹ запускаСтС инструмСнт управлСния вСрсиями Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ, Π²Π°ΠΌ придСтся ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ для этого Π΄Π²Π° Ρ€Π°Π·Π½Ρ‹Ρ… дСйствия (сначала ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ Π²Π΅Ρ€ΡΠΈΡŽ db Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ, Π° Π·Π°Ρ‚Π΅ΠΌ Ρ€Π°Π·Π²Π΅Ρ€Π½ΠΈΡ‚Π΅ Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅).

Π’Π°ΠΆΠ½ΠΎ. ΠŸΠΎΠΌΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ вновь созданный столбСц НЕ Π”ΠžΠ›Π–Π•Π Π±Ρ‹Ρ‚ΡŒ NOT NULL. Если Π²Ρ‹ Π΄Π΅Π»Π°Π΅Ρ‚Π΅ ΠΎΡ‚ΠΊΠ°Ρ‚, староС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π΅ Π·Π½Π°Π΅Ρ‚ ΠΎ Π½ΠΎΠ²ΠΎΠΌ столбцС ΠΈ Π½Π΅ установит Π΅Π³ΠΎ Π²ΠΎ врСмя Insert. Но Ссли Π²Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚Π΅ это ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅, ΠΈ ваша Π‘Π” Π±ΡƒΠ΄Π΅Ρ‚ v2, это ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ установки значСния Π½ΠΎΠ²ΠΎΠ³ΠΎ столбца. Π§Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ Π½Π°Ρ€ΡƒΡˆΠ΅Π½ΠΈΡΠΌ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠΉ.

Π’Π°ΠΆΠ½ΠΎ. Π’Π°ΠΌ слСдуСт ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ getLastName(), ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π² вСрсии 3.0.0 Π² ΠΊΠΎΠ΄Π΅ отсутствуСт понятиС столбца last_name. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΌ Π±ΡƒΠ΄ΡƒΡ‚ установлСны null. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° null, Π½ΠΎ Π³ΠΎΡ€Π°Π·Π΄ΠΎ Π»ΡƒΡ‡ΡˆΠΈΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ Π² Π»ΠΎΠ³ΠΈΠΊΠ΅ getSurname() Π²Ρ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ΅ Π½Π΅Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

A/B-тСстированиС

ВСкущая ситуация Ρ‚Π°ΠΊΠΎΠ²Π°, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 1.0.0, Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΠΎΠ΅ Π½Π° ΠΏΡ€ΠΎΠ΄Π΅, ΠΈ Π‘Π” Π² v1. ΠœΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π²Ρ‚ΠΎΡ€ΠΎΠΉ экзСмпляр прилоТСния вСрсии 2.0.0, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎ v2.

Π¨Π°Π³ΠΈ:

  1. Ρ€Π°Π·Π²Ρ‘Ρ€Π½ΡƒΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр прилоТСния вСрсии 2.0.0, которая обновляСт Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎ v2
  2. Ρ‚Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ запросы ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π»ΠΈΡΡŒ экзСмплярами вСрсии 1.0.0
  3. ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡˆΠ»ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, ΠΈ Ρƒ вас Π΅ΡΡ‚ΡŒ нСсколько Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΡ… экзСмпляров прилоТСния вСрсии 1.0.0 ΠΈ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ вСрсии 2.0.0. ВсС ΠΎΠ±Ρ‰Π°ΡŽΡ‚ΡΡ с Π‘Π” Π² v2
  4. вСрсия 1.0.0 Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π² Π‘Π” столбСц surname, Π° вСрсия 2.0.0 ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚. Они Π½Π΅ ΠΌΠ΅ΡˆΠ°ΡŽΡ‚ Π΄Ρ€ΡƒΠ³ Π΄Ρ€ΡƒΠ³Ρƒ, ΠΈ ошибок Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ.
  5. вСрсия 2.0.0 сохраняСт Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠ°ΠΊ Π² старом, Ρ‚Π°ΠΊ ΠΈ Π² Π½ΠΎΠ²ΠΎΠΌ столбцС, Ρ‡Ρ‚ΠΎ обСспСчиваСт ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ

Π’Π°ΠΆΠ½ΠΎ. Если Ρƒ вас Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Π»ΠΈΠ±ΠΎ запросы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ΄ΡΡ‡ΠΈΡ‚Ρ‹Π²Π°ΡŽΡ‚ элСмСнты Π½Π° основС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΈΠ· старого / Π½ΠΎΠ²ΠΎΠ³ΠΎ столбца, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Ρƒ вас Π΅ΡΡ‚ΡŒ Π΄ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ (скорСС всСго, ΠΎΠ½ΠΈ всС Π΅Ρ‰Π΅ ΠΌΠΈΠ³Ρ€ΠΈΡ€ΡƒΡŽΡ‚). НапримСр, Ссли Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ количСство ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ, Ρ‡ΡŒΡ фамилия (ΠΊΠ°ΠΊ Π±Ρ‹ Π½ΠΈ назывался столбСц) Π½Π°Ρ‡ΠΈΠ½Π°Π»Π°ΡΡŒ с Π±ΡƒΠΊΠ²Ρ‹ A, Ρ‚ΠΎ Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… (old β†’ new столбСц) Ρƒ вас ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ нСконсистСнтныС Π΄Π°Π½Π½Ρ‹Π΅, Ссли Π²Ρ‹ выполняСтС запрос ΠΊ Π½ΠΎΠ²ΠΎΠΌΡƒ столбцу.

ΠžΡ‚ΠΊΠ°Ρ‚ прилоТСния

БСйчас Ρƒ нас Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 2.0.0 ΠΈ Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… Π² v2.

Π¨Π°Π³ΠΈ:

  1. ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚Π΅ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎ вСрсии 1.0.0.
  2. вСрсия 1.0.0 Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π² Π‘Π” столбСц surname, поэтому ΠΎΡ‚ΠΊΠ°Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΌ

ИзмСнСния DB

Π‘Π” содСрТит столбСц с ΠΈΠΌΠ΅Π½Π΅ΠΌ last_name.

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ скрипт Flyway:

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

Π‘ΠΊΡ€ΠΈΠΏΡ‚ добавлСния surname.

Π’Π½ΠΈΠΌΠ°Π½ΠΈΠ΅. ΠŸΠΎΠΌΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ НЕЛЬЗЯ Π”ΠžΠ‘ΠΠ’Π›Π―Π’Π¬ ΠΊΠ°ΠΊΠΈΠ΅-Π»ΠΈΠ±ΠΎ ограничСния NOT NULL Π² добавляСмый столбСц. Если Π²Ρ‹ ΠΎΡ‚ΠΊΠ°Ρ‚Ρ‹Π²Π°Π΅Ρ‚Π΅ JAR, старая вСрсия Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ понятия ΠΎ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½ΠΎΠΌ столбцС, ΠΈ автоматичСски задаст Π΅ΠΌΡƒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ NULL. Π’ случаС наличия Ρ‚Π°ΠΊΠΎΠ³ΠΎ ограничСния староС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ просто сломаСтся.

-- 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

ИзмСнСния кода

ΠœΡ‹ сохраняСм Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠ°ΠΊ Π² last_name, Ρ‚Π°ΠΊ ΠΈ Π² surname. ΠŸΡ€ΠΈ этом Ρ‡ΠΈΡ‚Π°Π΅ΠΌ ΠΈΠ· 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;
    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: Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ last_name ΠΈΠ· ΠΊΠΎΠ΄Π°

ВСрсия прилоТСния: 3.0.0

ВСрсия Π”Π‘:v3

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

ΠŸΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: По всСй видимости, Π² исходной ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π°Π²Ρ‚ΠΎΡ€ΠΎΠΌ ΠΎΡˆΠΈΠ±ΠΎΡ‡Π½ΠΎ Π±Ρ‹Π» скопирован тСкст Π΄Π°Π½Π½ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° ΠΈΠ· шага 2. На Π΄Π°Π½Π½ΠΎΠΌ шагС Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½Ρ‹ измСнСния Π² ΠΊΠΎΠ΄Π΅ прилоТСния, Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π½Ρ‹Π΅ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ столбСц last_name.

Добавляя Π½ΠΎΠ²Ρ‹ΠΉ столбСц ΠΈ копируя Π΅Π³ΠΎ содСрТимоС, ΠΌΡ‹ создали ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимыС измСнСния Π‘Π”. Π’Π°ΠΊΠΆΠ΅, Ссли ΠΌΡ‹ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΠΌ JAR ΠΈΠ»ΠΈ Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠΉ старый JAR, ΠΎΠ½ Π½Π΅ сломаСтся Π²ΠΎ врСмя исполнСния.

ΠžΡ‚ΠΊΠ°Ρ‚ прилоТСния

Π’ настоящСС врСмя Ρƒ нас Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ вСрсии 3.0.0 ΠΈ Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ… v3. ВСрсия 3.0.0 Π½Π΅ сохраняСт Π΄Π°Π½Π½Ρ‹Π΅ Π² last_name. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Π² surname хранится самая Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Π°Ρ информация.

Π¨Π°Π³ΠΈ:

  1. ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚Π΅ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎ вСрсии 2.0.0.
  2. вСрсия 2.0.0 ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΈ last_name ΠΈ surname.
  3. вСрсия 2.0.0 Π²ΠΎΠ·ΡŒΠΌΡ‘Ρ‚ surname, Ссли ΠΎΠ½ Π½Π΅ Π½ΡƒΠ»Π΅Π²ΠΎΠΉ, Π° ΠΈΠ½Π°Ρ‡Π΅ —last_name

ИзмСнСния Π‘Π”

Π’ Π‘Π” Π½Π΅Ρ‚ структурных ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ. Π˜ΡΠΏΠΎΠ»Π½ΡΠ΅Ρ‚ΡΡ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ скрипт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ выполняСт ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ старых Π΄Π°Π½Π½Ρ‹Ρ…:

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

ИзмСнСния кода

ΠŸΡ€ΠΈΠΌ. ΠΏΠ΅Ρ€.: ОписаниС этого Π±Π»ΠΎΠΊΠ° Ρ‚Π°ΠΊΠΆΠ΅ Π±Ρ‹Π»ΠΎ ΠΎΡˆΠΈΠ±ΠΎΡ‡Π½ΠΎ скопировано Π°Π²Ρ‚ΠΎΡ€ΠΎΠΌ ΠΈΠ· шага 2. Π’ соотвСтствии с Π»ΠΎΠ³ΠΈΠΊΠΎΠΉ повСствования ΡΡ‚Π°Ρ‚ΡŒΠΈ, измСнСния Π² ΠΊΠΎΠ΄Π΅ Π½Π° Π΄Π°Π½Π½ΠΎΠΌ шагС Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Ρ‹ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΈΠ· Π½Π΅Π³ΠΎ элСмСнтов, ΠΎΡΡƒΡ‰Π΅ΡΡ‚Π²Π»ΡΡŽΡ‰ΠΈΡ… Ρ€Π°Π±ΠΎΡ‚Ρƒ со столбцом last_name.

ΠœΡ‹ Ρ…Ρ€Π°Π½ΠΈΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠ°ΠΊ Π² last_name, Ρ‚Π°ΠΊ ΠΈ Π² surname. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, ΠΌΡ‹ Ρ‡ΠΈΡ‚Π°Π΅ΠΌ ΠΈΠ· столбца 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 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: Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ last_name ΠΈΠ· Π‘Π”

ВСрсия прилоТСния: 4.0.0

ВСрсия Π‘Π”: v4

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Из-Π·Π° Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ΄ вСрсии 3.0.0 Π½Π΅ использовал столбСц last_name, Π²ΠΎ врСмя исполнСния Π½ΠΈΡ‡Π΅Π³ΠΎ ΠΏΠ»ΠΎΡ…ΠΎΠ³ΠΎ Π½Π΅ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚, Ссли ΠΌΡ‹ откатимся Π΄ΠΎ 3.0.0 послС удалСния столбца ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ….

Π›ΠΎΠ³ΠΈ исполнСния скрипта

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"}

ИзмСнСния Π”Π‘

ΠžΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ v3 ΠΌΡ‹ просто удаляСм столбСц last_name ΠΈ добавляСм ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ограничСния.

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

ИзмСнСния кода

ИзмСнСния Π² ΠΊΠΎΠ΄Π΅ ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚.

Π’Ρ‹Π²ΠΎΠ΄

ΠœΡ‹ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠ»ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимоС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠΌΠ΅Π½ΠΈ столбца, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠ² нСсколько ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимых Π΄Π΅ΠΏΠ»ΠΎΠ΅Π². НиТС сводка Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Ρ… дСйствий:

  1. Π΄Π΅ΠΏΠ»ΠΎΠΉ прилоТСния вСрсии 1.0.0 с v1 схСмы Π‘Π” (имя столбца = last_name)
  2. Π΄Π΅ΠΏΠ»ΠΎΠΉ прилоТСния вСрсии 2.0.0, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ сохраняСт Π΄Π°Π½Π½Ρ‹Π΅ Π² last_name ΠΈ surname. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‡ΠΈΡ‚Π°Π΅Ρ‚ ΠΈΠ· last_name. Π‘Π” находится Π² вСрсии v2, содСрТащСй столбцы ΠΊΠ°ΠΊ last_name, Ρ‚Π°ΠΊ ΠΈ surname. surname являСтся ΠΊΠΎΠΏΠΈΠ΅ΠΉ last_name. (ΠŸΠ Π˜ΠœΠ•Π§ΠΠΠ˜Π•: этот столбСц Π½Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ not null)
  3. Π΄Π΅ΠΏΠ»ΠΎΠΉ прилоТСния вСрсии 3.0.0, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ сохраняСт Π΄Π°Π½Π½Ρ‹Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² surname ΠΈ Ρ‡ΠΈΡ‚Π°Π΅Ρ‚ ΠΈΠ· surname. Π§Ρ‚ΠΎ касаСтся Π‘Π”, Ρ‚ΠΎ происходит послСдняя миграция last_name Π² surname. Π’Π°ΠΊΠΆΠ΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ NOT NULL снимаСтся с last_name. Π‘Π” сСйчас Π² вСрсии v3
  4. Π΄Π΅ΠΏΠ»ΠΎΠΉ прилоТСния вСрсии 4.0.0 β€” Π² ΠΊΠΎΠ΄Π΅ Π½Π΅ производится Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ. Π”Π΅ΠΏΠ»ΠΎΠΉ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… v4, которая удаляСт last_name. Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π»ΡŽΠ±Ρ‹Π΅ Π½Π΅Π΄ΠΎΡΡ‚Π°ΡŽΡ‰ΠΈΠ΅ ограничСния Π² Π‘Π”.

БлСдуя этому ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρƒ, Π²Ρ‹ всСгда ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒΡΡ Π½Π° ΠΎΠ΄Π½Ρƒ Π²Π΅Ρ€ΡΠΈΡŽ Π½Π°Π·Π°Π΄, Π½Π΅ ломая ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… / прилоТСния.

Код

Π’Π΅ΡΡŒ ΠΊΠΎΠ΄, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅, доступСн Π½Π° Github. НиТС Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ описаниС.

ΠŸΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹

ПослС клонирования рСпозитория, Π²Ρ‹ ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ структуру ΠΏΠ°ΠΏΠΎΠΊ.

β”œβ”€β”€ 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)

Π‘ΠΊΡ€ΠΈΠΏΡ‚Ρ‹

Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ сцСнарии, описанныС Π² скриптах Π½ΠΈΠΆΠ΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽΡ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимыС ΠΈ нСсовмСстимыС измСнСния Π² Π‘Π”.

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ случай с ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ совмСстимыми измСнСниями, запуститС:

./scripts/scenario_backward_compatible.sh

А Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ случай с ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ нСсовмСстимыми измСнСниями, запуститС:

./scripts/scenario_backward_incompatible.sh

Spring Boot Sample Flyway

ВсС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ взяты с Spring Boot Sample Flyway.

Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Π·Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π½Π° http://localhost:8080/flyway, Ρ‚Π°ΠΌ список скриптов.

Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя консоль H2 (ΠΏΠΎ адрСсу http://localhost:8080/h2-console), Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ ΠΌΠΎΠ³Π»ΠΈ ΠΏΡ€ΠΎΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ состояниС Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… (URL jdbc ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ β€” jdbc:h2:mem:testdb).

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ

Π’Π°ΠΊΠΆΠ΅ Ρ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ Π² нашСм Π±Π»ΠΎΠ³Π΅:

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ