Crie uma arquitetura escalável e resiliente com microsserviços dinâmicos

Olá de novo. Como você sabe, em março, a OTUS lança um curso completamente novo sobre padrões de arquitetura e design . Antes do início do curso, muito material foi traduzido para você sobre como criar uma arquitetura escalável e resiliente usando microsserviços dinâmicos. Gostar de ler!




anotação


Uma das tendências mais importantes da arquitetura industrial é o uso de microsserviços em detrimento das arquiteturas monolíticas que estão perdendo popularidade. Graças à arquitetura em nuvem, a implantação de sistemas de microsserviço é mais produtiva, flexível e econômica. Seja como for, muitas empresas já começaram a mudar de um tipo de arquitetura para outro, mas isso ainda está na sua infância. Neste artigo, resolvemos problemas decorrentes da necessidade de desenvolver um sistema escalável e tolerante a falhas com base em microsserviços. Em nossos experimentos, consideramos dois tipos de microsserviços, simples e avançados, e mostramos que a solução proposta é inovadora com base em seu comportamento dinâmico.

1. Introdução


Nas últimas décadas, a história das linguagens de programação e dos paradigmas da ciência da computação foi caracterizada pelo aumento da atenção à distribuição e modularização para melhorar a reutilização e a confiabilidade do código.

Havia uma necessidade de aumentar a quantidade e a qualidade do software [1]. Um dos fatores principais para esclarecer as várias divergências associadas ao design inovador é a adequação do uso de várias ferramentas para o design e desenvolvimento de sistemas de software mais avançados [2]. Um grande sucesso nesse processo foi recentemente demonstrado por sistemas baseados em microsserviços [3], que são um paradigma arquitetônico focado em várias aplicações (por exemplo, para pessoas com deficiência) [3]. Sob os auspícios dos microsserviços, o interesse pela arquitetura e design está crescendo. Atributos de qualidade (por exemplo, escalabilidade, desempenho e tolerância a erros) ou seleção de modelo, como "contrato de serviço" [5] ou API Gateway,não viola mais o princípio YAGNI (“Você não precisará dele” - “sofre de erros de BDUF” (“Big Design Up Front” - “Design em larga escala primeiro”). A principal questão de pesquisa que este artigo pretende responder é como podemos desenvolver um sistema baseado em microsserviços com a mesma simplicidade que um sistema monolítico? Além disso, a partir do tópico anterior, como podemos criar um ambiente que forneça uma distribuição dinâmica do poder de computação entre os clientes? Nossa hipótese de pesquisa sugere o uso de uma arquitetura de sistema cliente-servidor que combina computação distribuída e microsserviços para resolver esses problemas.A principal questão de pesquisa que este artigo pretende responder é como podemos desenvolver um sistema baseado em microsserviços com a mesma simplicidade que um sistema monolítico? Além disso, a partir do tópico anterior, como podemos criar um ambiente que forneça uma distribuição dinâmica do poder de computação entre os clientes? Nossa hipótese de pesquisa sugere o uso de uma arquitetura de sistema cliente-servidor que combina computação distribuída e microsserviços para resolver esses problemas.A principal questão de pesquisa que este artigo pretende responder é como podemos desenvolver um sistema baseado em microsserviços com a mesma simplicidade que um sistema monolítico? Além disso, a partir do tópico anterior, como podemos criar um ambiente que forneça uma distribuição dinâmica do poder de computação entre os clientes? Nossa hipótese de pesquisa sugere o uso de uma arquitetura de sistema cliente-servidor que combina computação distribuída e microsserviços para resolver esses problemas.que fornece distribuição dinâmica do poder de computação entre clientes? Nossa hipótese de pesquisa sugere o uso de uma arquitetura de sistema cliente-servidor que combina computação distribuída e microsserviços para resolver esses problemas.que fornece distribuição dinâmica do poder de computação entre clientes? Nossa hipótese de pesquisa sugere o uso de uma arquitetura de sistema cliente-servidor que combina computação distribuída e microsserviços para resolver esses problemas.

A estrutura do documento é a seguinte: a seção 2 fornece uma breve visão geral da literatura atual, explicando a importância dos microsserviços, incluindo dois serviços conhecidos oferecidos pelo Azure, e a seção 3 discute a arquitetura proposta. A seção 4 discute a avaliação deste sistema antes de tirar conclusões na última seção.

2. Revisão de literatura de microsserviços


Graças à arquitetura em nuvem, a implantação de sistemas de microsserviços é mais produtiva, flexível e econômica [6]. No entanto, Zimmermann observa que os microsserviços são um tópico sensível que está sendo estudado principalmente na academia [7] e na indústria. O termo “microsserviços” foi discutido pela primeira vez em um seminário de arquitetos de software na Itália em maio de 2011 para descrever o que os participantes viam como um estilo arquitetônico comum recentemente explorado por muitos deles. Um ano depois, o mesmo grupo confirmou que o termo "microsserviços" é o nome mais apropriado. De fato, os microsserviços foram desenvolvidos como uma resposta a problemas em aplicativos monolíticos ou arquiteturas orientadas a serviços que complicam a escalabilidade, a complexidade e as dependências do aplicativo que está sendo desenvolvido,juntamente com o uso de mecanismos de comunicação leves [8-9]. Como o monólito é um aplicativo de software cujos módulos não podem ser executados independentemente, devemos considerar uma solução baseada em microsserviços, pois é o único capaz de executar instruções independentes entre si [10-11]. Monólitos grandes tornam-se problemáticos para manter ao longo do tempo e são difíceis de avaliar devido à sua complexidade, mas a principal desvantagem é que eles limitam a escalabilidade do produto. Outro problema é que eles não fornecem tolerância a falhas e não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.Como o monólito é um aplicativo de software cujos módulos não podem ser executados independentemente, devemos considerar uma solução baseada em microsserviços, pois é o único capaz de executar instruções independentes entre si [10-11]. Monólitos grandes tornam-se problemáticos para manter ao longo do tempo e são difíceis de avaliar devido à sua complexidade, mas a principal desvantagem é que eles limitam a escalabilidade do produto. Outro problema é que eles não fornecem tolerância a falhas e não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.Como o monólito é um aplicativo de software cujos módulos não podem ser executados independentemente, devemos considerar uma solução baseada em microsserviços, pois é o único capaz de executar instruções independentes entre si [10-11]. Monólitos grandes tornam-se problemáticos para manter ao longo do tempo e são difíceis de avaliar devido à sua complexidade, mas a principal desvantagem é que eles limitam a escalabilidade do produto. Outro problema é que eles não fornecem tolerância a falhas e não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.capaz de executar instruções independentes umas das outras [10-11]. Monólitos grandes tornam-se problemáticos para manter ao longo do tempo e são difíceis de avaliar devido à sua complexidade, mas a principal desvantagem é que eles limitam a escalabilidade do produto. Outro problema é que eles não fornecem tolerância a falhas e não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.capaz de executar instruções independentes umas das outras [10-11]. Monólitos grandes tornam-se problemáticos para manter ao longo do tempo e são difíceis de avaliar devido à sua complexidade, mas a principal desvantagem é que eles limitam a escalabilidade do produto. Outro problema é que eles não fornecem tolerância a falhas e não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.e eles não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.e eles não permitem que um componente individual do sistema funcione quando outro componente não funciona, o que é possível em arquiteturas orientadas a microsserviços.

Na SOA (Service Oriented Architecture), os principais serviços são coordenados usando dois métodos: orquestração (onde existe um microsserviço central que envia solicitações a outros serviços e controla todo o processo enviando e recebendo respostas) e coreografia (que não envolve nenhuma centralização, mas cada serviço sabe com antecedência o que deve fazer) [1]. Como no caso de arquiteturas monolíticas e arquiteturas SOA, o problema mais difícil continua sendo o particionamento do sistema em serviços [12]. Além disso, em nenhum caso você deve negligenciar a questão de fornecer informações confidenciais através da distribuição descontrolada de serviços [13].

Nossa arquitetura combina computação distribuída com microsserviços para criar um ambiente que permite a distribuição dinâmica da computação entre clientes. Por computação distribuída, entendemos a disponibilidade de processar e armazenar grandes quantidades de dados na nuvem, que é um elemento-chave na indústria moderna, dentro e fora do campo de TI. Os sistemas de armazenamento distribuído são projetados para atender aos requisitos de aplicativos distribuídos e avançados em termos de computação, com ampla aplicabilidade, escalabilidade e alto desempenho. Uma solução conhecida é o MapReduce [14], que orquestra os cálculos classificando servidores distribuídos, gerenciando simultaneamente várias tarefas, todas as comunicações e transferência de dados entre partes do sistema,fornecendo redundância e tolerância a falhas.

O Azure Batch é outro modelo de programação usado para executar com eficiência aplicativos computadorizados em modo paralelo ou em grande escala, sem configuração manual ou gerenciamento de infraestrutura, com clusters mais poderosos de computação de alto desempenho (HPC - computação de alto desempenho) [15]. Para ilustrar essas idéias, lembremo-lo de SaaS (software como serviço) ou aplicativos clientes que precisam de ampla execução [16]. De fato, várias empresas de TI estão demonstrando um interesse crescente em SaaS, interessadas em reduzir suas despesas operacionais e, como resultado, em aumentar a flexibilidade de seus negócios [17]. Outro serviço oferecido pelos principais provedores de serviços em nuvem é o Azure Functions,que permite o lançamento sob demanda sem a necessidade de fornecimento ou gerenciamento explícito de infraestrutura [18].

Também aumenta o interesse dos aplicativos no lançamento fácil de pequenos pedaços de código ou "funções" na nuvem. O crescente interesse na Internet das Coisas (IoT) faz do Azure Functions [19] uma excelente solução para processamento de dados, integração de sistemas e criação de APIs e microsserviços simples.

3. Metodologia


O sistema estruturalmente proposto pode ser dividido em 3 áreas diferentes: (1) o cliente - que executará as tarefas atribuídas pelo servidor; (2) servidor - uma interface com um cliente, o cérebro das aplicações monolíticas; (3) uma área de gerenciamento de comunicação cliente-servidor que encapsula todos os detalhes associados à transferência de execução do servidor para o cliente. Todas as informações transmitidas pela rede entre o cliente e o servidor são criptografadas usando o algoritmo DES (Data Encryption Standard), e a chave é alterada usando o protocolo Diffie-Hellman [20], que, embora seja vulnerável sob certas condições, ainda implementado em uma variedade de soluções de segurança da Internet.

3.1 Arquitetura do sistema

Nosso sistema é fortemente baseado na arquitetura de sistemas dinâmicos de microsserviços. A arquitetura toma como base o cliente-servidor, no qual o servidor corresponde a um número maior de clientes. O servidor e o cliente executam microsserviços da web, o protocolo de comunicação é HTTP, o formato de dados é JSON. Essa arquitetura é útil para distribuir e redistribuir dinamicamente recursos entre clientes. Esse modelo de arquitetura é usado para criar aplicativos grandes, complexos e escalonáveis ​​horizontalmente, consistindo em processos pequenos, independentes e separados que interagem entre si usando a API [21].

Na fig. A Figura 1 mostra como um servidor distribui pacotes de funcionalidade para seus clientes. Dependendo do número de clientes, pode haver instruções que não serão atribuídas a nenhum cliente ou o mesmo conjunto de instruções atribuído a vários clientes.


FIG. 1. Distribuição de serviços aos clientes.

A arquitetura do aplicativo foi criada usando a estrutura ASP.NET MVC da Microsoft. Na parte central, vemos os microsserviços do servidor no próprio servidor e, à esquerda e à direita, há muitos clientes aguardando para iniciar tarefas do servidor. O componente de serviço da orquestração fornece, por um lado, a comunicação entre o servidor e os clientes, enviando tarefas aos clientes e, por outro lado, monitora o status dessas solicitações.

Essa arquitetura permite que um microsserviço chame outro microsserviço (assim obtemos um microsserviço estendido (estendido)) ou chame um ao outro, o que pode levar à dependência circular, o que deve ser evitado no nível do usuário. O protocolo de comunicação cliente-servidor é realizado nas seguintes etapas:

  1. O cliente se conecta ao servidor e inicia um protocolo de troca de chaves. Ele também os fornecerá ao servidor e porta à qual eles corresponderão.
  2. O servidor notifica o cliente da próxima tarefa a ser executada (a tarefa é representada por um par (microsserviço, dados de entrada)).
  3. O cliente recebe o trabalho e notifica o servidor de que a transferência e o download foram concluídos com êxito ou sem êxito.
  4. Assim que a conexão entre os dois objetos é estabelecida, o servidor envia os dados no formato JSON, criptografados usando DES, para o cliente para processamento.
  5. ( , ) JSON, DES.
  6. , .
  7. — .

Um caso especial dessa interação é um cenário em que um cliente executa uma tarefa para a qual o resultado de outro cliente é necessário. Para este caso, foram avaliadas duas possibilidades existentes: orquestração e coreografia.

No caso da coreografia, identificamos vários obstáculos: (a) uma lista de clientes disponíveis para a execução de uma tarefa externa deveria ter sido enviada pelo servidor ao cliente, e a manutenção dessa lista de valores atualizados geralmente resultará em maior carga na rede de troca de informações; (b) a comunicação entre os dois clientes era vulnerável a ataques. Duas situações foram resolvidas através da orquestração. De fato, todo o cuidado de gerenciamento fica com o servidor, e os clientes são apenas objetos simples e fáceis de trabalhar.

Para a opção de microsserviços estendidos, as fases da interação cliente-cliente serão as seguintes:

  1. . , . , DES.
  2. , , . , , , , . , ( . .).
  3. , ( ), , .
  4. .
  5. O cliente descriptografa o resultado com uma senha descartável e continua a execução.

3.2 Aplicativo

Para testar e avaliar essa arquitetura, implementamos vários microsserviços que solicitamos para o que queríamos verificar por vez.


FIG. 2. A interface

No primeiro experimento, usamos 3 microsserviços da seguinte maneira: (1) um microsserviço que executa uma operação matemática em dois números (usando o LibraryMath), (2) um microsserviço que nos informa se o número é positivo (MasterOfNumbers) e (3) um microsserviço estendido, que chamará o primeiro microsserviço quando receber dois números e o resultado será enviado ao segundo microsserviço para extrair informações sobre esse número (UniverseOfSuperMath).

A Figura 2 mostra como obtemos cálculos matemáticos usando os microsserviços apresentados. No nível da interface, apenas o resultado de uma operação matemática é exibido; o restante das informações pode ser visto como resultado do servidor receber uma chamada AJAX pressionando a tecla igual (ambos os resultados são positivos).

A seguir, consideraremos a principal funcionalidade do aplicativo, focada no que acontece quando há um, dois ou mais clientes conectados. Na Figura 3, vemos como, em nossos experimentos, lançamos mais clientes no computador local, usando portas diferentes para cada um deles.


FIG. 3. A interface

Temos 6 campos: ClientToken - um token exclusivo associado a cada cliente (quando a chamada é local e tem valor de host local); Data - o momento em que a solicitação foi feita; IP e porta = endereço IP do cliente e a porta através da qual a comunicação é feita; Função - nome da função chamada; Êxito - um sinalizador booleano que indica o sucesso da chamada. Por exemplo, percebemos que na primeira chamada (h: 8:38:21 o cliente não está conectado ao servidor, o processo é realizado pelo servidor). Na segunda chamada, observamos o comportamento dinâmico do sistema, uma das tarefas executadas por um dos clientes e as outras duas executadas pelo servidor. Mais especificamente, é chamado UniverserOfSuperMath (localmente - o cliente não está disponível para esta tarefa), que, por sua vez, chama dois outros microsserviços, um local e outro através de um cliente delegado para usar uma instrução específica etc.d.

Tolerância a falhas
Outra funcionalidade que eu levei em consideração ao criar essa arquitetura estava relacionada à tolerância a falhas do sistema. Com base no cenário anterior, podemos observar o que acontece se um ou mais clientes optarem por deixar o sistema.

Na Figura 3, à direita, a ligação às 8:46 demonstra esse cenário. Os clientes nas portas 8390 e 8827 têm um problema local ou de rede ou simplesmente fecham a conexão com o servidor, e o servidor não recebe uma notificação a tempo de removê-los da lista. O servidor tentará entrar em contato com os clientes e executar comandos, mas se eles não responderem em tempo hábil, o servidor assume suas tarefas e retorna o resultado solicitado. Para confirmação, os clientes serão solicitados novamente depois de um tempo e, se continuarem a não responder, serão removidos da lista de clientes disponíveis. A próxima chamada (8:47) deixará de solicitar inutilmente clientes que não estão mais disponíveis e as tarefas ignoradas pelos clientes disponíveis serão executadas pelo servidor.

Vantagens e desvantagens da solução proposta

As vantagens dessa arquitetura são óbvias: baixos custos de hospedagem, microsserviços oferecidos em uma rede distribuída são dinâmicos e escalonáveis ​​automaticamente (quando os clientes também oferecem poder de computação à medida que aumentam, o poder de computação do sistema aumenta).

As limitações devem ser enfatizadas igualmente: quando a curva de poder de computação não corresponde à curva de poder do cliente. Também temos uma restrição na capacidade de executar este aplicativo em qualquer sistema operacional. Para fazer isso, decidimos converter uma solução acessível do .NET para Java. Mas esta solução tem algumas desvantagens em relação à solução original (Java oferece menor velocidade de processamento de dados e menos transferência dinâmica de pacotes do que no .NET). No momento, estamos usando esta solução porque o .Net Core oferecido pela Microsoft para trabalhar em várias plataformas ainda não é uma solução madura e não oferece todas as funções da plataforma .NET padrão).

3.3 Componentes cliente-servidor

3.3.1. Cliente

Nessa arquitetura, o cliente é um aplicativo de desktop do Windows Presentation Foundation (WPF) projetado especificamente para se comunicar com o servidor e executar várias tarefas recebidas dele. Como o aplicativo é um arquivo executável que não requer instalação, o sistema operacional deve funcionar com o .Net Framework. Essencialmente, um microsserviço da web irá interagir com outro microsserviço da web.

Primeiro, o cliente inicia o agendador de tarefas em um encadeamento paralelo, que a cada minuto tenta notificar o servidor sobre sua presença. Uma tarefa pode assumir dois estados: (1) ou existe uma tarefa a ser executada (a inicialização do pacote de códigos já foi concluída) - nesse caso, apenas notifica a presença do servidor; (2) ou requer inicialização com o servidor.

A inicialização com o servidor inclui, em primeiro lugar, uma escolha arbitrária de código e porta que iniciará o servidor, que por sua vez são enviados a ele usando o protocolo de troca de chaves Diffie-Hellman (IKE). Assim que a conexão entre os dois objetos for estabelecida, o servidor notificará o cliente com um pacote de instruções para instalação. A principal função do cliente é receber um pacote de instruções do servidor, carregá-lo na memória, processar as informações recebidas do servidor e retornar o resultado obtido executando este pacote de instruções. A primeira etapa executada pelo cliente é entrar em contato com o servidor para obter um pacote de instruções. Este pacote de instruções vem como um arquivo ZIP.

Antes de extrair este pacote, exclua o diretório anterior com instruções da pasta "processo" (se existir), extraia o novo conteúdo para essa pasta e carregue-o na memória. O carregamento da memória começa uma vez, independentemente de quantas chamadas o cliente recebe. Isso é possível porque três propriedades permanecem inalteradas na sessão: assembly, methodInfo e tipo. Assembly armazena um link para a DLL carregada, a propriedade methodInfo contém o método chamado da DLL e type descreve o tipo da DLL. O arquivo install.zip é um pacote de instruções recebidas de um servidor que contém DLLs, XML, imagens, arquivos de configuração etc. e todo o código compilado que será executado em um processo futuro.

Esta etapa marca o início da comunicação entre o cliente e o servidor para executar uma tarefa específica. Assim que o cliente for inicializado com êxito para executar uma tarefa específica, o servidor enviará apenas o pacote de dados no formato criptografado, que deve ser processado, e também aguardará uma resposta no formato criptografado.

Ao executar o código recebido do servidor, o sistema está "bloqueado", o cliente pode se conectar aos bancos de dados, chamar outras APIs, em particular, chamar outros clientes que executam as mesmas instruções ou diferentes. A conexão é feita no sistema de orquestração, onde o servidor procura o próximo cliente disponível, solicita o resultado e sua resposta é redirecionada pelo servidor de volta ao cliente. Essa orquestração de microsserviço é chamada de "ExtendedService", e a única diferença no nível do cliente é que a criptografia é otimizada.

O problema técnico era reinicializar o cliente com outro pacote de instruções para executar. Como o carregamento de memória é estático em um contexto especial (servidor da Web), isso só foi possível reiniciando o processo inteiro para processar DLLs carregadas na memória. Para fazer isso, criamos eventos no Windows que são executados a partir de um aplicativo Web em execução em um aplicativo de desktop. Isso é necessário porque estamos lidando com dois contextos diferentes em dois segmentos diferentes de execução.

3.3.2 Servidor

O microsserviço incorporado possui uma interface ILibraryMath, que fornece o método SimpleMath, e a interface é implementada pela classe LibraryMath. A classe LibraryMath estende a classe abstrata universal MicroCore, que possui dois parâmetros correspondentes para entrada e saída. Estendendo essa classe abstrata, o método ProcessTask deve ser implementado onde todo o código a ser executado é gravado e a função Executar é chamada na classe abstrata estendida para executar esse código no método SimpleMath. Assim, é possível definir interfaces e métodos, não limitados a qualquer nome específico, mas, passando o código por uma classe abstrata, obteremos controle total sobre o código, que podemos distribuir entre diferentes clientes. Dentro desta classe, podemos facilmente ter mais funções e bibliotecas importadas,se eles estiverem agrupados em um pacote.

A próxima etapa é gravar essa interface no SimpleInjector, uma biblioteca que facilita a implantação de um padrão de injeção de dependência com componentes fracamente acoplados. Além de registrar classes intercaladas no contêiner Simple Injector, para interromper a dependência entre os níveis de aplicativo (introdução de dependências de modelo), precisamos registrar a classe no contêiner de armazenamento de microsserviço, que será dimensionado pelo aplicativo. Após esta etapa, poderemos usar a função fornecida pela interface para a finalidade criada.

O Service1 implementa o IService1 e estende a classe abstrata MicroCore e, em seguida, registra-se no MicroContainer.RegisterMicro neste contêiner. Vale mencionar a existência de APIs disponíveis em localohst / DynamicMicros / {Service} através do qual os clientes se comunicam com o servidor. Ações importantes disponíveis por meio dessas APIs: o cliente se conecta, o cliente notifica o servidor sobre sua atividade, os microsserviços se expandem etc. A seguir, apresentamos as classes MicroCore e MicroContainer, que juntas formam a base do nosso aplicativo.

A classe MicroCore é uma classe abstrata e universal e é responsável por chamar o código do método virtual ProcessTask. Isso é feito chamando o método Run, que por sua vez chama o método público TaskManager. Observe que o microsserviço, por sua vez, também chamará esse método. Quando um pacote ZIP é enviado ao cliente para carregar na memória e execução, ele é enviado com todas as suas dependências, incluindo esta classe, que é usada para gerenciar o microsserviço do cliente. O controle de execução inclui desserializar / serializar o pacote de dados a enviar, chamar o próprio código, chamar outras APIs e assim por

diante.Voltar ao lado do servidor, controlar a execução do código consiste nas seguintes etapas:

  1. Se for uma chamada ExtendedService, o servidor será chamado para atender.
  2. Se um cliente estiver disponível para a solicitação, ele será enviado a ele para processar o resultado; no caso negativo, o próprio servidor processará os dados.
  3. Solicitamos um cliente para processamento de dados.
  4. Se o cliente tiver problemas, solicitamos novamente a confirmação da disponibilidade, mas enviamos uma resposta do servidor (para evitar tempo de inatividade e longos tempos de espera).
  5. Registramos a atividade atual.

A classe MicroContainer é o espaço de gerenciamento para todo o microssistema incorporado. Aqui, os clientes que conectam o aplicativo (servidor) se conectam e há chamadas de função que estendem a classe abstrata do MicroCore para "serviços avançados". Essa é uma classe estática na qual a lista de tarefas executadas em microsserviços, a lista de clientes conectados e a lista de tarefas do cliente que executam essas tarefas são armazenadas no dicionário.

Quando iniciada, a classe será registrada para integração no microsserviço usando o RegisterMicro. Isso acontecerá apenas uma vez durante a inicialização. O método AddNewClient nos fornece o registro de um novo cliente, troca de chaves, registro do endereço IP do servidor e a porta na qual ele trabalhará. O token recebido pelo novo cliente será verificado antes de ser inserido na lista de clientes para confirmar sua exclusividade. Depois que a conexão com o cliente é estabelecida, o servidor chama o método InstallService, que empacota os dados, os envia e, depois que o cliente responder, ele será adicionado ao dicionário para esta tarefa. O tempo de serviço que será alocado para cada cliente depende da estratégia usada. Quando você inicia o microsserviço abstrato do MicroCore, chamado no servidor e no cliente (com ExtendedService),uma solicitação é feita para clientes disponíveis para a tarefa solicitada usando a função GetNextClient. Essa operação será executada com muita frequência e sua complexidade afetará diretamente o tempo de resposta do aplicativo. Por isso, nossa abordagem foi selecionar aleatoriamente um cliente. Isso é feito rapidamente e a partir de nossas experiências garante uma distribuição uniforme das chamadas.

Outra opção foi implementar uma lista de round-robin - uma solução que tem a desvantagem de que, no caso de um grande fluxo de E / S de cliente, a atualização da lista de round-robin exigirá mais tempo e complexidade, o que tentamos evitar. O método RecordClientError é chamado quando o cliente não responde à solicitação recebida. Após responder a essa pergunta, é tomada a decisão de salvar ou excluir esse cliente.Os clientes são identificados exclusivamente pelo código do token enviado pelo cliente durante a inicialização e cada microsserviço é identificado por um espaço para nome e nome da classe. Todos os recursos (clientes, código) são gerenciados através desta unidade unitária, que fornece suporte para as operações necessárias.

Em relação à segurança do sistema, foram tomadas medidas para evitar ataques, interceptações e proteção de dados. Todas as mensagens enviadas entre o servidor e os clientes são criptografadas usando o algoritmo de chave DES simétrica e a troca de chaves Diffie-Hellman entre o cliente e o servidor, o que ocorre durante a inicialização do cliente. Clientes disponíveis e programas em execução são armazenados na memória do servidor. Escolhemos esta solução porque, em nossa opinião, era a melhor opção, pois fornece acesso de alta velocidade aos dados, as informações podem mudar com muita frequência e a área de memória é muito difícil de atacar.

3.4 Comportamento dinâmico de um sistema de microsserviço

Primeiro de tudo, todos os computadores nos quais os clientes trabalharão podem estar na mesma ou em redes diferentes. Dois elementos são prioritários: (a) tempo gasto na transferência de dados; e (b) a sobrecarga adicionada pelo sistema para gerenciamento de dados (por exemplo, pesquisa de clientes, criptografia, descriptografia, tratamento de erros, etc.). Estávamos interessados ​​principalmente no comportamento do nosso sistema em redes locais (LAN) e globais (WAN) (Fig. 4).


FIG. 4. Registro do sistema que trabalha em uma rede local (a primeira coluna de logs) e global (a segunda coluna de logs).

A coluna Nome da tarefa contém todos os registros feitos pela chamada do cliente para cada tarefa, e as colunas Logs são as horas e a duração em ms para cada processamento de tarefa (à esquerda na rede local e à direita na rede global). Observe que as tarefas têm o tempo de resposta mais longo para a primeira chamada, após o que diminui. Naturalmente, porque todos os downloads de memória, endereços salvos etc. geralmente são feitos na primeira chamada. As três primeiras tarefas são operações matemáticas simples que geralmente são executadas em milissegundos - o tempo também necessário para o nosso sistema.

Para uma rede local, temos uma média de 20 a 30 milissegundos por tarefa, proveniente de criptografia, registro e transmissão pela rede (mesmo que seja local). Esse modelo de comunicação LAN também é usado na nuvem, onde os computadores estão localizados no mesmo local (data center) e a comunicação entre eles é via fibra ótica, o atraso da rede é mínimo. Os resultados são mostrados na figura. 4 na coluna esquerda de logs.

Para testar nosso aplicativo WAN, configuramos o roteador para rotear uma chamada da porta 80 para:http://192.168.1.160/(endereço de rede) e IIS (Internet Information Services) iniciaram o aplicativo, que estava acessível de qualquer lugar fora da rede local. Para executar o aplicativo no nível do cliente, era necessário o direito de usar as portas 8000: 9000 (portas arbitrárias). Os clientes estão dispostos em pontos arbitrários, conexão com o IP público foi apurado através de API: https://api.ipify.org/. Os resultados são mostrados na figura. 4 na coluna de log à direita.

Nos resultados apresentados na fig. 4, os valores na coluna direita da revista são 16 a 17% mais altos que os valores na coluna esquerda da revista para as três primeiras tarefas (sem comunicação com outros microsserviços) e ± 10% para microsserviços que baixaram documentos da Internet ou interagiram com um banco de dados no servidor específico.

4. Avaliação


Neste estudo, monitoramos o comportamento do sistema na rede local (conectando 5 computadores via rede sem fio) e na rede global (usando o espaço para nome mihaidm.ddns.net ), comparando nosso sistema com um sistema monolítico, essas operações são executadas da mesma maneira computador (consulte a tabela 1).

Tabela 1. Classificação do sistema para redes.
cálculo (ms)gravar no banco de dados (ms)geração de pdf (ms)
localhost1 14,45815,449
lan254,40816,415
wan544.82629,309


O teste foi realizado sequencialmente em um dispositivo com 5 clientes conectados para teste de rede. Cada tarefa foi concluída 100 vezes, avaliando o número total de milissegundos em todas as chamadas.

Era um produto de dois números como cálculo numérico. Um microsserviço não interage com outros microsserviços, a quantidade de informações transmitidas pela rede é pequena e a complexidade é minimizada para estudar estritamente o tempo gasto nas tarefas de gerenciamento de servidor, cliente e rede. Se o cálculo for realizado pelo servidor (host local), primeiro será verificado se há um cliente disponível e, como o cliente não está conectado, o servidor processará o resultado. No caso a seguir, a presença de clientes na rede local mostra a conclusão da tarefa em condições de operação de rede muito rápida e, do lado do processamento, criptografia / descriptografia, encontrando a resposta do cliente. Para 100 execuções, o tempo médio necessário para concluir a operação foi de 25 ms, valor promissor considerando a razão flexibilidade / velocidade. No caso de WAN, o tempo é duas vezes maiordo que na rede local (54 ms), isso se deve ao processo de criptografia, aos custos de transporte, mas para a execução real requer meio milissegundo.

Outra tarefa que investigamos está gravando no banco de dados. Em particular, a palavra que será gravada no banco de dados é usada como parâmetro. Estamos interessados ​​na rapidez com que o cliente contatará um banco de dados localizado fora da área local (para este estudo, o banco de dados foi localizado em www.my.gearhost.com ). Observe que os valores de tempo de execução na LAN e no host local estão próximos. Na rede global, a diferença é notável, porque o processamento, o gerenciamento de dados e clientes não leva tanto tempo quanto o intervalo de clientes que se conecta ao banco de dados para inserir o valor.

A última tarefa realizada neste estudo foi a criação de um arquivo PDF, nosso foco foi estimar o tempo de transmissão dos dados no sistema. Para fazer isso, baixamos o arquivo PDF em www.pdf-archive.com/2018/05/14/diploma/diploma.pdf , carregado na memória. O sistema gravará o nome em uma posição específica e retornará o resultado (na forma de vetores de bytes) de volta ao servidor. Para um host local e uma rede local, uma diferença de cerca de 1000 ms representa o tempo necessário para criptografar e transferir arquivos PDF localmente. Para a WAN, o valor resultante é maior porque o custo de transmissão do vetor de bytes é muito alto.

5. Conclusões e trabalhos futuros


A natureza geral e abstrata da arquitetura do sistema, apresentada neste trabalho no lado do servidor, dificultou o design, uma vez que o mesmo código é executado pelo servidor e pelo cliente. Podemos argumentar que a arquitetura atual é compacta, simples, fácil de entender e expandir; o cliente pode executar as tarefas atribuídas pelo servidor, o servidor é um monólito e a interface do cliente.

A arquitetura proposta facilita muito a criação de novos microsserviços, que são automaticamente integrados ao sistema incorporado. Elementos inovadores dessa arquitetura: ele pode ser dimensionado com muita facilidade, cada novo cliente recebe uma tarefa do servidor de acordo com a estratégia seguida (as tarefas mais caras, as mais comuns, uma combinação das duas listadas anteriormente ou puramente apenas uma estratégia arbitrária). De fato, temos um monólito com a flexibilidade de um sistema de microsserviço. O servidor processa a distribuição dinâmica de tarefas entre clientes, fornecendo escala dinâmica com base em vários parâmetros (o número de chamadas para a tarefa, seu tempo de execução ou uma combinação deles).

Uma das direções futuras leva em consideração que esse sistema pode ser integrado com sucesso a um site ou sistema de API com um caráter aplicativo pronunciado. A arquitetura proposta pode ser aprimorada e expandida a qualquer momento devido à disponibilidade para várias plataformas (por exemplo, para telefones celulares).

Outra direção no futuro que estamos considerando é considerada extremamente atraente hoje - é que o usuário fornece poder de computação em troca de uma taxa (por exemplo, o sistema BITCOIN), nosso aplicativo é desenvolvido para executar microsserviços em determinados computadores.

Link de origem


Este estudo foi publicado com o apoio do programa POC-A1-A1.2.3-G-2015, como parte do projeto PrivateSky (P_40_371 / 13/01/01/2016) e do projeto README “Aplicativo interativo e inovador para avaliar a legibilidade dos textos em romeno e melhorar a utilização do usuário estilos de escrita ”, contrato nº 114 / 09.15.2017, código MySMIS 2014 119286.

Referências


[1] Dragoni, N., Giallorenzo, S., Lluch-Lafuente, AL, Mazzara, M., Montesi, F., Mustafin, R. (2017a) "Microsserviços: ontem, hoje e amanhã". Mazzara M., Meyer B. (orgs.), Present and Ulterior Software Engineering. Springer
[2] Mazzara, M., Khanda, K., Mustafin, R., Rivera, V., Safina, L. e Silitti, A. (2018), “Microservices Science and Engineering”. Em: P. Ciancarini, S. Litvinov, A. Messina, A., Sillitti, G. Succi (eds.) Anais da 5ª Conferência Internacional em Engenharia de Software para Aplicações de Defesa, SEDA 2016, Springer, 10-20.
[3] Dragoni, N., Lanese, I., Larsen, ST, Mazzara, M., Mustafin, R. e Safina, L. (2017b), “Microsserviços: Como fazer sua aplicação escalar”. In: Petrenko A., Voronkov A. (eds.) Perspectives of System Informatics. PSI 2017. Notas de aula em Ciência da Computação, 10742. Springer, Cham.
[4] Melis, A., Mirri, S., Prandi, C., Prandini, M., Salomoni, P. e Callegati, F. (2016) “Um caso de uso de arquitetura de microsserviço para pessoas com deficiência”. Na 2ª Conferência Internacional da EAI sobre Objetos Inteligentes e Tecnologias para o Bem Social, DOI: 10.1007 / 978-3-319-61949-1_5.
[5] Zimmermann, O. (2017) "Princípios de microsserviços: abordagem ágil para desenvolvimento e implantação de serviços, Ciência da computação - pesquisa e desenvolvimento", 32 (3-4): 301-310.
[6] Xia, C., Zhang, Y., Wang, L, Coleman, S. e Liu, Y. (2018) "Sistema de robótica em nuvem baseado em microsserviços para espaço inteligente". In: Robótica e Sistemas Autônomos 110, DOI: 10.1016 / j.robot.2018.10.001.
[7] Bogner, J., Fritzsch, J., Wagner, S. e Zimmermann, A. (2019) “Microsserviços na indústria: insights sobre tecnologias, características e qualidade de software”. Na Conferência Internacional IEEE de 2019 sobre Workshops de Arquitetura de Software (ICSAW), em: Hamburgo, Alemanha.
[8] Akentev, E., Tchitchigin, A., Safina, L. e Mzzara, M. (2017) “Verificador de tipo verificado para a linguagem de programação Jolie”, https: // arXiv.org/pdf/1703.05186.pdf.
[9] Černý, T., Donahoo, MJ e Trnka, M. (2018) “Entendimento contextual da arquitetura de microsserviços: direções atuais e futuras”. ACM SIGAPP Applied Computing Review 17 (4): 29-45, DOI: 10.1145 / 3183628.3183631.
[10] Larucces, X., Santamaria, I., Colomo-Palacios, R. e Ebert, C. (2018) "Microservices". In: Software IEEE, 35/3: 96-100.
[11] Kalske, M. (2017) “Transformando a arquitetura monolítica em arquitetura de microsserviços”. M.Sc. Tese, Univ. de Helsinque.
[12] Lenarduzzi, V. e Taibi, D. (2016) “MVP Explained: Um estudo de mapeamento sistemático das definições de produto viável mínimo”. Na 42ª Conferência Euromicro sobre Engenharia de Software e Aplicativos Avançados (SEAA), 112-119.
[13] Taibi, D., Lenarduzzi, V., Janes, A., Liukkunen, K. e Ahmad, MO (2017) “Comparando a decomposição de requisitos dentro dos processos de desenvolvimento Scrum, Scrum com Kanban, XP e Banana”. Em: Baumeister H., Lichter H., Riebisch M. (eds.) Processos ágeis em engenharia de software e programação extrema. Notas da Palestra em Processamento de Informações de Negócios, 283. Springer, Cham.
[14] Gómez, A., Benelallam, A. e Tisi, M. (2015) "Persistência de modelo descentralizado para computação distribuída". No terceiro workshop do BigMDE, L'Aquila, Itália.
[15] Kandave, KR (2018) “Computação de alto desempenho no Azure”. Nanette Ray (ed.), AzureCAT, Microsoft Corporation.
[16] Sreenivas, V., SriHarsha, S. e Narasimham, C. (2012) "Um modelo de nuvem para implementar SaaS". In: Advanced Materials Research 341-342, Trans Tech Publications, Suíça, 499-503.
[17] Badidi, E. (2013) "Uma estrutura para seleção e provisionamento de software como serviço". In: International Journal of Computer Networks & Communications (IJCNC), 5 (3): 189-200.
[18] Lynn, T., Rosati, P., Lejeune, A. e Emeakaroha, V. (2017) “Uma revisão preliminar das plataformas de computação em nuvem sem servidor corporativo (Functionas-a-Service)”. Na 9ª Conferência Internacional IEEE 2017 sobre Tecnologia e Ciência da Computação em Nuvem, 162-169.
[19] Adzic, G. e Chatley, R. (2017) "Computação sem servidor: impacto econômico e arquitetural". Em: ESEC / FSE'17, de 4 a 8 de setembro de 2017, Paderborn, Alemanha, ACM.
[20] Diffie, W. e Hellman, M. (1976) "Novas direções em criptografia". In: Transações IEEE, Teoria da Informação, 22 (6): 644–654.
[21] Kratzke, N. (2015) “Sobre microsserviços, contêineres e seu impacto subestimado no desempenho da rede”. No CLOUD Comput. 2015, 180 arxiv.org/abs/1710.04049 .

Saiba mais sobre o curso

All Articles