A transición do monolito aos microservizos: historia e práctica

Neste artigo, falarei de como o proxecto no que estou a traballar se transformou dun gran monolito nun conxunto de microservizos.

O proxecto comezou a súa historia hai bastante tempo, a principios do ano 2000. As primeiras versións foron escritas en Visual Basic 6. Co paso do tempo quedou claro que o desenvolvemento desta linguaxe sería difícil de soportar no futuro, xa que o IDE e a propia lingua está pouco desenvolvida. A finais da década de 2000, decidiuse cambiar ao C# máis prometedor. A nova versión escribiuse en paralelo á revisión da antiga, pouco a pouco escribiuse máis código en .NET. O backend en C# estivo enfocado inicialmente nunha arquitectura de servizos, pero durante o desenvolvemento utilizáronse bibliotecas comúns con lóxica e os servizos lanzáronse nun único proceso. O resultado foi unha aplicación que chamamos "monólito de servizo".

Unha das poucas vantaxes desta combinación foi a capacidade dos servizos para chamarse entre si a través dunha API externa. Había requisitos previos claros para a transición a un servizo máis correcto e, no futuro, a arquitectura de microservizos.

Comezamos o noso traballo sobre a descomposición ao redor de 2015. Aínda non chegamos a un estado ideal: aínda hai partes dun gran proxecto que dificilmente se poden chamar monolitos, pero tampouco parecen microservizos. Con todo, o progreso é significativo.
Falareino no artigo.

A transición do monolito aos microservizos: historia e práctica

Contido

Arquitectura e problemas da solución existente


Inicialmente, a arquitectura tiña este aspecto: a IU é unha aplicación separada, a parte monolítica está escrita en Visual Basic 6, a aplicación .NET é un conxunto de servizos relacionados que traballan cunha base de datos bastante grande.

Desvantaxes da solución anterior

Punto único de falla
Tivemos un único punto de fallo: a aplicación .NET executouse nun único proceso. Se algún módulo fallaba, fallaba toda a aplicación e había que reiniciarse. Dado que automatizamos un gran número de procesos para diferentes usuarios, debido a un fallo nun deles, todos non puideron traballar durante algún tempo. E en caso de erro de software, nin sequera a copia de seguridade axudou.

Fila de melloras
Este inconveniente é máis ben organizativo. A nosa aplicación ten moitos clientes e todos queren mellorala canto antes. Anteriormente, era imposible facelo en paralelo e todos os clientes facían cola. Este proceso foi negativo para as empresas porque tiñan que demostrar que a súa tarefa era valiosa. E o equipo de desenvolvemento pasou tempo organizando esta cola. Isto levou moito tempo e esforzo, e o produto finalmente non puido cambiar tan rápido como lles gustaría.

Uso subóptimo dos recursos
Cando hospedamos servizos nun único proceso, sempre copiamos completamente a configuración dun servidor a outro. Queriamos colocar os servizos máis cargados por separado para non malgastar recursos e obter un control máis flexible sobre o noso esquema de implantación.

Difícil implementar tecnoloxías modernas
Un problema familiar para todos os desenvolvedores: hai o desexo de introducir tecnoloxías modernas no proxecto, pero non hai oportunidade. Cunha gran solución monolítica, calquera actualización da biblioteca actual, sen esquecer a transición a unha nova, convértese nunha tarefa bastante non trivial. Leva moito tempo demostrarlle ao líder do equipo que isto traerá máis bonos que nervios desperdiciados.

Dificultade para emitir cambios
Este era o problema máis grave: lanzabamos versións cada dous meses.
Cada lanzamento converteuse nun verdadeiro desastre para o banco, a pesar das probas e esforzos dos desenvolvedores. A empresa entendeu que a principios da semana algunhas das súas funcionalidades non funcionarían. E os desenvolvedores entenderon que lles agardaba unha semana de graves incidentes.
Todos tiñan o desexo de cambiar a situación.

Expectativas dos microservizos


Emisión de compoñentes cando estea listo. Entrega de compoñentes cando estean listos mediante a descomposición da solución e a separación dos distintos procesos.

Pequenos equipos de produto. Isto é importante porque un gran equipo que traballaba no vello monolito era difícil de xestionar. Un equipo así viuse obrigado a traballar segundo un proceso estrito, pero querían máis creatividade e independencia. Só os equipos pequenos podían permitirse isto.

Illamento de servizos en procesos separados. Idealmente, quería illalo en contedores, pero un gran número de servizos escritos no .NET Framework só funcionan en Windows. Agora aparecen servizos baseados en .NET Core, pero aínda hai poucos.

Flexibilidade de implantación. Gustaríanos combinar os servizos como o necesitamos, e non como o obriga o código.

Uso das novas tecnoloxías. Isto é interesante para calquera programador.

Problemas de transición


Por suposto, se fose doado romper un monólito en microservizos, non habería que falar diso en conferencias nin escribir artigos. Hai moitas trampas neste proceso, describirei as principais que nos impediron.

O primeiro problema típico da maioría dos monólitos: coherencia da lóxica empresarial. Cando escribimos un monólito, queremos reutilizar as nosas clases para non escribir código innecesario. E ao pasar aos microservizos, isto convértese nun problema: todo o código está bastante unido e é difícil separar os servizos.

No momento do inicio do traballo, o repositorio tiña máis de 500 proxectos e máis de 700 mil liñas de código. Esta é unha decisión bastante grande e segundo problema. Non foi posible simplemente tomalo e dividilo en microservizos.

Terceiro problema - Falta de infraestruturas necesarias. De feito, estabamos copiando manualmente o código fonte aos servidores.

Como pasar de monolito a microservizos


Aprovisionamento de microservizos

En primeiro lugar, inmediatamente determinamos por nós mesmos que a separación dos microservizos é un proceso iterativo. Sempre se nos esixía desenvolver problemas empresariais en paralelo. Como implementaremos isto tecnicamente xa é o noso problema. Por iso, preparámonos para un proceso iterativo. Non funcionará doutro xeito se tes unha aplicación grande e inicialmente non está lista para ser reescrita.

Que métodos usamos para illar os microservizos?

O primeiro camiño — mover módulos existentes como servizos. Neste sentido, tivemos sorte: xa había servizos rexistrados que funcionaban mediante o protocolo WCF. Separáronse en asembleas separadas. Portámolos por separado, engadindo un pequeno lanzador a cada compilación. Foi escrito usando a marabillosa biblioteca Topshelf, que che permite executar a aplicación tanto como servizo como consola. Isto é conveniente para a depuración xa que non se requiren proxectos adicionais na solución.

Os servizos estaban conectados segundo a lóxica empresarial, xa que utilizaban conxuntos comúns e traballaban cunha base de datos común. Dificilmente poderían denominarse microservizos na súa forma pura. Non obstante, poderiamos ofrecer estes servizos por separado, en procesos diferentes. Só isto permitiu reducir a súa influencia entre si, reducindo o problema co desenvolvemento paralelo e un único punto de falla.

A montaxe co host é só unha liña de código na clase Program. Agachamos o traballo con Topshelf nunha clase auxiliar.

namespace RBA.Services.Accounts.Host
{
   internal class Program
   {
      private static void Main(string[] args)
      {
        HostRunner<Accounts>.Run("RBA.Services.Accounts.Host");

       }
    }
}

A segunda forma de asignar microservizos é: crealos para resolver novos problemas. Se ao mesmo tempo o monolito non crece, isto xa é excelente, o que significa que imos na dirección correcta. Para resolver novos problemas, tentamos crear servizos separados. Se houbo tal oportunidade, entón creamos servizos máis "canónicos" que xestionan completamente o seu propio modelo de datos, unha base de datos separada.

Nós, como moitos, comezamos cos servizos de autenticación e autorización. Son perfectos para iso. Son independentes, por regra xeral, teñen un modelo de datos separado. Eles mesmos non interactúan co monolito, só recorre a eles para resolver algúns problemas. Usando estes servizos, pode comezar a transición a unha nova arquitectura, depurar a infraestrutura neles, probar algúns enfoques relacionados coas bibliotecas de rede, etc. Non temos ningún equipo na nosa organización que non poida crear un servizo de autenticación.

A terceira forma de asignar microservizosO que usamos é un pouco específico para nós. Esta é a eliminación da lóxica empresarial da capa da IU. A nosa aplicación principal de IU é o escritorio; como o backend, está escrito en C#. Os desenvolvedores cometían erros periódicamente e transferían partes da lóxica á IU que deberían existir no backend e reutilizarse.

Se observas un exemplo real do código da parte da IU, podes ver que a maior parte desta solución contén lóxica empresarial real que é útil noutros procesos, non só para construír o formulario da IU.

A transición do monolito aos microservizos: historia e práctica

A lóxica real da IU só está aí nas últimas liñas. Trasladámolo ao servidor para que puidese ser reutilizado, reducindo así a IU e conseguindo a arquitectura correcta.

A cuarta e máis importante forma de illar os microservizos, que permite reducir o monólito, é a eliminación dos servizos existentes con tramitación. Cando sacamos os módulos existentes tal e como están, o resultado non sempre é do agrado dos desenvolvedores e o proceso de negocio pode estar desactualizado desde que se creou a funcionalidade. Coa refactorización, podemos apoiar un novo proceso empresarial porque os requisitos comerciais están en constante cambio. Podemos mellorar o código fonte, eliminar defectos coñecidos e crear un modelo de datos mellor. Hai moitos beneficios acumulados.

A separación dos servizos do procesamento está inextricablemente ligada ao concepto de contexto limitado. Este é un concepto de Domain Driven Design. Significa unha sección do modelo de dominio na que se definen de forma única todos os termos dunha única lingua. Vexamos o contexto dos seguros e as facturas como exemplo. Temos unha aplicación monolítica, e necesitamos traballar coa conta no seguro. Agardamos que o programador atope unha clase de Conta existente noutro conxunto, que a faga referencia desde a clase Insurance e teremos código de traballo. Respectarase o principio DRY, a tarefa farase máis rápido utilizando o código existente.

Como resultado, resulta que os contextos de contas e seguros están conectados. A medida que xurdan novos requisitos, este acoplamento interferirá co desenvolvemento, aumentando a complexidade da xa complexa lóxica empresarial. Para resolver este problema, cómpre atopar os límites entre contextos no código e eliminar as súas violacións. Por exemplo, no contexto do seguro, é moi posible que un número de conta do Banco Central de 20 díxitos e a data de apertura da conta sexan suficientes.

Para separar estes contextos limitados entre si e comezar o proceso de separación dos microservizos dunha solución monolítica, utilizamos un enfoque como a creación de API externas dentro da aplicación. Se sabiamos que algún módulo debería converterse nun microservizo, modificado dalgún xeito dentro do proceso, inmediatamente fixemos chamadas á lóxica que pertence a outro contexto limitado mediante chamadas externas. Por exemplo, a través de REST ou WCF.

Decidimos firmemente que non evitariamos códigos que requiran transaccións distribuídas. No noso caso, resultou bastante sinxelo seguir esta regra. Aínda non atopamos situacións nas que realmente sexan necesarias transaccións distribuídas estritas: a coherencia final entre módulos é suficiente.

Vexamos un exemplo específico. Temos o concepto de orquestrador: unha canalización que procesa a entidade da "aplicación". Crea á súa vez un cliente, unha conta e unha tarxeta bancaria. Se o cliente e a conta se crean correctamente, pero a creación da tarxeta falla, a aplicación non pasa ao estado "exitoso" e permanece no estado de "tarxeta non creada". No futuro, a actividade en segundo plano recollerao e rematará. O sistema leva algún tempo nun estado de inconsistencia, pero en xeral estamos satisfeitos con isto.

Se se produce unha situación na que é necesario gardar de forma consistente parte dos datos, o máis probable é que optemos pola consolidación do servizo para procesalo nun só proceso.

Vexamos un exemplo de asignación dun microservizo. Como podes levalo á produción de forma relativamente segura? Neste exemplo, temos unha parte separada do sistema: un módulo de servizo de nóminas, unha das seccións de código da cal queremos facer un microservizo.

A transición do monolito aos microservizos: historia e práctica

En primeiro lugar, creamos un microservizo reescribindo o código. Estamos mellorando algúns aspectos cos que non estabamos contentos. Implementamos novos requisitos comerciais do cliente. Engadimos unha pasarela API á conexión entre a IU e o backend, que proporcionará o desvío de chamadas.

A transición do monolito aos microservizos: historia e práctica

A continuación, liberamos esta configuración en funcionamento, pero nun estado piloto. A maioría dos nosos usuarios aínda traballan con procesos comerciais antigos. Para os novos usuarios, estamos a desenvolver unha nova versión da aplicación monolítica que xa non contén este proceso. Esencialmente, temos unha combinación dun monólito e un microservizo que funciona como piloto.

A transición do monolito aos microservizos: historia e práctica

Cun piloto exitoso, entendemos que a nova configuración é efectivamente viable, podemos eliminar o antigo monolito da ecuación e deixar a nova configuración no lugar da antiga solución.

A transición do monolito aos microservizos: historia e práctica

En total, usamos case todos os métodos existentes para dividir o código fonte dun monólito. Todos eles permítennos reducir o tamaño de partes da aplicación e traducilos a novas bibliotecas, facendo mellor o código fonte.

Traballando coa base de datos


A base de datos pódese dividir peor que o código fonte, xa que contén non só o esquema actual, senón tamén os datos históricos acumulados.

A nosa base de datos, como moitas outras, tiña outro inconveniente importante: o seu enorme tamaño. Esta base de datos foi deseñada segundo a intrincada lóxica empresarial dun monólito e as relacións acumuladas entre as táboas de varios contextos limitados.

No noso caso, para rematar todos os problemas (base de datos grande, moitas conexións, límites ás veces pouco claros entre táboas), xurdiu un problema que se dá en moitos proxectos de gran tamaño: o uso do modelo de base de datos compartida. Os datos foron tomados das táboas a través da visualización, a través da replicación e enviáronse a outros sistemas nos que se precisaba esta replicación. Como resultado, non puidemos mover as táboas a un esquema separado porque se usaron activamente.

A mesma división en contextos limitados no código axúdanos á separación. Normalmente dános unha idea bastante boa de como desglosamos os datos a nivel de base de datos. Entendemos que táboas pertencen a un contexto limitado e cales a outro.

Usamos dous métodos globais de partición de bases de datos: partición de táboas existentes e partición con procesamento.

Dividir as táboas existentes é un bo método para usar se a estrutura de datos é boa, cumpre os requisitos comerciais e todos están satisfeitos con ela. Neste caso, podemos separar as táboas existentes nun esquema separado.

Precísase un departamento con tramitación cando o modelo de negocio cambiou moito, e as táboas xa non nos satisfacen para nada.

Dividir táboas existentes. Temos que determinar o que separaremos. Sen este coñecemento, nada funcionará, e aquí a separación de contextos limitados no código axudaranos. Como regra xeral, se pode comprender os límites dos contextos no código fonte, queda claro que táboas deben incluírse na lista do departamento.

Imaxinemos que temos unha solución na que dous módulos monolíticos interactúan cunha base de datos. Debemos asegurarnos de que só un módulo interactúa coa sección de táboas separadas e o outro comeza a interactuar con ela a través da API. Para comezar, abonda con que só se realice a gravación a través da API. Esta é unha condición necesaria para que falemos da independencia dos microservizos. As conexións de lectura poden permanecer mentres non haxa un gran problema.

A transición do monolito aos microservizos: historia e práctica

O seguinte paso é que podemos separar a sección de código que funciona con táboas separadas, con ou sen procesamento, nun microservizo separado e executalo nun proceso separado, un contedor. Este será un servizo separado cunha conexión á base de datos monolith e aquelas táboas que non se relacionan directamente con ela. O monolito aínda interactúa para a lectura coa parte desmontable.

A transición do monolito aos microservizos: historia e práctica

Máis adiante eliminaremos esta conexión, é dicir, a lectura de datos dunha aplicación monolítica de táboas separadas tamén se transferirá á API.

A transición do monolito aos microservizos: historia e práctica

A continuación, seleccionaremos da base de datos xeral as táboas coas que só funciona o novo microservizo. Podemos mover as táboas a un esquema separado ou incluso a unha base de datos física separada. Aínda hai unha conexión de lectura entre o microservizo e a base de datos monolith, pero non hai nada de que preocuparse, nesta configuración pode vivir bastante tempo.

A transición do monolito aos microservizos: historia e práctica

O último paso é eliminar completamente todas as conexións. Neste caso, é posible que necesitemos migrar os datos da base de datos principal. Ás veces queremos reutilizar algúns datos ou directorios replicados desde sistemas externos en varias bases de datos. Isto pásanos periódicamente.

A transición do monolito aos microservizos: historia e práctica

Departamento de procesamento. Este método é moi semellante ao primeiro, só en orde inversa. Inmediatamente asignamos unha nova base de datos e un novo microservizo que interactúa co monolito a través dunha API. Pero ao mesmo tempo, queda un conxunto de táboas de bases de datos que queremos eliminar no futuro. Xa non o necesitamos, substituímolo no novo modelo.

A transición do monolito aos microservizos: historia e práctica

Para que este esquema funcione, probablemente necesitaremos un período de transición.

Hai entón dous enfoques posibles.

Primeiro: duplicamos todos os datos nas bases de datos novas e antigas. Neste caso, temos redundancia de datos e poden xurdir problemas de sincronización. Pero podemos tomar dous clientes diferentes. Un funcionará coa nova versión, o outro coa antiga.

Segundo: dividimos os datos segundo uns criterios empresariais. Por exemplo, tiñamos 5 produtos no sistema que estaban almacenados na base de datos antiga. Colocamos o sexto dentro da nova tarefa empresarial nunha nova base de datos. Pero necesitaremos unha pasarela API que sincronice estes datos e mostre ao cliente de onde e de que obter.

Ambos enfoques funcionan, elixe dependendo da situación.

Despois de estar seguros de que todo funciona, pódese desactivar a parte do monólito que funciona con estruturas de bases de datos antigas.

A transición do monolito aos microservizos: historia e práctica

O último paso é eliminar as antigas estruturas de datos.

A transición do monolito aos microservizos: historia e práctica

En resumo, podemos dicir que temos problemas coa base de datos: é difícil traballar con ela en comparación co código fonte, é máis difícil de compartir, pero pódese e debe facerse. Atopamos algunhas formas que nos permiten facelo de forma bastante segura, pero aínda é máis fácil cometer erros cos datos que co código fonte.

Traballar co código fonte


Así era o diagrama do código fonte cando comezamos a analizar o proxecto monolítico.

A transición do monolito aos microservizos: historia e práctica

Pódese dividir aproximadamente en tres capas. Esta é unha capa de módulos lanzados, complementos, servizos e actividades individuais. De feito, estes eran puntos de entrada dentro dunha solución monolítica. Todos eles estaban ben selados cunha capa común. Tiña lóxica empresarial que os servizos compartían e moitas conexións. Cada servizo e complemento utilizaba ata 10 ou máis conxuntos comúns, dependendo do seu tamaño e da conciencia dos desenvolvedores.

Tivemos a sorte de contar con bibliotecas de infraestrutura que se podían utilizar por separado.

Ás veces xurdía unha situación cando algúns obxectos comúns non pertencían realmente a esta capa, senón que eran bibliotecas de infraestrutura. Isto resolveuse cambiando o nome.

A maior preocupación eran os contextos limitados. Aconteceu que 3-4 contextos mesturáronse nunha asemblea común e utilizáronse entre si dentro das mesmas funcións empresariais. Era necesario comprender onde se podía dividir e ao longo de que límites, e que facer a continuación coa asignación desta división en conxuntos de código fonte.

Formulamos varias regras para o proceso de división do código.

O primeiro: Xa non queriamos compartir a lóxica empresarial entre servizos, actividades e complementos. Queriamos facer independente a lóxica empresarial dentro dos microservizos. Os microservizos, por outra banda, son pensados ​​idealmente como servizos que existen de forma completamente independente. Creo que este enfoque é un pouco despilfarrador, e é difícil de conseguir, porque, por exemplo, os servizos en C# estarán conectados en calquera caso mediante unha biblioteca estándar. O noso sistema está escrito en C#; aínda non utilizamos outras tecnoloxías. Por iso, decidimos que podíamos permitirnos o luxo de utilizar conxuntos técnicos comúns. O principal é que non conteñen ningún fragmento de lóxica empresarial. Se tes un envoltorio práctico sobre o ORM que estás a usar, copialo de servizo en servizo é moi caro.

O noso equipo é un fanático do deseño dirixido por dominios, polo que a arquitectura de cebola encaixaba moi ben para nós. A base dos nosos servizos non é a capa de acceso a datos, senón un conxunto con lóxica de dominio, que só contén lóxica empresarial e non ten conexións coa infraestrutura. Ao mesmo tempo, podemos modificar de forma independente o conxunto de dominios para resolver problemas relacionados cos frameworks.

Nesta fase atopamos o noso primeiro problema grave. O servizo tiña que referirse a un conxunto de dominios, queriamos que a lóxica fose independente e o principio DRY impediunos moito aquí. Os desenvolvedores querían reutilizar as clases de conxuntos veciños para evitar a duplicación e, como resultado, os dominios comezaron a enlazarse de novo. Analizamos os resultados e decidimos que quizais o problema tamén resida na área do dispositivo de almacenamento do código fonte. Tiñamos un gran repositorio que contiña todo o código fonte. A solución para todo o proxecto foi moi difícil de montar nunha máquina local. Por iso, creáronse pequenas solucións separadas para partes do proxecto, e ninguén prohibiu engadirlles algún conxunto común ou de dominio e reutilizalos. A única ferramenta que non nos permitiu facelo foi a revisión do código. Pero ás veces tamén fracasou.

Despois comezamos a pasar a un modelo con repositorios separados. A lóxica empresarial xa non flúe de servizo en servizo, os dominios independizáronse de verdade. Os contextos delimitados son compatibles con máis claridade. Como reutilizamos as bibliotecas de infraestruturas? Separámolas nun repositorio separado e, a continuación, puxémolas en paquetes Nuget, que introducimos en Artifactory. Con calquera cambio, a montaxe e publicación prodúcese automaticamente.

A transición do monolito aos microservizos: historia e práctica

Os nosos servizos comezaron a facer referencia aos paquetes de infraestrutura interna do mesmo xeito que aos externos. Descargamos bibliotecas externas de Nuget. Para traballar con Artifactory, onde colocamos estes paquetes, utilizamos dous xestores de paquetes. En pequenos repositorios tamén usamos Nuget. En repositorios con múltiples servizos, usamos Paket, que proporciona máis coherencia de versión entre módulos.

A transición do monolito aos microservizos: historia e práctica

Así, traballando no código fonte, cambiando lixeiramente a arquitectura e separando os repositorios, facemos os nosos servizos máis independentes.

Problemas de infraestrutura


A maioría das desvantaxes de pasar aos microservizos están relacionadas coa infraestrutura. Necesitará un despregamento automatizado, necesitará novas bibliotecas para executar a infraestrutura.

Instalación manual en ambientes

Inicialmente, instalamos manualmente a solución para ambientes. Para automatizar este proceso, creamos unha canalización CI/CD. Escollemos o proceso de entrega continua porque a implantación continua aínda non é aceptable para nós desde o punto de vista dos procesos empresariais. Polo tanto, o envío para a operación realízase mediante un botón e para probar automaticamente.

A transición do monolito aos microservizos: historia e práctica

Usamos Atlassian, Bitbucket para almacenar o código fonte e Bamboo para a construción. Gústanos escribir scripts de compilación en Cake porque é o mesmo que C#. Os paquetes preparados chegan a Artifactory e Ansible chega automaticamente aos servidores de proba, despois de que poden ser probados inmediatamente.

A transición do monolito aos microservizos: historia e práctica

Rexistro separado


Nun tempo, unha das ideas do monolito era proporcionar un rexistro compartido. Tamén necesitabamos entender que facer cos rexistros individuais que hai nos discos. Os nosos rexistros están escritos en ficheiros de texto. Decidimos usar unha pila ELK estándar. Non escribimos a ELK directamente a través dos provedores, pero decidimos que modificaríamos os rexistros de texto e escribiriamos o ID de rastrexo neles como identificador, engadindo o nome do servizo, para que estes rexistros puidesen ser analizados máis tarde.

A transición do monolito aos microservizos: historia e práctica

Usando Filebeat, temos a oportunidade de recoller os nosos rexistros dos servidores, despois transformalos, usar Kibana para crear consultas na IU e ver como foi a chamada entre os servizos. Trace ID axuda moito con isto.

Servizos relacionados coa proba e depuración


Inicialmente, non entendiamos completamente como depurar os servizos que se estaban a desenvolver. Todo era sinxelo co monolito; executámolo nunha máquina local. Nun principio intentaron facer o mesmo cos microservizos, pero ás veces para lanzar un microservizo por completo é necesario lanzar varios outros, e isto é un inconveniente. Démonos conta de que necesitamos pasar a un modelo no que deixemos na máquina local só o servizo ou servizos que queremos depurar. Os servizos restantes utilízanse desde servidores que coinciden coa configuración con prod. Despois da depuración, durante a proba, para cada tarefa, só se envían ao servidor de proba os servizos modificados. Así, a solución é probada na forma na que aparecerá en produción no futuro.

Hai servidores que só executan versións de produción dos servizos. Estes servidores son necesarios en caso de incidencias, para comprobar a entrega antes da implantación e para a formación interna.

Engadimos un proceso de proba automatizado mediante a popular biblioteca Specflow. As probas execútanse automaticamente usando NUnit inmediatamente despois da implantación desde Ansible. Se a cobertura da tarefa é totalmente automática, non hai necesidade de probas manuais. Aínda que ás veces aínda se requiren probas manuais adicionais. Usamos etiquetas en Jira para determinar que probas executar para un problema específico.

Ademais, a necesidade de probas de carga aumentou; anteriormente só se realizaba en casos raros. Usamos JMeter para realizar probas, InfluxDB para almacenalas e Grafana para crear gráficos de procesos.

Que conseguimos?


En primeiro lugar, desfixémonos do concepto de "lanzamento". Atrás quedaron os monstruosos lanzamentos de dous meses cando este coloso se despregou nun ambiente de produción, interrompendo temporalmente os procesos comerciais. Agora despregamos servizos de media cada 1,5 días, agrupándoos porque entran en funcionamento despois da aprobación.

Non hai fallos mortais no noso sistema. Se liberamos un microservizo cun erro, a funcionalidade asociada a el quedará rota e todas as demais funcionalidades non se verán afectadas. Isto mellora moito a experiencia do usuario.

Podemos controlar o patrón de implantación. Pode seleccionar grupos de servizos por separado do resto da solución, se é necesario.

Ademais, reducimos significativamente o problema cunha gran cola de melloras. Agora temos equipos de produtos separados que traballan con algúns dos servizos de forma independente. O proceso Scrum xa encaixa ben aquí. Un equipo específico pode ter un produtor separado que lle asigne tarefas.

Resumo

  • Os microservizos son moi axeitados para descompoñer sistemas complexos. No proceso, comezamos a comprender o que hai no noso sistema, que contextos limitados hai, onde están os seus límites. Isto permítelle distribuír correctamente as melloras entre os módulos e evitar a confusión de código.
  • Os microservizos ofrecen vantaxes organizativas. Moitas veces fálase deles só como arquitectura, pero calquera arquitectura é necesaria para resolver as necesidades empresariais, e non por si mesma. Polo tanto, podemos dicir que os microservizos son moi axeitados para resolver problemas en equipos pequenos, dado que Scrum é moi popular agora.
  • A separación é un proceso iterativo. Non pode tomar unha aplicación e simplemente dividila en microservizos. É improbable que o produto resultante sexa funcional. Á hora de dedicar microservizos, é beneficioso reescribir o legado existente, é dicir, convertelo en código que nos guste e que satisfaga mellor as necesidades empresariais en canto a funcionalidade e velocidade.

    Unha pequena advertencia: Os custos de pasar aos microservizos son bastante importantes. Levou moito tempo resolver só o problema das infraestruturas. Polo tanto, se tes unha aplicación pequena que non require unha escala específica, a non ser que teñas un gran número de clientes competindo pola atención e o tempo do teu equipo, entón os microservizos poden non ser o que necesitas hoxe. É bastante caro. Se inicias o proceso con microservizos, os custos serán inicialmente maiores que se inicias o mesmo proxecto co desenvolvemento dun monólito.

    PS Unha historia máis emotiva (e como para ti persoalmente) - segundo Ligazón.
    Aquí está a versión completa do informe.

Fonte: www.habr.com

Engadir un comentario