Como non dispararte no pé usando Liquibase

Nunca pasou, e aquí está de novo!

No seguinte proxecto, decidimos usar Liquibase dende o principio para evitar problemas no futuro. Como se viu, non todos os mozos do equipo saben usalo correctamente. Fixen un obradoiro interno, que logo decidín converter nun artigo.

Este artigo inclúe consellos útiles e descricións de tres das trampas máis obvias nas que pode caer ao traballar con ferramentas de migración de bases de datos relacionais, Liquibase en particular. Deseñado para desenvolvedores Java de nivel Júnior e Medio, para desenvolvedores máis experimentados pode ser interesante para estruturar e repetir o que probablemente xa se coñece.

Como non dispararte no pé usando Liquibase

Liquibase e Flyway son as principais tecnoloxías competidoras para resolver os problemas de control de versións das estruturas relacionais no mundo Java. O primeiro é completamente gratuíto, na práctica elíxese con máis frecuencia para o seu uso, polo que Liquibase foi elixido como o heroe da publicación. Non obstante, algunhas das prácticas descritas poden ser xenéricas, dependendo da arquitectura da súa aplicación.

As migracións relacionais son unha forma obrigada de xestionar a débil flexibilidade dos almacéns de datos relacionais. Na era da moda para OOP, o estilo de traballar coa base de datos significaba que describiríamos o esquema unha vez e non o tocariamos de novo. Pero a realidade sempre é que as cousas cambian, e os cambios na estrutura das táboas son necesarios con bastante frecuencia. Por suposto, o proceso en si é doloroso e desagradable.

Non vou afondar na descrición da tecnoloxía e as instrucións para engadir a biblioteca ao teu proxecto, xa se escribiron suficientes artigos sobre este tema:

Ademais, xa había un gran artigo sobre o tema dos consellos útiles:

Советы

Quero compartir os meus consellos e comentarios, que naceron coa suor, o sangue e a dor de resolver problemas coa migración.

1. Antes de comezar, debes ler a sección de prácticas recomendadas sobre On-line Liquibase

Alí Descríbense cousas sinxelas pero moi importantes, sen as cales o uso da biblioteca pode complicarche a vida. Por exemplo, un enfoque non estrutural da xestión de conxuntos de cambios levará tarde ou cedo a confusión e migracións rotas. Se non realiza cambios mutuamente dependentes na estrutura da base de datos e na lóxica dos servizos ao mesmo tempo, entón hai unha alta probabilidade de que isto leve a probas vermellas ou un ambiente roto. Ademais, as recomendacións para usar Liquibase no sitio web oficial conteñen un parágrafo sobre o desenvolvemento e verificación de scripts de retroceso xunto cos principais scripts de migración. Ben, no artigo https://habr.com/ru/post/178665/ hai exemplos de código relacionados coas migracións e o mecanismo de retroceso.

2. Se comezou a usar ferramentas de migración, non permita correccións manuais na estrutura da base de datos

Como di o refrán: "Unha vez Persil, sempre Persil". Se a base da súa aplicación comezou a ser xestionada polas ferramentas de Liquibase, calquera cambio manual levará instantáneamente a un estado inconsistente e o nivel de confianza nos conxuntos de cambios pasa a ser cero. Riscos potenciais - varias horas dedicadas a restaurar a base de datos, no peor dos casos - un servidor morto. Se o teu equipo ten un arquitecto DBA da "vella escola", explícalle con paciencia e coidado o mal que serán as cousas se só edita a base de datos á súa maneira desde o programador SQL condicional.

3. Se o conxunto de cambios xa foi enviado ao repositorio, evite a edición

Se outro programador sacou e aplicou un conxunto de cambios que se editará máis tarde, definitivamente recordarache cunha palabra amable cando reciba un erro cando se inicie a aplicación. Se editar o conxunto de cambios se filtra dalgún xeito no desenvolvemento, terás que baixar pola pendente escorregadiza das correccións. A esencia do problema reside na validación dos cambios mediante a suma hash, o principal mecanismo de Liquibase. Ao editar o código do conxunto de cambios, a suma hash cambia. A edición de conxuntos de cambios só é posible cando é posible implementar toda a base de datos desde cero sen perder datos. Neste caso, a refactorización do código SQL ou XML pode, pola contra, facilitar a vida, facer que as migracións sexan máis lexibles. Un exemplo sería unha situación na que, ao inicio da aplicación, o esquema da base de datos fonte estaba coordinado dentro do equipo.

4. Ter copias de seguranza da base de datos verificadas se é posible

Aquí, creo, todo está claro. Se de súpeto a migración non tivo éxito, todo pode ser devolto. Liquibase ten unha ferramenta de retroceso, pero os scripts de reversión tamén están escritos polo propio desenvolvedor e poden ter problemas coa mesma probabilidade que nos scripts de cambios principais. Isto significa que xogar seguro coas copias de seguridade é útil en calquera caso.

5. Use copias de seguridade de bases de datos verificadas en desenvolvemento se é posible

Se isto non contradí os contratos e a privacidade, non hai datos persoais na base de datos e non pesa como dous soles; antes de aplicalo en servidores de migración en directo, pode comprobar como funciona na máquina do programador e calcular case o 100% posibles problemas durante a migración.

6. Chatea con outros desenvolvedores do equipo

Nun proceso de desenvolvemento ben organizado, todos os membros do equipo saben quen fai que. En realidade, moitas veces non é o caso, polo tanto, se está a preparar cambios na estrutura da base de datos como parte da súa tarefa, é recomendable notificar adicionalmente a todo o equipo sobre isto. Se alguén está a facer cambios en paralelo, debes organizalo con coidado. Paga a pena comunicarse cos compañeiros incluso ao final do traballo, non só ao comezo. Moitos problemas potenciais cos conxuntos de cambios pódense resolver na fase de revisión do código.

7. Pensa o que estás facendo!

Consellos aparentemente evidentes aplicables a calquera situación. Non obstante, poderían evitarse moitos problemas se o desarrollador tivese analizado unha vez máis o que estaba a facer e o que podería afectar. Traballar con migracións sempre require atención e precisión extra.

Trampas

Vexamos agora as trampas típicas nas que pode caer se non segue o consello anterior, e que, de feito, se debe facer?

Situación 1. Dous desenvolvedores están tentando engadir novos conxuntos de cambios ao mesmo tempo

Como non dispararte no pé usando Liquibase
Vasya e Petya queren crear un conxunto de cambios da versión 4 sen coñecerse o un do outro. Fixeron cambios na estrutura da base de datos e lanzaron unha solicitude de extracción, con diferentes ficheiros de conxunto de cambios. A continuación proponse o seguinte mecanismo:

Como resolver

  1. Dalgunha maneira, os compañeiros deben poñerse de acordo sobre a orde na que deben ir os seus conxuntos de cambios, digamos que primeiro debe aplicarse Petin.
  2. Unha persoa debería verter a outra e marcar o conxunto de cambios de Vasya coa versión 5. Isto pódese facer mediante Cherry Pick ou unha combinación ordenada.
  3. Despois dos cambios, asegúrese de comprobar a validez das accións realizadas.
    De feito, os mecanismos de Liquibase permítenche ter dous conxuntos de cambios da versión 4 no repositorio, polo que podes deixar todo como está. É dicir, simplemente terá dúas revisións da versión 4 con nomes diferentes. Con este enfoque, as versións da base de datos fanse moi difíciles de navegar máis tarde.

Ademais, Liquibase, como as casas dos hobbits, garda moitos segredos. Un deles é a chave validCheckSum, que aparece dende a versión 1.7 e que permite especificar un valor hash válido para un conxunto de cambios específico, independentemente do que estea almacenado na base de datos. Documentación https://www.liquibase.org/documentation/changeset.html di o seguinte:

Engade unha suma de verificación que se considere válida para este conxunto de cambios, independentemente do que estea almacenado na base de datos. Úsase principalmente cando precisa cambiar un conxunto de cambios e non quere que se produzan erros nas bases de datos nas que xa se executou (non é un procedemento recomendado)

Si, isto non é recomendable. Pero ás veces un mago de luz forte tamén domina técnicas escuras.

Caso 2: Migración impulsada por datos

Como non dispararte no pé usando Liquibase

Digamos que non pode usar copias de seguridade de bases de datos desde servidores activos. Petya creou un conxunto de cambios, probouno localmente e, con total confianza en que tiña razón, fixo unha solicitude de extracción ao programador. Por se acaso, o líder do proxecto aclarou se Petya o comprobou e despois vertiu. Pero a implantación no servidor de desenvolvemento caeu.

De feito, isto é posible, e ninguén é inmune a iso. Isto ocorre se as modificacións da estrutura da táboa están vinculadas dalgún xeito a datos específicos da base de datos. Obviamente, se a base de datos de Petya está chea só de datos de proba, é posible que non cubra todos os casos problemáticos. Por exemplo, ao eliminar unha táboa, resulta que hai rexistros noutras táboas por chave estranxeira asociados a rexistros da que se está eliminando. Ou ao cambiar o tipo de columna, resulta que non se poden converter o 100% dos datos ao novo tipo.

Como resolver

  • Escribe scripts especiais que se aplicarán unha vez xunto coa migración e trae os datos ao formato adecuado. Esta é unha forma xeral de resolver o problema da transferencia de datos a novas estruturas despois de aplicar as migracións, pero algo semellante pódese aplicar antes, en casos especiais. Este camiño, por suposto, non sempre está dispoñible, porque editar datos en servidores en directo pode ser perigoso e mesmo fatal.
  • Outra forma complicada é editar un conxunto de cambios existente. A dificultade é que haberá que restaurar todas as bases de datos onde xa se aplicou na súa forma existente. É moi posible que todo o equipo de backend se vexa obrigado a enrolar localmente a base de datos desde cero.
  • E a forma máis universal é transferir o problema de datos ao entorno do programador, recrear a mesma situación e engadir un novo conxunto de cambios, a un roto, que evitará o problema.
    Como non dispararte no pé usando Liquibase

En xeral, canto máis semella a composición da base de datos á base de datos do servidor de produción, menos probable é que os problemas coas migracións vaian lonxe. E, por suposto, antes de enviar o conxunto de cambios ao repositorio, deberías pensar varias veces se romperá algo.

Situación 3. Liquibase comeza a utilizarse despois de entrar en produción

Supoñamos que o líder do equipo pediu a Petya que inclúa Liquibase no proxecto, pero o proxecto xa está en produción e xa existe unha estrutura de base de datos.

En consecuencia, o problema é que en calquera servidor ou máquina de desenvolvemento novos, os datos da táboa deben recrearse desde cero e o ambiente xa existente debe permanecer nun estado consistente, estando preparado para aceptar novos conxuntos de cambios.

Como resolver

Tamén hai varias formas:

  • O primeiro e máis obvio é ter un script separado que debe aplicarse manualmente ao inicializar un novo ambiente.
  • O segundo, menos obvio, é ter unha migración de Liquibase que estea nun contexto de Liquibase diferente e aplicala. Podes ler máis sobre Liquibase Context aquí: https://www.liquibase.org/documentation/contexts.html. En xeral, este é un mecanismo interesante que se pode aplicar con éxito, por exemplo, para probar.
  • O terceiro camiño consta de varios pasos. En primeiro lugar, debe crearse unha migración para as táboas existentes. Despois debe aplicarse nalgún ambiente e así obterase a súa suma hash. O seguinte paso é inicializar táboas baleiras de Liquibase no noso servidor non baleiro, e podes poñer manualmente un rexistro dun conxunto de cambios "como se aplicase" cos cambios que xa hai na base de datos na táboa co historial de aplicación de conxuntos de cambios. Así, nun servidor xa existente, o historial comezará a partir da versión 2, e todos os novos ambientes comportaranse de forma idéntica.
    Como non dispararte no pé usando Liquibase

Escenario 4: as migracións son enormes e non poden seguir o ritmo

Ao comezo do desenvolvemento do servizo, por regra xeral, Liquibase utilízase como dependencia externa e todas as migracións son procesadas cando se inicia a aplicación. Non obstante, co paso do tempo, podes tropezar cos seguintes casos:

  • As migracións fanse enormes e tardan moito tempo en completarse.
  • Hai unha necesidade de migrar en ambientes distribuídos, por exemplo, en varias instancias de servidores de bases de datos ao mesmo tempo.
    Neste caso, a aplicación de migracións durante demasiado tempo producirá un tempo de espera cando se inicie a aplicación. Ademais, a aplicación de migracións por instancia de aplicación pode provocar que distintos servidores estean en estado de sincronía.

Como resolver

Nestes casos, o teu proxecto xa é grande, quizais ata un adulto, e Liquibase comeza a actuar como unha ferramenta externa separada. O caso é que Liquibase, como biblioteca, está montada nun ficheiro jar, e pode funcionar como dependencia dentro do proxecto, así como como autónomo.

Fóra de liña, pode deixar a aplicación das migracións ao seu contorno CI/CD ou aos fortes ombreiros dos seus administradores de sistemas/implementadores. Para iso, precisa a liña de comandos de Liquibase https://www.liquibase.org/documentation/command_line.html. Neste modo, é posible iniciar a aplicación despois de que se completen todas as migracións necesarias.

Saída

De feito, hai moitas máis trampas cando se traballa con migracións de bases de datos, e moitas delas requiren un enfoque creativo. É importante entender que se usa a ferramenta correctamente, a maioría destas trampas pódense evitar. En concreto, tiven que enfrontarme a todos os problemas enumerados en diferentes formas, e algúns deles foron o resultado das miñas xambas. Basicamente, isto ocorre, por suposto, debido á falta de atención, pero ás veces - debido á incapacidade criminal para usar a ferramenta.

Fonte: www.habr.com

Engadir un comentario