<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Isaac Alves Pinheiro</title>
    <description>The latest articles on Forem by Isaac Alves Pinheiro (@isaacalves7).</description>
    <link>https://forem.com/isaacalves7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1037891%2Fe8450df6-4329-43ac-9620-db998683a2a5.jpeg</url>
      <title>Forem: Isaac Alves Pinheiro</title>
      <link>https://forem.com/isaacalves7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/isaacalves7"/>
    <language>en</language>
    <item>
      <title>Vibe Coding (2025)</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Tue, 12 Aug 2025 00:21:28 +0000</pubDate>
      <link>https://forem.com/isaacalves7/vibe-coding-1af3</link>
      <guid>https://forem.com/isaacalves7/vibe-coding-1af3</guid>
      <description>&lt;p&gt;&lt;a href=""&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn3d.iconscout.com%2F3d%2Fpremium%2Fthumb%2Fworking-in-virtual-reality-experience-10999580-8881078.png" width="450" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos últimos anos, o desenvolvimento de software tem passado por transformações impulsionadas pela Inteligência Artificial, e um dos conceitos que mais tem ganhado relevância nesse cenário é o &lt;strong&gt;vibe coding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Introduzido por Andrej Karpathy em 2025, o termo descreve uma nova abordagem à programação, em que as pessoas desenvolvedoras deixam de se concentrar na escrita do código e passam a expressar suas intenções em linguagem natural, enquanto agentes de IA se encarregam da implementação técnica.&lt;/p&gt;

&lt;p&gt;Essa mudança de paradigma está sendo rapidamente adotada em escala global: segundo o Vibe Coding Dashboard 2025 da Innobu, a IA já é responsável por gerar 41% de todo novo código, com 256 bilhões de linhas escritas somente em 2024. Esses dados evidenciam o impacto e a velocidade dessa evolução, além de redefinir o papel da pessoa programadora na era da IA.&lt;/p&gt;

&lt;p&gt;Basicamente, vibe coding é uma nova forma de programar que coloca a ideia de quem está desenvolvendo no centro do processo. &lt;/p&gt;

&lt;p&gt;Assim, em vez de uma pessoa escrever cada linha de código manualmente, ela descreve o que deseja criar (ou seja, a “vibe” do projeto) e a Inteligência Artificial cuida da parte técnica, sugerindo códigos prontos, montando estruturas básicas e automatizando tarefas repetitivas.&lt;/p&gt;

&lt;p&gt;Essa abordagem permite que a pessoa desenvolvedora foque mais na criatividade e no design da solução, enquanto a IA trata dos detalhes operacionais.&lt;/p&gt;

&lt;p&gt;Na prática, o vibe coding também torna o desenvolvimento de software mais rápido, intuitivo e acessível, representando uma grande mudança na forma como a programação é feita e como é criada.&lt;/p&gt;

&lt;p&gt;A expressão vibe coding, que pode ser traduzida como “codificação por intenção” ou “programar pela vibe”, representa muito mais do que uma técnica. Trata-se de uma mudança na forma de pensar o desenvolvimento de software. &lt;/p&gt;

&lt;p&gt;Nesse modelo, como vimos, o fluxo é iterativo: a pessoa explica, a IA gera o código, a pessoa desenvolvedora testa e ajusta, e esse ciclo se repete até que o resultado desejado esteja satisfatório. Isso favorece a experimentação rápida e permite a refinação da solução com base em testes contínuos, alinhando-se aos princípios das metodologias ágeis.&lt;/p&gt;

&lt;p&gt;Vale ressaltar também que, mesmo ao codar com IA, o papel do(a) profissional de desenvolvimento continua essencial, por ser quem garante que o código faça sentido, esteja alinhado aos objetivos do projeto e seja seguro. Por isso, podemos concluir que o sucesso do vibe coding depende da capacidade humana de orientar a IA com clareza, revisar com senso crítico e tomar decisões estratégicas com base no contexto do negócio.&lt;/p&gt;

&lt;p&gt;E, praticamente, TUDO na vida de um profissional de tecnologia é &lt;strong&gt;método científico&lt;/strong&gt;, baseado em (Who, What, How, When, Where and Why?), onde fazemos seleções, consultas e projeções de algo. É sempre baseado no que eu quero ver ou pra que eu preciso. E, é até curioso como, mesmo sem perceber, a gente vive aplicando um ciclo científico no dia a dia do trabalho em tecnologia.&lt;/p&gt;

&lt;p&gt;Você parte de um “por que” (o problema ou necessidade real), passa pelo “o que” (definição do objeto ou resultado desejado), segue para o “como” (métodos, ferramentas e arquitetura para chegar lá), depois determina “quem” (atores, equipes, usuários, stakeholders), “quando” (prazos, releases, janelas de manutenção) e “onde” (ambiente, infraestrutura, contexto de uso).&lt;/p&gt;

&lt;p&gt;No fundo, é a mesma lógica que o método científico formal usa:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn3d.iconscout.com%2F3d%2Fpremium%2Fthumb%2Fhands-holding-virtual-reality-glasses-10999596-8881067.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn3d.iconscout.com%2F3d%2Fpremium%2Fthumb%2Fhands-holding-virtual-reality-glasses-10999596-8881067.png" width="450" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observação&lt;/strong&gt; (notar um problema ou oportunidade);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pergunta&lt;/strong&gt; (Who, What, How, When, Where, Why);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hipótese&lt;/strong&gt; (solução proposta ou estratégia);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Experimentação&lt;/strong&gt; (testes, PoCs, prototipagem);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Análise&lt;/strong&gt; (validar resultados, métricas, feedback);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conclusão&lt;/strong&gt; (aprovar, refatorar ou pivotar).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;E como na ciência, quase tudo é iterativo — cada entrega, cada sprint, cada refatoração é um novo “experimento” validando ou derrubando hipóteses.&lt;/p&gt;

&lt;p&gt;Por essa razão, esse método alinhado ao &lt;strong&gt;Vibe Coding&lt;/strong&gt; é uma revolução, mas não substitui o profissional sendo ele Júnior, Pleno ou Sênior, mas sim o impulsiona e amplifica seus dons, pois estaremos sempre em busca da viabilidade e da automação. Então, o que antes era mais complexo de desenvolver por estimar prazos, processos e obstáculos enfrentados, atualmente é possível por um curto período.&lt;/p&gt;

&lt;p&gt;No entanto, claro, sempre alinhado com os stakeholders, utilizando feedbacks e usando Soft Skills (pensamento crítico, criatividade, comunicação, colaboração, etc), são o que mantém essa engrenagem funcionando. Sem isso, mesmo com toda tecnologia, a chance de desalinhamento é alta.&lt;/p&gt;

&lt;p&gt;Mesmo que uma IA evolua para ter um “senso crítico” técnico, como proposto para modelos futuros de AGI (Artificial General Intelligence), ele ainda será moldado por dados, regras, protocolos e objetivos que não abrangem todas as nuances da experiência humana. Ou seja, ela também pode ser sujeita a muitos erros, falhas e inconsistências de resultados.&lt;/p&gt;

&lt;p&gt;E o julgamento humano é criterioso, atravessado por contextos subjetivos, valores culturais, memórias, opiniões, intuições e até contradições internas, algo que não pode ser completamente capturado e preenchido por modelos estatísticos ou algoritmos de aprendizado.&lt;/p&gt;

&lt;p&gt;Uma IA pode ser excelente em identificar inconsistências lógicas, propor soluções criativas dentro de parâmetros e até fazer análises de risco, mas ela não tem vivência pessoal, não sente o impacto emocional e não percebe prioridades sutis que para um humano podem ser óbvias — como saber quando seguir uma regra e quando quebrá-la por razões éticas ou contextuais.&lt;/p&gt;

&lt;p&gt;Por isso, o equilíbrio entre capacidade técnica da IA e senso crítico humano é o que realmente potencializa resultados, principalmente em tecnologia, onde as decisões envolvem não só o “funciona ou não”, mas também o que “deve ou não ser feito” e “como será recebido pelo mundo real”.&lt;/p&gt;

&lt;p&gt;É uma nova filosofia de trabalho moderna para desenvolvimento de software, combinando o método científico como base da análise e decisão com uma mentalidade Vibe Coding para fluidez criativa e entrega rápida.&lt;/p&gt;

&lt;p&gt;No fundo, programar não é só escrever código, mas um processo contínuo de formular hipóteses (Who, What, How, When, Where, Why?), testar, analisar e ajustar. Isso é exatamente como funciona o método científico, só que aplicado ao mundo da tecnologia.&lt;/p&gt;

&lt;p&gt;Assim como a citação: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A mudança é a lei da vida. E aqueles que apenas olham para o passado ou para o presente irão com certeza perder o futuro." - John Kennedy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa citação de John Kennedy ressalta que devemos acompanhar as crescentes mudanças do mercado e nos prepararmos para o futuro. &lt;/p&gt;

&lt;p&gt;Portanto, o Vibe Coding entra como o catalisador: ele reduz o atrito, dá fluidez ao processo e faz com que o desenvolvedor possa experimentar e validar ideias em ciclos muito menores, sem perder o alinhamento com stakeholders. Isso muda o jogo, porque:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Antes&lt;/strong&gt;: Certas ideias eram descartadas por serem “impraticáveis” ou demoradas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agora&lt;/strong&gt;: Com a abordagem certa, conseguimos provar (ou descartar) hipóteses em dias ou até horas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resultado&lt;/strong&gt;: Mais inovação, menos medo de experimentar, mas ainda com responsabilidade e métricas.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para experimentar o vibe coding, na prática, basta utilizar uma das diversas ferramentas capazes de gerar AI coding (código com IA) a partir de comandos em linguagem natural, denominados &lt;code&gt;prompts&lt;/code&gt;. Atualmente, existem várias soluções no mercado que viabilizam essa abordagem de forma eficiente. &lt;/p&gt;

&lt;p&gt;A seguir, apresentamos quatro das ferramentas mais populares:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Copilot&lt;/strong&gt; (Microsoft): Desenvolvido em parceria com a OpenAI, o GitHub Copilot é uma das ferramentas mais populares de codificação assistida por IA. Ela se integra diretamente ao VS Code, Neovim, JetBrains e outros editores, oferecendo sugestões em tempo real com base em comentários e no próprio contexto do código.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Melhor uso: ideal para acelerar tarefas rotineiras de programação, gerar trechos de código repetitivos, prototipar funcionalidades rapidamente e explorar novas APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cursor&lt;/strong&gt;: O Cursor é um editor de código com IA baseado no VS Code, mas otimizado desde o início para colaboração com IA. Ele permite conversar com o código e realizar buscas contextuais, correções, testes e refatorações usando comandos em linguagem natural.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Melhor uso: fluxos de trabalho iterativos, onde a pessoa desenvolvedora precisa testar ideias para prototipação, exploração de novos projetos ou refatorações em grande escala.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ghostwriter&lt;/strong&gt;: Integrado à plataforma online Replit, o Ghostwriter permite a codificação assistida em tempo real no navegador, com suporte para dezenas de linguagens. Seu sistema oferece sugestões completas de código, depuração assistida por IA e até mesmo explicações em linguagem simples do que cada trecho faz.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Melhor uso: perfeito para pessoas desenvolvedoras iniciantes ou para fins educativos. Também é útil em contextos colaborativos, onde múltiplos membros de uma equipe compartilham um mesmo projeto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Q Developer&lt;/strong&gt;: Voltado principalmente para pessoas desenvolvedoras que usam o ecossistema AWS, o Amazon Q oferece sugestões de código, snippets, integração com serviços da nuvem e suporte para diversas linguagens de programação, como Python, Java e JavaScript.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Melhor uso: indicado para equipes que desenvolvem em ambientes de produção usando infraestrutura da AWS. Também é uma escolha sólida para empresas preocupadas com conformidade e segurança em aplicações corporativas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Embora o vibe coding esteja frequentemente associado ao uso de IA na programação, ele possui uma definição específica (e controversa). Em sua forma original, a abordagem significa "aceitar o código gerado pela IA sem necessariamente compreendê-lo por completo".&lt;/p&gt;

&lt;p&gt;Essa característica é o que mais diferencia essa abordagem de uma prática mais tradicional de desenvolvimento assistido por IA, onde a pessoa programadora continua sendo responsável por revisar, testar e entender tudo o que está sendo implementado. Essa diferença foi destacada pelo pesquisador Simon Willison, que afirmou:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Se um LLM escreveu cada linha do seu código, mas você revisou, testou e entendeu tudo, isso não é vibe coding na minha opinião — isso é usar um LLM como um assistente de digitação.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O termo vibe coding captura justamente essa ideia de “deixar fluir” o código gerado pela IA, sem uma análise crítica rigorosa, um pouco aquela pegada de “aceitar o que o gerador sugere e partir para frente”, mesmo que o entendimento ou a qualidade do código fiquem um pouco nebulosos.&lt;/p&gt;

&lt;p&gt;No entanto, isso lembra bastante o famoso Go Horse Process — aquela prática informal e irônica de “vai que dá certo”, com pouco planejamento, pouca revisão e muita tentativa e erro.&lt;/p&gt;

&lt;p&gt;Enquanto o desenvolvimento tradicional assistido por IA foca na colaboração consciente entre humano e máquina — com a pessoa programadora revisando, ajustando, entendendo e validando o que a IA sugere — o vibe coding abre espaço para um fluxo mais espontâneo, menos engessado, onde a velocidade e a experimentação imperam.&lt;/p&gt;

&lt;p&gt;Essa diferença, de fato, gera controvérsia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Para uns, vibe coding é uma forma inovadora e pragmática de acelerar o desenvolvimento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Para outros, é uma receita para criar dívida técnica, bugs e sistemas difíceis de manter.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simon Willison, ao destacar essa nuance, chama atenção para o risco de delegar demais à IA sem a devida responsabilidade humana — o que pode gerar soluções frágeis, pouco robustas, quase um “Go Horse” tecnológico. Essa distinção é crucial, especialmente porque o termo vibe coding passou a ser usado amplamente no mercado, muitas vezes por empresas que promovem ferramentas de IA como soluções profissionais sob esse rótulo. Ao fazer isso, existe o risco de mudar o significado original do termo e, pior, de promover práticas potencialmente perigosas.&lt;/p&gt;

&lt;p&gt;Por trás do nome atrativo, algumas organizações podem acabar incentivando a ideia de que é aceitável “esquecer que o código existe”. Ou seja, adotar o código com IA sem questionamento, mesmo em sistemas críticos de produção.&lt;/p&gt;

&lt;p&gt;Por este motivo, mais do que uma discussão técnica, o debate em torno do vibe coding revela um choque ético e cultural.&lt;/p&gt;

&lt;p&gt;De um lado, estão os valores clássicos da engenharia de software: rigorosidade, responsabilidade técnica e compreensão profunda do sistema. Do outro, surge uma nova cultura, baseada na velocidade, nos prompts e na experimentação rápida, impulsionada pela acessibilidade das ferramentas de IA.&lt;/p&gt;

&lt;p&gt;Essa discussão já provocou reações fortes dentro da comunidade das pessoas desenvolvedoras. Inclusive, o termo vibe coding já foi duramente criticado, chegando a ser classificado por muitos(as) profissionais como uma prática “descuidada”, “preguiçosa” ou até mesmo como um “insulto à engenharia de software”.&lt;/p&gt;

&lt;p&gt;A questão é, qual a diferença entre as ferramentas de vibe coding e os famosos sites de perguntas e respostas da comunidade dev (Stack Overflow, Reddit e etc)? Ou ainda perguntar para o Pleno ou Sênior da sua equipe como resolver ou contornar aquele erro.&lt;/p&gt;

&lt;p&gt;Diante disso, o verdadeiro desafio não está somente em adotar novas ferramentas, mas em equilibrar dois mundos: de um lado, a inovação e agilidade oferecidas pela Inteligência Artificial; de outro, os fundamentos sólidos da programação.&lt;/p&gt;

&lt;p&gt;Entretanto, quais os riscos de codar com IA? Complementando as questões éticas que o vibe coding possui, existem outros riscos que, se ignorados, podem comprometer seriamente a qualidade e a segurança de diferentes projetos. Abaixo, estão os principais desafios associados à prática de codificação com IA — especialmente em sua forma mais automatizada, como no vibe coding puro.&lt;/p&gt;

&lt;p&gt;Compreensão superficial do código: Ao aceitar um IA coding sem revisar cuidadosamente sua lógica, as pessoas desenvolvedoras correm o risco de implementar soluções que funcionam momentaneamente, mas que não são totalmente compreendidas. Isso afeta diretamente a capacidade de manter, escalar ou adaptar o sistema criado no futuro.&lt;/p&gt;

&lt;p&gt;Introdução de falhas e vulnerabilidades: Modelos de IA, como LLMs, aprendem com grandes volumes de código disponível na internet, incluindo padrões inseguros, desatualizados ou errôneos. Isso significa que o código gerado pode conter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;erros lógicos difíceis de identificar em testes superficiais;&lt;/li&gt;
&lt;li&gt;vulnerabilidades de segurança, como falhas em autenticação e problemas de validação de entrada;&lt;/li&gt;
&lt;li&gt;práticas obsoletas, como o uso de bibliotecas descontinuadas ou abordagens ultrapassadas de arquitetura.&lt;/li&gt;
&lt;li&gt;Se o código for colocado em produção sem validação adequada, esses riscos podem resultar em falhas sistêmicas, vazamentos de dados ou exploração de vulnerabilidades por ciberataques.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sobre a &lt;strong&gt;dependência da IA&lt;/strong&gt;, o uso frequente de ferramentas de codificação assistida sem reflexão crítica pode levar à perda de autonomia técnica. Isso significa que as pessoas desenvolvedoras podem deixar de praticar habilidades fundamentais como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Estruturação lógica de algoritmos;&lt;/li&gt;
&lt;li&gt;Escrita e interpretação de código limpo;&lt;/li&gt;
&lt;li&gt;Análise de desempenho;&lt;/li&gt;
&lt;li&gt;Compreensão de documentação e bibliotecas.&lt;/li&gt;
&lt;li&gt;Problemas de propriedade intelectual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A IA pode gerar código com base em exemplos extraídos de repositórios públicos, como o GitHub, durante seu treinamento. Embora os modelos não copiem código diretamente, há o risco de reprodução parcial de trechos protegidos por licenças específicas (como GPL ou MIT). Isso pode gerar implicações legais, especialmente em produtos comerciais que exigem direitos autorais e licenças de software.&lt;/p&gt;

&lt;p&gt;Como usar o vibe coding nas empresas? Apesar dos desafios envolvidos, a abordagem vibe coding, como vimos ao longo do texto, representa uma verdadeira faca de dois gumes.&lt;/p&gt;

&lt;p&gt;Por um lado, há riscos que não podem ser ignorados, como a falta de compreensão total do código com IA gerado. Por outro lado, também existem benefícios concretos, como ganho de produtividade, aceleração na prototipação e mais fluidez nos processos criativos de desenvolvimento.&lt;/p&gt;

&lt;p&gt;O que ninguém pode contestar é que essa prática já é uma realidade no mercado. Sendo assim, a questão que devemos evidenciar é: como as empresas podem usar o vibe coding de forma ética em seus projetos? Para isso, separamos algumas etapas abaixo que, para empresas que querem adotar essa abordagem, serão essenciais para enfrentar os desafios e usar essa tecnologia a favor da organização:&lt;/p&gt;

&lt;p&gt;1ª etapa: fale com sua equipe e escolha a ferramenta - Antes de tudo, entenda como o vibe coding pode ser introduzido na sua empresa. Para isso, converse com seu time de desenvolvimento juntamente com a sua liderança tech para entender como essa abordagem pode ser benéfica para o setor. Nesta conversa, alinhe também os objetivos e, a partir deles, busque a ferramenta de vibe coding que mais se alinhe à equipe, como as opções que apresentamos anteriormente. A escolha deve considerar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nível de autonomia desejado;&lt;/li&gt;
&lt;li&gt;linguagens de programação utilizadas;&lt;/li&gt;
&lt;li&gt;integração com plataformas já existentes (como AWS, Git, CI/CD).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2ª etapa: estabeleça diretrizes claras de uso - Para evitar usos irresponsáveis, as empresas devem criar políticas internas de governança de IA. Isso inclui padrões mínimos de validação de código e definições sobre onde e quando a IA pode ser usada, como nas fases de produção e prototipagem. Essas diretrizes equilibram criatividade e controle para promover responsabilidade e segurança, tanto para os projetos da empresa quanto para a equipe, pois mostra que o trabalho de seus colaboradores e colaboradoras é essencial e insubstituível no processo.&lt;/p&gt;

&lt;p&gt;3ª etapa: capacite a equipe para trabalhar com IA - Implementar vibe coding exige uma mudança de processos, mas também de cultura. Para que as pessoas desenvolvedoras da sua empresa usem essa abordagem com eficiência, é preciso que toda a equipe seja treinada em letramento em IA. Assim, todas as pessoas podem conseguir formular prompts eficientes, avaliar criticamente as respostas da IA e melhorar os resultados gerados.&lt;/p&gt;

&lt;p&gt;4ª etapa: acompanhe o uso e os resultados do vibe coding - Após implementar ferramentas e integrar o vibe coding ao fluxo de trabalho do seu time, é essencial monitorar continuamente seu uso e os impactos gerados. Essa etapa garante que a prática esteja realmente agregando valor ao desenvolvimento, além de ajudar a identificar pontos de melhoria e evitar desvios que comprometam a qualidade do código.&lt;/p&gt;

&lt;p&gt;Para concluir, podemos resumir que o vibe coding representa uma oportunidade concreta de transformar a maneira como o software é construído dentro das empresas. Com uso responsável, processos bem definidos e capacitação das equipes, a IA pode se tornar uma aliada estratégica poderosa. Destacamos que o futuro do desenvolvimento corporativo não está em substituir pessoas desenvolvedoras por máquinas, mas sim em potencializar suas capacidades humanas com o apoio inteligente da tecnologia.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>career</category>
      <category>productivity</category>
      <category>softskills</category>
    </item>
    <item>
      <title>Docker</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 21:34:54 +0000</pubDate>
      <link>https://forem.com/isaacalves7/docker-4fci</link>
      <guid>https://forem.com/isaacalves7/docker-4fci</guid>
      <description>&lt;p&gt;O &lt;strong&gt;Docker&lt;/strong&gt; é um software/ plataforma open source para construir, armazenar, distribuir e rodar contêineres (containers são ambientes virtualizados, isolados e voláteis), o qual permite a equipe emular ambientes de desenvolvimento e que empacota um todo sistema operacional, como também a sua aplicação para dentro de um container. &lt;/p&gt;

&lt;p&gt;Em 2013, foi criado o Docker, escrito na linguagem Go (Golang), por &lt;a href="https://github.com/shykes" rel="noopener noreferrer"&gt;Solomon Hykes&lt;/a&gt;, onde o Docker começou como um projeto interno, inicialmente desenvolvido pelo &lt;strong&gt;dotCloud&lt;/strong&gt; engineers, essa empresa é uma &lt;strong&gt;PaaS&lt;/strong&gt; (Plataform as a Service), uma empresa que você manda o código da sua aplicação feita em Java, PHP, Node ou Python etc e a empresa toma todo o cuidado possível para você hospedar sua aplicação. Um exemplo de empresas PaaS são as empresas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heroku;&lt;/li&gt;
&lt;li&gt;AWS - Amazon Web Services;&lt;/li&gt;
&lt;li&gt;GCP - Google Cloud Plataform;&lt;/li&gt;
&lt;li&gt;AZ - Microsoft Azure;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127539895-e0c3f3e9-3d78-40e4-9546-0feb39e233a2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127539895-e0c3f3e9-3d78-40e4-9546-0feb39e233a2.png" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando o Docker nasceu, a dotCloud utilizava a &lt;strong&gt;AWS - Amazon Web Services&lt;/strong&gt;, que é um serviço que provê VMs ou máquinas físicas, então ela queria hospedar na VM a aplicação dela, porém ela usou seu sistema de containers para subir sua aplicação, e assim nasceu o Docker, um intermediário entre um sistema operacional e seus containers contendo aplicações em uma mesma máquina.&lt;/p&gt;

&lt;p&gt;De desktop a cloud, o Docker é considerado padrão e a ferramenta mais popular: é  usado por milhões de desenvolvedores para construir e compartilhar aplicações conteinerizadas. Para termos uma ideia de volume, 30% das empresas usavam Docker em ambientes AWS, em 2019. &lt;/p&gt;

&lt;p&gt;Embora seja uma das ferramentas de conteinerização mais usadas e conhecidas, o Docker não está sozinho. Há outros fornecedores no ecossistema: ConteinerD, CoreOS, Canonical, LXC Linux Conteiners, CRIO-D, OpenShift e Mesos Containerizer. &lt;/p&gt;

&lt;p&gt;Além da empresa dotCloud ser focada em manter o Docker, ela também liberou o Docker para Open Source, exatamente isso, o Docker possui também código-livre para desenvolvimento!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.github.com/docker" rel="noopener noreferrer"&gt;https://www.github.com/docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://renatogroffe.medium.com/docker-dicas-e-truques-na-utiliza%C3%A7%C3%A3o-de-containers-parte-1-ef3f981fbcf5" rel="noopener noreferrer"&gt;https://renatogroffe.medium.com/docker-dicas-e-truques-na-utiliza%C3%A7%C3%A3o-de-containers-parte-1-ef3f981fbcf5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Está tudo lá, as bibliotecas, as contribuições para o desenvolvimento de tecnologias do Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantagens de um container Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F500%2F1%2Alu5prM28fxIlbHmjPT8VIg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F500%2F1%2Alu5prM28fxIlbHmjPT8VIg.jpeg" width="500" height="389"&gt;&lt;/a&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Por não possuir um sistema operacional, o container é muito mais leve e não possui o custo de manter múltiplos sistemas operacionais, já que só teremos um sistema operacional, que será dividido entre os containers.&lt;/p&gt;

&lt;p&gt;Além disso, por ser mais leve, o container é muito rápido de subir, subindo em questão de segundos. Logo, o container é uma solução para suprir o problema de múltiplas máquinas virtuais em um hardware físico, já que com o container, nós dividimos o sistema operacional entre as nossas aplicações.&lt;/p&gt;

&lt;p&gt;Volátil, ou seja, sobe e mata um container, é da natureza do container sumir e subir rapidamente.&lt;/p&gt;
&lt;h2&gt;
  
  
  Necessidade do uso de containers Docker
&lt;/h2&gt;

&lt;p&gt;Mas por que precisamos dos containers, não podemos simplesmente instalar as aplicações no nosso próprio sistema operacional? Até por que já fazemos isso, já que no nosso sistema operacional temos um editor de texto, terminal, navegador, etc.&lt;/p&gt;

&lt;p&gt;No caso das nossas aplicações, essa abordagem pode ter alguns problemas. Por exemplo, se dois aplicativos precisarem utilizar a mesma porta de rede? Precisaremos de algo para isolar uma aplicação da outra. E se uma aplicação consumir toda a CPU, a ponto de prejudicar o funcionamento das outras aplicações? Isso acontece se não limitarmos a aplicação. Outro problema que pode ocorrer é cada aplicação precisar de uma versão específica de uma linguagem, por exemplo, uma aplicação precisa do Java 7 e outra do Java 8. Além disso, uma aplicação pode acabar congelando todo o sistema. Por isso é bom ter essa separação das aplicações, isolar uma da outra, e isso pode ser feito com os containers.&lt;/p&gt;

&lt;p&gt;Com os containers, conseguimos limitar o consumo de CPU das aplicações, melhorando o controle sobre o uso de cada recurso do nosso sistema (CPU, rede, etc). Também temos uma facilidade maior em trabalhar com versões específicas de linguagens/bibliotecas, além de ter uma agilidade maior na hora de criar e subir containers, já que eles são mais leves que as máquinas virtuais.&lt;/p&gt;

&lt;p&gt;Vamos agora ver as diversas tecnologias presentes no Docker e como são incríveis as possibilidades de se trabalhar em cada uma delas!&lt;/p&gt;
&lt;h2&gt;
  
  
  O ecossistema/ambiente do container Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%3AANd9GcSJFwWA2jwjH5Zc_MrhbUpjUj-dsiHEeA5w4jWEjiiKIDEbxbB-ZrZjzP_Zg-Q3c0yPzGg%26usqp%3DCAU" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%3AANd9GcSJFwWA2jwjH5Zc_MrhbUpjUj-dsiHEeA5w4jWEjiiKIDEbxbB-ZrZjzP_Zg-Q3c0yPzGg%26usqp%3DCAU" width="225" height="225"&gt;&lt;/a&gt;&lt;br&gt; &lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;ambiente do container&lt;/strong&gt; é todo um ecossistema de desenvolvimento, ou seja, toda uma infraestrutura com:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F125382079-6460bf80-e36b-11eb-91e3-85f860b8bb84.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F125382079-6460bf80-e36b-11eb-91e3-85f860b8bb84.png" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os &lt;strong&gt;servidores web&lt;/strong&gt; em NGINX ou Apache; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Banco de dados&lt;/strong&gt; como PostgreSQL, MySQL, MongoDB, Cassandra, etc; &lt;/li&gt;
&lt;li&gt;Os &lt;strong&gt;interpretadores de linguagem de programação&lt;/strong&gt; como Python, Node.js, PHP, GO, Ruby, etc; &lt;/li&gt;
&lt;li&gt;As &lt;strong&gt;bibliotecas&lt;/strong&gt; e &lt;strong&gt;frameworks&lt;/strong&gt; utilizadas para desenvolvimento, como o React.js, Django, Spring, etc.;&lt;/li&gt;
&lt;li&gt;As &lt;strong&gt;scripts e plugins&lt;/strong&gt; são arquivos de bash-script ou shell-script responsáveis por executar uma determinada ação no container, como: Automatizar alguma ação manual, Instalar programas adicionais, criar ou mudar configurações, preencher ambiente, etc.&lt;/li&gt;
&lt;li&gt;As &lt;strong&gt;variáveis de ambiente&lt;/strong&gt; são arquivos responsáveis por guardar segredos relacionados a qualquer informação sigilosa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, é basicamente tudo o que a gente instala no nosso sistema operacional (Windows, Mac OS ou Linux) para conseguir fazer o desenvolvimento de software e rodar uma aplicação nela.&lt;/p&gt;

&lt;p&gt;Com o Docker é possível resolver aquele velho problema dos desenvolvedores: &lt;/p&gt;

&lt;p&gt;&amp;gt; Como assim!? Na minha máquina funciona, na sua não?&lt;/p&gt;
&lt;h2&gt;
  
  
  Etapas e ferramentas/modos do Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205305615-b13a5479-1e1d-4921-a24e-d5ae779bacc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205305615-b13a5479-1e1d-4921-a24e-d5ae779bacc3.png" width="800" height="228"&gt;&lt;/a&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Além disso, existem algumas "etapas" com terminologias para a criação desses containers, pois afinal são uma evolução de VMs e não são instaladas por padrão na nossa máquina pessoal. São elas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt;: Pacote com todas as dependências para criar o nosso container (nossa aplicação rodando no container);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;: Arquivo de texto que contém todas as instruções para iniciar o processo de &lt;strong&gt;&lt;em&gt;Build&lt;/em&gt;&lt;/strong&gt; na nossa imagem do container; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt;: É uma ação que cria a imagem a partir do Dockerfile (lê as instruções e cria uma imagem);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: Feito a imagem pelo Build é instanciado o container (execução de uma aplicação, ou processo ou um serviço);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volumes&lt;/strong&gt;: Armazena dados em disco, ou seja, se o container morrer é o volume que salva os dados do container (os dados do container não serão perdidos dentro do volume);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: Ajuda no versionamento das nossas imagens;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-stage Build&lt;/strong&gt;: Múltiplos estágios de Build onde usamos uma imagem para compilar a nossa aplicação, e essa chama outra imagem (Roy na Aplicação);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: Nada mais é do que uma coleção de imagens, então é como se fosse uma caixa cheia de imagens;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registry&lt;/strong&gt;: É um serviço que provê acesso do Docker ao repositório, como o &lt;strong&gt;Docker Hub&lt;/strong&gt; (repositório remoto de imagens de containers públicas e privadas);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose&lt;/strong&gt;: É uma metadata que você pode executar múltiplos containers com um simples comando.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Docker Engine
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205306089-70ce69b3-23d2-446c-8b30-3b8a2ae6ae6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205306089-70ce69b3-23d2-446c-8b30-3b8a2ae6ae6c.png" width="371" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As tecnologias de containers para prover ferramentas modernas para deployar e rodar aplicações.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127540946-fdaf8dbc-cadd-4278-91e4-835d9f06d3ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127540946-fdaf8dbc-cadd-4278-91e4-835d9f06d3ff.png" width="800" height="283"&gt;&lt;/a&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Docker Compose
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopenwhisk.apache.org%2Fimages%2Fdeployments%2Flogo-docker-compose-text.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopenwhisk.apache.org%2Fimages%2Fdeployments%2Flogo-docker-compose-text.svg" width="4" height="2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Docker Compose&lt;/strong&gt; é um modo do Docker onde podemos escalar e diminuir o número de containers necessário para nossa aplicação rodar com melhor aproveitamento, ou seja, é um jeito simples de definir múltiplos containers, o que é ideal para uma &lt;strong&gt;stack&lt;/strong&gt; de tecnologia (.NET, Spring, LAMP, LEMP, MEAN, MERN, MENV, RoR, FReMP, etc), utilizar um balanceador de carga, banco de dados e até adotar a arquitetura de micro serviços.&lt;/p&gt;

&lt;p&gt;No entanto, para aplicações e arquiteturas mais robustas é um pouco limitado em utilidades, se comparado ao modo Docker Swarm.&lt;/p&gt;
&lt;h3&gt;
  
  
  Docker Swarm
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pinclipart.com%2Fpicdir%2Fbig%2F83-834158_docker-swarm-logo-clipart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.pinclipart.com%2Fpicdir%2Fbig%2F83-834158_docker-swarm-logo-clipart.png" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Docker Swarm&lt;/strong&gt; é um modo do Docker com uma ferramenta para orquestrar múltiplos docker engines para trabalharem juntos em um cluster com dezenas ou centenas de containers. As versões atuais do Docker incluem o modo swarm para gerenciar nativamente um cluster de Docker Engines chamado &lt;strong&gt;swarm&lt;/strong&gt; (enxame). Use a CLI do Docker para criar um swarm, implantar serviços de aplicativo em um swarm e gerenciar o comportamento do swarm.&lt;/p&gt;

&lt;p&gt;O modo Docker Swarm é integrado ao Docker Engine. E possui algumas utilidades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gerenciamento de cluster integrado ao Docker Engine&lt;/strong&gt;: Use a CLI do Docker Engine para criar um enxame de Docker Engines onde você pode implantar serviços de aplicativos. Você não precisa de software de orquestração adicional para criar ou gerenciar um enxame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Design descentralizado&lt;/strong&gt;: em vez de lidar com a diferenciação entre as funções do nó no momento da implantação, o Docker Engine lida com qualquer especialização no tempo de execução. Você pode implantar os dois tipos de nós, gerentes e trabalhadores, usando o Docker Engine. Isso significa que você pode criar um enxame inteiro a partir de uma única imagem de disco.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modelo de serviço declarativo&lt;/strong&gt;: o Docker Engine usa uma abordagem declarativa para permitir que você defina o estado desejado dos vários serviços em sua pilha de aplicativos. Por exemplo, você pode descrever um aplicativo composto por um serviço de front-end da Web com serviços de enfileiramento de mensagens e um back-end de banco de dados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dimensionamento&lt;/strong&gt;: Para cada serviço, você pode declarar o número de tarefas que deseja executar. Quando você aumenta ou diminui, o gerenciador de enxame se adapta automaticamente adicionando ou removendo tarefas para manter o estado desejado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconciliação do estado desejado&lt;/strong&gt;: O nó do gerenciador de swarm monitora constantemente o estado do cluster e reconcilia quaisquer diferenças entre o estado real e o estado desejado expresso. Por exemplo, se você configurar um serviço para executar 10 réplicas de um contêiner e uma máquina de trabalho que hospeda duas dessas réplicas falhar, o gerente criará duas novas réplicas para substituir as réplicas que falharam. O gerenciador de swarm atribui as novas réplicas aos trabalhadores que estão em execução e disponíveis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rede multi-host&lt;/strong&gt;: você pode especificar uma rede de sobreposição para seus serviços. O gerenciador de swarm atribui automaticamente endereços aos contêineres na rede de sobreposição quando inicializa ou atualiza o aplicativo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Descoberta de serviço&lt;/strong&gt;: os nós do Swarm Manager atribuem a cada serviço no Swarm um nome DNS exclusivo e equilibram a carga dos contêineres em execução. Você pode consultar todos os contêineres em execução no enxame por meio de um servidor DNS incorporado no enxame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Balanceamento de carga&lt;/strong&gt;: você pode expor as portas para serviços a um balanceador de carga externo. Internamente, o enxame permite especificar como distribuir contêineres de serviço entre os nós.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seguro por padrão&lt;/strong&gt;: cada nó no enxame impõe autenticação e criptografia mútuas TLS para proteger as comunicações entre ele e todos os outros nós. Você tem a opção de usar certificados raiz autoassinados ou certificados de uma CA raiz personalizada.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Atualizações contínuas&lt;/strong&gt;: no momento da implementação, você pode aplicar atualizações de serviço aos nós de forma incremental. O gerenciador de enxame permite controlar o atraso entre a implantação do serviço em diferentes conjuntos de nós. Se algo der errado, você pode reverter para uma versão anterior do serviço.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Docker Machine &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2Ftool-deprecated-red" width="102" height="20"&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.mundodocker.com.br%2Fwp-content%2Fuploads%2F2016%2F06%2Fmachine.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.mundodocker.com.br%2Fwp-content%2Fuploads%2F2016%2F06%2Fmachine.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma ferramenta que nos permite instalar e gerenciar o Docker Engine em hosts virtuais, com comandos &lt;code&gt;docker-machine&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Você pode usar o Machine para criar hosts do Docker em sua caixa local do Mac ou Windows, na rede da empresa, no data center ou em provedores de nuvem como Azure, AWS ou Digital Ocean.&lt;/p&gt;

&lt;p&gt;&amp;gt; O Docker encerrou o desenvolvimento ativo e o suporte para o Docker Machine. Um método principal para escalonamento automático do GitLab runner em instâncias de máquina virtual de nuvem pública é o Runner configurado com o executor do Docker Machine.&lt;/p&gt;
&lt;h3&gt;
  
  
  Docker Hub &lt;a href="https://hub.docker.com/u/isaacalves7" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-Docker_Hub-ffffff%3Fstyle%3Dflat%26logo%3DDocker%26logoColor%3D2496ED" alt="Docker HUB" width="93" height="20"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Um repositório com mais de 250 mil imagens diferentes para os nossos containers. Para instalar, você precisa ter os seguintes requisitos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um sistema de 64 bits;&lt;/li&gt;
&lt;li&gt;Se você utiliza o Windows 10, você precisar utilizar a versão Windows 10 PRO;&lt;/li&gt;
&lt;li&gt;Habilitar a virtualização do Windows;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Play with Docker
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://labs.play-with-docker.com/" title="Download Docker Desktop" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgalaxyproject.github.io%2Ftraining-material%2Ftopics%2Fadmin%2Fimages%2Fdocker_whale.png" width="508" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://labs.play-with-docker.com/" rel="noopener noreferrer"&gt;https://labs.play-with-docker.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse é um ambiente totalmente grátis para testar a todos os recursos do Docker pela web, o que facilita muito no aprendizado para iniciantes! Com práticas e exercícios.&lt;/p&gt;

&lt;p&gt;Você verá que cada instância é um nó com seu endereço de IP e tem tempo para escalar seus ambientes antes que eles sejam removidos.&lt;/p&gt;

&lt;p&gt;&amp;gt; Em exemplos posteriores, vamos utilizar o modo Docker Swarm com Flask e Hashicorp Consul como malha de serviço!&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalação do Docker
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker.io
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker &lt;span class="nt"&gt;--now&lt;/span&gt;
docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F01%2Fimagens%2Fvirtualizacao-habilitada.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F01%2Fimagens%2Fvirtualizacao-habilitada.png" width="553" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Habilitar a Virtualização de CPU na BIOS (programa da placa-mãe) do seu computador&lt;/li&gt;
&lt;li&gt;Baixar o pacote de atualização do kernel do Linux (WSL 2)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/pt-br/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package" rel="noopener noreferrer"&gt;https://docs.microsoft.com/pt-br/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycnpegmm7wb1h592pxnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycnpegmm7wb1h592pxnv.png" alt="Sem título" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seguimos o passo a passo do instalador para aceitar a licença, autorizamos o instalador e seguimos com a instalação. Ao clicar em Finish, precisamos encerrar a sessão do Windows e iniciá-la novamente. Ao fazer o login, precisamos habilitar o Hyper-V, clicando em Ok, para que o computador será reiniciado.&lt;/p&gt;

&lt;p&gt;Quando o computador terminar a reinicialização, irá aparecer um ícone do Docker na barra inferior, à direita, ao lado do relógio. O Docker pode demorar um pouco para inicializar, mas quando a mensagem Docker is running for exibida, significa que ele foi instalado com sucesso e já podemos utilizá-lo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exibir a versão do Docker
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Exibir os todos os dados do Docker
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Lembrando que você precisa estar executando o Docker na sua máquina.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;code&gt;Hello, World!&lt;/code&gt; - Docker
&lt;/h1&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Lembrando que quando aparece a seguinte mensagem no terminal &lt;code&gt;Unable to find image 'hello-world' locally&lt;/code&gt;, significa que o docker não achou a imagem localmente, mas sim precisou buscar a imagem e baixar ela!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26i6udnljsrtfpfxnfwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26i6udnljsrtfpfxnfwz.png" alt="Sem título" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Imagens e Containers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flinuxiac.com%2Fwp-content%2Fuploads%2F2021%2F06%2Fwhat-is-docker-container.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flinuxiac.com%2Fwp-content%2Fuploads%2F2021%2F06%2Fwhat-is-docker-container.png" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na aula anterior, para executar a imagem &lt;code&gt;hello-world&lt;/code&gt;, executamos o comando &lt;code&gt;docker run hello-world&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Quando executado esse comando, a primeira coisa que o Docker faz é verificar se temos a imagem &lt;code&gt;hello-world&lt;/code&gt; no nosso computador, e caso não tenhamos, o Docker buscará e baixará essa imagem no &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub/Docker Store&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127689988-66b3ce01-14ef-4843-8240-691da30a81ba.png" width="800" height="408"&gt;&lt;/td&gt;
    &lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127694974-765bf63d-335d-4287-87ac-0b315102e343.png" width="800" height="424"&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A &lt;strong&gt;imagem&lt;/strong&gt; é como se fosse uma receita de bolo, uma série de instruções que o Docker seguirá para criar &lt;em&gt;um container&lt;/em&gt;, que irá conter as instruções da imagem, do &lt;code&gt;hello-world&lt;/code&gt;. Criado o container, o Docker executa-o. Então, tudo isso é feito quando executamos o &lt;code&gt;docker run hello-world&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Há milhares de imagens na Docker Store disponíveis para executarmos a nossa aplicação. Por exemplo, temos a imagem do Ubuntu:&lt;/p&gt;
&lt;h1&gt;
  
  
  Rodar a imagem do Sistema Operacional Ubuntu
&lt;/h1&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;É normal o nome do container ser seguida de nomes aleatórios, não tem problema nenhum! a imagem possui o nome escrita em azul para você identificar no Docker Desktop, assim como no terminal também informa.&lt;/p&gt;
&lt;h2&gt;
  
  
  Listar todos os containers ativos no momento
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Listar todos os containers que eu criei
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Listar todos os containers que eu criei (somente os id's)
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Executar um Olá, Mundo dentro do container do Ubuntu
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run ubuntu &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Ola Mundo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Interagir mais com o container do Ubuntu
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Dessa forma, ele retorna o terminal do Ubuntu:&lt;/p&gt;

&lt;pre&gt;root@9fea4151a9f8:/#&lt;/pre&gt;

&lt;p&gt;Se você rodar qualquer comando do Linux irá funcionar, porém não dentro do Sistema Operacional, mas sim dentro do container.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@9fea4151a9f8:/# &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Retorno:&lt;/p&gt;

&lt;pre&gt;bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var&lt;/pre&gt;

&lt;p&gt;Para sair é só &lt;code&gt;ctrl+D&lt;/code&gt; ou &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Startando o container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker start &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Como também:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker start &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;3 dígitos iniciais &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Agora vamos brincar, digite a série de comandos de entrada abaixo:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls
touch &lt;/span&gt;hello-world.txt
&lt;span class="nb"&gt;ls
echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello, World!"&lt;/span&gt; &amp;amp;gt&lt;span class="p"&gt;;&lt;/span&gt; hello-world.txt
&lt;span class="nb"&gt;cat &lt;/span&gt;hello-world.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Saída:&lt;/p&gt;

&lt;pre&gt;Hello, World!&lt;/pre&gt;
&lt;h2&gt;
  
  
  Startando o container de forma interativa
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker start &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;nome &lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Sai do container interativo, mas desejo voltar novamente
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker start &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;id-do-container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ou também você pode usar a seguinte forma:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker start &lt;span class="o"&gt;[&lt;/span&gt;nome container]
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;nome &lt;span class="k"&gt;do &lt;/span&gt;container] bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Parar o container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Existem formas mais eficientes de rodar ou parar o docker, pois a execução as vezes demora muito...Para saber mais, use:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Então, com a lista de parâmetros, utilizaremos o parâmetro &lt;code&gt;-t&lt;/code&gt; e com ele podemos, instantaneamente, executar o tempo de uma execução no docker, como:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &lt;span class="nt"&gt;-t&lt;/span&gt; 0 &lt;span class="o"&gt;[&lt;/span&gt;3 dig. &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Parar mais de um id
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &lt;span class="si"&gt;$(&lt;/span&gt;docker ps &lt;span class="nt"&gt;-q&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;ou&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop &lt;span class="nt"&gt;-t&lt;/span&gt; 0 &lt;span class="si"&gt;$(&lt;/span&gt;docker ps &lt;span class="nt"&gt;-q&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Layered File System
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Festados-container.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Festados-container.png" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aqueles dois principais estados de um container, quando criamos um ou iniciamos, ele fica no estado de &lt;strong&gt;running&lt;/strong&gt;, e quanto a sua execução encerra ou &lt;br&gt;
paramos, ele fica no estado de &lt;strong&gt;stopped&lt;/strong&gt;:&lt;/p&gt;
&lt;h2&gt;
  
  
  Limpar container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Limpar containers inativos
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deletar ou Remover containers
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deletar todos os containers
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Remover ou Deletar as imagens do Docker
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Remover ou Deletar todas as imagens do Docker
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Remover ou deletar um Volume
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Forçar remover um container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Listando imagens
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Removendo imagens
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker rmi &lt;span class="o"&gt;[&lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Ver logs de um container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &lt;span class="o"&gt;[&lt;/span&gt;ID &lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;E do mesmo jeito que temos o comando &lt;code&gt;docker container&lt;/code&gt; para mexermos com o container, temos o comando &lt;code&gt;docker images&lt;/code&gt;, que nos exibe as imagens que temos na nossa máquina. Para remover uma imagem, utilizarmos o comando &lt;code&gt;docker rmi&lt;/code&gt;, passando para ele o nome da imagem a ser removida, por exemplo:&lt;/p&gt;
&lt;h2&gt;
  
  
  Rodar uma determinada versão da imagem
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run ubuntu:14.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Camada de imagens
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fcamadas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fcamadas.png" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando baixamos a imagem do Ubuntu, reparamos que ela possui camadas, mas como elas funcionam? Toda imagem que baixamos é composta de uma ou mais &lt;em&gt;camadas&lt;/em&gt;, e esse sistema tem o nome de &lt;strong&gt;Layered File System&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As pricincipais características das camadas, são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As camadas na imagem são de leitura apenas;&lt;/li&gt;
&lt;li&gt;Essas camadas podem ser reaproveitadas em outras imagens, acelerando assim o tempo de download;&lt;/li&gt;
&lt;li&gt;Toda imagem que baixamos é composta de uma ou mais camadas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas camadas podem ser reaproveitadas em outras imagens. Por exemplo, já temos a imagem do Ubuntu, isso inclui as suas camadas, e agora queremos baixar a imagem do CentOS. Se o CentOS compartilha alguma camada que já tem na imagem do Ubuntu, o Docker é inteligente e só baixará as camadas diferentes, e não baixará novamente as camadas que já temos no nosso computador:&lt;/p&gt;

&lt;p&gt;No caso da imagem acima, o Docker só baixará as duas primeiras camadas da imagem do CentOS, já que as duas últimas são as mesmas da imagem do Ubuntu, que já temos na nossa máquina. Assim poupamos tempo, já que precisamos de menos tempo para baixar uma imagem.&lt;/p&gt;

&lt;p&gt;Uma outra vantagem é que as camadas de uma imagem são somente para leitura. Mas como então conseguimos criar arquivos na aula anterior? O que acontece é que não escrevemos na imagem, já que quando criamos um container, ele cria uma nova camada acima da imagem, e nessa camada podemos ler e escrever:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fcontainer-layer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fcontainer-layer.png" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então, quando criamos um container, ele é criado em cima de uma imagem já existente e nele nós conseguimos escrever. E com uma imagem base, podemos reaproveitá-la para diversos containers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fimagem-varios-containers.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcaelum-online-public%2F646-docker%2F02%2Fimagens%2Fimagem-varios-containers.png" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isso nos traz economia de espaço, já que não precisamos ter uma imagem por container.&lt;/p&gt;
&lt;h2&gt;
  
  
  Praticando com o &lt;code&gt;docker run&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Já podemos fazer um container mais interessante, um pouco mais complexo. Então, vamos criar um container que segurará um site estático, para entendermos também como funciona a parte de redes do Docker. Para tal, vamos baixar a imagem &lt;code&gt;dockersamples/static-site&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run dockersamples/static-site
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;As imagens não oficiais, ou seja, imagens de terceiros, precisam ser especificadas pelo username e pela imagem.&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Baixando a imagem apenas pelo docker, sem atrelar ao terminal
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; dockersamples/static-site
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Se você executar os dois comandos, criará dois containers diferentes, pois o Docker é inteligente no quesito de solicitações de imagem, ele sabe criar um id e ambientes diferentes!&lt;/p&gt;
&lt;h2&gt;
  
  
  Acessando o site
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;nome da imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A flag &lt;code&gt;-P&lt;/code&gt; significa que fará com que o Docker atribua uma porta aleatória do mundo externo, que no caso é a nossa máquina, para poder se comunicar com o que está dentro do &lt;em&gt;container&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Abrindo uma porta externa para uma interna
&lt;/h2&gt;

&lt;p&gt;Vamos ver como abrir portas e acessar o site com elas.&lt;/p&gt;
&lt;h4&gt;
  
  
  Descobrir a porta
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Descobrir a porta de uma maneira mais legível
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker port [id do container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Logo, ele retornará a porta pelo &lt;strong&gt;protocolo TCP&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;
80/tcp -&amp;gt; 0.0.0.0:49155
80/tcp -&amp;gt; :::49155
443/tcp -&amp;gt; 0.0.0.0:49154
443/tcp -&amp;gt; :::49154
&lt;/pre&gt;

&lt;p&gt;Se você copiar o endereço:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="err"&gt;49155&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;E ir para o browser digitando na aba do navegador:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localhost:49155
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Você verá o preview do site estático!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34fw6h0kvgxy6mu3ak66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34fw6h0kvgxy6mu3ak66.png" alt="Sem título" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Nomeando um container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;nome &lt;span class="k"&gt;do &lt;/span&gt;container] &lt;span class="o"&gt;[&lt;/span&gt;nome da imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Acessando os detalhes do container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dive &lt;span class="o"&gt;[&lt;/span&gt;nome &lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Dessa forma, ele irá nomear o container que possuia um nome aleatório, isso facilita nosso aprendizado e nossos projetos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Renomeando um container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker rename &lt;span class="o"&gt;[&lt;/span&gt;nome ou &lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container] &lt;span class="o"&gt;[&lt;/span&gt;novo nome]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Mapeando portas do computador para a porta do servidor
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 12345:80 &lt;span class="o"&gt;[&lt;/span&gt;nome da imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Assim, ele muda o endereço da porta do localhost para &lt;code&gt;12345&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgscgnz4gjfxcy85zi30k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgscgnz4gjfxcy85zi30k.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Definindo a variável autor
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"seu username"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Dessa forma, ele apresentará você no site estático. Mas primeiro acesse o endereço ip que ele mudou!&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Dessa foma, coloque junto ao localhost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsoka6sr3easyrx42mpvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsoka6sr3easyrx42mpvq.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker para DevOps
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DevOps&lt;/strong&gt; é um tópico bem amplo que envolve tanto aspectos culturais como técnicos, mas possui como principal objetivo aumentar a qualidade e eficiência da entrega de software. DevOps é uma metodologia que visa integrar os times de desenvolvimento com infraestrutura e o Docker está tendo um papel importante nessa tarefa.&lt;/p&gt;

&lt;p&gt;Repare que com Docker os desenvolvedores não precisam se preocupar em configurar um ambiente de desenvolvimento específico de cada vez. Em vez disso, eles podem se concentrar na construção de um código de boa qualidade. Isso, obviamente, leva à aceleração nos esforços de desenvolvimento. O Docker facilita muito construir o ambiente: é rapido, simples e confiável.&lt;/p&gt;

&lt;p&gt;No outro lado, para a equipe de operações de TI/Sysadmins, o Docker possibilita configurar ambientes que são exatamente como um servidor de produção e permite que qualquer pessoa trabalhe no mesmo projeto com exatamente as mesmas configurações, independentemente do ambiente de host local. As configurações são descritas em arquivos simples facilmente aplicáveis pelo desenvolvedor.&lt;/p&gt;

&lt;p&gt;Com a padronização de um entregável Docker é possível que o desenvolvedor tenha um ambiente similar ao de produção na sua máquina sem todo o custo de configuração e o Sysadmin consiga lidar apenas com um tipo de entregável conseguindo, desta forma, dar atenção aos desafios de monitoramento e orquestração para que nada dê errado. Neste caso, o melhor para os dois.&lt;/p&gt;
&lt;h2&gt;
  
  
  Salvando dados com volumes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127754767-71296970-913c-4dca-8866-4e4be6c70ebc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127754767-71296970-913c-4dca-8866-4e4be6c70ebc.png" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É da natureza dos containers a &lt;em&gt;volatilidade&lt;/em&gt;, isto é, eles são criados e removidos rapidamente e facilmente, mas devemos ter um lugar para salvar os dados, e esse lugar são os &lt;strong&gt;volumes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando escrevemos em um container, assim que ele for removido, os dados também serão. Mas podemos criar um local especial dentro dele, e especificamos que esse local será o nosso volume de dados.&lt;/p&gt;

&lt;p&gt;Quando criamos um volume de dados, o que estamos fazendo é apontá-lo para uma pequena pasta no &lt;em&gt;Docker Host&lt;/em&gt;. Então, quando criamos um volume, criamos uma pasta dentro do container, e o que escrevermos dentro dessa pasta na verdade estaremos escrevendo do Docker Host. Ou seja, fica salvo no computador onde a Docker Engine está rodando.&lt;/p&gt;

&lt;p&gt;Isso faz com que não percamos os nossos dados, pois o container até pode ser removido, mas a pasta no Docker Host ficará intacta.&lt;/p&gt;
&lt;h2&gt;
  
  
  Trabalhando com volumes
&lt;/h2&gt;

&lt;p&gt;Sabendo disso, vamos ver como trabalhar com o &lt;strong&gt;Docker Host&lt;/strong&gt;. No Terminal ou PowerShell (ou Docker Quickstart Terminal), criamos um container com o &lt;code&gt;docker run&lt;/code&gt;, mas dessa vez utilizando a flag &lt;code&gt;-v&lt;/code&gt; para criar um volume, seguido do nome do mesmo:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"/var/www"&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;No exemplo acima, criamos o volume &lt;code&gt;/var/www&lt;/code&gt;, mas a que pasta no &lt;strong&gt;Docker Host&lt;/strong&gt; ele faz referência? Para descobrir, podemos inspecionar o container, executando o comando docker inspect, passando o seu id para o mesmo:&lt;/p&gt;
&lt;h2&gt;
  
  
  Inspecionando o container
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker inspect &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ele retornará uma série de dados, mas o mais importante, no momento, é o &lt;code&gt;Mounts&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
      "Mounts": [
            {
                "Type": "volume",
                "Name": "54a5fad5f6c046a4afad7854caf90089a40d9c9d60d3eb604982b6084b799cc2",
                "Source": "/var/lib/docker/volumes/54a5fad5f6c046a4afad7854caf90089a40d9c9d60d3eb604982b6084b799cc2/_data",
                "Destination": "/var/www",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
         ]
&lt;/pre&gt;

&lt;p&gt;Mesmo se eu remover o container, mas se tiver algo escrito no destination &lt;code&gt;/var/www&lt;/code&gt; ele ainda vai existir, pois o que está escrito lá está ligada ao &lt;strong&gt;Docker Host&lt;/strong&gt;, como se fosse um link. &lt;/p&gt;

&lt;p&gt;Portanto, os dados vão continuar ainda dentro do computador.&lt;/p&gt;
&lt;h2&gt;
  
  
  Iniciando uma escrita no volume (montando ou linkando em /var/www pelo desktop)
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\U&lt;/span&gt;&lt;span class="s2"&gt;sers&lt;/span&gt;&lt;span class="se"&gt;\A&lt;/span&gt;&lt;span class="s2"&gt;lura&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;esktop:/var/www"&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Os &lt;code&gt;:&lt;/code&gt; servem para separar os dois meios do container que vai rodar a imagem do ubuntu.&lt;/p&gt;

&lt;p&gt;Funcionou, então:&lt;/p&gt;

&lt;pre&gt;root@abd0286c0083:/#&lt;/pre&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls
cd &lt;/span&gt;var/www/
&lt;span class="nb"&gt;touch &lt;/span&gt;novo-arquivo.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"este arquivo foi criado dentro de um volume"&lt;/span&gt; &amp;amp;gt&lt;span class="p"&gt;;&lt;/span&gt; novo-arquivo.txt
&lt;span class="nb"&gt;cat &lt;/span&gt;novo-arquivo.txt
&lt;span class="nb"&gt;touch &lt;/span&gt;segundo-arquivo.txt
&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  O que acontece se eu remover esse container?
&lt;/h2&gt;

&lt;p&gt;Continuando o tópico acima, vamos sair do container e remover ele:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;exit
&lt;/span&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Aquela camada do container foi removida, porém os seus arquivos ainda permaneceram na sua Desktop!&lt;/p&gt;
&lt;h2&gt;
  
  
  [Stand alone] Rodando código em apenas um container Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1600%2F1%2A_MtS4HqN2srTcrSyet61DQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1600%2F1%2A_MtS4HqN2srTcrSyet61DQ.jpeg" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Já vimos que o que escrevemos no volume (pasta &lt;code&gt;/var/www&lt;/code&gt; do container) aparece na pasta configurada da nossa máquina local, que no vídeo anterior foi o Desktop. Mas podemos pensar o contrário, ou seja, tudo o que escrevemos no Desktop será acessível na pasta &lt;code&gt;/var/www&lt;/code&gt; do container.&lt;/p&gt;

&lt;p&gt;Isso nos dá a possibilidade de implementar localmente um código de uma linguagem que não está instalada na nossa máquina, e colocá-lo para compilar e rodar dentro do container. Se o container possui &lt;strong&gt;Node&lt;/strong&gt;, &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;PHP&lt;/strong&gt;, seja qual for a linguagem, não precisamos tê-los instalados na nossa máquina, nosso ambiente de desenvolvimento pode ser dentro do container.&lt;/p&gt;

&lt;p&gt;É isso que faremos, pegaremos um código nosso, que está na nossa máquina, e colocaremos para rodar dentro do container, utilizando essa técnica com volumes.&lt;/p&gt;

&lt;p&gt;Para isso, vamos usar um exemplo escrito Node.js. Até podemos executar esse código na nossa máquina, mas temos que instalar o Node na versão certa em que o desenvolvedor implementou o código.&lt;/p&gt;

&lt;p&gt;Agora, como fazemos para criar um container, que irá pegar e rodar esse código Node que está na nossa máquina? Vamos utilizar os volumes. Então, vamos começar a montar o comando.&lt;/p&gt;

&lt;p&gt;Primeiramente, como vamos rodar um código em Node.js, precisamos utilizar a sua imagem:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ou&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; running-node.js node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Além disso, precisamos criar um volume, que faça referência à pasta do código no nosso Desktop:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\U&lt;/span&gt;&lt;span class="s2"&gt;sers&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;ell&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;esktop&lt;/span&gt;&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="s2"&gt;olume-exemplo:/var/www"&lt;/span&gt; node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Mas para fazer esse servidor rodar, precisamos inserir o famoso NPM (Node Package Manager), com o comando &lt;code&gt;npm start&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\U&lt;/span&gt;&lt;span class="s2"&gt;sers&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;ell&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;esktop&lt;/span&gt;&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="s2"&gt;olume-exemplo:/var/www"&lt;/span&gt; node npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Mas de acordo com a nossa aplicação, está programada para abrir a porta (endereço de ip) &lt;code&gt;:3000&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\U&lt;/span&gt;&lt;span class="s2"&gt;sers&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;ell&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;esktop&lt;/span&gt;&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="s2"&gt;olume-exemplo:/var/www"&lt;/span&gt; node npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Não funcionou, devido o nosso container não rodar na pasta &lt;code&gt;/var/www&lt;/code&gt; e sim numa pasta aleatória! No caso do Ubuntu, ele rodou na pasta do boot do Ubuntu, então para ele rodar o comando do npm devemos especificar onde ele deve abrir o meu container!&lt;/p&gt;

&lt;p&gt;Para isso passaremos mais uma flag, a &lt;code&gt;-w&lt;/code&gt; que significa "working directory", então é só referenciar nosso diretório a ele:&lt;/p&gt;
&lt;h2&gt;
  
  
  [Stand alone] Código completo do Docker + Node.js
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\U&lt;/span&gt;&lt;span class="s2"&gt;sers&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;ell&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;esktop&lt;/span&gt;&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="s2"&gt;olume-exemplo:/var/www"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/var/www"&lt;/span&gt; node npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Feito todos esses passos, o container irá funcionar no &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswnl0gc4njxh1zatqz8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswnl0gc4njxh1zatqz8j.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eu posso modificar esse arquivo e atualizar a página localmente, que o servidor vai automaticamente atualizar. Portanto, eu tenho um ambiente de desenvolvimento dentro do meu desktop.&lt;/p&gt;

&lt;p&gt;O container pode ser compartilhado entre a equipe e todos conteram a mesma versão dos programas e do ambiente.&lt;/p&gt;

&lt;p&gt;Portanto, isso já resolve aquele velho erro de produção:&lt;/p&gt;

&lt;p&gt;&amp;gt; Funcionou na minha máquina, na sua não? Como assim!? 🤔😕&lt;/p&gt;

&lt;p&gt;&amp;gt; Então, se funcionou em uma máquina, funcionou em todas as máquinas! Esse é o grande benefício do Docker! 🐋 🐳 💙&lt;/p&gt;
&lt;h2&gt;
  
  
  Interpolação de comando
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/var/www"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/var/www"&lt;/span&gt; node npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  [Stand alone] Dockerfile
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205774538-5e50423e-5ab9-43c7-b039-400838a55f43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205774538-5e50423e-5ab9-43c7-b039-400838a55f43.png" width="376" height="478"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Já trabalhamos com a imagem do &lt;strong&gt;ubuntu&lt;/strong&gt;, &lt;strong&gt;hello-world&lt;/strong&gt;, &lt;strong&gt;dockersamples/static-site&lt;/strong&gt; e por fim do &lt;strong&gt;node&lt;/strong&gt;, mas até agora não criamos a nossa própria imagem, para podermos distribuir para as outras pessoas.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;imagem&lt;/strong&gt; é como se fosse uma receita de bolo. Então, para criarmos a nossa própria imagem, temos que criar a nossa receita de bolo, o &lt;strong&gt;Dockerfile&lt;/strong&gt; (arquivo Docker), ensinando o Docker a criar uma imagem a partir da nossa aplicação, para que ela seja utilizada em outros locais.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-dockerfile-cyan%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3D5050" alt="dockerfile" width="93" height="20"&gt; &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-node.dockerfile-cyan%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3D5050" alt="dockerfile" width="121" height="20"&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Dockerfile&lt;/strong&gt; nada mais é do que um arquivo de texto, e ele possui o nome identificador, porém se alterarmos o nome com o identificador , como &lt;code&gt;node.dockerfile&lt;/code&gt;, ele será reconhecido, mesmo assim. No caso de possuir muitos Dockerfile é realmente interessante modificar o nome pela tecnologia que você está utilizando.&lt;/p&gt;

&lt;p&gt;Vamos agora, distribuir nosso arquivo para que os outros desenvolvedores possam utilizar, para isso utilizaremos os comandos do Dockerfile:&lt;/p&gt;
&lt;h2&gt;
  
  
  [Stand alone] Montando imagem no Dockerfile
&lt;/h2&gt;

&lt;p&gt;Você pode criar do zero ou pegar uma imagem base para isso! Vamos fazer nosso dockerfile se basear no node, então:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-dockerfile-cyan%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3D5050" alt="dockerfile" width="93" height="20"&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:latest&lt;/span&gt;
&lt;span class="k"&gt;MAINTAINER&lt;/span&gt;&lt;span class="s"&gt; isaacalves7 &lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT=3000&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /var/www&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /var/www&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; 
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; npm start ["npm", "start"]&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; $PORT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Identificamos com o &lt;code&gt;FROM&lt;/code&gt; e depois imputamos a imagem e o sinal &lt;code&gt;:&lt;/code&gt; servem para especificar a versão da imagem, no caso &lt;code&gt;latest&lt;/code&gt; (última versão);&lt;/li&gt;
&lt;li&gt;Outra instrução que é comum colocarmos é quem cuida, quem criou a imagem, através do &lt;code&gt;MAINTAINER&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Variável de ambiente &lt;code&gt;ENV&lt;/code&gt;, servem apenas para não gerar um log ao cliente;&lt;/li&gt;
&lt;li&gt;Com o &lt;code&gt;COPY&lt;/code&gt; copiamos nosso diretório padrão para rodar o node;&lt;/li&gt;
&lt;li&gt;Com o &lt;code&gt;WORKDIR&lt;/code&gt; assim que o container carregar o diretório, ele executará o mesmo com o &lt;code&gt;npm start&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Com o &lt;code&gt;RUN&lt;/code&gt; instalamos nossas dependências necessárias. E assim, podemos deletar a pasta &lt;code&gt;node_modules&lt;/code&gt;, pois o que vale é apenas o dockerfile;&lt;/li&gt;
&lt;li&gt;Com o &lt;code&gt;ENTRYPOINT&lt;/code&gt;, cujo gerencia as dependências com base no &lt;em&gt;JSON&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feito a imagem, é hora de &lt;em&gt;buildar&lt;/em&gt; essa imagem, para isso devemos ir ao terminal e inserir:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-f&lt;/span&gt; Dockerfile &lt;span class="nt"&gt;-t&lt;/span&gt; isaacalves7/node-file &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Após rodar esse comando, o docker fará dele uma imagem. Portanto:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Dessa forma, poderá startar o comando dentro do repositório do arquivo:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 isaacalves7/node-file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Podemos alterar a variável de ambiente:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 1234:8080 isaacalves7/node-file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  [Stand alone] Subindo imagens no Docker Hub
&lt;/h2&gt;

&lt;p&gt;Faça sua conta no &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;, depois ensira os comandos no terminal:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker login
docker push &lt;span class="o"&gt;[&lt;/span&gt;nome da imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;No caso &lt;code&gt;docker login&lt;/code&gt; é para se logar no Docker Hub, para ele reconhecer nosso ambiente e usuário. &lt;/p&gt;

&lt;p&gt;Depois, inserimos &lt;code&gt;docker push [nome da imagem]&lt;/code&gt; para ele subir nossa imagem no Docker Hub, para outros usuários terem acesso!&lt;/p&gt;
&lt;h2&gt;
  
  
  Somente baixar a imagem
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull &lt;span class="o"&gt;[&lt;/span&gt;nome da imagem]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Link do meu perfil: &lt;a href="https://hub.docker.com/u/isaacalves7" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-Docker_Hub-ffffff%3Fstyle%3Dflat%26logo%3DDocker%26logoColor%3D2496ED" alt="Docker HUB" width="93" height="20"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  🖧 Networking no Docker (Tipos de Redes)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127785006-850089e0-c8e6-48f2-9a1f-776bffab2928.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127785006-850089e0-c8e6-48f2-9a1f-776bffab2928.png" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Veremos como funciona a rede, e como fazemos para &lt;strong&gt;interligar diversos containers&lt;/strong&gt; no Docker. Normalmente uma aplicação é composta por diversas partes, sejam elas o &lt;code&gt;load balancer/proxy&lt;/code&gt;, a &lt;code&gt;aplicação em si&lt;/code&gt;, &lt;code&gt;um banco de dados&lt;/code&gt;, etc. Quando estamos trabalhando com containers, é bem comum separarmos cada uma dessas partes em um container específico, para cada container ficar com somente uma única responsabilidade.&lt;/p&gt;

&lt;p&gt;Mas se temos uma parte da nossa aplicação em cada container, como podemos fazer para essas partes falarem entre elas? Pois para a nossa aplicação funcionar como um todo, os containers precisam trocar dados entre eles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo832j7rg7p2wvl6w0c4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo832j7rg7p2wvl6w0c4s.png" alt="tipos de redes no Docker" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Bridge network
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmtnqr244dy8h5z3c841.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbmtnqr244dy8h5z3c841.png" alt="bridge-network-docker" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Host network
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi90s1uz681d2xaa58c40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi90s1uz681d2xaa58c40.png" alt="host-network-docker" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Overlay network
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv42spvkol7ibunw11zjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv42spvkol7ibunw11zjv.png" alt="overlay-network-docker" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A boa notícia é que no Docker, por padrão, já existe uma &lt;em&gt;default network&lt;/em&gt;, que no caso é a rede &lt;strong&gt;bridge&lt;/strong&gt;. Isso significa que, quando criamos os nossos containers, por padrão eles funcionam na mesma rede:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127784447-8a94e9a0-6b97-4313-9322-8241518242e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F127784447-8a94e9a0-6b97-4313-9322-8241518242e1.png" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  [Stand alone] Verificando o default container com o Ubuntu
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  [Stand alone] Inspecionando a rede
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker inspect &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;pre&gt;
"Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "905b02e0985ba89a81e437141cfbc432e7aa82c73fd51b2979ef989c9f8ec2a5",
                    "EndpointID": "",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }
&lt;/pre&gt;

&lt;p&gt;Logo, inserimos o comando:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;
ping 172.17.0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Depois disso, o comando não funcionará, pois a imagem do Ubuntu só possui o básico para o Ubuntu funcionar via container.&lt;/p&gt;

&lt;p&gt;Para isso, precisamos utilizar os comandos do Linux, como o de instalação de pacotes:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get update &amp;amp;amp&lt;span class="p"&gt;;&lt;/span&gt;&amp;amp;amp&lt;span class="p"&gt;;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Agora o nome do pacote:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get update &amp;amp;amp&lt;span class="p"&gt;;&lt;/span&gt;&amp;amp;amp&lt;span class="p"&gt;;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; iputils-ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;O &lt;code&gt;iputils-ping&lt;/code&gt; serve para fazer o ping dentro do container.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping &lt;span class="nt"&gt;--help&lt;/span&gt;
ping 172.17.0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Comunicação de containers
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create &lt;span class="nt"&gt;--driver&lt;/span&gt; bridge &lt;span class="o"&gt;[&lt;/span&gt;nome da rede]
docker network &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Criando um novo container atrelada a rede
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; meu-container-de-ubuntu &lt;span class="nt"&gt;--network&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;nome da rede] ubuntu
docker inspect &lt;span class="o"&gt;[&lt;/span&gt;nome &lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Pegando dados de um banco
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2560%2F1%2AI6ln5yd_pGKl93_iX-RkyQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F2560%2F1%2AI6ln5yd_pGKl93_iX-RkyQ.jpeg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para praticar o que vimos sobre redes no Docker, vamos criar uma pequena aplicação que se conectará ao banco de dados, utilizando tudo o que vimos no vídeo anterior.&lt;/p&gt;

&lt;p&gt;O que vamos fazer é utilizar a aplicação alura-books, que irá pegar os dados de um banco de dados de livros e exibi-los em uma página web. É uma aplicação feita em &lt;strong&gt;Node.js&lt;/strong&gt; e o banco de dados é o &lt;strong&gt;MongoDB&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pegando dados de um banco em um outro container
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1316%2F1%2AW3hJmVyfUFvolUowVDlBkA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1316%2F1%2AW3hJmVyfUFvolUowVDlBkA.png" width="658" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então, primeiramente vamos baixar essas duas imagens, a imagem &lt;code&gt;&lt;a href="https://s3.amazonaws.com/caelum-online-public/646-docker/05/projetos/alura-docker-cap05.zip" rel="noopener noreferrer"&gt;douglasq/alura-books&lt;/a&gt;&lt;/code&gt; na versão cap05 e a imagem &lt;code&gt;mongo&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull douglasq/alura-books:cap05
docker pull mongo
docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Na imagem &lt;code&gt;douglasq/alura-books&lt;/code&gt;, não há muito mistério. Ela possui o arquivo &lt;code&gt;server.js&lt;/code&gt;, que carrega algumas dependências e módulos que são instalados no momento em que rodamos a imagem. Esse arquivo carrega também as configurações do banco, que diz onde o banco de dados estará em execução, no caso o seu host será &lt;strong&gt;meu-mongo&lt;/strong&gt;, e o &lt;strong&gt;database&lt;/strong&gt;, com nome de &lt;strong&gt;alura-books&lt;/strong&gt;. Então, quando formos rodar o container de MongoDB, seu nome deverá ser &lt;strong&gt;meu-mongo&lt;/strong&gt;. Além disso, o arquivo realiza a conexão com o banco, configura a porta que será utilizada (3000) e levanta o servidor.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-server.js-yellow%3Fstyle%3Dsocial%26logo%3DJavaScript%26logoColor%3Dyellow" alt="server.js" width="85" height="20"&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fot447tpktypnw5behxp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fot447tpktypnw5behxp9.png" alt="code" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No Dockerfile da imagem, também não há mistério, é basicamente o que vimos no vídeo anterior. Por fim, temos as rotas, que são duas: a &lt;code&gt;rota /&lt;/code&gt;, que carrega os livros e os exibe na página, e a rota &lt;code&gt;/seed&lt;/code&gt;, que salva os livros no banco de dados.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-alura--books.dockerfile-cyan%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3D5050" alt="alura-books.dockerfile" width="159" height="20"&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j4hr5gkzw8v1brhpjwq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j4hr5gkzw8v1brhpjwq.png" alt="code" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso queira, você pode baixar aqui o código da versão cap05 da imagem alura-books.&lt;/p&gt;

&lt;p&gt;Visto isso, já podemos subir a imagem:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 douglasq/alura-books:cap05
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Ao acessar a página &lt;code&gt;http://localhost:8080/&lt;/code&gt;, nenhum livro nos é exibido, pois além de não termos levantado o banco de dados, nós não salvamos nenhum dado nele. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7t22mgmw4botlrb7g6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7t22mgmw4botlrb7g6e.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 43
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Então, vamos excluir esse container e subir o container do &lt;strong&gt;MongoDB&lt;/strong&gt;, lembrando que o seu nome deve ser &lt;strong&gt;meu-mongo&lt;/strong&gt;, e vamos colocá-lo na rede que criamos na sessão anterior:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; meu-mongo &lt;span class="nt"&gt;--network&lt;/span&gt; minha-rede mongo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Com o banco de dados rodando, podemos subir a aplicação do mesmo jeito que fizemos anteriormente, mas não podemos nos esquecer que &lt;strong&gt;ele deve estar na mesma rede do banco de dados&lt;/strong&gt;, logo vamos configurar isso também:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--network&lt;/span&gt; minha-rede &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:3000 douglasq/alura-books:cap05
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Verificando a rede:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network &lt;span class="nb"&gt;ls
&lt;/span&gt;docker inspect minha-rede
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Possuimos então dois containers na mesma rede (&lt;code&gt;minha-rede&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;
"Containers": {
            "7dcce72922f00b3e3db3c9bc925c72cefb6495b0bb6e6d4a525629b62cc5a297": {
                "Name": "meu-mongo",
                "EndpointID": "89bb420463f092d057118137ce5b08d936194cae35db7f9886e3afcd8612042e",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "c68d8bbc9cdaea5fe75a3fce1e024eb6251f72e762c38b76670dd0ee7049d911": {
                "Name": "dreamy_wilbur",
                "EndpointID": "c3010c6d9c05af02d38b8816530677199d020b9c01d232f9fb86037375a3f5a4",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
&lt;/pre&gt;

&lt;p&gt;Agora, acessamos a página &lt;code&gt;http://localhost:8080/seed/&lt;/code&gt; para salvar os livros no banco de dados. Após isso, acessamos a página &lt;code&gt;http://localhost:8080/&lt;/code&gt; e vemos os dados livros são extraídos do banco e são exibidos na página. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkmbi006styuu9241ikt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkmbi006styuu9241ikt.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmavlnibtpexozjzmkp78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmavlnibtpexozjzmkp78.png" alt="docker" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para provar isso, podemos parar a execução do &lt;strong&gt;meu-mongo&lt;/strong&gt; e atualizar a página, veremos que nenhum livro mais será exibido.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker stop meu-mongo
docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Então, esse foi um exemplo para praticar a comunicação entre containers, sempre lembrando que devemos colocá-los na mesma rede.&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker Swarm
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pridybailo.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2015%2F01%2Fswar-q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.pridybailo.com%2Fwp-content%2Fuploads%2Fsites%2F2%2F2015%2F01%2Fswar-q.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, tudo bem até aqui. Agora vou ter vários serviços rodando usando o Docker. E para facilitar a criação desses containers já aprendemos usar o &lt;em&gt;Docker Compose&lt;/em&gt; que sabe subir vários containers. O Docker Compose é a ferramenta ideal para coordenar a criação dos containers, no entanto para melhorar a escalabilidade e desempenho pode ser necessário criar muito mais containers para um serviço específico. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F171045139-68a0b570-7649-47ac-bf39-65649c486d2a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F171045139-68a0b570-7649-47ac-bf39-65649c486d2a.gif" width="312" height="390"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Em outras palavras, agora gostaríamos de criar muitos containers aproveitando várias máquinas (virtuais ou físicas)! Ou seja, pode ser que um microsserviço fique rodando em 20 containers usando três máquinas físicas diferentes. Como podemos facilmente subir e parar esses containers? Repare que o Docker Compose não é para isso e por isso existe uma outra ferramenta que se chama &lt;strong&gt;Docker Swarm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Swarm&lt;/strong&gt; facilita a criação e administração de um &lt;strong&gt;cluster&lt;/strong&gt; de containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network: Bridge Mode
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create &lt;span class="nt"&gt;-d&lt;/span&gt; bridge petaBridge
docker network &lt;span class="nb"&gt;ls
&lt;/span&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; petaBridge &lt;span class="nt"&gt;--name&lt;/span&gt; db consul:latest
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="s2"&gt;"DB=db"&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; petaBridge &lt;span class="nt"&gt;--name&lt;/span&gt; web &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:5000 poroko/flask-demo-app
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; web bash
bash&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;bash&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;exit
&lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; web sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Network: Host Mode
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; host &lt;span class="nt"&gt;--name&lt;/span&gt; db consul 
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="s2"&gt;"DB=localhost"&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; host poroko/flask-demo-app
docker ps
netstat &lt;span class="nt"&gt;-nltp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;b&gt;WARNING&lt;/b&gt;: Nesse modelo de rede, você não pode colocar outra aplicação da mesma linguagem na mesma porta, você precisa abrir outra porta!&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  [SWARM] Duas instâncias em rede bridge
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205681549-06914673-d715-4ba8-b834-d9d6274bebcc.png" width="500" height="500"&gt;&lt;br&gt;

&lt;p&gt;Faremos um Docker Swarm, onde uma das duas máquinas será o gerenciador, ou seja, o principal controlando os demais nós desse cluster (no caso, a máquina).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F192.168.0.8-node1-0095D5%3F%26style%3Dfor-the-badge%26logo%3DDocker%26logoColor%3Dwhite" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F192.168.0.8-node1-0095D5%3F%26style%3Dfor-the-badge%26logo%3DDocker%26logoColor%3Dwhite" alt="Node2" width="185" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Container de front-end (Flask = chrch/docker-pets:1.0 = web) e rede Bridge (petsBridge). No caso, esse vai ser o container principal do Docker SWARM. &lt;/p&gt;

&lt;p&gt;Podemos escalonar o tráfego de rede com o Docker SWARM, criando assim o Load Balancer entre os dois containers (cada um em uma instância diferente).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create &lt;span class="nt"&gt;-d&lt;/span&gt; bridge petsBridge
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="s2"&gt;"DB=db"&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; petsBridge &lt;span class="nt"&gt;--name&lt;/span&gt; web &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:5000 chrch/docker-pets:1.0
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker restart &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;&lt;span class="k"&gt;do &lt;/span&gt;container]
ifconfig
docker swarm init &lt;span class="nt"&gt;--advertise-addr&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;IP &lt;span class="k"&gt;do &lt;/span&gt;container]
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; docker swarm &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; SWMTKN-1-1qrnyxbd5bja864nx27sdzpuwd52j60kdt1350ox42h45pkage-1jrrm0afvugxzdin34a5y6k1y 192.168.0.28:2377
docker node &lt;span class="nb"&gt;ls
hostname
&lt;/span&gt;docker network create &lt;span class="nt"&gt;-d&lt;/span&gt; overlay petsOverlay 
docker service create &lt;span class="nt"&gt;--network&lt;/span&gt; petsOverlay &lt;span class="nt"&gt;--name&lt;/span&gt; db consul
docker service create &lt;span class="nt"&gt;--network&lt;/span&gt; petsOverlay &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:5000 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"DB=db"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; web chrch/docker-pets:1.0
docker service &lt;span class="nb"&gt;ls
&lt;/span&gt;docker service scale &lt;span class="nv"&gt;web&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F192.168.0.7-node2-0095D5%3F%26style%3Dfor-the-badge%26logo%3DDocker%26logoColor%3Dwhite" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F192.168.0.7-node2-0095D5%3F%26style%3Dfor-the-badge%26logo%3DDocker%26logoColor%3Dwhite" alt="Node2" width="185" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Container de back-end (Consul = db) e rede Bridge (petsBridge). Esse será chamado através do token de acesso do docker swarm para se juntar com o outro container, ligados pelo mesmo modelo de rede.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create &lt;span class="nt"&gt;-d&lt;/span&gt; bridge petsBridge
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; petsBridge &lt;span class="nt"&gt;--name&lt;/span&gt; db consul
docker swarm &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; SWMTKN-1-1qrnyxbd5bja864nx27sdzpuwd52j60kdt1350ox42h45pkage-1jrrm0afvugxzdin34a5y6k1y 192.168.0.28:2377
docker logs &lt;span class="o"&gt;[&lt;/span&gt;ID container]
netstat &lt;span class="nt"&gt;-nltp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Armazenamento no Docker (Docker storage)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F143244782-08e93b38-b7b9-4424-8abc-06bb2c81a862.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F143244782-08e93b38-b7b9-4424-8abc-06bb2c81a862.png" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tanto o &lt;strong&gt;bind mounts&lt;/strong&gt; quanto o &lt;strong&gt;volume&lt;/strong&gt;, se o container for removido ou reiniciado, as informações serão persistidas em disco.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;tmpfs mounts&lt;/strong&gt; é um disco temporário para guardar logs e caches da sua aplicação, o container for reiniciado ou removido esses arquivos serão deletados, ou seja, não foram para a camada de escrita do container. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo 1&lt;/strong&gt;: Criando volume&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create meuPrimeiroVolume
docker volume &lt;span class="nb"&gt;ls
&lt;/span&gt;docker volume inspect meuPrimeiroVolume
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 &lt;span class="nt"&gt;--name&lt;/span&gt; container-volume &lt;span class="nt"&gt;--mount&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;meuPrimeiroVolume,nginx:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Limites no Docker
&lt;/h2&gt;

&lt;p&gt;Precisamos ter limites de memória e CPU no Docker, se acaso a sua aplicação consumir muito recurso de memória ou CPU desnecessariamente, siga o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--memory&lt;/span&gt; 10m busybox &lt;span class="nb"&gt;sleep &lt;/span&gt;3600
docker stats
docker run &lt;span class="nt"&gt;--cpus&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;".5"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; programium/stress &lt;span class="nt"&gt;-c&lt;/span&gt; 8 &lt;span class="nt"&gt;-t&lt;/span&gt; 50s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tqqp0grrp5lewqx8rfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tqqp0grrp5lewqx8rfn.png" alt="projeto-dio" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker Compose
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopenwhisk.apache.org%2Fimages%2Fdeployments%2Flogo-docker-compose-text.svg" width="4" height="2"&gt;&lt;br&gt;

&lt;p&gt;Agora vamos subir múltiplos containers! Mas como? Simples! Basta rodar os dois comandos ao mesmo tempo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; meu-mongo &lt;span class="nt"&gt;--network&lt;/span&gt; rede-producao mongo
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="nt"&gt;--name&lt;/span&gt; alura-books &lt;span class="nt"&gt;--network&lt;/span&gt; rede-producao douglasq/alura-books 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Contudo, essa forma de subir containers é um tanto falha, pois possue a maior probabilidade de:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Esquecer de uma flag;&lt;/li&gt;
&lt;li&gt;Esquecer um parâmetro importante;&lt;/li&gt;
&lt;li&gt;Muito manual;&lt;/li&gt;
&lt;li&gt;Fácil de errar;&lt;/li&gt;
&lt;li&gt;Preciso garantir a ordem.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  [Compose] Funcionamento das aplicações em geral
&lt;/h3&gt;

&lt;p&gt;Na vida real, sabemos que a aplicação é maior que somente dois containers, geralmente temos dois, três ou mais containers para segurar o tráfego da aplicação, distribuindo a carga. Além disso, temos que colocar todos esses containers para se comunicar com o &lt;strong&gt;banco de dados&lt;/strong&gt; em um outro container, mas quanto &lt;strong&gt;maior a aplicação&lt;/strong&gt;, devemos ter mais de um container para o banco também.&lt;/p&gt;

&lt;p&gt;E claro, se temos três aplicações rodando, não podemos ter três endereços diferentes, então nesses casos utilizamos um &lt;strong&gt;Load Balancer&lt;/strong&gt; em um outro container, para fazer a distribuição de carga quando tivermos muitos acessos. Ele recebe as requisições e distribui para uma das aplicações, e ele também é muito utilizado para servir os arquivos estáticos, como &lt;em&gt;imagens&lt;/em&gt;, &lt;em&gt;arquivos CSS&lt;/em&gt; e &lt;em&gt;JavaScript&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Assim, a nossa aplicação controla somente a &lt;em&gt;lógica, as regras de negócio&lt;/em&gt;, com os &lt;em&gt;arquivos estáticos&lt;/em&gt; ficando a cargo do &lt;strong&gt;Load Balancer&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" alt="docker" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se formos seguir esse diagrama, teríamos que criar cinco containers na mão, e claro, cada container com configurações e flags diferentes, além de termos que nos preocupar com a ordem em que vamos subi-los. Ou seja, subir 5 flags na mão??? subir tudo isso de forma manual??? Que trabalhooooo....&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flockmedown.com%2Fwp-content%2Fuploads%2F2017%2F01%2Fdocker-compose-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flockmedown.com%2Fwp-content%2Fuploads%2F2017%2F01%2Fdocker-compose-logo.png" width="800" height="1409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-docker--compose.yaml-pink%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3Dmagenta" alt="dockerfile" width="157" height="20"&gt;&lt;/p&gt;

&lt;p&gt;Então, para isso foi criada uma ferramenta no Docker chamada &lt;strong&gt;Docker Compose&lt;/strong&gt;, que ele executa e auxilia na build ou criação de vários (múltiplos) containers simultaneamente. Ele funciona seguindo um arquivo de texto, chamado &lt;code&gt;docker-compose.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esse arquivo serve para dar um conjunto de passos ao Docker e com ele podemos controlar quais containers sobem primeiro, ou seja, funciona como um processo de BIOS ou um automatizador de containers.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;Docker Compose&lt;/em&gt; cria uma rede padrão. Também é possível criar uma nova rede usando o comando &lt;code&gt;docker network&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;OBS&lt;/strong&gt;: O &lt;strong&gt;YAML&lt;/strong&gt; é semelhante ao &lt;strong&gt;JSON&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seguindo o mesmo diagrama, vejamos nossa nova aplicação rodando atualizada para o uso do Docker Compose:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" alt="docker" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O código do projeto pode ser &lt;a href="https://s3.amazonaws.com/caelum-online-public/646-docker/06/projetos/alura-docker-cap06.zip" rel="noopener noreferrer"&gt;baixado aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para começarmos a entender como funciona o Docker Compose, primeiramente vamos entender como funciona a aplicação que utilizaremos como base. É uma aplicação bem semelhante à utilizada na sessão anterior, &lt;strong&gt;com o mesmo servidor, rotas e banco de dados&lt;/strong&gt;. De novidade, é que agora precisamos criar o &lt;strong&gt;NGINX&lt;/strong&gt;, que é mais um container que devemos subir.&lt;/p&gt;

&lt;p&gt;Então, ao utilizamos a &lt;strong&gt;imagem nginx&lt;/strong&gt;, ou criamos a nossa própria. Como vamos configurar o NGINX para algumas coisas específicas, como lidar com os &lt;em&gt;arquivos estáticos&lt;/em&gt;, vamos criar a nossa própria imagem, por isso que na aplicação há o &lt;code&gt;nginx.dockerfile&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusd0ks4t2nc6t8tcm9e7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fusd0ks4t2nc6t8tcm9e7.png" alt="image" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-nginx.dockerfile-blue%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3Dblue" alt="dockerfile" width="123" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:latest&lt;/span&gt;
&lt;span class="k"&gt;MAINTAINER&lt;/span&gt;&lt;span class="s"&gt; isaacalves7&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; /public /var/www/public&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; /docker/config/nginx.conf /etc/nginx/nginx.conf&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80 443&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["nginx"]&lt;/span&gt;
&lt;span class="c"&gt;# Parametros extras para o entrypoint&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse arquivo, nós utilizamos a última versão disponível da imagem do nginx como base, e copiamos o conteúdo da pasta &lt;code&gt;public&lt;/code&gt;, que contém os &lt;em&gt;arquivos estáticos&lt;/em&gt;, e &lt;em&gt;um arquivo de configuração do NGINX para dentro do container&lt;/em&gt;. Além disso, abrimos as portas &lt;code&gt;80&lt;/code&gt; e &lt;code&gt;443&lt;/code&gt; e executa o NGINX através do comando nginx, passando os parâmetros extras &lt;code&gt;-g&lt;/code&gt; e &lt;code&gt;daemon off&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por fim, vamos ver um pouco sobre o &lt;em&gt;arquivo de configuração do NGINX&lt;/em&gt;, para entendermos um pouco como o &lt;strong&gt;load balancer&lt;/strong&gt; está funcionando.&lt;/p&gt;

&lt;p&gt;No arquivo &lt;code&gt;nginx.conf&lt;/code&gt;, dentro server, está a parte que trata de servir os &lt;em&gt;arquivos estáticos&lt;/em&gt;. Na &lt;code&gt;porta 80&lt;/code&gt;, no localhost, em &lt;code&gt;/var/www/public&lt;/code&gt;, ele será responsável por servir as pastas &lt;code&gt;css&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt; e &lt;code&gt;js&lt;/code&gt;. E todo resto, que não for esses três locais, ele irá jogar para o &lt;code&gt;node_upstream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;node_upstream&lt;/strong&gt;, é onde ficam as configurações para o NGINX redirecionar as conexões que ele receber para um dos três containers da nossa aplicação. O redirecionamento acontecerá de forma circular, ou seja, a &lt;strong&gt;primeira conexão irá para o primeiro container&lt;/strong&gt;, a &lt;strong&gt;segunda irá para o segundo container&lt;/strong&gt;, a &lt;strong&gt;terceira irá para o terceiro container&lt;/strong&gt;, na &lt;strong&gt;quarta, começa tudo de novo&lt;/strong&gt;, &lt;strong&gt;e ela vai para o primeiro container e assim por diante&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;Isso já está tudo pronto, basta baixarmos o &lt;a href="https://s3.amazonaws.com/caelum-online-public/646-docker/06/projetos/alura-docker-cap06.zip" rel="noopener noreferrer"&gt;código da imagem e da aplicação aqui&lt;/a&gt;.&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Criando o &lt;code&gt;docker-compose.yaml&lt;/code&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Tanto faz as duas extensões, as duas são a mesma linguagem!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-docker--compose.yaml-pink%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3Dmagenta" alt="dockerfile" width="157" height="20"&gt; &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-docker--compose.yml-pink%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3Dmagenta" alt="dockerfile" width="151" height="20"&gt; &lt;/p&gt;

&lt;p&gt;Para utilizar o Docker Compose, devemos criar o seu arquivo de configuração, o &lt;code&gt;docker-compose.yml&lt;/code&gt;, na raiz do projeto. Em todo arquivo de Docker Compose, que é uma espécie de receita de bolo para construirmos as diferentes partes da nossa aplicação, a primeira coisa que colocamos nele é a versão do Docker Compose que estamos utilizando:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-docker--compose.yaml-pink%3Fstyle%3Dsocial%26logo%3Ddocker%26logoColor%3Dmagenta" alt="dockerfile" width="157" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./docker/nginx.dockerfile&lt;/span&gt;
            &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;douglasq/nginx&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production-network&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node1"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node2"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node3"&lt;/span&gt;

    &lt;span class="na"&gt;mongodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production-network&lt;/span&gt;

    &lt;span class="na"&gt;node1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./docker/alura-books.dockerfile&lt;/span&gt;
            &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;douglasq/alura-books&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alura-books-1&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000"&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production-network&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mongodb"&lt;/span&gt;

    &lt;span class="na"&gt;node2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./docker/alura-books.dockerfile&lt;/span&gt;
            &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;douglasq/alura-books&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alura-books-2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000"&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production-network&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mongodb"&lt;/span&gt;

    &lt;span class="na"&gt;node3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./docker/alura-books.dockerfile&lt;/span&gt;
            &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;douglasq/alura-books&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alura-books-3&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000"&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production-network&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mongodb"&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;production-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estamos utilizando a versão 3 pois é a versão mais recente no momento da criação do treinamento. O YAML lembra um pouco o JSON, mas ao invés de utilizar as chaves para indentar o código, ele utiliza espaços.&lt;/p&gt;

&lt;p&gt;Agora, começamos a descrever os nossos serviços, os nossos services:&lt;/p&gt;

&lt;p&gt;No &lt;em&gt;YAML&lt;/em&gt;, toda vez que colocamos o caractére &lt;code&gt;-&lt;/code&gt; significa que disponibilizamos um array.&lt;/p&gt;

&lt;p&gt;Um serviço é uma parte da nossa aplicação. Lembrando do nosso diagrama:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfg92gsyog8ecothlqas.png" alt="docker" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Temos &lt;strong&gt;NGINX&lt;/strong&gt;, &lt;strong&gt;três Node&lt;/strong&gt;, e o &lt;strong&gt;MongoDB&lt;/strong&gt; como &lt;em&gt;serviços&lt;/em&gt;. Logo, se queremos construir &lt;em&gt;cinco containers&lt;/em&gt;, vamos construir &lt;em&gt;cinco serviços&lt;/em&gt;, cada um deles com um nome específico.&lt;/p&gt;

&lt;p&gt;Então, vamos começar construindo o &lt;em&gt;NGINX&lt;/em&gt;, que terá o nome *&lt;em&gt;nginx&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Em cada serviço, devemos dizer como devemos construí-lo, como devemos fazer o seu build:&lt;/p&gt;

&lt;p&gt;O serviço será construído através de um Dockerfile, então devemos passá-lo onde ele está. E também devemos passar um contexto, para dizermos a partir de onde o Dockerfile deve ser buscado. Como ele será buscado a partir da pasta atual, vamos utilizar o ponto:&lt;/p&gt;

&lt;p&gt;Construída a imagem, devemos dar um nome para ela, por exemplo douglasq/nginx:&lt;/p&gt;

&lt;p&gt;E quando o Docker Compose criar um container a partir dessa imagem, vamos dizer que o seu nome será nginx:&lt;/p&gt;

&lt;p&gt;Sabemos também que o NGINX trabalha com duas portas, a 80 e a 443. Como não estamos trabalhando com HTTPS, vamos utilizar somente a porta 80, e no próprio arquivo, podemos dizer para qual porta da nossa máquina queremos mapear a porta 80 do container. Vamos mapear para a porta de mesmo número da nossa máquina:&lt;/p&gt;

&lt;p&gt;No YAML, toda vez que colocamos um traço, significa que a propriedade pode receber mais de um item. Agora, para os containers conseguirem se comunicar, eles devem estar na mesma rede, então vamos configurar isso também. Primeiramente, devemos criar a rede, que não é um serviço, então vamos escrever do começo do arquivo, sem as tabulações:&lt;/p&gt;

&lt;p&gt;O nome da rede será production-network e utilizará o driver bridge:&lt;/p&gt;

&lt;p&gt;Com a rede criada, vamos utilizá-la no serviço:&lt;/p&gt;

&lt;p&gt;Isso é para construir o serviço do NGINX, agora vamos construir o serviço do MongoDB, com o nome mongodb. Como ele será construído a partir da imagem mongo, não vamos utilizar nenhum Dockerfile, logo não utilizamos a propriedade build. Além disso, não podemos nos esquecer de colocá-lo na rede que criamos:&lt;/p&gt;

&lt;p&gt;Falta agora criarmos os três serviços em que ficará a nossa aplicação, node1, node2 e node3. Para eles, será semelhante ao NGINX, com Dockerfile alura-books.dockerfile, contexto, rede production-network e porta 3000:&lt;/p&gt;

&lt;p&gt;Com isso, a construção dos nossos serviços está finalizada.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ordem dos serviços
&lt;/h4&gt;

&lt;p&gt;Por último, quando subimos os containers na mão, temos uma ordem, primeiro devemos subir o mongodb, depois a nossa aplicação, ou seja, node1, node2 e node3 e após tudo isso subimos o nginx. Mas como que fazemos isso no docker-compose.yml?&lt;/p&gt;

&lt;p&gt;Nós podemos dizer que os serviços da nossa aplicação dependem que um serviço suba antes deles, o serviço do mongodb.&lt;/p&gt;

&lt;p&gt;Da mesma forma, dizemos que o serviço do nginx depende dos serviços node1, node2 e node3.&lt;/p&gt;

&lt;h2&gt;
  
  
  [Docker Compose] Subindo os serviços
&lt;/h2&gt;

&lt;p&gt;Com o &lt;code&gt;docker-compose.yml&lt;/code&gt; pronto, podemos subir os serviços, mas antes devemos garantir que temos todas as imagens envolvidas neste arquivo na nossa máquina. Para isso, dentro da pasta do nosso projeto, executamos o seguinte comando:&lt;/p&gt;

&lt;h4&gt;
  
  
  Inicia o Docker Compose
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de buildar os serviços, eles podem ser vistos em:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, podemos inserir o comando:&lt;/p&gt;

&lt;h4&gt;
  
  
  Starta todas as solicitações (build) do Docker Compose
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Listando e verificando o docker-compose
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Para e remove todos os containers do docker-compose
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verificando que os containers estão se comunicando
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; alura-books-1 ping alura-books-2
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; alura-books-1 ping node2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Reinicializando containers
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker e Microsserviços
&lt;/h2&gt;

&lt;p&gt;Trabalhar com uma arquitetura de microsserviços gera a necessidade de publicar o serviço de maneira rápida, leve, isolada e vimos que o Docker possui exatamente essas características! Com Docker e Docker Compose podemos criar um ambiente ideal para a publicação destes serviços.&lt;/p&gt;

&lt;p&gt;O Docker é uma ótima opção para rodar os microsserviços pelo fato de isolar os containers. Essa utilização de containers para serviços individuais faz com que seja muito simples gerenciar e atualizar esses serviços, de maneira automatizada e rápida.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>distributedsystems</category>
      <category>devops</category>
    </item>
    <item>
      <title>Nginx</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 21:31:42 +0000</pubDate>
      <link>https://forem.com/isaacalves7/nginx-2i3l</link>
      <guid>https://forem.com/isaacalves7/nginx-2i3l</guid>
      <description>&lt;p&gt;O &lt;strong&gt;NGINX&lt;/strong&gt; é um servidor web/proxy reverso rápido, de alto rendimento e um proxy para correio eletrônico (IMAP/POP3), é um software livre e de código-aberto. Ele é um serviço, é um programa que roda e que serve para responder requisições web.&lt;/p&gt;

&lt;p&gt;Ele não usa somente aquela ideia de processos do servidor Apache, threads e programação paralela, ele usa um outro conceito de &lt;strong&gt;programação assíncrona&lt;/strong&gt; muito interessante:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204335254-c050775b-5e13-43a7-a2e4-ece2064d05df.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204335254-c050775b-5e13-43a7-a2e4-ece2064d05df.png" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então, temos aqui uma base do funcionamento do NGINX. Quando você inicia um serviço do NGINX, ele cria um processo principal como se fosse o patrão desses colaboradores aqui. No qual esse patrão vai criar alguns processos colaboradores, alguns &lt;strong&gt;worker process&lt;/strong&gt;. Esses worker process são criados baseado no número de núcleos (cores) que o seu processador tem. Suponha que eu tenho um servidor que tem &lt;strong&gt;um processador com quatro núcleos&lt;/strong&gt;. Então eu poderia criar, por exemplo, &lt;strong&gt;4 processos worker process&lt;/strong&gt; para tratar requisições. Porque assim eu tenho um maior número de processos tratando cada número de requisições, então eu consigo tratar mais requisições.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Só que a sacada é: Não é como se cada processo tratasse uma requisição. Não é isso! Cada um desses processos trata um número grande de requisições, várias requisições, e para que ele consiga tratar mais de uma requisição, ele usa um conceito de &lt;strong&gt;Multiplexing I/O&lt;/strong&gt;. Ou seja, ele faz mais de uma coisa de forma &lt;strong&gt;assíncrona&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Então, imagine que chegou uma requisição nesse worker aqui e depois chega uma nova requisição que caiu nesse mesmo worker. O que ele vai fazer? Ele vai colocar para executar o primeiro. Enquanto esse processo está esperando essa tarefa ser executada - por exemplo: o servidor de aplicação responder e o arquivo ser carregado - ele já trata outra requisição, coloca para carregar imagem e manda requisição para servidor de imagem. Depois ele pega a resposta da primeira requisição e devolve, continua tratando a segunda e devolve. Por isso o NGINX veio com a proposta de ser o servidor web mais rápido.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Existem benchmarks que colocam realmente o NGINX lá no topo, ou seja, é um servidor muito performático. Mas obviamente não existe bala de prata e ele tem seus cenários onde ele trabalha muito bem e não é ferramenta ideal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funcionamento do NGINX&lt;/strong&gt;: Ele inicia um servidor, um processo. Esse processo cria outros processos colaboradores, e cada um desses processos consegue tratar várias requisições utilizando o conceito de programação assíncrona, garantindo assim uma grande performance.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/_/nginx" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.worldvectorlogo.com%2Flogos%2Fnginx-1.svg" width="882" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Difere-se muito do servidor Apache, porque ele transfere a responsabilidade de um servidor web para um servidor de aplicação além de ser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tolerante a falhas;&lt;/li&gt;
&lt;li&gt;Compatível com o IPv6;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Com Java você pode ter um Tomcat rodando, ou com PHP você vai ter um PHP FPM rodando. Enfim, você vai ter algum servidor de aplicação aqui, e o NGINX consegue se conectar à ele. Mas nós vamos focar só na parte do NGINX, sem nos conectarmos a algum servidor de aplicação.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Instalação do NGINX
&lt;/h2&gt;

&lt;p&gt;Como baixar e configurar o NGINX server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nginx.org/en/download.html" rel="noopener noreferrer"&gt;http://nginx.org/en/download.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;macOS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;nginx 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para iniciar o nginx é simples, basta escrever o nome dele na linha de comando no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basta somente executa-lo e acessar o &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204398044-71e2ced9-7789-4abc-bc17-8dd682c5f6a2.png" class="article-body-image-wrapper"&gt;&lt;img alt="welcome-screen-e1450116630667" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204398044-71e2ced9-7789-4abc-bc17-8dd682c5f6a2.png" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [NGINX] Servidor HTTP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.svgrepo.com%2Fshow%2F373315%2Fnginx-opened.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.svgrepo.com%2Fshow%2F373315%2Fnginx-opened.svg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Exibe ajuda e lá podemos ver os caminhos do arquivo de configuração
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nginx -h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Arquivos de configuração do servidor (&lt;code&gt;nginx.conf&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Essa é a área que configuramos o nosso servidor Nginx:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-nginx.conf-000000%3Fstyle%3Dsocial%26logo%3DNginx%26logoColor%3D%23009639" alt="NGINX" width="95" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#user  nobody;
&lt;/span&gt;&lt;span class="n"&gt;worker_processes&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# auto
&lt;/span&gt;
&lt;span class="c1"&gt;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
&lt;/span&gt;
&lt;span class="c1"&gt;#pid        logs/nginx.pid;
&lt;/span&gt;

&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worker_connections&lt;/span&gt;  &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# limite de processos em um sistema operacional de arquivos assíncronos (file descriptors = sockets, connections, etc...)
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;# Servidor HTTP
&lt;/span&gt;    &lt;span class="n"&gt;include&lt;/span&gt;       &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;default_type&lt;/span&gt;  &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;octet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
&lt;/span&gt;    &lt;span class="c1"&gt;#                  '$status $body_bytes_sent "$http_referer" '
&lt;/span&gt;    &lt;span class="c1"&gt;#                  '"$http_user_agent" "$http_x_forwarded_for"';
&lt;/span&gt;
    &lt;span class="c1"&gt;#access_log  logs/access.log  main;
&lt;/span&gt;
    &lt;span class="n"&gt;sendfile&lt;/span&gt;        &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;#tcp_nopush     on;
&lt;/span&gt;
    &lt;span class="c1"&gt;#keepalive_timeout  0;
&lt;/span&gt;    &lt;span class="n"&gt;keepalive_timeout&lt;/span&gt;  &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;#gzip  on;
&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;# Servidor Web
&lt;/span&gt;        &lt;span class="n"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;server_name&lt;/span&gt;  &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;#charset koi8-r;
&lt;/span&gt;
        &lt;span class="c1"&gt;#access_log  logs/host.access.log  main;
&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;   &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;index&lt;/span&gt;  &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;htm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;#error_page  404              /404.html;
&lt;/span&gt;
        &lt;span class="c1"&gt;# redirect server error pages to the static page /50x.html
&lt;/span&gt;        &lt;span class="c1"&gt;#
&lt;/span&gt;        &lt;span class="n"&gt;error_page&lt;/span&gt;   &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="mi"&gt;502&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="mi"&gt;504&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;   &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# proxy the PHP scripts to Apache listening on 127.0.0.1:80
&lt;/span&gt;        &lt;span class="c1"&gt;#
&lt;/span&gt;        &lt;span class="c1"&gt;#location ~ \.php$ {
&lt;/span&gt;        &lt;span class="c1"&gt;#    proxy_pass   http://127.0.0.1;
&lt;/span&gt;        &lt;span class="c1"&gt;#}
&lt;/span&gt;
        &lt;span class="c1"&gt;# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
&lt;/span&gt;        &lt;span class="c1"&gt;#
&lt;/span&gt;        &lt;span class="c1"&gt;#location ~ \.php$ {
&lt;/span&gt;        &lt;span class="c1"&gt;#    root           html;
&lt;/span&gt;        &lt;span class="c1"&gt;#    fastcgi_pass   127.0.0.1:9000;
&lt;/span&gt;        &lt;span class="c1"&gt;#    fastcgi_index  index.php;
&lt;/span&gt;        &lt;span class="c1"&gt;#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
&lt;/span&gt;        &lt;span class="c1"&gt;#    include        fastcgi_params;
&lt;/span&gt;        &lt;span class="c1"&gt;#}
&lt;/span&gt;
        &lt;span class="c1"&gt;# deny access to .htaccess files, if Apache's document root
&lt;/span&gt;        &lt;span class="c1"&gt;# concurs with nginx's one
&lt;/span&gt;        &lt;span class="c1"&gt;#
&lt;/span&gt;        &lt;span class="c1"&gt;#location ~ /\.ht {
&lt;/span&gt;        &lt;span class="c1"&gt;#    deny  all;
&lt;/span&gt;        &lt;span class="c1"&gt;#}
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="c1"&gt;# another virtual host using mix of IP-, name-, and port-based configuration
&lt;/span&gt;    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="c1"&gt;#server {
&lt;/span&gt;    &lt;span class="c1"&gt;#    listen       8000;
&lt;/span&gt;    &lt;span class="c1"&gt;#    listen       somename:8080;
&lt;/span&gt;    &lt;span class="c1"&gt;#    server_name  somename  alias  another.alias;
&lt;/span&gt;
    &lt;span class="c1"&gt;#    location / {
&lt;/span&gt;    &lt;span class="c1"&gt;#        root   html;
&lt;/span&gt;    &lt;span class="c1"&gt;#        index  index.html index.htm;
&lt;/span&gt;    &lt;span class="c1"&gt;#    }
&lt;/span&gt;    &lt;span class="c1"&gt;#}
&lt;/span&gt;

    &lt;span class="c1"&gt;# HTTPS server
&lt;/span&gt;    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="c1"&gt;#server {
&lt;/span&gt;    &lt;span class="c1"&gt;#    listen       443 ssl;
&lt;/span&gt;    &lt;span class="c1"&gt;#    server_name  localhost;
&lt;/span&gt;
    &lt;span class="c1"&gt;#    ssl_certificate      cert.pem;
&lt;/span&gt;    &lt;span class="c1"&gt;#    ssl_certificate_key  cert.key;
&lt;/span&gt;
    &lt;span class="c1"&gt;#    ssl_session_cache    shared:SSL:1m;
&lt;/span&gt;    &lt;span class="c1"&gt;#    ssl_session_timeout  5m;
&lt;/span&gt;
    &lt;span class="c1"&gt;#    ssl_ciphers  HIGH:!aNULL:!MD5;
&lt;/span&gt;    &lt;span class="c1"&gt;#    ssl_prefer_server_ciphers  on;
&lt;/span&gt;
    &lt;span class="c1"&gt;#    location / {
&lt;/span&gt;    &lt;span class="c1"&gt;#        root   html;
&lt;/span&gt;    &lt;span class="c1"&gt;#        index  index.html index.htm;
&lt;/span&gt;    &lt;span class="c1"&gt;#    }
&lt;/span&gt;    &lt;span class="c1"&gt;#}
&lt;/span&gt;    &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você pode usar o comando abaixo para retirar os comentários e visualizar somente o necessário, funciona como um filtro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /opt/homebrew/etc/nginx/nginx.conf | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-ve&lt;/span&gt; &lt;span class="s1"&gt;'^.\s*#'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-ve&lt;/span&gt; &lt;span class="s1"&gt;'^#'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/^$/d'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, o arquivo de configuração fica assim:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-nginx.conf-000000%3Fstyle%3Dsocial%26logo%3DNginx%26logoColor%3D%23009639" alt="NGINX" width="95" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;worker_processes&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worker_connections&lt;/span&gt;  &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;include&lt;/span&gt;       &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;default_type&lt;/span&gt;  &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;octet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;sendfile&lt;/span&gt;        &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;keepalive_timeout&lt;/span&gt;  &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;server_name&lt;/span&gt;  &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;   &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;index&lt;/span&gt;  &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;htm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;error_page&lt;/span&gt;   &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="mi"&gt;502&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="mi"&gt;504&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;   &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos editar nosso arquivo principal da página do Nginx. Para isso, acesse o comando abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /opt/homebrew/Cellar/nginx/1.23.2/html/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se definirmos &lt;code&gt;location /&lt;/code&gt;, significa &lt;code&gt;/&lt;/code&gt; literalmente tudo, ou seja, podemos definir qual o diretório raiz do projeto, qual o arquivo padrão, regras de redirecionamento, etc. Percebe-se que o arquivo não mostra o preview dele no localhost. &lt;/p&gt;

&lt;h4&gt;
  
  
  Recarrega o arquivo nginx
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx &lt;span class="nt"&gt;-s&lt;/span&gt; reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Testar o arquivo de configuração
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Páginas de erro HTTP
&lt;/h3&gt;

&lt;p&gt;Os códigos de erro de protocolo HTTP começam na faixa dos &lt;code&gt;400&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="mi"&gt;402&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  [NGINX] Proxy Reverso
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flinuxhandbook.com%2Fcontent%2Fimages%2F2020%2F09%2Fdeploy-multiple-services-with-nginx-reverse-proxy-container.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flinuxhandbook.com%2Fcontent%2Fimages%2F2020%2F09%2Fdeploy-multiple-services-with-nginx-reverse-proxy-container.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;proxy&lt;/strong&gt; de rede funciona basicamente como se fosse um "túnel" ou "filtro", quando acessamos uma determinada área, o proxy . Então é assim que funciona um proxy, ele literalmente pega as requisições e dispara na internet para um servidor web acessar as informações, ou sejam um &lt;strong&gt;proxy reverso&lt;/strong&gt; ele pega as requisições feitas e redireciona ainda para outro servidor (Como se acrescentasse mais uma etapa no processo de proxy).&lt;/p&gt;

&lt;blockquote&gt;Então, o &lt;b&gt;proxy reverso&lt;/b&gt; é um servidor web que recebe as requisições e distribui para outros servidores.&lt;/blockquote&gt;

&lt;p&gt;Porque normalmente um proxy fica no lado do cliente. O conceito padrão de proxy é algo que fica no lado do cliente interceptando os pacotes de rede. Como nesse caso o proxy está no lado do servidor, chamamos de &lt;em&gt;proxy reverso&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com esse simples código, eu tenho o conceito de proxy reverso.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Por que realizar um proxy reverso e não apenas deixar o servidor de aplicação lidar com todas as requisições? Com nginx na frente podemos responder arquivos estáticos muito mais rapidamente. Esse é um dos principais motivos. O nginx é um servidor incrivelmente performático, então nós ganhamos muito ao não enviar todas as requisições para o servidor de aplicação. O nginx pode enviar diretamente os arquivos estáticos sem processar nada, além de poder definir cache, compressão, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Servidor 2 em 1
&lt;/h3&gt;

&lt;p&gt;Com o proxy reverso podemos receber uma requisição e devolver muito rápido se for um arquivo estático, fazer cash e etc. Já para fazer uma rota ou uma URL que precisa de lógica, que precisa ser processada, eu mando para o servidor de aplicação.&lt;/p&gt;

&lt;p&gt;Exemplo (default.conf):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="mi"&gt;402&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com nginx na frente podemos responder arquivos estáticos muito mais rapidamente. Esse é um dos principais motivos. O nginx é um servidor incrivelmente performático, então nós ganhamos muito ao não enviar todas as requisições para o servidor de aplicação. O nginx pode enviar diretamente os arquivos estáticos sem processar nada, além de poder definir cache, compressão, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  [NGINX] API Gateway
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205203395-dab2e0ee-13b6-4499-a75d-015942262517.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205203395-dab2e0ee-13b6-4499-a75d-015942262517.svg" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Monolítica, Microserviços e Múltiplos serviços
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.redhat.com%2Fcms%2Fmanaged-files%2Fmonolithic-vs-microservices.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.redhat.com%2Fcms%2Fmanaged-files%2Fmonolithic-vs-microservices.png" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resumidamente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monolithic&lt;/strong&gt; (Monolítica): é nada mais e nada menos do que uma arquitetura para uma aplicação rodando em somente &lt;strong&gt;um serviço&lt;/strong&gt; contendo uma estrutura com poucas seções de maneira estruturada para o servidor;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microserviços&lt;/strong&gt; (Microservices): é nada mais é do que uma arquitetura com &lt;strong&gt;muitos micro (pequenos) serviços&lt;/strong&gt; rodando em uma ou várias aplicações, ideal para projetos de grande porte e com diversas áreas diferentes. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos criar dois serviços dentro de (microserviços.conf):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8002&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;error_page&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos criar a index.html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;Dev/nginx/servico1 Dev/nginx/servico2
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Servico 1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Dev/nginx/servico1/index.html
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Servico 2"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Dev/nginx/servico1/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configurando um servidor web que faz o redirecionamento para outros múltiplos servidores baseados na URL recebida (ponto de entrada para centralizar o acesso a múltiplos serviços em um único host):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8002&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, todas as requisições podem ser feitas para o mesmo servidor, facilitando a vida do cliente, dentre outras vantagens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Um servidor web que faz o redirecionamento para outros múltiplos servidores baseado na URL recebida. Dessa forma, todas as requisições podem ser feitas para o mesmo servidor, facilitando a vida do cliente, dentre outras vantagens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A partir do API Gateway é decidido onde essa requisição será direcionada.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problema: Clientes acessando livremente os serviços geram caos&lt;/li&gt;
&lt;li&gt;Gateway fornece um proxy, uma fachada, para as necessidades reais&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Desvantagem: Esse portão de entrada pode se tornar um pouco central de falha&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O comportamento do Gateway&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplesmente autorizar e redirecionar os requests&lt;/li&gt;
&lt;li&gt;Uso de Decorator para adicionar informações necessárias aos requests&lt;/li&gt;
&lt;li&gt;Limitar o acesso ou conteúdo trafegado&lt;/li&gt;
&lt;li&gt;Impedir que determinadas URLs sejam acessadas por completo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora que conhecemos o conceito de um API Gateway, temos uma base melhor para esse artigo fenomenal do próprio Nginx: &lt;a href="https://www.nginx.com/blog/deploying-nginx-plus-as-an-api-gateway-part-1/" rel="noopener noreferrer"&gt;https://www.nginx.com/blog/deploying-nginx-plus-as-an-api-gateway-part-1/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  [NGINX] Load Balancing (Balanceamento de carga)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205202929-3a9cacc2-221f-4e8f-9cb5-9ba501a2e491.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205202929-3a9cacc2-221f-4e8f-9cb5-9ba501a2e491.svg" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É um balanceador de carga (como um switch para serviços).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;Dev/nginx/servico2/servico.html Dev/nginx/servico2/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos configura-lo de forma muito simples, com o &lt;code&gt;upstream&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;upstream&lt;/span&gt; &lt;span class="n"&gt;servicos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8002&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8003&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;servicos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na prática, através do nome definido em upstream, podemos acessar algum dos servidores deste grupo dependendo de algumas regras definidas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuração de logs
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;access_log&lt;/code&gt; é qualquer log de acesso, já o &lt;code&gt;error_log&lt;/code&gt; é um log somente de erros. Vamos ver um exemplo no (nginx.conf):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#user nobody;
&lt;/span&gt;&lt;span class="n"&gt;worker_processes&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;#error_log  logs/error.log;
#error_log  logs/error.log notice;
#error_log  logs/error.log info;
&lt;/span&gt;
&lt;span class="c1"&gt;#pid        logs/nginx.pid
&lt;/span&gt;

&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worker_connections&lt;/span&gt;  &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;include&lt;/span&gt;        &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;default_type&lt;/span&gt;   &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;octet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;logs_format&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;  &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$remote_addr - $remote_user [$time_local] &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$request&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;
                      &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$status $body_bytes_sent &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$http_referer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
                      &lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;$http_user_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$http_x_fowarded_for&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="s"&gt;;

   #access_log  logs/access.log  main;
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;Dev/nginx/logs
nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
nginx &lt;span class="nt"&gt;-s&lt;/span&gt; reload
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; Dev/nginx/logs/servico1
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; Dev/nginx/logs/servico2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Formato de logs (nginx.conf)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#user nobody;
&lt;/span&gt;&lt;span class="n"&gt;worker_processes&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;#error_log  logs/error.log;
#error_log  logs/error.log notice;
#error_log  logs/error.log info;
&lt;/span&gt;
&lt;span class="c1"&gt;#pid        logs/nginx.pid
&lt;/span&gt;

&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worker_connections&lt;/span&gt;  &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;include&lt;/span&gt;        &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;default_type&lt;/span&gt;   &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;octet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;logs_format&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;  &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Remote Addr: $remote_addr - Time: [$time_local] &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$request&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;
                      &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Status: $status, Referer: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$http_referer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;

   #access_log  logs/access.log  main;
}

     sendfile          on;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Formato de logs (microservicos.conf)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;access_log&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8002&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;access_log&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;servico2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adicionando informações
&lt;/h2&gt;

&lt;p&gt;Dentro do &lt;code&gt;load-balancer.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;upstream&lt;/span&gt; &lt;span class="n"&gt;servicos&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8002&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8003&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;servicos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;proxy_set_header&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Real&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;nginx.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;#user nobody;
worker_processes &lt;span class="m"&gt;1&lt;/span&gt;;

#error_log  logs/error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;;
#error_log  logs/error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; notice;
#error_log  logs/error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; info;

#pid        logs/nginx&lt;span class="p"&gt;.&lt;/span&gt;pid


events &lt;span class="p"&gt;{&lt;/span&gt;
    worker_connections  &lt;span class="m"&gt;1024&lt;/span&gt;;
&lt;span class="p"&gt;}&lt;/span&gt;


http &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;include&lt;/span&gt;        mime&lt;span class="p"&gt;.&lt;/span&gt;types;
    default_type   application/octet&lt;span class="p"&gt;-&lt;/span&gt;stream;

    logs_format main  &lt;span class="s1"&gt;'Remote Addr: $http_x_real_ip, Time: [$time_local] "$request"'&lt;/span&gt;
                      'Status&lt;span class="p"&gt;:&lt;/span&gt; $status&lt;span class="p"&gt;,&lt;/span&gt; Referer&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"$http_referer"&lt;/span&gt;

   #access_log  logs/access&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;  main;
&lt;span class="p"&gt;}&lt;/span&gt;

     sendfile          &lt;span class="k"&gt;on&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Definindo pesos (load-balancer.conf)
&lt;/h3&gt;

&lt;p&gt;Se não distriuimos corretamente o peso para cada um servidor, deixaremos um desses servidores sobrecarregados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;upstream servicos &lt;span class="p"&gt;{&lt;/span&gt;
     server localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8001&lt;/span&gt; weight&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;;
     server localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8002&lt;/span&gt;;
&lt;span class="p"&gt;}&lt;/span&gt;

server &lt;span class="p"&gt;{&lt;/span&gt;
    listen &lt;span class="m"&gt;8003&lt;/span&gt;;
    server_name localhost;

    location / &lt;span class="p"&gt;{&lt;/span&gt;
        proxy_pass http&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;servicos;
        proxy_set_header X&lt;span class="p"&gt;-&lt;/span&gt;Real&lt;span class="p"&gt;-&lt;/span&gt;IP $remote_addr;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplicamos o cenário de quando temos servidores com capacidades diferentes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Servidores de backup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nginx.org/en/docs/http/ngx_http_upstream_module.html" rel="noopener noreferrer"&gt;https://nginx.org/en/docs/http/ngx_http_upstream_module.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos fazer o seguinte, vamos utilizar o servidor1 como o servidor principal e o servidor2 como o nosso servidor de backup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;upstream servicos &lt;span class="p"&gt;{&lt;/span&gt;
     server localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8001&lt;/span&gt; fail_timeout&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;120&lt;/span&gt;s;
     server localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8002&lt;/span&gt; &lt;span class="nb"&gt;backup&lt;/span&gt;;
&lt;span class="p"&gt;}&lt;/span&gt;

server &lt;span class="p"&gt;{&lt;/span&gt;
    listen &lt;span class="m"&gt;8003&lt;/span&gt;;
    server_name localhost;

    location / &lt;span class="p"&gt;{&lt;/span&gt;
        proxy_pass http&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;servicos;
        proxy_set_header X&lt;span class="p"&gt;-&lt;/span&gt;Real&lt;span class="p"&gt;-&lt;/span&gt;IP $remote_addr;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Utilizaremos o servidor backup somente para casos extremos, ou seja, se o servidor principal falhar e estiver em instabilidade, o servidor backup o substitue.&lt;/p&gt;

&lt;h2&gt;
  
  
  [NGINX] Fast CGI
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdab1nmslvvntp.cloudfront.net%2Fwp-content%2Fuploads%2F2013%2F09%2Fnginx-fcgi-1a.png" width="476" height="154"&gt;&lt;br&gt;

&lt;p&gt;Lógicas do lado do servidor, e para isso foi criado o &lt;strong&gt;CGI&lt;/strong&gt;. Com a mesma ideia do CGI, surgiu então o &lt;strong&gt;FastCGI&lt;/strong&gt; cujo você não precisa criar outro processo por cada requisição, o que melhora muito na performance. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffastcgi-archives.github.io%2Fimages%2Flitespeed-screenshot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffastcgi-archives.github.io%2Fimages%2Flitespeed-screenshot.jpg" width="660" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A principal diferença entre o &lt;strong&gt;CGI&lt;/strong&gt; e o &lt;strong&gt;FastCGI&lt;/strong&gt; está no processo, o &lt;strong&gt;FastCGI&lt;/strong&gt; permanece vivo após o encerramento de uma requisição. Ao iniciar um processo FastCGO, ele ouvirá novas conexões e não morrerá mais, ou seja, o mesmo processo continua gerenciando os recursos da aplicação. Usando CGI, a cada requisição um processo é criado e depois morre.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configurando o proxy
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;index.php
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;?php phpinfo();'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.php
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:9000 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/caminho/projeto php:fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Quero um serviço para rodar no &lt;code&gt;localhost:8004&lt;/code&gt;, vamos criar um novo documento (fpm.conf):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;server &lt;span class="p"&gt;{&lt;/span&gt;
   listen &lt;span class="m"&gt;8004&lt;/span&gt;;

   location / &lt;span class="p"&gt;{&lt;/span&gt;
       fastcgi_pass localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;9000&lt;/span&gt;;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parâmetros adicionais
&lt;/h3&gt;

&lt;p&gt;Ainda dentro do (fpm.conf):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;server &lt;span class="p"&gt;{&lt;/span&gt;
    listen &lt;span class="m"&gt;8004&lt;/span&gt;;
    root &lt;span class="sr"&gt;/caminho/&lt;/span&gt;projeto;

    location / &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;include&lt;/span&gt; fastcgi&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;conf&lt;/span&gt;;
        fastcgi_pass localhost&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;9000&lt;/span&gt;;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É um protocolo mais enxuto com fendas comprimidas e dessa forma a requisição do app não precisa receber todo o protocolo HTTP&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cache HTTP
&lt;/h3&gt;

&lt;p&gt;O navegador (browser) pode ignorar os cabeçalhos de cache e não cachear o recurso. Tanto isso é verdade que temos a opção de desabilitar o cache do nosso navegador. Os cabeçalhos de cache instruem o navegador sobre o quanto tempo ele pode/deve manter o recurso em cache, mas cabe a ele aceitar essa instrução ou não. Todos os navegadores modernos tendem a seguir a instrução a menos que configuremos de forma diferente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;server &lt;span class="p"&gt;{&lt;/span&gt;
    listen &lt;span class="m"&gt;8005&lt;/span&gt;;
    root &lt;span class="sr"&gt;/Users/&lt;/span&gt;isaac&lt;span class="sr"&gt;/Dev/&lt;/span&gt;performance;
    &lt;span class="nb"&gt;index&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;html;

    location &lt;span class="p"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;jpg$ &lt;span class="p"&gt;{&lt;/span&gt;
       expires &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="k"&gt;d&lt;/span&gt;;
       add_header Cache&lt;span class="p"&gt;-&lt;/span&gt;Control public;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compreensão
&lt;/h2&gt;

&lt;p&gt;Modo de compreensão instalado no próprio NGINX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8005&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip_types&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Control&lt;/span&gt; &lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os tipos de recursos que são mais beneficiados pela compressão com gzip na web são os arquivos de texto (estáticos): html, css, js, svg, etc...&lt;/p&gt;

&lt;p&gt;Os arquivos de texto podem ser facilmente comprimidos e são os que mais levam vantagem desta técnica. Arquivos binários ou arquivos de imagem, por exemplo, naturalmente já são comprimidos, por isso o efeito seria bem menor (ou inexistente).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conexões
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8005&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip_types&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Keep&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Alive&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout=5, max=1000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Control&lt;/span&gt; &lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cache
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Caminho do Cache
&lt;/h3&gt;

&lt;p&gt;É possível tranformar nosso servidor em um servidor cache, armazenando dados de resposta para não reprocessar determinadas requisições. Em um cenário em que URLs precisam de processamento e não mudam de usuário para usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fastcgi_cache_path&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;keys_zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fpm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;proxy_cache_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;levels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;keys_zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8004&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;caminho&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projeto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com uma simples página web por exemplo, nós não precisamos realizar todas as queries de cursos, formações, etc o tempo todo. Podemos executar uma vez só e armazenar o html montado em cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usando o cache
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fastcgi_cache_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;keys_zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fpm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8004&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;caminho&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projeto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache_key&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request_method&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache&lt;/span&gt; &lt;span class="n"&gt;fpm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache_valid&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verificando o status
&lt;/h3&gt;

&lt;p&gt;Para podermos depurar quando necessário, se precisarmos saber se um cache está sendo encontrado ou não, ter um cabeçalho na resposta é uma forma bem fácil de obter essa informação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fastcgi_cache_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;keys_zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fpm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8004&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;caminho&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projeto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="n"&gt;fastcgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache_key&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request_method&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache&lt;/span&gt; &lt;span class="n"&gt;fpm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fastcgi_cache_valid&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;upstream_cache_status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  HTTPS
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F130708015-a80f3f14-3d5b-42a7-877c-fe19a2966d3c.png" width="288" height="175"&gt;&lt;br&gt;

&lt;p&gt;Um protocolo de Hipertexto seguro criptografado. Quanto utilizamos o HTTP os dados são transportados em texto puro para o servidor, visível para qualquer um. Nossos dados são enviados em um texto puro, ficando visível para qualquer um que consiga interceptar nossa conexão!&lt;/p&gt;

&lt;h3&gt;
  
  
  Gerando nosso próprio certificado
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 30 &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:2048 &lt;span class="nt"&gt;-keyout&lt;/span&gt; /tmp/localhost.key &lt;span class="nt"&gt;-out&lt;/span&gt; /tmp/localhost.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;security add-certificate /tmp/localhost.crt
security add-trusted-cert /tmp/localhost.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurando o NGINX
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip_types&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Keep&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Alive&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout=5, max=1000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ssl_certificate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Control&lt;/span&gt; &lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8005&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;isaac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;gzip_types&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Keep&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Alive&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout=5, max=1000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; \&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jpg&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="n"&gt;add_header&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Control&lt;/span&gt; &lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nginx</category>
      <category>distributedsystems</category>
      <category>devops</category>
    </item>
    <item>
      <title>HTTPD - Servidor Web Apache2 (Apache2 Web Server)</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 21:25:47 +0000</pubDate>
      <link>https://forem.com/isaacalves7/httpd-servidor-web-apache2-apache2-web-server-28k9</link>
      <guid>https://forem.com/isaacalves7/httpd-servidor-web-apache2-apache2-web-server-28k9</guid>
      <description>&lt;p&gt;&lt;a href="https://hub.docker.com/_/httpd" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.worldvectorlogo.com%2Flogos%2Fapache-13.svg" width="2500" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentre os programas mais utilizados em servidores da internet em todo o mundo está o &lt;strong&gt;Apache&lt;/strong&gt;. Para começar este tópico, precisamos entender o que é o &lt;strong&gt;Apache&lt;/strong&gt; e o papel que ele desempenha em servidores.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Apache&lt;/strong&gt;, também conhecido como &lt;strong&gt;Httpd&lt;/strong&gt;, é um &lt;em&gt;servidor HTTP&lt;/em&gt; ou, como muitos chamam, um servidor Web (Web Server). Ele é responsável por receber e processar requisições enviadas por clientes HTTP. Quando acessamos um site, do outro lado estamos sendo atendidos por um servidor HTTP.&lt;/p&gt;

&lt;p&gt;Os &lt;strong&gt;Servidores HTTP&lt;/strong&gt; são executados em processos do tipo background, ou seja, sem intervenção manual de um administrador para responder às solicitações recebidas.&lt;/p&gt;

&lt;p&gt;O Apache se destaca por ser um software de alta confiabilidade, gratuito e de código-fonte aberto, permitindo que qualquer pessoa possa modificá-lo para uso pessoal ou contribuir com melhorias para a comunidade de usuários.&lt;/p&gt;

&lt;p&gt;Sobre o processamento de um servidor Apache rodando, quando chega uma requisição, esse processo cria um novo processo e trata essa requisição, depois mata esse processo e fica tudo certo. Só que isso é muito custoso. Criar um processo, fazer a mudança de contexto de um processo para o outro e depois matar um processo. Isso é uma tarefa custosa. Outros servidores web, resolveram esse processo, você verá a diferença com Nginx.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fd%2Fdb%2FApache_Software_Foundation_Logo_%25282016%2529.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fd%2Fdb%2FApache_Software_Foundation_Logo_%25282016%2529.svg" width="939" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Apache é mantido pela &lt;strong&gt;The Apache Software Foundation&lt;/strong&gt; e um grande número de programadores contribui com o seu desenvolvimento. Como possui diversos módulos opcionais para variadas funcionalidades, tem grande versatilidade.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: É importante frisar que diferentes distribuições Linux utilizam distintos esquemas de organização das configurações do Apache. Neste tema, abordaremos a organização usada nas distribuições baseadas no Debian, como a Ubuntu Linux.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mais importante do que entender a organização é compreender a lógica de administração. Assim, você saberá do que precisa quando se deparar com uma distribuição que utiliza um esquema diferente.&lt;/p&gt;

&lt;h2&gt;
  
  
  INSTALAÇÃO DO APACHE
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F1%2F10%2FApache_HTTP_server_logo_%25282019-present%2529.svg" width="5" height="2"&gt;&lt;br&gt;

&lt;p&gt;Geralmente, o Apache pode ser instalado por dois caminhos:&lt;/p&gt;

&lt;b title="(click to open)"&gt;Caminho 1&lt;/b&gt;
  
Baixando seu código-fonte e compilando-o. Apesar de existir farta documentação, é uma atividade mais complexa e exige a instalação prévia de bibliotecas, compiladores etc. Em geral, é a opção para usuários avançados e em casos mais específicos.
  
  
  

&lt;b title="(click to open)"&gt;Caminho 2&lt;/b&gt;

O segundo caminho, mais simples, é a instalação por meio de pacotes fornecidos pelas principais distribuições Linux. Os pacotes já trazem o programa pronto para executar, além de bibliotecas e outras dependências. As rotinas de atualização também são facilitadas, assim como a instalação de módulos opcionais.
  
  
  

&lt;p&gt;A instalação do Apache na distribuição Ubuntu/Debian Linux é feita com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;apache2 &lt;span class="se"&gt;\ &lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 start &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso queira instalar o Apache na distribuição Fedora/CentOS/Red Hat Enterprise Linux é feita com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;httpd &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;httpd &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso esteja instalando pelo código-fonte: &lt;a href="https://httpd.apache.org/docs/2.4/en/install.html" rel="noopener noreferrer"&gt;https://httpd.apache.org/docs/2.4/en/install.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O ‘apt’ é o programa gerenciador de pacotes usado pelo Ubuntu. Ele irá obter na internet os pacotes do Apache e fará sua instalação. Após isso, o Apache estará configurado com uma página inicial de demonstração, que pode ser acessada a partir de outro computador.&lt;/p&gt;

&lt;p&gt;Usando o comando &lt;code&gt;ip addr&lt;/code&gt;, obtenha o endereço IP do servidor. Em outra máquina, na mesma rede, abra um navegador (Internet Explorer, Firefox, Chrome) e digite o endereço do servidor. Exemplo: &lt;a href="http://192.168.1.70" rel="noopener noreferrer"&gt;http://192.168.1.70&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas, no meu caso, farei simplesmente no localhost, cujo basta somente dar o comando &lt;code&gt;sudo service apache2 start&lt;/code&gt;, com o endereço: &lt;a href="http://127.0.0.1" rel="noopener noreferrer"&gt;http://127.0.0.1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsukvlfczjijgid5xg51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsukvlfczjijgid5xg51.png" alt="Sem título" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ao aparecer essa tela, isso significa que seu web server está funcionando corretamente!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Alterar a página inicial do Apache:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /var/www/html/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuração do Apache
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/apache2/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/apache2/apache2.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/apache2/ports.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mudando a porta do Apache
&lt;/h3&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-apache2.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt="Apache2.conf" width="111" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;Listen&lt;/span&gt; 801
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Após mudar o endereço da porta, você deve reiniciar o Apache!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antes, era comum escrever toda a configuração do Apache em um único arquivo, como o ‘/etc/httpd.conf’.&lt;/p&gt;

&lt;p&gt;O problema dessa abordagem é que, quanto mais sites eram criados no servidor, maior ficava esse arquivo, até ser impraticável administrá-lo. Para piorar, aumentavam as chances de se cometer um erro acidental na configuração, afetando todo o servidor.&lt;/p&gt;

&lt;p&gt;Não era incomum o servidor sair do ar, e consequentemente todos os sites hospedados, por um erro acidental, muitas vezes difícil de ser diagnosticado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Para facilitar a administração, a configuração do Apache passou a ser modularizada, composta por diversos arquivos, organizados por tipo de configuração, em diretórios específicos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma árvore de diretórios de configuração típica está representada a seguir:&lt;/p&gt;

&lt;pre&gt;
/etc/apache2/
├── conf-available
├── conf-enabled
├── mods-available
├── mods-enabled
├── sites-available
└── sites-enabled
&lt;/pre&gt;

&lt;h3&gt;
  
  
  Arquivos do Apache
&lt;/h3&gt;

&lt;p&gt;No diretório '/etc/apache2' estão localizados arquivos com configurações globais do Apache. Entre eles:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-ports.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt=".RB" width="93" height="20"&gt; , em que são declaradas as portas TCP que o Apache abre para receber solicitações – Por padrão, &lt;code&gt;80&lt;/code&gt; para HTTP e &lt;code&gt;443&lt;/code&gt; para HTTPS.&lt;/li&gt;
&lt;li&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-apache2.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt=".RB" width="111" height="20"&gt; , o arquivo principal de configuração. Mas, nenhuma configuração deve ser incluída aqui. Por padrão, esse arquivo contém instruções para que as configurações sejam obtidas nos demais arquivos e diretórios.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Divisão dos diretórios em grupos
&lt;/h3&gt;

&lt;p&gt;Dentro de &lt;code&gt;/etc/apache2&lt;/code&gt; há seis diretórios, divididos em três grupos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;conf&lt;/code&gt; - Para configurações gerais do Apache.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mods&lt;/code&gt; - Para configuração de módulos.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sites&lt;/code&gt; - Para configuração de sites.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Leitura dos arquivos
&lt;/h3&gt;

&lt;p&gt;Para cada um desses grupos, há um diretório ‘available’ (disponível) e um ‘enabled’ (habilitado). Quando o Apache é iniciado, ele lê todos os arquivos dos diretórios ‘enabled’:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-enabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/mods-enable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/sites-enabled&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada um dos arquivos presentes nesses diretórios será lido e sua configuração carregada pelo Apache. Se listarmos, porém, o conteúdo de qualquer um desses diretórios, veremos que todos os seus arquivos são, na verdade, links.&lt;/p&gt;

&lt;pre&gt;
$ ls –l /etc/apache2/conf-enabled
lrwxrwxrwx 1 root root 30 May 26 12:53 charset.conf -&amp;gt; ../conf-available/charset.conf
lrwxrwxrwx 1 root root 44 May 26 12:53 localized-error-pages.conf -&amp;gt; ../conf-available/localized-
lrwxrwxrwx 1 root root 46 May 26 12:53 other-vhosts-access-log.conf -&amp;gt; ../conf-available/other-
lrwxrwxrwx 1 root root 31 May 26 12:53 security.conf -&amp;gt; ../conf-available/security.conf
lrwxrwxrwx 1 root root 36 May 26 12:53 serve-cgi-bin.conf -&amp;gt; ../conf-available/serve-cgi-bin.conf
&lt;/pre&gt;
  

&lt;p&gt;Observe o &lt;code&gt;l&lt;/code&gt; no início de cada linha, indicando que se trata de links simbólicos.&lt;/p&gt;

&lt;p&gt;Todos os links no diretório &lt;code&gt;conf-enabled&lt;/code&gt; apontam para arquivos que estão no respectivo diretório &lt;code&gt;conf-available&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Mas por que essa organização? Para permitir que as configurações possam ser escritas livremente e só ativadas quando desejado. Um arquivo nos diretórios 'available' não será lido pelo Apache. Isso permite que escrevamos uma configuração, mas só a ative posteriormente, criando o link em ‘enabled’ para esse arquivo.&lt;/p&gt;

&lt;p&gt;Assim, o Apache pode trazer diversas configurações de módulos opcionais que permanecerão inativas até que o administrador as ative manualmente. Isso vale para as configurações de site. É possível retirar um site do ar meramente apagando o ‘link’ da configuração deste, não sendo necessário editar arquivos com outras configurações.&lt;/p&gt;

&lt;p&gt;Nos diretórios ‘available’ estarão os arquivos de texto com as configurações, ativas ou não. Nos diretórios ‘enabled’ existirão apenas links para as configurações ativas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: O arquivo &lt;code&gt;/etc/apache2/mods-available/ssl.conf&lt;/code&gt; possui configurações para ativar o protocolo criptografado HTTPS. Se o seu servidor não vai utilizar esse recurso, não há necessidade de ter esse módulo habilitado. Por outro lado, para ativar o HTTPS, basta criar o link no diretório ‘enabled’ e o recurso estará disponível para uso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: O nome dos arquivos de configuração deve terminar com &lt;code&gt;.conf&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ATIVANDO E DESATIVANDO MÓDULOS, CONFIGURAÇÕES E SITES
&lt;/h2&gt;

&lt;p&gt;Sabemos que para ativar as configurações devem ser criados links nos diretórios ‘enabled’ apontando para arquivos no diretório ‘available’. No entanto, o Apache traz comandos que facilitam essa tarefa:&lt;/p&gt;

&lt;p&gt;&lt;b title="(click to open)"&gt;&lt;code&gt;a2enconf&lt;/code&gt; e &lt;code&gt;a2disconf&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;O comando &lt;code&gt;a2enconf&lt;/code&gt; habilita (enable) as configurações, enquanto o &lt;code&gt;a2disconf&lt;/code&gt; as desabilita (disable). Exemplo de uso:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enconf charset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;O nome da configuração é passado no argumento, e a terminação &lt;code&gt;.conf&lt;/code&gt; dos arquivos pode ser omitida. &lt;/p&gt;

&lt;p&gt;Nesse exemplo, foi ativada a configuração &lt;code&gt;charset&lt;/code&gt;. O programa criou o link: &lt;code&gt;/etc/apache2/conf-enabled/charset.conf&lt;/code&gt; apontando para &lt;code&gt;/etc/apache2/conf-available/charset.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Os comandos para habilitar e desabilitar módulos e sites são semelhantes.&lt;/p&gt;

&lt;p&gt;&lt;b title="(click to open)"&gt;&lt;code&gt;a2enmod&lt;/code&gt; e &lt;code&gt;a2dismod&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;O comando &lt;code&gt;a2enmod&lt;/code&gt; habilita módulos opcionais do Apache, enquanto o &lt;code&gt;a2dismod&lt;/code&gt; desabilita.&lt;/p&gt;

&lt;p&gt;&lt;b title="(click to open)"&gt;&lt;code&gt;a2ensite&lt;/code&gt; e &lt;code&gt;a2dissite&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;O comando &lt;code&gt;a2ensite&lt;/code&gt; habilita sites, enquanto o &lt;code&gt;a2dissite&lt;/code&gt; desabilita.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Após qualquer alteração nas configurações, é necessário avisar ao Apache para que ele as releia ou reinicie o processo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para as tarefas de controle do processo do Apache existe o comando &lt;code&gt;apache2ctl&lt;/code&gt;, que oferece diversas opções. Entre elas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicia o processo do Apache, retornando erro se o processo já estiver executando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encerra e reinicia o processo do Apache. Não deve ser usado apenas para carregar novas configurações, pois as requisições em andamento serão interrompidas imediatamente. Deve-se usar com cuidado, já que eventuais erros de configuração poderão impedir o processo de reiniciar, deixando-o parado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl configtest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executa uma análise dos arquivos de configuração do Apache em busca de erros de sintaxe, sem interferir com o processo em execução. Deve-se observar que nem todo erro será detectável por esse teste.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl graceful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Envia um sinal para o Apache reiniciar, relendo os arquivos de configuração, porém sem interromper as requisições em andamento. Se o processo não estava em execução, ele é iniciado. Também é possível que erros na configuração impeçam o processo de reiniciar, deixando-o parado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encerra o processo do Apache. Nenhuma nova requisição será recebida e os usuários receberão um aviso do tipo “servidor inacessível”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exibe informações sobre o processo em execução do Apache. Há também o argumento &lt;code&gt;fullstatus&lt;/code&gt;, com informações detalhadas sobre as requisições sendo atendidas (requer o módulo &lt;code&gt;mod_status&lt;/code&gt; habilitado).&lt;/p&gt;

&lt;p&gt;Como já vimos, quando o Apache é instalado é feita uma configuração inicial com uma página de teste. O nome do arquivo deste site pode variar dependendo da distribuição Linux.&lt;/p&gt;

&lt;p&gt;Nas distribuições Debian e Ubuntu, esse arquivo é o &lt;code&gt;/etc/apache2/sites-enables/000-default.conf&lt;/code&gt; e seu conteúdo é reproduzido a seguir:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-apache2.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt="Apache2.conf" width="111" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;VirtualHost *&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        # The ServerName directive sets the request scheme&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nb"&gt;and&lt;/span&gt; port that
        # the server uses &lt;span class="k"&gt;to&lt;/span&gt; identify itself&lt;span class="p"&gt;.&lt;/span&gt; This &lt;span class="k"&gt;is&lt;/span&gt; used when creating
        # redirection URLs&lt;span class="p"&gt;.&lt;/span&gt; In the context of virtual hosts&lt;span class="p"&gt;,&lt;/span&gt; the ServerName
        # specifies what &lt;span class="nb"&gt;hostname&lt;/span&gt; must appear &lt;span class="k"&gt;in&lt;/span&gt; the request's Host&lt;span class="p"&gt;:&lt;/span&gt; header &lt;span class="k"&gt;to&lt;/span&gt;
        # &lt;span class="k"&gt;match&lt;/span&gt; this virtual host&lt;span class="p"&gt;.&lt;/span&gt; For the default virtual host &lt;span class="p"&gt;(&lt;/span&gt;this &lt;span class="k"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; this
        # value &lt;span class="k"&gt;is&lt;/span&gt; not decisive &lt;span class="k"&gt;as&lt;/span&gt; it &lt;span class="k"&gt;is&lt;/span&gt; used &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt; resort host regardless&lt;span class="p"&gt;.&lt;/span&gt;
        # However&lt;span class="p"&gt;,&lt;/span&gt; you must &lt;span class="k"&gt;set&lt;/span&gt; it &lt;span class="k"&gt;for&lt;/span&gt; any further virtual host explicitly&lt;span class="p"&gt;.&lt;/span&gt;
        #ServerName www&lt;span class="p"&gt;.&lt;/span&gt;example&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;

        ServerAdmin webmaster@localhost
        DocumentRoot &lt;span class="sr"&gt;/var/&lt;/span&gt;www/html

        # Available loglevels&lt;span class="p"&gt;:&lt;/span&gt; trace8&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; trace1&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; info&lt;span class="p"&gt;,&lt;/span&gt; notice&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        # error&lt;span class="p"&gt;,&lt;/span&gt; crit&lt;span class="p"&gt;,&lt;/span&gt; alert&lt;span class="p"&gt;,&lt;/span&gt; emerg&lt;span class="p"&gt;.&lt;/span&gt;
        # It &lt;span class="k"&gt;is&lt;/span&gt; also possible &lt;span class="k"&gt;to&lt;/span&gt; configure the loglevel &lt;span class="k"&gt;for&lt;/span&gt; particular
        # modules&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        #LogLevel info &lt;span class="nb"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;warn&lt;/span&gt;

        ErrorLog $&lt;span class="p"&gt;{&lt;/span&gt;APACHE_LOG_DIR&lt;span class="p"&gt;}&lt;/span&gt;/error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;
        CustomLog $&lt;span class="p"&gt;{&lt;/span&gt;APACHE_LOG_DIR&lt;span class="p"&gt;}&lt;/span&gt;/access&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; combined

        # For most configuration &lt;span class="k"&gt;files&lt;/span&gt; from &lt;span class="k"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;available/&lt;span class="p"&gt;,&lt;/span&gt; which are
        # enabled &lt;span class="nb"&gt;or&lt;/span&gt; disabled at &lt;span class="k"&gt;a&lt;/span&gt; global level&lt;span class="p"&gt;,&lt;/span&gt; it &lt;span class="k"&gt;is&lt;/span&gt; possible &lt;span class="k"&gt;to&lt;/span&gt;
        # &lt;span class="nb"&gt;include&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt; one particular virtual host&lt;span class="p"&gt;.&lt;/span&gt; For example the
        # following &lt;span class="nb"&gt;line&lt;/span&gt; enables the CGI configuration &lt;span class="k"&gt;for&lt;/span&gt; this host &lt;span class="k"&gt;only&lt;/span&gt;
        # after it &lt;span class="nb"&gt;has&lt;/span&gt; been globally disabled with &lt;span class="s2"&gt;"a2disconf"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        #Include &lt;span class="k"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;available/serve&lt;span class="p"&gt;-&lt;/span&gt;cgi&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;conf&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O arquivo parece grande, mas repare que muitas linhas começam com o caractere ‘#’. Toda linha iniciada com o ‘#’ é considerada comentário e não é lida pelo Apache. As linhas em branco também são ignoradas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: A maioria dos arquivos de configuração no Linux usa essa mesma lógica, assim, é fácil inserir textos, comentários e observações para serem lidos por pessoas e não pela máquina.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Portanto, desse arquivo, o que será efetivamente lido pelo Apache é somente isso:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-apache2.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt="Apache2.conf" width="111" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;VirtualHost *&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ServerAdmin webmaster@localhost
        DocumentRoot &lt;span class="sr"&gt;/var/&lt;/span&gt;www/html
        ErrorLog $&lt;span class="p"&gt;{&lt;/span&gt;APACHE_LOG_DIR&lt;span class="p"&gt;}&lt;/span&gt;/error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;
        CustomLog $&lt;span class="p"&gt;{&lt;/span&gt;APACHE_LOG_DIR&lt;span class="p"&gt;}&lt;/span&gt;/access&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; combined
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Uma diretiva importante na configuração do Apache é a &lt;code&gt;&amp;lt; VirtualHost &amp;gt;&lt;/code&gt;, que nos possibilita configurar o endereço do servidor que irá responder por um site e a respectiva porta. Essa diretiva é uma das mais importantes na configuração de um site no Apache. Por meio dela é possível definir o endereço pelo qual o servidor irá responder e a porta que será usada. Sites que atendem pelos protocolos HTTP (porta &lt;code&gt;80&lt;/code&gt;) e HTTPS (porta &lt;code&gt;443&lt;/code&gt;) precisarão ser definidos com duas diretivas, uma para cada porta.&lt;/p&gt;

&lt;p&gt;Uma diretiva importante de configuração do Apache é a &lt;code&gt;DocumentRoot&lt;/code&gt;, usada na definição de sites. Essa diretiva tem como objetivo indicar o diretório onde estão os arquivos que compõem determinado site. Ou seja, informa ao Apache em qual diretório do sistema está a raiz do site, ou seja, todo e qualquer recurso acessível pelo site deverá estar nesse diretório.&lt;/p&gt;
&lt;h2&gt;
  
  
  EXAMINANDO O ARQUIVO DE CONFIGURAÇÃO
&lt;/h2&gt;

&lt;p&gt;Antes de analisar o significado de cada uma dessas linhas, precisamos ter em mente qual é o objetivo dessa configuração: trata-se de uma configuração inicial, com uma página simples de demonstração, a única presente no servidor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um servidor com vários sites, existirão vários arquivos de configuração semelhantes a esse, um para cada site.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A diretiva &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; permite configurar os endereços e as portas em que o site responde. &lt;/p&gt;

&lt;p&gt;Um servidor Linux pode ser configurado com diversos endereços IP.  O Apache permite que determinados sites respondam em somente um desses endereços. É possível, por exemplo, designar um endereço IP para cada site. A desvantagem desse tipo de configuração é que você precisará de novos endereços para cada novo site, o que nem sempre é possível. &lt;/p&gt;

&lt;p&gt;A configuração mais usada hoje consiste em um único endereço IP sendo usado para atender a diversos sites. &lt;/p&gt;

&lt;p&gt;Nessa linha de &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;, o &lt;code&gt;*:80&lt;/code&gt; significa que o site responderá em todos os endereços IP do servidor e na porta &lt;code&gt;80&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Lembre-se que a porta &lt;code&gt;80&lt;/code&gt; é a padrão (&lt;em&gt;well known port&lt;/em&gt;) para o protocolo HTTP, assim como a porta &lt;code&gt;443&lt;/code&gt; é a padrão para o protocolo HTTPS. A princípio, qualquer porta pode ser utilizada pelo Apache, se já não estiver em uso por outro processo. Mas será necessário divulgar, além do endereço, o número da porta para compor a URL.&lt;/p&gt;

&lt;p&gt;Por exemplo, se for usada a porta &lt;code&gt;8000&lt;/code&gt;, a URL será: &lt;a href="http://www.meusite.com:" rel="noopener noreferrer"&gt;http://www.meusite.com:&lt;/a&gt;&lt;b&gt;8000&lt;/b&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ErrorLog /var/log/apache/error.log&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A diretiva &lt;code&gt;ErrorLog&lt;/code&gt; define em que arquivo serão gravados os registros (logs) de erro. A cada erro ocorrido, uma nova linha é gerada nesse arquivo, com as informações sobre ele, além de data e hora.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ServerAdmin webmaster@localhost&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Informação que será passada a um cliente em caso de erro no acesso ao site, contendo um e-mail para contato.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;CustomLog /var/log/apache/access.log combined&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A diretiva &lt;code&gt;CustomLog&lt;/code&gt; define em que arquivo serão gravados os registros de acesso aos sites. O parâmetro &lt;code&gt;combined&lt;/code&gt; define um formato predeterminado para esses registros.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;DocumentRoot /var/www/html&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Uma das configurações mais importantes de um site é onde está seu conteúdo. Nesse caso, o diretório &lt;code&gt;/var/www/html&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A DIRETIVA &lt;code&gt;DIRECTORYINDEX&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;O acesso a um site é sempre feito por meio de uma URL (Uniform Resource Locator) digitada no navegador. A URL é, em resumo, uma frase que contém todas as informações para localizar um recurso como site ou arquivo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: &lt;a href="http://site-exemplo.com/info.html" rel="noopener noreferrer"&gt;http://site-exemplo.com/info.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nessa URL constam o protocolo (HTTP), o endereço do site (&lt;code&gt;site-exemplo.com&lt;/code&gt;) e o nome do recurso procurado (&lt;code&gt;info.html&lt;/code&gt;). O cliente (navegador) se conecta ao servidor do site e requisita o recurso &lt;code&gt;info.html&lt;/code&gt;. Nesse exemplo, o servidor Apache buscaria o arquivo &lt;code&gt;info.html&lt;/code&gt; no diretório do site e o enviaria ao cliente.&lt;/p&gt;

&lt;p&gt;Muitas vezes, porém, usamos uma URL sem indicar um recurso, como em &lt;code&gt;http://site-exemplo.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nesses casos, como o Apache sabe que arquivo buscar?&lt;/p&gt;

&lt;p&gt;Para esta função, há a diretiva &lt;code&gt;DirectoryIndex&lt;/code&gt;, que permite definir um ou mais arquivos que serão procurados pelo Apache, em ordem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: &lt;code&gt;DirectoryIndex principal.html&lt;/code&gt; define o nome do arquivo a ser procurado.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DirectoryIndex principal.html opcional.html&lt;/code&gt; o Apache procurará o arquivo &lt;code&gt;principal.html&lt;/code&gt;. Se não encontrar, irá procurar o &lt;code&gt;opcional.html&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Na ausência dessa diretiva, o Apache assume como padrão o arquivo &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://play.yduqs.videolib.live/index.html?token=4118b3a8b85f439c8b4cd63d306e8e0e" rel="noopener noreferrer"&gt;CONFIGURANDO DOIS SITES (Múltiplos)&lt;/a&gt; NO MESMO SERVIDOR APACHE
&lt;/h2&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F199121160-c169c713-3206-4344-a25a-b6e6a8c075b4.jpg" width="800" height="450"&gt;&lt;br&gt;

&lt;p&gt;Atualmente, é muito comum um servidor hospedar diversos sites independentes utilizando somente um endereço IP (&lt;code&gt;192.168.0.30&lt;/code&gt;). A diretiva &lt;code&gt;Servername&lt;/code&gt; permite determinar na configuração do site o nome (domínio) pelo qual ele responderá.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas é importante lembrar que o cliente deverá conseguir resolver esse nome, assim, não basta configurar o Apache para responder por ele, também é preciso registrá-lo em um &lt;a href=""&gt;servidor DNS&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos simular a configuração de dois sites em um servidor Apache?&lt;/p&gt;

&lt;p&gt;Na tabela a seguir, relacionaremos todas as informações necessárias para a configuração:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;/td&gt;
    &lt;td&gt;Site A&lt;/td&gt;
    &lt;td&gt;Site B&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;Nome (domínio) do site&lt;/td&gt;
    &lt;td&gt;www.site-test1.com&lt;/td&gt;
    &lt;td&gt;www.site-teste2.com&lt;/td&gt;
  &lt;/tr&gt;
  
  &lt;tr&gt;
    &lt;td&gt;Diretório com o conteúdo do site&lt;/td&gt;
    &lt;td&gt;/var/www/site-teste1&lt;/td&gt;
    &lt;td&gt;/var/www/site-teste2&lt;/td&gt;
  &lt;/tr&gt;
    
  &lt;tr&gt;
    &lt;td&gt;Arquivo "principal" (DirectoryIndex)&lt;/td&gt;
    &lt;td&gt;index.html&lt;/td&gt;
    &lt;td&gt;default.htm&lt;/td&gt;
  &lt;/tr&gt;
    
  &lt;tr&gt;
    &lt;td&gt;Arquivo de configuração (/etc/apache2/sites-available)&lt;/td&gt;
    &lt;td&gt;site-teste1.conf&lt;/td&gt;
    &lt;td&gt;site-teste2.conf&lt;/td&gt;
  &lt;/tr&gt;
  
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Criando os diretórios para os sites
&lt;/h3&gt;

&lt;p&gt;Também é necessário colocar o conteúdo. Nesse exemplo, copiaremos o arquivo de demonstração (&lt;code&gt;/var/www/html/index.html&lt;/code&gt;) para este fim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; /var/www/site-teste1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /var/www/html/index.html /var/www/site-teste1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; /var/www/site-teste2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /var/www/html/index.html /var/www/site-teste2/default.htm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que, no segundo exemplo, o arquivo foi copiado mudando o nome para &lt;code&gt;default.htm&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lembre-se&lt;/strong&gt;: O nome e o caminho do arquivo HTML de demonstração, que usamos como base, variam conforme a distribuição Linux. Qualquer arquivo HTML pode ser usado como conteúdo nesse teste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: O Apache é executado por um usuário com poucos privilégios. O nome do usuário varia com a distribuição Linux: &lt;code&gt;www-data&lt;/code&gt;, &lt;code&gt;apache&lt;/code&gt; etc. É importante que os arquivos nos diretórios dos sites (&lt;code&gt;/var/www/site-teste1&lt;/code&gt; etc.) possam ser lidos pelo usuário do Apache. Uma opção é garantir que os arquivos possuam permissão de leitura para outros e os diretórios, permissões de leitura &lt;code&gt;r&lt;/code&gt; e de acesso &lt;code&gt;x&lt;/code&gt; também para outros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando os arquivos de configuração para os sites
&lt;/h3&gt;

&lt;p&gt;Usando um editor de textos, como o Vim ou nano, criamos o arquivo &lt;code&gt;/etc/apache2/sites-available/site-teste1.conf&lt;/code&gt; e o preenchemos com o seguinte conteúdo:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-site_teste1.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt="Apache2.conf" width="121" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;VirtualHost *&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ServerName www&lt;span class="p"&gt;.&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;
        ServerAdmin webmaster@site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;
        DocumentRoot &lt;span class="sr"&gt;/var/&lt;/span&gt;www/site&lt;span class="p"&gt;-&lt;/span&gt;teste1
        DirectoryIndex &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;html
        ErrorLog &lt;span class="sr"&gt;/var/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="sr"&gt;/apache2/&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;-&lt;/span&gt;error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;
        CustomLog &lt;span class="sr"&gt;/var/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="sr"&gt;/apache2/&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;-&lt;/span&gt;access&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; combined
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do mesmo modo, criamos o arquivo &lt;code&gt;/etc/apache2/sites-available/site-teste2.conf&lt;/code&gt; e o preenchemos:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-site_teste2.conf-fff%3Fstyle%3Dsocial%26logo%3DApache%26logoColor%3DD22128" alt="Apache2.conf" width="121" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;VirtualHost *&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ServerName www&lt;span class="p"&gt;.&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;
        ServerAdmin webmaster@site&lt;span class="p"&gt;-&lt;/span&gt;teste2&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;
        DocumentRoot &lt;span class="sr"&gt;/var/&lt;/span&gt;www/site&lt;span class="p"&gt;-&lt;/span&gt;teste2
        DirectoryIndex &lt;span class="nb"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;html
        ErrorLog &lt;span class="sr"&gt;/var/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="sr"&gt;/apache2/&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;-&lt;/span&gt;error&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;
        CustomLog &lt;span class="sr"&gt;/var/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="sr"&gt;/apache2/&lt;/span&gt;site&lt;span class="p"&gt;-&lt;/span&gt;teste1&lt;span class="p"&gt;-&lt;/span&gt;access&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; combined
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;/VirtualHost&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Habilitando os sites
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2ensite site-teste1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2ensite site-teste2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enviando um sinal para o Apache reler as configurações
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apache2ctl graceful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É possível acessar os novos sites a partir de um navegador, simulando o acesso de um usuário comum. Isso poderá ser feito a partir de um computador executando o sistema operacional Windows.&lt;/p&gt;

&lt;p&gt;No entanto, é preciso que o navegador consiga resolver os nomes dos sites para o endereço do servidor Apache. Como os domínios dos sites que criamos não existem na internet, será necessário “enganar” o Windows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O procedimento a seguir deve ser feito com cautela, pois pode causar danos ao Windows. Será necessário que o usuário tenha permissão de administrador do sistema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Execute o editor notepad como administrador.&lt;/li&gt;
&lt;li&gt;Abra o arquivo &lt;code&gt;C:\Windows\System32\drivers\etc\HOSTS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inclua as seguintes linhas, trocando o endereço IP pelo endereço IP do servidor Apache que você obteve com o comando &lt;code&gt;ip addr&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.70 www.site-teste1.com
192.168.1.70 www.site-teste2.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Salve o arquivo. Não se esqueça de desfazer essa configuração após terminar seus testes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa alteração fará com que o Windows reconheça os endereços dos novos sites, mesmo que eles não existam na internet.&lt;/p&gt;

&lt;p&gt;No seu computador com Windows, abra um navegador de sua preferência. Digite os sites configurados: &lt;a href="http://www.site-teste1.com" rel="noopener noreferrer"&gt;www.site-teste1.com&lt;/a&gt; e &lt;a href="http://www.site-teste2.com" rel="noopener noreferrer"&gt;www.site-teste2.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Os dois sites serão exibidos da mesma maneira, pois o conteúdo é o mesmo, obtido na página de demonstração. Mesmo sem conhecer HTML, edite esses arquivos e faça uma pequena alteração no texto deles. Recarregue as páginas no seu navegador e veja as alterações. Confira alguns exemplos e aproveite para praticar!&lt;/p&gt;

&lt;h3&gt;
  
  
  Prática 1 - Apache2
&lt;/h3&gt;

&lt;p&gt;Na configuração dos sites, indicamos arquivos de log em que o Apache incluirá os registros de acessos, um por linha:&lt;/p&gt;

&lt;p&gt;Busque esses arquivos e veja o seu conteúdo. Observe o formato e as informações que ele contém. Você pode usar o comando &lt;code&gt;less ARQUIVO&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Prática 2 - Apache2
&lt;/h3&gt;

&lt;p&gt;Vamos acessar um recurso que não existe no servidor e veremos o que acontece:&lt;/p&gt;

&lt;p&gt;No seu navegador, busque um recurso inexistente no site. Por exemplo, digite a URL: &lt;code&gt;http://www.site-teste1.com/abc.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Como não existe um recurso com o nome &lt;code&gt;abc.html&lt;/code&gt;, o Apache retornará uma página com o conhecido &lt;code&gt;erro 404&lt;/code&gt; (recurso não encontrado). &lt;/p&gt;

&lt;h3&gt;
  
  
  Habilitanto o HTTPS - Apache2
&lt;/h3&gt;

&lt;p&gt;Uma limitação do protocolo HTTP é que ele não conta com a criptografia dos dados para tráfegos, sendo possível que um terceiro consiga interceptar as informações transmitidas e até modificá-las. Para resolver essa fragilidade, foi criado o protocolo HTTPS que é, basicamente, o protocolo HTTP com uma camada adicional de criptografia.&lt;/p&gt;

&lt;p&gt;Atualmente, é considerado obrigatório que um site utilize o HTTPS se transmite dados pessoais de um usuário, solicita senhas, cartão de crédito etc.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;HTTPS&lt;/strong&gt; é simples de configurar no Apache, mas pode parecer complicado porque se baseia em &lt;strong&gt;certificação digital&lt;/strong&gt; e são necessárias algumas ações, além da simples configuração de um arquivo.&lt;/p&gt;

&lt;p&gt;Em poucas palavras, o &lt;strong&gt;certificado digital&lt;/strong&gt; é como um documento autenticado no cartório, afirmando que você é realmente quem diz ser. O cartório desse exemplo são as autoridades certificadoras (CA).&lt;/p&gt;

&lt;p&gt;O processo de obtenção de um certificado deve seguir alguns passos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criação das chaves criptográficas (pública e privada). &lt;/li&gt;
&lt;li&gt;Elaboração da requisição de certificado (CSR).&lt;/li&gt;
&lt;li&gt;Envio da requisição (CSR) a uma autoridade certificadora (CA).&lt;/li&gt;
&lt;li&gt;Emissão do certificado pela autoridade certificadora (CA).&lt;/li&gt;
&lt;li&gt;Instalação do certificado digital emitido pela autoridade certificadora (CA). &lt;/li&gt;
&lt;li&gt;É importante lembrar que a maioria das autoridades certificadoras cobra pelo serviço, já que precisa realizar verificações de segurança. O valor varia dependendo do tipo de certificado solicitado e da autoridade certificadora. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos habilitar o protocolo HTTPS no site &lt;code&gt;www.site-teste1.com&lt;/code&gt;. Nessa atividade, assumiremos o papel da autoridade certificadora, gerando um certificado do tipo &lt;strong&gt;self­-signed&lt;/strong&gt; (assinado por mim). Na prática, esse tipo de certificado não é reconhecido por nenhum navegador e sempre será exibido um aviso de segurança. &lt;/p&gt;

&lt;p&gt;Lembre-se de que esse é um procedimento simplificado, pois nosso objetivo é a configuração do Apache. Sempre que for gerar um certificado, leia as instruções da autoridade certificadora escolhida, que costuma disponibilizar procedimentos detalhados.&lt;/p&gt;

&lt;p&gt;Para gerar nosso &lt;strong&gt;certificado self-signed&lt;/strong&gt;, usaremos o comando a seguir (tudo em uma única linha):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:2048 &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-keyout&lt;/span&gt; /etc/ssl/private/site-teste1.key &lt;span class="nt"&gt;-out&lt;/span&gt; /etc/ssl/certs/site-teste1.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o comando &lt;code&gt;openssl&lt;/code&gt; não for encontrado, será necessário instalar esse pacote de software. Verifique a documentação da distribuição Linux que estiver usando.&lt;/p&gt;

&lt;p&gt;Por exemplo: No Ubuntu Linux, a instalação é feita com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openssl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando &lt;code&gt;openssl&lt;/code&gt; é uma ferramenta para gerenciamento, entre outras coisas, de chaves criptográficas. Nessa única linha estamos gerando as chaves (criptografia RSA de 2048 bits), preparando a requisição e emitindo um certificado com 365 dias de validade.&lt;/p&gt;

&lt;p&gt;Chegou o momento de entrar com os dados do novo certificado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Country Name (2 letter code) [AU]:BR
State or Province Name (full name) [Some-State]:Rio de Janeiro
Locality Name (eg, city) []:Nome da cidade
Organization Name (eg, company) []:Minha Empresa LTDA
Organizational Unit Name (eg, section) []:Departamento de TI
Common Name (e.g. server FQDN or YOUR name) []:www.site-teste1.com
Esse é o endereço do seu site.
Email Address []: Não é necessário preencher o e-mail.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao término, dois arquivos são gerados nos caminhos indicados: a chave criptográfica e o certificado digital. Nesse exemplo foram escolhidos os diretórios &lt;code&gt;/etc/ssl/private&lt;/code&gt; e &lt;code&gt;/etc/ssl/certs&lt;/code&gt;, padrão na distribuição Ubuntu, porém você pode criar outro diretório para esses arquivos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: O arquivo &lt;code&gt;site-teste1.key&lt;/code&gt; contém a chave privada do seu certificado e deve ser protegido ao máximo, pois um invasor será capaz de decifrar a comunicação do servidor, além de forjar um site com o mesmo domínio. É recomendável que o arquivo possua proprietário e grupo &lt;code&gt;root&lt;/code&gt; e permissão do tipo &lt;code&gt;400&lt;/code&gt; ou &lt;code&gt;600&lt;/code&gt;. Sempre confira a segurança das suas chaves privadas!&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;chave pública&lt;/strong&gt; está armazenada junto ao certificado digital, e ambos são entregues aos usuários quando se conectam ao servidor.&lt;/p&gt;

&lt;p&gt;O próximo passo é configurar o Apache:&lt;/p&gt;

&lt;p&gt;Habilite o módulo de ssl do Apache (SSL é a camada criptográfica usada pelo HTTPS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;a2enmod ssl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inclua o seguinte conteúdo no final do arquivo de configuração, sem modificar o conteúdo que já existe (&lt;code&gt;/etc/apache2/sites-available/site-teste1.conf&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt; &lt;span class="err"&gt;*:443&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
ServerName www.site-teste1.com 
ServerAdmin webmaster@site-teste1.com
DocumentRoot /var/www/site-teste1
DirectoryIndex index.html
ErrorLog /var/log/apache2/site-teste1-error.log
CustomLog /var/log/apache2/site-teste1-access.log combined

SSLEngine on
SSLCertificateFile      /etc/ssl/certs/site-teste1.crt
SSLCertificateKeyFile /etc/ssl/private/site-teste1.key 
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que é um conjunto de diretivas iguais às já existentes com quatro diferenças: a primeira é a porta &lt;code&gt;443&lt;/code&gt; na diretiva &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; – lembrando que o &lt;strong&gt;protocolo HTTPS tem porta padrão 443&lt;/strong&gt;; as outras são as três últimas linhas, onde a diretiva &lt;code&gt;SSLEngine&lt;/code&gt; ativa o uso da camada SSL e as demais indicam onde estão a chave e o certificado digital.&lt;/p&gt;

&lt;p&gt;Carregue a nova configuração no Apache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apache2ctl graceful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203377361-d11b1a75-8c81-4e3a-b1f0-94a39a27d953.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203377361-d11b1a75-8c81-4e3a-b1f0-94a39a27d953.jpg" width="324" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acesse o site: &lt;code&gt;https://www.site-teste1.com&lt;/code&gt;. (Atenção ao https)&lt;/p&gt;

&lt;p&gt;Uma mensagem de segurança será exibida, afinal o certificado não foi emitido por uma CA conhecida e confiável. Selecione a opção para acessar assim mesmo. Você deverá ver o seu site. A diferença é que agora toda a comunicação ocorreu por um canal criptografado.&lt;/p&gt;

&lt;p&gt;No navegador, peça para exibir o certificado digital do site e veja os dados que foram digitados na requisição:&lt;/p&gt;

&lt;p&gt;Repita o procedimento e habilite o HTTPS também para o domínio &lt;code&gt;www.site-teste2.com&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  REFERÊNCIAS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;APACHE HTTP SERVER PROJECT. Documentação do servidor HTTP Apache versão 2.4. Consultado em meio eletrônico em: 17 jul. 2020.&lt;/li&gt;
&lt;li&gt;MAXWELL, S. Administração de sistemas Unix. 1. ed. Rio de Janeiro: Ciência Moderna, 2003.&lt;/li&gt;
&lt;li&gt;MOTA FILHO, J. Descobrindo o Linux: Entenda o Sistema Operacional GNU/Linux. 3. ed. São Paulo: Novatec, 2012.&lt;/li&gt;
&lt;li&gt;PETERSEN, R. Ubuntu 18.04 LTS Server: Administration and Reference. 1. ed. Surfing Turtle Press, 2018. &lt;/li&gt;
&lt;li&gt;UBUNTU SERVER GUIDE.  HTTPD Apache2 Web server. Consultado em meio eletrônico em: 17 jul. 2020.\&lt;/li&gt;
&lt;li&gt;UBUNTU DOCUMENTATION. Ubuntu desktop guide. Consultado em meio eletrônico em: 17 jul. 2020.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>distributedsystems</category>
      <category>asf</category>
    </item>
    <item>
      <title>TAXONOMIA DE FLYNN: Computação Paralela</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 21:22:20 +0000</pubDate>
      <link>https://forem.com/isaacalves7/taxonomia-de-flynn-computacao-paralela-45jb</link>
      <guid>https://forem.com/isaacalves7/taxonomia-de-flynn-computacao-paralela-45jb</guid>
      <description>&lt;p&gt;A &lt;strong&gt;computação paralela&lt;/strong&gt; (Parallel Computing) é uma computação em que os trabalhos são divididos em partes discretas que podem ser executadas simultaneamente. Cada parte é subdividida em uma série de instruções. As instruções de cada parte são executadas simultaneamente em CPUs diferentes. Os &lt;strong&gt;sistemas paralelos&lt;/strong&gt; lidam com o uso simultâneo de vários recursos de computador que podem incluir um único computador com vários processadores, vários computadores conectados por uma rede para formar um &lt;strong&gt;cluster de processamento paralelo&lt;/strong&gt; ou &lt;strong&gt;uma combinação de ambos&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Os &lt;strong&gt;sistemas paralelos&lt;/strong&gt; são mais difíceis de programar do que os computadores com um único processador, porque a arquitetura dos computadores paralelos varia de acordo com os recursos disponíveis, sendo assim, os processos de várias CPUs devem ser coordenados e sincronizados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A primeira descrição formal desse tipo de abordagem foi a &lt;strong&gt;taxonomia de Flynn&lt;/strong&gt;. Essa taxonomia foi desenvolvida em 1966 e ligeiramente expandida em 1972:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;É uma metodologia para classificar formas gerais de operação paralela disponíveis em um processador.&lt;/li&gt;
&lt;li&gt;Propõe uma abordagem para esclarecer os tipos de paralelismo suportados no hardware por um sistema de processamento ou disponíveis em uma aplicação.&lt;/li&gt;
&lt;li&gt;Sua classificação é baseada na visão da máquina ou do aplicativo pelo programador de linguagem de máquina (machine code).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203384851-8f5d4a2d-4bb6-47e9-900d-398a1d223b91.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203384851-8f5d4a2d-4bb6-47e9-900d-398a1d223b91.jpg" width="438" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A taxonomia de Flynn é uma categorização de formas de arquiteturas de computador paralelas.&lt;/p&gt;

&lt;p&gt;Do ponto de vista do programador de linguagem assembly (linguagem de montagem), os &lt;strong&gt;computadores paralelos&lt;/strong&gt; são classificados pela simultaneidade em &lt;strong&gt;sequências de processamento&lt;/strong&gt; (ou &lt;strong&gt;fluxos&lt;/strong&gt;), &lt;strong&gt;dados&lt;/strong&gt; e &lt;strong&gt;instruções&lt;/strong&gt;. Isso resulta em quatro classes: &lt;strong&gt;SISD&lt;/strong&gt; (instrução única, dados únicos), &lt;strong&gt;SIMD&lt;/strong&gt; (instrução única, dados múltiplos), &lt;strong&gt;MISD&lt;/strong&gt; (instrução múltipla, dados únicos) e &lt;strong&gt;MIMD&lt;/strong&gt; (instrução múltipla, dados múltiplos).&lt;/p&gt;

&lt;p&gt;A taxonomia de Flynn pode ser sumarizada de forma ilustrativa segundo a imagem a seguir.&lt;/p&gt;

&lt;h2&gt;
  
  
  SISTEMAS DE INSTRUÇÃO ÚNICA E DADOS ÚNICOS (SINGLE-INSTRUCTION, SINGLE-DATA – SISD)
&lt;/h2&gt;

&lt;p&gt;Um &lt;strong&gt;sistema de computação de instrução única e dados únicos&lt;/strong&gt; (&lt;strong&gt;Single-Instruction&lt;/strong&gt;, &lt;strong&gt;Single-Data – SISD&lt;/strong&gt;) é uma máquina de &lt;strong&gt;um processador&lt;/strong&gt; que é capaz de executar &lt;strong&gt;uma única instrução&lt;/strong&gt;, &lt;strong&gt;operando em um único fluxo de dados&lt;/strong&gt;, como se observa na imagem seguinte.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203386451-98ca0a46-c545-4f5c-ad03-3f32c7404b29.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203386451-98ca0a46-c545-4f5c-ad03-3f32c7404b29.jpg" width="292" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;SISD&lt;/strong&gt;, as instruções de máquina são &lt;strong&gt;processadas de maneira sequencial&lt;/strong&gt;, e os computadores que adotam esse modelo são popularmente chamados de &lt;strong&gt;computadores sequenciais&lt;/strong&gt;. A maioria dos computadores convencionais derivados da proposição de Von Neumann possui arquitetura SISD. Todas as instruções e dados a serem processados devem ser armazenados na memória primária.&lt;/p&gt;

&lt;p&gt;A velocidade do elemento de processamento no modelo SISD é limitada (dependente) pela taxa por meio da qual o computador pode transferir informações internamente. Os sistemas SISD representativos dominantes são &lt;strong&gt;IBM PC&lt;/strong&gt; e &lt;strong&gt;estações de trabalho&lt;/strong&gt;, entre outros.&lt;/p&gt;

&lt;h2&gt;
  
  
  SISTEMAS DE INSTRUÇÃO ÚNICA E DADOS MÚLTIPLOS (SINGLE-INSTRUCTION, MULTIPLE-DATA – SIMD)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203391088-0bc6f480-8276-46a8-8666-451cd5a70d9e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203391088-0bc6f480-8276-46a8-8666-451cd5a70d9e.jpg" width="328" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;sistema SIMD&lt;/strong&gt; é uma &lt;strong&gt;máquina multiprocessada&lt;/strong&gt; capaz de executar a &lt;strong&gt;mesma instrução em todas as CPUs&lt;/strong&gt;, mas &lt;strong&gt;operando em diferentes fluxos de dados&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As máquinas baseadas em um modelo SIMD são adequadas para &lt;strong&gt;computação científica&lt;/strong&gt;, pois envolvem muitas operações de vetor e matriz. Para que a informação possa ser passada para todos os elementos de processamento (Processing Elements – PEs), os elementos de dados organizados dos vetores podem ser divididos em vários conjuntos (N-conjuntos para sistemas N PE) e cada PE pode processar um conjunto de dados. Veja a imagem a seguir.&lt;/p&gt;

&lt;p&gt;Os sistemas SIMD representativos são, por exemplo, &lt;strong&gt;máquinas de processamento vetorial da Cray&lt;/strong&gt; e as &lt;strong&gt;Unidades de Processamento Gráfico&lt;/strong&gt;, as famosas &lt;strong&gt;placas de vídeo&lt;/strong&gt; (Graphical Processing Unit – GPU).&lt;/p&gt;

&lt;h2&gt;
  
  
  SISTEMAS DE INSTRUÇÃO MÚLTIPLA E DADOS ÚNICOS (MULTIPLE-INSTRUCTION, SINGLE-DATA – MISD)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203446240-4509037e-d362-4cc2-a8a4-c73c4544be94.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203446240-4509037e-d362-4cc2-a8a4-c73c4544be94.jpg" width="329" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;sistema de computação MISD&lt;/strong&gt; é uma &lt;strong&gt;máquina multiprocessada&lt;/strong&gt; capaz de executar diferentes instruções em diferentes PEs, mas todas operando no mesmo conjunto de dados, conforme a próxima imagem.&lt;/p&gt;

&lt;p&gt;O sistema executa diferentes operações no mesmo conjunto de dados. As máquinas construídas usando o modelo MISD não são úteis na maioria das aplicações, algumas máquinas são construídas, mas nenhuma delas está disponível comercialmente.&lt;/p&gt;

&lt;h2&gt;
  
  
  SISTEMAS DE MÚLTIPLAS INSTRUÇÕES E MÚLTIPLOS DADOS (MULTIPLE-INSTRUCTION, MULTIPLE-DATA – MIMD)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203448492-4650ed05-f9ed-4198-af9b-286f619e0424.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203448492-4650ed05-f9ed-4198-af9b-286f619e0424.jpg" width="596" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;sistema de múltiplas instruções e múltiplos dados&lt;/strong&gt; (&lt;strong&gt;MIMD&lt;/strong&gt;) é &lt;strong&gt;uma máquina com multiprocessador&lt;/strong&gt; capaz de executar &lt;strong&gt;várias instruções em vários conjuntos de dados&lt;/strong&gt;, conforme a imagem a seguir.&lt;/p&gt;

&lt;p&gt;Cada PE no modelo MIMD tem instruções e fluxos de dados separados, portanto, as máquinas construídas a partir desse modelo suportam qualquer tipo de aplicação. Ao contrário das máquinas SIMD e MISD, os PEs em máquinas MIMD funcionam de forma assíncrona.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: As &lt;strong&gt;máquinas MIMD&lt;/strong&gt; são amplamente categorizadas em MIMD de memória compartilhada e MIMD de memória distribuída com base na maneira como os PEs são acoplados à memória principal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No modelo MIMD de &lt;strong&gt;memória compartilhada&lt;/strong&gt; (sistemas multiprocessadores &lt;strong&gt;fortemente&lt;/strong&gt; acoplados), todos os PEs são conectados a uma única memória global e todos têm acesso a ela. A comunicação entre os PEs nesse modelo ocorre por meio da memória compartilhada, e a modificação dos dados armazenados na memória global por um PE é visível para todos os outros PEs. Os sistemas MIMD representativos dominantes de memória compartilhada são as &lt;strong&gt;máquinas Silicon Graphics&lt;/strong&gt; e &lt;strong&gt;SMP&lt;/strong&gt; (Symmetric Multi-Processing) da &lt;strong&gt;Sun / IBM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em máquinas MIMD de &lt;strong&gt;memória distribuída&lt;/strong&gt; (sistemas multiprocessadores &lt;strong&gt;fracamente&lt;/strong&gt; acoplados), todos os PEs têm uma memória local. A comunicação entre PEs nesse modelo ocorre por meio da &lt;strong&gt;rede de interconexão&lt;/strong&gt; (o canal de comunicação entre processos, ou &lt;strong&gt;IPC&lt;/strong&gt;). A rede que conecta os PEs pode ser configurada em &lt;strong&gt;árvore&lt;/strong&gt;, &lt;strong&gt;malha&lt;/strong&gt; ou de acordo com o requisito.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Árvore&lt;/strong&gt; (Tree): A topologia de rede em árvore é uma topologia que possibilita a visualização da interligação de várias redes e sub-redes, caracterizando-se pela presença de um concentrador que interliga todos os &lt;strong&gt;nodos&lt;/strong&gt; (nós - nodes) (computadores, servidores, PEs etc.) de uma rede local, enquanto outro concentrador interliga as demais redes, interligando dessa forma um conjunto de redes locais (LAN) e fazendo com que estas sejam dispostas no formato de árvore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Malha&lt;/strong&gt; (Mesh): A topologia de rede em malha consiste em uma topologia de rede de computadores onde cada nodo da rede (computador, servidor, PE etc.) está conectado aos demais diretamente, o que possibilita que todos os nodos da rede sejam capazes de trocar informações diretamente com todos os demais. Nessa topologia, a informação pode ser transmitida da origem ao destino por diversos meios ou caminhos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A arquitetura MIMD de memória compartilhada é mais fácil de programar, mas é menos tolerante a falhas e mais difícil de estender em relação ao modelo MIMD de memória distribuída.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Falhas em um &lt;strong&gt;MIMD de memória compartilhada&lt;/strong&gt; afetam todo o sistema, ao passo que este não é o caso do modelo distribuído, no qual cada um dos PEs pode ser facilmente isolado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Além disso, as arquiteturas MIMD de memória compartilhada têm menos probabilidade de serem escaláveis porque a adição de mais PEs leva à contenção de memória, situação que não ocorre no caso da memória distribuída, em que cada PE possui sua própria memória. Por causa dos resultados práticos e requisitos do usuário, a arquitetura de memória distribuída MIMD é superior aos outros modelos existentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  LEI DE AMDAHL E SPEEDUP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F03fe1651-1737-436c-9b78-ef3e916d17d8" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F03fe1651-1737-436c-9b78-ef3e916d17d8" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando buscamos o paralelismo da execução de instruções, desejamos que o nosso sistema realize suas tarefas da forma mais rápida possível. Entretanto, existe um limite teórico para a execução dessas tarefas, e ele é determinado pela &lt;strong&gt;lei de Amdahl&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Que no caso é a resolução de um simples problema, nós temos o nosso ganho, que é 1 dividido pelo Sequencial do programa + a diferença (1 - Sequencial, ou seja o percentual do meu programa que é paralelizável), dividido pela quantidade de processadores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F562536a0-e4c8-4505-a13a-9c33c32a7eff" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F562536a0-e4c8-4505-a13a-9c33c32a7eff" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: A lei de Amdahl afirma que podemos paralelizar e/ou distribuir nossos cálculos tanto quanto quisermos, ganhando em desempenho à medida que adicionamos recursos de computação. No entanto, nosso código não pode ser mais rápido do que a velocidade de suas partes sequenciais combinadas (ou seja, não paralelizáveis) em um único processador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos ver um exemplo de problema: Suponhamos que 80% do nosso programa não podemos paralelizarm então:&lt;/p&gt;

&lt;p&gt;Colocado de modo mais formal, a lei de Amdahl tem a seguinte formulação.&lt;/p&gt;

&lt;p&gt;Dado um algoritmo que é parcialmente paralelo, vamos chamar &lt;em&gt;&lt;code&gt;P&lt;/code&gt;&lt;/em&gt; sua &lt;strong&gt;fração paralela&lt;/strong&gt; e &lt;em&gt;&lt;code&gt;S&lt;/code&gt;&lt;/em&gt; sua &lt;strong&gt;fração serial&lt;/strong&gt; (&lt;em&gt;&lt;code&gt;S&lt;/code&gt;&lt;/em&gt; &lt;code&gt;+&lt;/code&gt; &lt;em&gt;&lt;code&gt;P&lt;/code&gt;&lt;/em&gt; &lt;code&gt;= 100%&lt;/code&gt;). Além disso, chamemos &lt;em&gt;&lt;code&gt;T&lt;/code&gt;&lt;/em&gt;&lt;code&gt;(n)&lt;/code&gt; o &lt;strong&gt;tempo de execução&lt;/strong&gt; (em segundos) do algoritmo ao usar &lt;em&gt;&lt;code&gt;n&lt;/code&gt;&lt;/em&gt; processadores.&lt;/p&gt;

&lt;p&gt;Então, a seguinte relação se mantém:&lt;/p&gt;

&lt;pre&gt;
T(n) ≥ S . T(1) + P . T(1) / n
&lt;/pre&gt;

&lt;p&gt;A relação anterior afirma o seguinte:&lt;/p&gt;

&lt;p&gt;O tempo de execução do algoritmo descrito aqui em n processadores é igual — e geralmente maior — do que o tempo de execução de sua parte serial em um processador (isto é, &lt;code&gt;S.T(1)&lt;/code&gt;) mais o tempo de execução de sua parte paralela em um processador (ou seja, &lt;code&gt;P.T(1)&lt;/code&gt;) dividido por n (número de processadores).&lt;/p&gt;

&lt;p&gt;À medida que aumentamos o número n de processadores usados por nosso código, o segundo termo da equação fica cada vez menor, tornando-se insignificante em relação ao primeiro termo. Nesses casos, a relação anterior simplesmente se torna esta:&lt;/p&gt;

&lt;pre&gt;
T(∞) ≈ S.T(1)
&lt;/pre&gt;

&lt;p&gt;A tradução dessa relação pode ser interpretada da seguinte forma:&lt;/p&gt;

&lt;p&gt;O tempo de execução do algoritmo descrito aqui em um número infinito de processadores (ou seja, um número realmente grande de processadores) é aproximadamente igual ao tempo de execução de sua parte serial em um único processador (ou seja, &lt;code&gt;S.T(1)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Agora, vamos parar por um segundo e pensar sobre as implicações da lei de Amdahl. O que temos aqui é uma observação bastante simples: muitas vezes, não podemos paralelizar totalmente nossos algoritmos.&lt;/p&gt;

&lt;p&gt;O que significa que, na maioria das vezes, não podemos ter &lt;code&gt;S = 0&lt;/code&gt; nas relações anteriores. As razões para isso são inúmeras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copiar dados e/ou código para onde os vários processadores serão capazes de acessá-los.&lt;/li&gt;
&lt;li&gt;Dividir os dados em pedaços e mover esses pedaços pela rede.&lt;/li&gt;
&lt;li&gt;Coletar os resultados de todas as tarefas simultâneas e executar algum processamento adicional nelas, e assim por diante.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Seja qual for o motivo, se não pudermos paralelizar totalmente o algoritmo, eventualmente o tempo de execução do código será dominado pelo desempenho da fração serial. Não apenas isso, mas mesmo antes que aconteça, começaremos a ver acelerações cada vez menores do que o esperado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como uma observação lateral, algoritmos que são totalmente paralelos são geralmente chamados de “&lt;strong&gt;embaraçosamente paralelos&lt;/strong&gt;” e oferecem propriedades de escalabilidade impressionantes (com acelerações geralmente lineares com o número de processadores). É claro que não há nada de constrangedor nesses softwares. Porém, infelizmente, eles não são tão comuns quanto gostaríamos.&lt;/p&gt;

&lt;p&gt;Como a execução paralela dos algoritmos pode realmente fazer com que a tarefa seja executada de forma mais rápida, temos de mensurar esse ganho, o que chamamos de &lt;strong&gt;speedup&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O &lt;strong&gt;speedup&lt;/strong&gt; é definido como a razão entre o tempo de execução serial do melhor algoritmo sequencial para resolver um problema e o tempo gasto pelo algoritmo paralelo para resolver o mesmo problema com &lt;em&gt;&lt;code&gt;p&lt;/code&gt;&lt;/em&gt; processadores.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É simplesmente a razão entre o tempo gasto com uma execução serial dividido pelo tempo gasto pela execução paralela, conforme podemos ver na fórmula a seguir.&lt;/p&gt;

&lt;pre&gt;
Speedup = Temposerial / TempoParalelo = T8 / Tp
&lt;/pre&gt;

&lt;p&gt;Vamos tentar visualizar toda a lei de Amdahl, bem como o speedup associado com alguns números.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suponha que o algoritmo leve 100 segundos para ser executado em um único processador.&lt;/li&gt;
&lt;li&gt;Vamos supor também que podemos paralelizar 99% disso, o que seria uma façanha incrível, na maioria das vezes.&lt;/li&gt;
&lt;li&gt;Podemos tornar o código mais rápido aumentando o número de processadores que usamos, conforme esperado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Veja o cálculo:&lt;/p&gt;

&lt;pre&gt;
T(1) = 100s
T(10) ≈ 0,01 . 100s + 0,99*100s / 10 = 10,9s =&amp;gt; Speedup = 100/10,9 = 9,2x
T(100) ≈ 1s + 0,99s = 1,99s ===&amp;gt; Speedup = 100/1,99 = 50,2x
T(1000) ≈ 1s + 0,099s = 1,099s =&amp;gt; Speedup = 100/1,099 = 91x
&lt;/pre&gt;

&lt;p&gt;A partir dos números anteriores, vemos que o aumento da aceleração com valores crescentes de &lt;code&gt;n&lt;/code&gt; é bastante decepcionante.&lt;/p&gt;

&lt;p&gt;Começamos com um aumento de velocidade realmente incrível de &lt;code&gt;9,2x&lt;/code&gt; usando 10 processadores, e então caímos para apenas 50x ao usar 100 processadores e um insignificante &lt;code&gt;91x&lt;/code&gt; ao usar 1.000 processadores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203646843-1dae3922-4dce-496c-b60a-e9076dc519e7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203646843-1dae3922-4dce-496c-b60a-e9076dc519e7.jpg" width="672" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A imagem anterior mostra a aceleração de melhor caso esperada para o mesmo algoritmo (calculado até ). Não importa quantos processadores usamos; não podemos obter um aumento de velocidade maior que , o que significa que o mais rápido que o código rodará é um segundo, que é o tempo que sua fração serial leva em um único processador, exatamente como foi previsto pela lei de Amdahl.&lt;/p&gt;

&lt;p&gt;A lei de Amdahl nos diz duas coisas:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A primeira é o quanto de aceleração podemos razoavelmente esperar na melhor das hipóteses e quando parar de adicionar hardware ao sistema devido aos retornos decrescentes.&lt;/p&gt;

&lt;p&gt;A segunda é que a lei de Amdahl se aplica igualmente a sistemas distribuídos e &lt;strong&gt;sistemas híbridos distribuídos&lt;/strong&gt;, ou seja são aqueles que combinam diferentes tipos de aspectos arquiteturais, paralelamente. Nesses casos, n refere-se ao número total de processadores em computadores disponíveis no sistema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um aspecto que deve ser mencionado nesse ponto é que à medida que os sistemas que podemos usar se tornam mais poderosos, nossos algoritmos distribuídos levarão cada vez menos tempo para rodar, se puderem fazer uso dos ciclos extras.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://player.vimeo.com/video/549004821?h=68a286301b&amp;amp;app_id=122963" rel="noopener noreferrer"&gt;https://player.vimeo.com/video/549004821?h=68a286301b&amp;amp;app_id=122963&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Memória Compartilhada
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203855492-806e02b4-c521-489e-bc7c-6d25194ceaeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203855492-806e02b4-c521-489e-bc7c-6d25194ceaeb.png" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para se aproveitar do paralelismo disponível nos sistemas modernos, os programas podem ser desenvolvidos para utilizar mais de um core (núcleos) simultaneamente. Isso significa que um programa com essa capacidade, sendo executado em um servidor, por exemplo, com 8 cores, poderia ser executado até oito vezes mais rápido (já vimos de acordo com a lei de Amdahl que isso não é verdade). Para isso, o programa precisa ser explicitamente programado com essa capacidade, usando bibliotecas ou técnicas específicas.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;memória compartilhada&lt;/strong&gt; é a memória que pode ser acessada simultaneamente por vários programas com a intenção de fornecer comunicação entre eles. Além de ser uma forma de comunicação entre os diversos programas, possibilita a economia de recursos, evitando cópias redundantes. Dentro desse contexto, os programas podem ser executados em um único processador ou mesmo em vários processadores separados.&lt;/p&gt;

&lt;p&gt;O conceito de memória compartilhada pode ser aplicado tanto em hardware como em software. Sua aplicação em hardware não é o foco do nosso estudo neste tema, assim, passaremos apenas a considerar sua aplicação em software.&lt;/p&gt;

&lt;p&gt;Em termos de software, a memória compartilhada pode ser um método de comunicação entre processos (Interprocess Communication – IPC), ou seja, uma maneira de trocar dados entre programas em execução ao mesmo tempo. Um processo criará uma área na RAM a qual outros processos podem acessar.&lt;/p&gt;

&lt;p&gt;Como dissemos anteriormente, o uso de memória compartilhada permite a conservação de recursos de memória, evitando cópias de dados de uma mesma instância, usando mapeamentos de memória virtual ou com suporte explícito do programa em questão.&lt;/p&gt;

&lt;p&gt;Uma vez que ambos os processos podem acessar a área de memória compartilhada como memória de trabalho regular, essa é uma forma muito rápida de comunicação, utilizando-se, via de regra, a comunicação síncrona nesses sistemas. Por outro lado, é menos escalável, pois os processos de comunicação devem estar rodando na mesma máquina, ficando limitado aos recursos desta. Existem ainda outros problemas, pois se os processos que compartilham a mesma memória compartilhada estiverem sendo executados em CPUs separadas, podem surgir problemas de coerência de cache.&lt;/p&gt;

&lt;p&gt;Passemos a um exemplo onde todos os cores de CPUs utilizados estão sempre no mesmo servidor, e tem acesso a mesma memória, chamamos essa técnica de &lt;strong&gt;paralelização de memória compartilhada&lt;/strong&gt;. São termos relacionados a esse mecanismo: SMP, Threads, OpenMP, os quais não serão objetos de nosso estudo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Thread&lt;/strong&gt; é uma forma como um processo/tarefa de um programa de computador é divido em duas ou mais tarefas que podem ser executadas concorrentemente. Os threads criados ocupam a CPU do mesmo modo que o processo criador, e também são escalonadas pelo próprio processo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Programas em C/C++ podem ser “facilmente” paralelizados para esse modelo usando a biblioteca &lt;strong&gt;OpenMP&lt;/strong&gt;. Para isso, são necessárias as inclusões de algumas diretivas de compilação (pragmas) no código e a utilização de um compilador compatível. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A seguir, temos um exemplo de memória compartilhada utilizando a linguagem C. Claro que para utilizá-lo, a &lt;strong&gt;biblioteca OMP&lt;/strong&gt; já deve estar instalada em seu computador.&lt;/p&gt;

&lt;p&gt;Inicialmente, temos que incluir o cabeçalho OpenMP para nosso programa junto com os arquivos de cabeçalho padrão.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaCompartilhada.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="173" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//OpenMP header&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;omp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;strong&gt;OpenMP&lt;/strong&gt;, precisamos mencionar a região que vamos fazer como paralela usando a palavra-chave &lt;code&gt;pragma omp parallel&lt;/code&gt;. O &lt;code&gt;pragma omp parallel&lt;/code&gt; é usado para bifurcar threads adicionais para realizar o trabalho paralelo na região determinada. O encadeamento original será indicado como o encadeamento mestre com ID de encadeamento 0.&lt;/p&gt;

&lt;p&gt;O código para a criação de uma região paralela seria:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaCompartilhada.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="173" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma omp parallel
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// As variáveis criadas aqui serão compartilhadas por todas&lt;/span&gt;
&lt;span class="c1"&gt;// as theads em execução&lt;/span&gt;
&lt;span class="c1"&gt;//Parallel region code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na região entre colchetes, todas as variáveis ali declaradas serão compartilhadas por todos os threads em execução. Em outras palavras, todas as variáveis criadas nesse espaço de memória serão compartilhadas por todas as instâncias de thread criadas.&lt;/p&gt;

&lt;p&gt;O comando poderia ser, por exemplo:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaCompartilhada.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="173" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma omp parallel
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ola Mundo... da thread = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;omp_get_thread_num&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defina o número de threads para executar o programa usando a variável externa.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaCompartilhada.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="173" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="n"&gt;OMP_NUM_THREADS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205095949-e2d23790-4f92-41a1-9130-6474e911a8e3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205095949-e2d23790-4f92-41a1-9130-6474e911a8e3.jpg" width="398" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De acordo com a imagem anterior, uma vez que o compilador encontra o código das regiões paralelas, o thread mestre (thread que tem o id de thread 0) será bifurcado no número especificado de threads.&lt;/p&gt;

&lt;p&gt;Aqui, ele será dividido em 5 threads porque inicializaremos o número de threads a serem executados como 5, usando o comando &lt;code&gt;export OMP_NUM_THREADS = 5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Todo o código dentro da região paralela será executado por todos os threads simultaneamente, bem como todas as variáveis eventualmente declaradas nesse código serão compartilhadas. Uma vez que a região paralela terminar, todos os threads serão mesclados no thread mestre.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Não se preocupe em executar este programa no seu computador. A biblioteca &lt;strong&gt;OpenMP&lt;/strong&gt; não será o foco do nosso estudo. Mas, caso se interesse no exemplo atual, siga os comandos abaixo descritos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compile o programa no ambiente Linux, utilizando o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcc &lt;span class="nt"&gt;-o&lt;/span&gt; hello &lt;span class="nt"&gt;-fopenmp&lt;/span&gt; hello.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute o programa com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A seguir, está o programa completo descrito anteriormente.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaCompartilhada.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="173" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Usando o OpenMP para executar o Hello World compartilhado&lt;/span&gt;
&lt;span class="c1"&gt;// utilizando a linguagem C&lt;/span&gt;

&lt;span class="c1"&gt;// OpenMP header&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;omp.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Inicio da Regiao Paralela&lt;/span&gt;
    &lt;span class="cp"&gt;#pragma omp parallel
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ola Mundo... da thread = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;omp_get_thread_num&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Fim da regiao paralela&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como especificamos, o número de &lt;strong&gt;threads&lt;/strong&gt; a serem executados como &lt;code&gt;5&lt;/code&gt;, estes &lt;code&gt;5 threads&lt;/code&gt; executarão a mesma instrução de impressão ao mesmo tempo. Aqui, não podemos garantir a ordem de execução dos threads, ou seja, a ordem de execução da instrução na região paralela não será a mesma para todas as execuções.&lt;/p&gt;

&lt;p&gt;Na imagem a seguir, durante a primeira execução do programa, o encadeamento 1 é concluído primeiro, sendo que na segunda execução do programa, o encadeamento &lt;code&gt;0&lt;/code&gt; é o primeiro a ser concluído. &lt;code&gt;omp_get_thread_num ()&lt;/code&gt; retornará o número do thread (tarefa) associado ao segmento.&lt;/p&gt;

&lt;p&gt;Veja a saída de uma execução do programa.&lt;/p&gt;

&lt;pre&gt;
aluno@ubuntu: ~$ export OMP_NUM_THREADS=5
aluno@ubuntu: ~$ gcc -o hello -fopenmp hello.c
aluno@ubuntu: ~$ ./hello
Ola Mundo... da thread = 1
Ola Mundo... da thread = 0
Ola Mundo... da thread = 4
Ola Mundo... da thread = 3
Ola Mundo... da thread = 2
&lt;/pre&gt;

&lt;p&gt;Quando executado por várias vezes: a ordem de execução dos threads muda a cada vez.&lt;/p&gt;

&lt;pre&gt;
aluno@ubuntu: ~$ ./hello
Ola Mundo... da thread = 1
Ola Mundo... da thread = 0
Ola Mundo... da thread = 4
Ola Mundo... da thread = 3
Ola Mundo... da thread = 2
aluno@ubuntu: ~$ ./hello
Ola Mundo... da thread = 0
Ola Mundo... da thread = 4
Ola Mundo... da thread = 3
Ola Mundo... da thread = 2
Ola Mundo... da thread = 1
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;A memória compartilhada pode ser um método de comunicação entre processos. A memória compartilhada não é escalável, pois os processos compartilham a mesma memória no mesmo computador, dificultando a expansão da quantidade de memória disponível. Por compartilharem o mesmo espaço de memória, ocorrem problemas de coerência, pois os processos estão disputando o mesmo espaço de memória.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Memória Distribuída
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.stack.imgur.com%2FdqrzE.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.stack.imgur.com%2FdqrzE.jpg" width="329" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;memória distribuída&lt;/strong&gt; refere-se a um sistema de computador multiprocessador no qual cada processador tem sua própria memória privada. As tarefas computacionais só podem operar em dados locais e, se forem necessários dados remotos, a tarefa computacional deve se comunicar com um ou mais processadores remotos.&lt;/p&gt;

&lt;p&gt;Em contraste, como vimos anteriormente, um multiprocessador de memória compartilhada oferece um único espaço de memória usado por todos os processadores. Os processadores não precisam estar cientes de onde os dados residem, exceto de que pode haver penalidades de desempenho e que as &lt;strong&gt;condições de corrida&lt;/strong&gt; devem ser evitadas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Condições de corrida&lt;/strong&gt; são situações caracterizadas pelo acesso simultâneo de dois ou mais processos a dados compartilhados, em um processamento ou sistema cujo resultado final depende da ordem de execução de seus processos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um sistema de memória distribuída, normalmente, há um processador, uma memória e alguma forma de interconexão que permite que os programas em cada processador interajam uns com os outros. A interconexão pode ser organizada com enlaces ponto a ponto ou o hardware separado pode fornecer uma rede de comutação.&lt;/p&gt;

&lt;p&gt;A topologia da rede é um fator chave para determinar como a máquina multiprocessadora é dimensionada. Os enlaces entre os nós podem ser implementados usando algum protocolo de rede padrão (onde a comunicação via placas Ethernet é a mais comum) ou algum outro tipo de comunicação. Como a comunicação, geralmente, é por protocolos de rede, pode existir uma grande latência nestas operações, que em operações bloqueantes (síncronas) pode não ser apropriado. Assim, as comunicações assíncronas (em regra as não bloqueantes) são as mais utilizadas nesse tipo de sistema.&lt;/p&gt;

&lt;p&gt;O principal problema na programação de sistemas de memória distribuída é como distribuir os dados pelas memórias. Dependendo do problema resolvido, os dados podem ser distribuídos estaticamente ou podem ser movidos através dos nós. Os dados podem ser movidos sob demanda ou podem ser enviados para os novos nós com antecedência.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A principal vantagem da memória compartilhada é que ela oferece um espaço de endereço unificado no qual todos os dados podem ser encontrados, além dos dados serem acessados com maior rapidez.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A vantagem da memória distribuída é que ela &lt;strong&gt;exclui condições de corrida&lt;/strong&gt;, e a principal preocupação do programador é pensar sobre a distribuição de dados. Da mesma forma, a memória distribuída é muito mais escalável do que a memória compartilhada, bastando acessar novos nós a rede. Por outro lado, em que pese a ocultar o mecanismo de comunicação, não é possível deixar de considerar a latência de comunicação para acessar os dados.&lt;/p&gt;

&lt;p&gt;Um programa que usa as funcionalidades de memória distribuída tem de ser explicitamente desenvolvido com essa capacidade. Geralmente, isso é feito usando uma biblioteca &lt;strong&gt;MPI&lt;/strong&gt; (no caso da memória compartilhada, usamos no nosso exemplo o &lt;strong&gt;OpenMP&lt;/strong&gt;). Não se preocupe em executar este código no seu computador, alguns conceitos não foram tratados, mas irá permitir que você tenha uma visão do emprego da memória distribuída, conforme veremos em nosso vídeo: &lt;a href="https://player.vimeo.com/video/549006057" rel="noopener noreferrer"&gt;https://player.vimeo.com/video/549006057&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-memoriaDistribuida.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="153" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bibliotecas do MPI necessarias&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"mpi.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;  &lt;span class="n"&gt;numtasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MPI_MAX_PROCESSOR_NAME&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// initializando o MPI&lt;/span&gt;
    &lt;span class="n"&gt;MPI_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// obtendo o numero de tasks&lt;/span&gt;
    &lt;span class="n"&gt;MPI_Comm_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MPI_COMM_WORLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;numtasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// obtendo o rank&lt;/span&gt;
    &lt;span class="n"&gt;MPI_Comm_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MPI_COMM_WORLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// obtendo o nome do processador&lt;/span&gt;
    &lt;span class="n"&gt;MPI_Get_processor_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Number of tasks= %d My rank= %d Running on %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numtasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// finalizando o MPI&lt;/span&gt;
    &lt;span class="n"&gt;MPI_Finalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A memória distribuída é altamente escalável e a vantagem da memória distribuída é que ela exclui condições de corrida. O programador deve pensar sobre a distribuição de dados. Os processadores não precisam estar cientes de onde os dados residem, exceto de que pode haver penalidades de desempenho e que as condições de corrida devem ser evitadas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  PARALELISMO DE DADOS
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;paralelismo de dados&lt;/strong&gt; é a paralelização dos dados entre vários processadores em ambientes de computação paralela:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Concentra-se na distribuição dos dados em nós diferentes, que operam nos dados em paralelo.&lt;/li&gt;
&lt;li&gt;Pode ser aplicado em &lt;strong&gt;estruturas de dados regulares&lt;/strong&gt;, como &lt;strong&gt;arrays&lt;/strong&gt; e &lt;strong&gt;matrizes&lt;/strong&gt;, trabalhando em cada elemento em paralelo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um &lt;strong&gt;trabalho paralelo de dados em uma matriz&lt;/strong&gt; de &lt;code&gt;n&lt;/code&gt; elementos pode ser dividido igualmente entre todos os processadores.&lt;/p&gt;

&lt;p&gt;Vamos supor que queremos somar todos os elementos da matriz fornecida e o tempo para uma única operação de adição é unidades de tempo &lt;code&gt;Ta&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No caso de execução sequencial, o tempo gasto pelo processo será &lt;code&gt;n x Ta&lt;/code&gt; unidades de tempo, pois soma todos os elementos de uma matriz.&lt;/p&gt;

&lt;p&gt;Por outro lado, se executarmos esse trabalho como um trabalho paralelo de dados em 4 processadores, o tempo gasto seria reduzido para &lt;code&gt;(n x Ta)/4&lt;/code&gt;, desconsiderando eventuais atrasos de execução e operações obrigatoriamente serializáveis já citados na lei Amdahl. Nesse caso, a &lt;strong&gt;execução paralela&lt;/strong&gt; resulta em uma aceleração de 4 em relação à execução sequencial.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Uma questão interessante a se notar é que a localidade das referências de dados desempenha um papel importante na avaliação do desempenho de um modelo de programação paralela de dados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A localidade dos dados depende de dois fatores:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acessos à memória realizados pelo programa.&lt;/li&gt;
&lt;li&gt;Tamanho do cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em um sistema multiprocessador que executa um único conjunto de instruções (SIMD), arquitetura de dados que já explanamos, o paralelismo de dados é obtido quando cada processador executa a mesma tarefa em diferentes dados distribuídos.&lt;/p&gt;

&lt;p&gt;Em algumas situações, um único thread de execução controla as operações em todos os dados.&lt;/p&gt;

&lt;p&gt;Em outras, diferentes threads controlam a operação, mas executam o mesmo código.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F122ca74f-4f8d-4f7e-822a-f49e8778171a" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F122ca74f-4f8d-4f7e-822a-f49e8778171a" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Exemplo: Considere a multiplicação e adição de matrizes de maneira sequencial. Veja a seguir o pseudocódigo sequencial para multiplicação e adição de duas matrizes onde o resultado é armazenado na matriz C. O pseudocódigo para multiplicação calcula o produto escalar de duas matrizes A e B e armazena o resultado na matriz de saída C.&lt;/p&gt;

&lt;p&gt;Se os programas a seguir forem executados sequencialmente, o tempo necessário para calcular o resultado seria &lt;code&gt;O(n&lt;sup&gt;3&lt;/sup&gt;)&lt;/code&gt;, assumindo que os comprimentos de linha e de coluna de ambas as matrizes são &lt;code&gt;n&lt;/code&gt; e &lt;code&gt;O(n)&lt;/code&gt; para multiplicação e adição, respectivamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-multiplicacaoDeMatrizes.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="179" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Multiplicacao de matrizes&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;row_length_A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;column_length_B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;column_length_A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Adicao de arrays&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos explorar o paralelismo de dados no código anterior para executá-lo mais rapidamente, pois a aritmética é independente em relação ao loop.&lt;/p&gt;

&lt;p&gt;A paralelização do código de multiplicação da matriz é obtida usando o &lt;strong&gt;OpenMP&lt;/strong&gt;. Uma diretiva OpenMP, "&lt;code&gt;omp parallel for&lt;/code&gt;" instrui o compilador a executar o código no loop &lt;code&gt;for&lt;/code&gt; em paralelo. Para multiplicação, podemos dividir a matriz &lt;code&gt;A&lt;/code&gt; e &lt;code&gt;B&lt;/code&gt; em blocos ao longo de linhas e colunas, respectivamente. Isso nos permite calcular cada elemento na matriz C individualmente, tornando a tarefa paralela.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Matriz &lt;code&gt;A&lt;/code&gt; versus Matriz &lt;code&gt;B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;A[m x n].B[n x k]&lt;/code&gt; pode ser finalizado em &lt;code&gt;O(n)&lt;/code&gt; em vez de &lt;code&gt;O(m*n*k)&lt;/code&gt; quando executado em paralelo usando &lt;code&gt;m * k&lt;/code&gt; processadores.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205207101-17660f51-c44b-48b6-8102-c71df3760b30.jpg" width="700" height="172"&gt;&lt;br&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-multiplicacaoDeMatrizesEmParalelo.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="239" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Multiplicação de matrizes em paralelo&lt;/span&gt;
&lt;span class="cp"&gt;#pragma omp parallel for schedule(dynamic,1) collapse(2)
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;row_length_A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;column_length_B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;column_length_A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pode-se observar a partir do exemplo que, conforme os tamanhos das matrizes continuam aumentando, serão necessários muitos processadores. Manter o tempo de execução baixo é a prioridade, mas, na medida em que o tamanho da matriz aumenta, nos deparamos com outras restrições, como a complexidade de tal sistema e seus custos associados. Portanto, restringindo o número de processadores no sistema, podemos ainda aplicar o mesmo princípio e dividir os dados em blocos maiores para calcular o produto de duas matrizes.&lt;/p&gt;

&lt;p&gt;Para adição de matrizes em uma implementação paralela de dados, vamos supor um sistema mais modesto com duas CPUs A e B. A CPU A poderia adicionar todos os elementos da metade superior das matrizes, enquanto a CPU B poderia adicionar todos os elementos da metade inferior das matrizes. Como os dois processadores funcionam em paralelo, a tarefa de realizar a adição do array levaria metade do tempo de realizar a mesma operação em série usando apenas uma CPU.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O paralelismo de dados está muito em voga nos dias atuais, e talvez as placas com tecnologia GPU sejam o sinônimo desta tecnologia. Esse tipo de abordagem não será o foco do nosso estudo.&lt;/p&gt;

&lt;p&gt;Utiliza-se computação síncrona no paralelismo de dados. A mesma tarefa é executada em diferentes subconjuntos de dados e a quantidade de paralelização é proporcional ao tamanho da entrada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para saber mais sobre os assuntos explorados neste tema, pesquise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os livros mais adotados para sistemas distribuídos, que são os de COULOURIS et al., 2013 e TANENBAUM e STEEM, 2006. Neles, podem ser encontrados os principais conceitos referentes a esses assuntos.&lt;/li&gt;
&lt;li&gt;O tutorial de OpenMP do Lawrence Livermore National Laboratory, onde se encontram orientações bem detalhadas sobre programação paralela e distribuída.&lt;/li&gt;
&lt;li&gt;Um exemplo completo e detalhado da multiplicação de matrizes, disponível em Matrix Multiplication with OpenMP e Mxm Openmp c.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PARALELISMO DE TAREFAS
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;paralelismo de tarefas&lt;/strong&gt; (também conhecido como &lt;strong&gt;paralelismo de função&lt;/strong&gt; e &lt;strong&gt;paralelismo de controle&lt;/strong&gt;) é uma forma de paralelismo de código de computador em vários processadores em ambientes de computação paralela. Concentra-se na distribuição de tarefas — executadas simultaneamente por processos ou threads — em diferentes processadores. Em contraste com o paralelismo de dados, que envolve a execução da mesma tarefa em diferentes componentes de dados, distingue-se pela execução de muitas tarefas diferentes ao mesmo tempo nos mesmos dados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Em um sistema multiprocessador, o paralelismo de tarefas é obtido quando cada processador executa um thread diferente (ou processo) nos mesmos dados ou em dados diferentes, diferentemente do que vimos no paralelismo de dados, onde os threads executam a mesma tarefa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os threads podem executar o mesmo código ou código diferente. No caso geral, diferentes threads de execução se comunicam uns com os outros enquanto funcionam, mas isso não é um requisito. A comunicação geralmente ocorre passando dados de um thread para o próximo como parte de um fluxo de trabalho. Essa comunicação entre threads pode ser executada inclusive utilizando mecanismos de memória distribuída.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Se um sistema está executando o código em um sistema de dois processadores (CPUs "a" e "b") em um ambiente paralelo e queremos fazer as tarefas "A" e "B", é possível dizer CPU "a" para fazer a tarefa "A" e CPU "b" para fazer a tarefa "B" simultaneamente, reduzindo assim o tempo de execução. As tarefas podem ser atribuídas usando instruções condicionais.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O paralelismo de tarefas enfatiza a natureza distribuída (paralelizada) do processamento (ou seja, threads), em oposição aos dados (paralelismo de dados).&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;paralelismo de nível de thread&lt;/strong&gt; (&lt;strong&gt;TLP&lt;/strong&gt;) é o paralelismo inerente a um aplicativo que executa vários threads de uma vez. Esse tipo de paralelismo é encontrado principalmente em aplicativos escritos para servidores comerciais, como bancos de dados. Ao executar muitos threads de uma vez, esses aplicativos são capazes de tolerar as altas quantidades de input e output e latência do sistema de memória em que suas cargas de trabalho podem incorrer - enquanto um thread está atrasado esperando por um acesso à memória ou disco, outros threads podem fazer um trabalho útil.&lt;/p&gt;

&lt;p&gt;A exploração do paralelismo de nível de thread também começou a fazer incursões no mercado de desktops com o advento dos microprocessadores multicores. Nos computadores de mesa, isso ficou evidenciado com o advento do Windows NT e do Windows 95, em que pese a essas tecnologias, já eram possíveis em outros sistemas operacionais, como o SunOS e o Solaris. Isso ocorreu porque, por várias razões, tornou-se cada vez mais impraticável aumentar a velocidade do clock ou as instruções por clock de um único núcleo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Se essa tendência continuar, novos aplicativos terão de ser projetados para utilizar vários threads para se beneficiar do aumento potencial do poder de computação. Isso contrasta com as inovações anteriores do microprocessador, nas quais o código existente era automaticamente acelerado ao ser executado em um computador mais novo / mais rápido.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O exemplo que mostramos em memórias compartilhada também serve como exemplo de uma tarefa distribuída, onde cada thread executava a função de imprimir o seu Id. Uma forma simples seria colocar uma função dentro do espaço reservado para o paralelismo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://player.vimeo.com/video/549007806" rel="noopener noreferrer"&gt;https://player.vimeo.com/video/549007806&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;As tarefas diferentes podem ser executadas nos mesmos dados que foram disponibilizados para processamento. A quantidade de paralelização é proporcional ao número de tarefas independentes realizadas e como cada processador executará um thread, ou processo, diferente no mesmo conjunto de dados ou em um conjunto diferente de dados, a aceleração é menor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Fundamentos de Computação Paralela
&lt;/h1&gt;

&lt;p&gt;O desenvolvimento dos sistemas distribuídos nos permitiu acessar diversos tipos de aplicações, disponibilizadas na internet. Essas aplicações mudaram a forma de estudarmos, de trabalharmos, de nos divertimos e até a maneira como as pessoas se relacionam.&lt;/p&gt;

&lt;p&gt;Uma aplicação distribuída, porém, tem algumas complexidades. Por ser distribuída, existem vários processos que vão compô-la e, consequentemente, há a necessidade de uma coordenação entre esses processos.&lt;/p&gt;

&lt;p&gt;Vários processos sendo executados simultaneamente dão origem ao conceito de programação paralela − divisão de uma tarefa computacional em instâncias (processos) independentes e que podem ser executados de forma paralela.&lt;/p&gt;

&lt;p&gt;Os processos que são executados em paralelo, no entanto, podem trazer algumas situações inconvenientes durante sua execução. Imagine, por exemplo, que existe um recurso − como uma impressora − que deve ser acessado por esses processos que estão executando em paralelo. Se todos quiserem acessar simultaneamente, teremos problemas para definir quem irá imprimir primeiro.&lt;/p&gt;

&lt;p&gt;É necessário conhecer os fundamentos da computação paralela para entender os problemas que existem nesse paradigma computacional e quais mecanismos podemos utilizar para evitar ou, pelo menos, minimizar os seus efeitos.&lt;/p&gt;

&lt;p&gt;Por fim, conheceremos diversas plataformas que podem ser utilizadas para o desenvolvimento de programas paralelos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://player.vimeo.com/video/558221759" rel="noopener noreferrer"&gt;https://player.vimeo.com/video/558221759&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O thread mestre normalmente espera por solicitações de trabalho − por exemplo, em uma rede −, e, quando um novo pedido chega, ele bifurca/inicia um thread de trabalho.&lt;/p&gt;

&lt;p&gt;Esse thread executa a solicitação e, quando conclui o trabalho, termina e se junta ao thread mestre. Esse tipo de modelo faz uso eficiente dos recursos do sistema, uma vez que os recursos exigidos por um thread só estão sendo usados enquanto este está realmente em execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  VARIÁVEIS COMPARTILHADAS
&lt;/h2&gt;

&lt;p&gt;Antes de mais nada, saiba que:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em programas de memória compartilhada, as &lt;strong&gt;variáveis&lt;/strong&gt; podem ser &lt;strong&gt;compartilhadas&lt;/strong&gt; ou &lt;strong&gt;privadas&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um ambiente onde um processo possui vários &lt;strong&gt;threads&lt;/strong&gt;, as &lt;strong&gt;variáveis compartilhadas podem ser lidas ou escritas por qualquer um deles&lt;/strong&gt;, e &lt;strong&gt;variáveis privadas normalmente podem ser acessadas apenas por um thread&lt;/strong&gt;. Quando a comunicação entre os threads é feita por meio de variáveis compartilhadas, ela é implícita, não explícita − como por soquetes (sockets) ou named pipes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Em muitos ambientes, os programas de memória compartilhada usam threads dinâmicos. Nesse modelo, geralmente há um thread mestre e, em qualquer momento, uma coleção (possivelmente vazia de início) de threads de trabalho.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O &lt;strong&gt;thread mestre&lt;/strong&gt; normalmente espera por solicitações de trabalho − por exemplo, em uma rede −, e, quando um novo pedido chega, ele bifurca/inicia um thread de trabalho.&lt;/p&gt;

&lt;p&gt;Esse thread executa a solicitação e, quando conclui o trabalho, termina e se junta ao thread mestre. Esse tipo de modelo faz uso eficiente dos recursos do sistema, uma vez que os recursos exigidos por um thread só estão sendo usados enquanto este está realmente em execução.&lt;/p&gt;

&lt;h3&gt;
  
  
  PARADIGMA DE THREAD ESTÁTICO
&lt;/h3&gt;

&lt;p&gt;Uma alternativa ao paradigma dinâmico é o &lt;strong&gt;paradigma de thread estático&lt;/strong&gt;. Nesse paradigma, todos os threads são bifurcados/iniciados após qualquer configuração necessária pelo thread mestre e os threads são executados até que todo o trabalho seja concluído. Depois que os threads se juntam ao thread mestre, este pode fazer alguma limpeza (por exemplo, liberação de memória) e, então, também finaliza esses threads.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Em termos de uso de recursos, isso pode ser menos eficiente: se um thread estiver ocioso, seus recursos (por exemplo: pilha, contador de programa etc.) não podem ser liberados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No entanto, bifurcar e unir threads podem ser operações bastante demoradas. Portanto, se os recursos necessários estiverem disponíveis, o paradigma de thread estático tem potencial de melhor desempenho do que o paradigma dinâmico. Ele também tem a virtude de estar mais próximo do paradigma mais amplamente usado para programação de memória distribuída, então, parte da memória que é usada para um tipo de sistema é preservada para o outro.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Assim, o paradigma de thread estático é o mais frequente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  CÁLCULO NÃO DETERMINÍSTICO
&lt;/h3&gt;

&lt;p&gt;Em qualquer sistema &lt;strong&gt;MIMD&lt;/strong&gt;, Instrução Múltipla - Dados Múltiplos – em inglês, &lt;em&gt;Multiple Instruction Multiple Data&lt;/em&gt;, no qual os processadores são executados de forma assíncrona, é provável que haja não determinismo das tarefas. Um cálculo é não determinístico se uma entrada específica pode resultar em saídas diferentes. Se vários threads estiverem executando de forma independente, a taxa relativa na qual eles concluirão as instruções varia de execução para execução e, portanto, os resultados do programa podem ser diferentes a cada execução.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Suponha que temos dois threads, um com &lt;code&gt;id 0&lt;/code&gt; e o outro com &lt;code&gt;id 1&lt;/code&gt;. Suponha também que cada um está armazenando uma variável privada &lt;code&gt;x&lt;/code&gt;, o valor de &lt;code&gt;x&lt;/code&gt; na thread &lt;code&gt;0&lt;/code&gt; é &lt;code&gt;5&lt;/code&gt; e na thread &lt;code&gt;1&lt;/code&gt; é &lt;code&gt;8&lt;/code&gt;. Além disso, imagine que ambos os threads executem o seguinte código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread %d &amp;gt; val = %dnn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, a saída pode ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas pode ser também:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;

&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Na verdade, as coisas podem ser ainda piores: a saída de um thread pode ser interrompida pela saída de outro thread. No exemplo anterior, estamos apenas tratando de uma saída.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No entanto, como os threads estão executando de forma independente e interagindo com o sistema operacional, o tempo que leva para um thread completar um bloco de instruções varia de execução para execução. Portanto, a ordem em que essas instruções são concluídas não pode ser prevista.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Em muitos casos, o não determinismo não é um problema. Em nosso exemplo, uma vez que rotulamos a saída com a classificação do tópico, a ordem em que a saída aparece provavelmente não importa. No entanto, também existem muitos casos em que o não determinismo, especialmente em programas de memória compartilhada, pode ser desastroso, porque pode facilmente resultar em erros de programa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vejamos um exemplo simples com dois threads: suponha que cada thread calcule um valor inteiro, que ele armazena em uma variável privada &lt;code&gt;val&lt;/code&gt;, e que queremos adicionar os valores armazenados em &lt;code&gt;val&lt;/code&gt; em um local de memória compartilhada &lt;code&gt;x&lt;/code&gt; que foi inicializado em &lt;code&gt;0&lt;/code&gt;. Ambos os threads, portanto, desejam executar um código semelhante a este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Compute_val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_rank&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, lembre-se de que uma adição normalmente requer o carregamento dos dois valores a serem adicionados aos registradores, a adição dos valores e, por fim, o armazenamento do resultado. Para manter o exemplo relativamente simples, vamos presumir que os valores são carregados da memória principal diretamente nos registradores e armazenados na memória principal diretamente dos registradores. Na tabela a seguir, visualizamos uma sequência possível de execução desses threads utilizando os valores &lt;code&gt;5&lt;/code&gt; e &lt;code&gt;8&lt;/code&gt; do exemplo anterior:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Tempo&lt;/th&gt;
    &lt;th&gt;Núcleo 1&lt;/th&gt;
    &lt;th&gt;Núcleo 2&lt;/th&gt;
  &lt;/tr&gt;                         
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega o valor de val&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Chama a função Compute_val&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega x = 0 para o registrador&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega o valor de val&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega val = 5 para o registrador&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega x = 0 para o registrador&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Adiciona val a x&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Carrega val = 8 para o registrador&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Armazena x = 5&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Adiciona val a x&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Inicia outro trabalho&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Armazena x = 8&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
 

&lt;p&gt;Claramente, não é isso que queremos, pois o resultado deveria considerar que estamos incrementando o valor de &lt;code&gt;x&lt;/code&gt;, e o resultado esperado deveria ser &lt;code&gt;13&lt;/code&gt;. Assim, é fácil imaginar outras sequências de eventos que resultam em um valor incorreto para &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O não determinismo aqui é resultado do fato de que duas threads estão tentando atualizar mais ou menos simultaneamente à localização da memória &lt;code&gt;x&lt;/code&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando threads ou processos tentam acessar simultaneamente um recurso, e os acessos podem resultar em erro, costumamos dizer que o programa tem uma condição de corrida, porque os threads ou processos estão em uma “corrida de cavalos”. Ou seja, o resultado do cálculo depende de qual thread ganha a corrida. Em nosso exemplo, os threads estão em uma corrida para executar &lt;code&gt;x + = val&lt;/code&gt;. Nesse caso, a menos que um encadeamento conclua &lt;code&gt;x + = val&lt;/code&gt; antes do outro encadeamento iniciar, o resultado será incorreto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Você sabia&lt;/strong&gt;: Um bloco de código que só pode ser executado por um thread de cada vez é chamado de &lt;strong&gt;seção crítica&lt;/strong&gt; (veremos isso em mais detalhes adiante), e, geralmente, é nosso trabalho como programadores garantir acesso mutuamente exclusivo à seção crítica. Em outras palavras, precisamos garantir que, se um encadeamento estiver executando o código na seção crítica, os outros encadeamentos serão excluídos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  MUTEX
&lt;/h3&gt;

&lt;p&gt;O mecanismo mais comumente utilizado para garantir a exclusão mútua é um &lt;strong&gt;bloqueio de exclusão mútua&lt;/strong&gt; ou &lt;strong&gt;mutex&lt;/strong&gt; ou &lt;strong&gt;bloqueio&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: A ideia básica é que cada seção crítica seja protegida por um “tipo de fechadura”. Antes que um thread possa executar o código na seção crítica, ele deve "obter" essa fechadura, no caso o mutex, chamando uma função mutex e, quando terminar de executar o código na seção crítica, deve "abandonar" o mutex, chamando uma função de desbloqueio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enquanto um thread "possui" o bloqueio − isto é, retornou de uma chamada para a função de bloqueio, mas ainda não chamou a função de desbloqueio −, qualquer outro thread que tentar executar o código na seção crítica aguardará em sua chamada para a função de bloqueio.&lt;/p&gt;

&lt;p&gt;Para garantir que nosso código funcione corretamente, podemos modificá-lo para que se pareça com isto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Compute_val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_rank&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;my_val_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;my_val_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim, garante-se que apenas um thread de cada vez possa executar a instrução &lt;code&gt;x + = val&lt;/code&gt;. Observe que o código não impõe nenhuma ordem predeterminada nos threads que executam o código. Tanto o thread &lt;code&gt;0&lt;/code&gt; quanto o thread &lt;code&gt;1&lt;/code&gt; podem executar &lt;code&gt;x + = val&lt;/code&gt; primeiro.&lt;/p&gt;

&lt;p&gt;Observe também que o uso de um mutex impõe a serialização da seção crítica. Como apenas um thread por vez pode executar o código na seção crítica, esse código é efetivamente serial. Portanto, queremos que nosso código tenha o menor número possível de seções críticas, e que nossas seções críticas sejam as mais curtas possíveis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Existem alternativas para seções críticas além do mutex. Na espera ocupada, por exemplo, um thread entra em um loop cujo único propósito é testar uma condição.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suponha que haja uma variável compartilhada &lt;code&gt;ok&lt;/code&gt; que foi inicializada como &lt;code&gt;falsa&lt;/code&gt;. Então, algo como o código a seguir pode garantir que o thread &lt;code&gt;1&lt;/code&gt; não atualize &lt;code&gt;x&lt;/code&gt; até que o thread &lt;code&gt;0&lt;/code&gt; o tenha atualizado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Compute_val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_rank&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Espera ocupada&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// Bloqueia a entrada de outros thread&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Executa a seção crítica&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// Desbloqueia a variável&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Até que o thread &lt;code&gt;0&lt;/code&gt; seja executado, a variável &lt;code&gt;ok&lt;/code&gt; passa para o valor &lt;code&gt;0&lt;/code&gt;, bloqueando a entrada de outros threads. Assim, o thread &lt;code&gt;1&lt;/code&gt; ficará preso no loop while (&lt;code&gt;ok != 1&lt;/code&gt;); − chamado de "espera ocupada", porque o thread pode estar muito ocupado esperando a condição.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Saiba mais&lt;/strong&gt;: Simples de entender e implementar, isso, no entanto, pode ser um grande desperdício de recursos do sistema, porque mesmo quando um encadeamento não está fazendo nenhum trabalho útil, o núcleo que o executa verifica repetidamente se a seção crítica pode ser acessada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  MEMÓRIA COMPARTILHADA
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F209672382-dbc5ee8a-7710-429a-aaa0-91c28b114ef1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F209672382-dbc5ee8a-7710-429a-aaa0-91c28b114ef1.jpg" width="690" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tratamos, até aqui, do uso simplificado de memória compartilhada utilizando threads dentro de um mesmo processo. Entretanto, é possível fazer o uso de memória compartilhada usando processos diferentes, como você pode observar na imagem a seguir:&lt;/p&gt;

&lt;p&gt;Sabemos que, para nos comunicarmos entre dois ou mais processos, usamos memória compartilhada. Mas, antes de usar a memória compartilhada, o que precisa ser feito com as chamadas de sistema, tendo uma sequência de operações para isso?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Devemos criar o segmento de memória compartilhada. No Linux, isso pode ser feito com a chamada &lt;code&gt;shmget()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Devemos, posteriormente, anexar o segmento de memória anteriormente criado ao nosso programa com a chamada &lt;code&gt;shmget()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Fazemos nossas operações sobre a memória, como escrita e leitura, com a chamada &lt;code&gt;shmget()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Vale ressaltar que devemos ter todos os cuidados necessários, decorrentes da programação concorrente, citados neste conteúdo.&lt;/li&gt;
&lt;li&gt;Por fim, devemos desanexar o segmento de memória compartilhada de nosso programa com a chamada &lt;code&gt;shmget()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O uso de memória compartilhada em processos distintos também está disponível nos diversos sistemas operacionais, como, por exemplo, o Windows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://player.vimeo.com/video/558216109" rel="noopener noreferrer"&gt;https://player.vimeo.com/video/558216109&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CONDIÇÕES DE CORRIDA
&lt;/h2&gt;

&lt;p&gt;Uma &lt;strong&gt;condição de corrida&lt;/strong&gt; ou &lt;strong&gt;risco de corrida&lt;/strong&gt;, como vimos anteriormente, é a condição na qual o comportamento do sistema depende da sequência ou do tempo de outros eventos incontroláveis.&lt;/p&gt;

&lt;p&gt;Torna-se um &lt;strong&gt;bug&lt;/strong&gt; quando um ou mais dos comportamentos possíveis são indesejáveis.&lt;/p&gt;

&lt;p&gt;Uma &lt;strong&gt;condição de corrida&lt;/strong&gt; surge no software quando um programa de computador, para operar corretamente, depende da sequência ou do tempo dos processos ou threads do programa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Saiba mais&lt;/strong&gt;: &lt;strong&gt;Condições críticas de corrida&lt;/strong&gt; − que frequentemente acontecem quando os processos ou threads dependem de algum estado compartilhado − causam execução inválida e bugs de software. As operações em estados compartilhados são feitas em seções críticas que devem ser mutuamente exclusivas. O não cumprimento dessa regra pode corromper o estado compartilhado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma condição de corrida pode ser difícil de reproduzir e depurar, pois o resultado não é determinístico e depende do tempo relativo entre threads interferentes. Problemas dessa natureza podem, então, desaparecer durante a execução no modo de depuração, adicionando log extra ou anexando um depurador. Os erros que desaparecem durante as tentativas de depuração são geralmente chamados de &lt;em&gt;heisenbug&lt;/em&gt;. Portanto, é melhor evitar condições de corrida por meio de um projeto de software cuidadoso.&lt;/p&gt;

&lt;p&gt;Suponha que cada um de dois threads incremente o valor de uma variável inteira global em &lt;code&gt;1&lt;/code&gt;. Idealmente, a seguinte sequência de operações ocorreria:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Thread 1&lt;/th&gt;
    &lt;th&gt;Thread 2&lt;/th&gt;
    &lt;th&gt; &lt;/th&gt;
    &lt;th&gt;Valor da variável&lt;/th&gt;
  &lt;/tr&gt;                         
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;0&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;Ler valor&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;←&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;0&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;Incrementar valor&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;0&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
&lt;p&gt;Escrever valor&lt;/p&gt;
    &lt;/td&gt;
&lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;→&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Ler valor&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;←&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Incrementar valor&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt; &lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Escrever valor&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;→&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;2&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nesse caso, o valor final é &lt;code&gt;1&lt;/code&gt;, em vez do resultado correto de &lt;code&gt;2&lt;/code&gt;. Isso ocorre porque aqui as operações de incremento não são &lt;strong&gt;mutuamente exclusivas&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mutuamente exclusivas&lt;/strong&gt; operações mutuamente exclusivas são aquelas que não podem ser interrompidas durante o acesso a algum recurso, como um local de memória.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Nem todos consideram as corridas de dados como um subconjunto das condições de corrida. A definição precisa de corrida de dados é específica para o modelo de simultaneidade formal que está sendo usado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normalmente, porém, refere-se a uma situação na qual uma operação de memória em um encadeamento de threads pode tentar acessar um local de memória ao mesmo tempo que uma operação de memória em outro encadeamento está escrevendo para esse local da memória, em um contexto no qual isso é perigoso. Isso implica que uma corrida de dados é diferente de uma condição de corrida, pois é possível haver não determinismo devido ao tempo, mesmo em um programa sem corrida de dados. Por exemplo, em um programa no qual todos os acessos à memória usam apenas &lt;strong&gt;operações atômicas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Isso pode ser perigoso, porque, em muitas plataformas, se dois threads gravam em um local da memória ao mesmo tempo, é possível que o local da memória acabe mantendo um valor que é uma combinação arbitrária e sem sentido dos bits que representam os valores que cada thread estava tentando escrever. Com isso, pode haver uma corrupção de memória, se o valor resultante for um que nenhum thread tentou gravar (às vezes, isso é chamado de "&lt;strong&gt;gravação interrompida&lt;/strong&gt;").&lt;/p&gt;

&lt;p&gt;Da mesma forma, se um thread lê um local enquanto outro thread está gravando nele, é possível que a leitura retorne um valor que é uma combinação arbitrária e sem sentido dos bits que representam o valor que o local da memória mantinha antes da gravação e dos bits que representam o valor que está sendo escrito.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Em muitas plataformas, &lt;strong&gt;operações de memória especiais&lt;/strong&gt; são fornecidas para &lt;strong&gt;acesso simultâneo&lt;/strong&gt;; nesses casos, normalmente o acesso simultâneo é seguro, mas o acesso simultâneo usando outras operações de memória é perigoso. Às vezes, essas &lt;strong&gt;operações especiais&lt;/strong&gt; (que são seguras para acesso simultâneo) são chamadas de &lt;strong&gt;operações atômicas&lt;/strong&gt; ou de &lt;strong&gt;sincronização&lt;/strong&gt;, enquanto as &lt;strong&gt;operações comuns&lt;/strong&gt; (que não são seguras para acesso simultâneo) são chamadas de &lt;strong&gt;operações de dados&lt;/strong&gt;, sendo esse termo denominado de &lt;strong&gt;corrida de dados&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SINCRONIZAÇÃO DE PROCESSOS (Operações Atômicas)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;sincronização&lt;/strong&gt; é a tarefa de coordenar a execução de processos, de forma que dois deles não possam ter acesso aos mesmos dados e recursos compartilhados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: É especialmente necessária em um sistema de vários processos, quando vários deles estão sendo executados juntos e mais de um processo tenta obter, simultaneamente, acesso ao mesmo recurso ou dado compartilhado, o que pode levar à inconsistência de dados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isso porque a mudança feita por um processo não se reflete necessariamente quando outros acessam os mesmos dados compartilhados. Por exemplo: o processo A altera os dados em um local da memória enquanto outro processo B tenta ler os dados do mesmo local da memória. Há grande probabilidade de que os dados lidos pelo segundo sejam errôneos. &lt;strong&gt;Portanto, para evitar esse tipo de inconsistência de dados, os processos precisam ser sincronizados entre si&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;sincronização de threads&lt;/strong&gt; é definida como um mecanismo que garante que dois ou mais processos ou threads simultâneos não executem simultaneamente algum segmento de programa específico conhecido como &lt;strong&gt;seção crítica&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O &lt;strong&gt;acesso dos processos&lt;/strong&gt; à seção crítica é controlado por meio de técnicas de sincronização. Quando um thread começa a executar a seção crítica (segmento serializado do programa), o outro thread deve esperar até que o primeiro termine. Se as técnicas de sincronização adequadas não forem aplicadas, isso pode causar uma condição de corrida na qual os valores das variáveis podem ser imprevisíveis, dependendo dos tempos de troca de contexto dos processos ou threads.&lt;/p&gt;

&lt;p&gt;Suponha que haja três processos: 1, 2 e 3. Todos os três estão executando simultaneamente e precisam compartilhar um recurso comum (seção crítica), conforme mostrado na imagem a seguir:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjt1oq1tl5vfrtevr0bx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjt1oq1tl5vfrtevr0bx.jpg" alt="img2-1" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A sincronização deve ser usada aqui para evitar quaisquer conflitos para acessar esse recurso compartilhado. Portanto, quando os Processos 1 e 2 tentam acessar esse recurso, ele deve ser atribuído a apenas um processo por vez. Se for atribuído ao Processo 1, o Processo 2 precisa esperar até que o primeiro libere esse recurso. Veja na próxima imagem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F211170083-8269c088-dad5-42a2-861e-a30d968581d2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F211170083-8269c088-dad5-42a2-861e-a30d968581d2.jpg" width="534" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Precisamos satisfazer quatro condições para chegar a uma solução:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dois processos nunca podem estar simultaneamente em suas regiões críticas.&lt;/li&gt;
&lt;li&gt;Nada pode ser afirmado sobre a velocidade ou sobre o número de CPUs.&lt;/li&gt;
&lt;li&gt;Nenhum processo executando fora de sua seção crítica pode bloquear outros processos.&lt;/li&gt;
&lt;li&gt;Nenhum processo deve esperar eternamente para entrar em sua seção crítica.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Outro requisito de sincronização a ser considerado é a ordem na qual determinados processos ou threads devem ser executados. Não é possível, por exemplo, embarcar em um avião antes de comprar uma passagem ou verificar e-mails antes de validar as credenciais apropriadas (nome de usuário e senha). Da mesma forma, um caixa eletrônico não fornecerá nenhum serviço até que receba um PIN correto.&lt;/p&gt;

&lt;p&gt;Além da exclusão mútua, a sincronização também lida com o seguinte:&lt;/p&gt;

&lt;h3&gt;
  
  
  Deadlock (impasse)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Conforme veremos mais detalhadamente adiante, deadlocks ocorrem quando muitos processos estão esperando por um recurso compartilhado (seção crítica) que está sendo mantido por algum outro processo. Nesse caso, os processos simplesmente continuam esperando e não são mais executados. Deadlocks também podem ocorrer entre máquinas.&lt;/p&gt;

&lt;p&gt;Por exemplo, diversos escritórios têm redes locais com vários computadores conectados entre elas. Muitas vezes, dispositivos como scanners e impressoras são conectadas a essas redes como recursos compartilhados, disponíveis a qualquer usuário em qualquer máquina. Se esses dispositivos puderem ser reservados remotamente, o mesmo tipo de deadlock poderá ocorrer, como descrito anteriormente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Starvation (fome)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Ocorre quando um processo está esperando para entrar na seção crítica, mas outros processos a monopolizam, e o primeiro é forçado a esperar indefinidamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inversão de prioridade
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Ocorre quando um processo de alta prioridade está na seção crítica e é interrompido por um de média prioridade. Essa violação das regras de prioridade pode acontecer em certas circunstâncias, e pode levar a sérias consequências em sistemas de tempo real.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Espera ocupada
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Ocorre quando um processo pesquisa frequentemente para determinar se tem acesso a uma seção crítica. Essa pesquisa frequente rouba o tempo de processamento de outros processos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um dos desafios para o projeto do algoritmo em ambientes distribuídos é minimizar ou reduzir a sincronização − que pode levar mais tempo do que a computação, especialmente na computação distribuída. A redução da sincronização atraiu a atenção dos cientistas da computação por décadas e, à medida que a lacuna entre a melhoria da computação e a latência aumenta, isso se torna um problema cada vez mais significativo.&lt;/p&gt;

&lt;h2&gt;
  
  
  PROBLEMAS CLÁSSICOS DE SINCRONIZAÇÃO
&lt;/h2&gt;

&lt;p&gt;A seguir, alguns problemas clássicos de sincronização:&lt;/p&gt;

&lt;h3&gt;
  
  
  PROBLEMA PRODUTOR-CONSUMIDOR (PROBLEMA DE BUFFER LIMITADO)
&lt;/h3&gt;

&lt;p&gt;Nesse problema, há um &lt;strong&gt;produtor&lt;/strong&gt; (que está produzindo algo) e um &lt;strong&gt;consumidor&lt;/strong&gt; (que está consumindo esses produtos produzidos). Os &lt;strong&gt;produtores&lt;/strong&gt; e &lt;strong&gt;consumidores&lt;/strong&gt; compartilham o mesmo buffer de memória de tamanho fixo.&lt;/p&gt;

&lt;p&gt;O trabalho do &lt;strong&gt;produtor é gerar os dados, colocá-los no buffer&lt;/strong&gt; (Em ciência da computação, buffer de dados é uma região de memória física utilizada para armazenar temporariamente os dados enquanto eles estão sendo movidos de um lugar para outro.) e, novamente, começar a gerar dados. Enquanto o trabalho do &lt;strong&gt;consumidor é consumir os dados do buffer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O produtor deve produzir dados apenas quando o buffer não estiver cheio. Se estiver cheio, o produtor não deve ter permissão para colocar nenhum dado no buffer.&lt;/p&gt;

&lt;p&gt;O consumidor, por sua vez, deve consumir dados apenas quando o buffer não está vazio. Se estiver vazio, o consumidor não deve ter permissão para retirar nenhum dado do buffer. O produtor e o consumidor não devem acessar o buffer ao mesmo tempo.&lt;/p&gt;

&lt;h3&gt;
  
  
  PROBLEMA DOS LEITORES-ESCRITORES
&lt;/h3&gt;

&lt;p&gt;O problema dos leitores-escritores está relacionado a um objeto, como um arquivo que é compartilhado entre vários processos. Alguns desses processos são &lt;strong&gt;leitores&lt;/strong&gt; (querem apenas ler os dados do objeto) e alguns são &lt;strong&gt;escritores&lt;/strong&gt; (querem escrever no objeto).&lt;/p&gt;

&lt;p&gt;O problema dos leitores-escritores é usado para gerenciar a sincronização, de forma que não haja intercorrências com os dados do objeto.&lt;/p&gt;

&lt;p&gt;Se dois leitores, por exemplo, acessarem o objeto ao mesmo tempo, não há problema. No entanto, se dois escritores ou um leitor e um escritor o acessarem ao mesmo tempo, pode haver problemas. Para resolver essa situação, um escritor deve obter acesso exclusivo a um objeto. Ou seja, quando um escritor está acessando o objeto, nenhum leitor ou escritor pode acessá-lo. No entanto, vários leitores podem acessar o objeto ao mesmo tempo.&lt;/p&gt;

&lt;h3&gt;
  
  
  PROBLEMA DO JANTAR DOS FILÓSOFOS
&lt;/h3&gt;

&lt;p&gt;O problema do jantar dos filósofos afirma que há cinco filósofos compartilhando uma mesa circular, e eles comem e pensam alternativamente. Há uma tigela de arroz para cada um dos filósofos, além de cinco hashis. Um filósofo precisa de dois hashis para comer. Um filósofo faminto só pode comer se houver os dois talheres disponíveis. Do contrário, ele abaixa o talher e começa a pensar novamente. O grande problema nesse algoritmo é que, se todos os filósofos pegarem somente um hashi, todos ficarão parados para sempre, aguardando o segundo talher ficar disponível, gerando um &lt;strong&gt;deadlock&lt;/strong&gt; (ou impasse).&lt;/p&gt;

&lt;p&gt;Esses problemas são usados para testar quase todos os esquemas de sincronização ou primitivos recentemente propostos.&lt;/p&gt;

&lt;h2&gt;
  
  
  EXCLUSÃO MÚTUA
&lt;/h2&gt;

&lt;p&gt;Na ciência da computação, a &lt;strong&gt;exclusão mútua&lt;/strong&gt; é uma propriedade do controle de concorrência, instituída com o objetivo de prevenir condições de corrida.&lt;/p&gt;

&lt;p&gt;É o requisito de que um thread de execução nunca entre em uma seção crítica enquanto um thread simultâneo de execução já a está acessando. Refere-se a um intervalo de tempo durante o qual um thread de execução acessa um recurso compartilhado, como memória e objetos de dados compartilhados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Conforme vimos, a seção crítica é um objeto de dados que dois ou mais threads simultâneos estão tentando modificar (no qual duas operações de leitura simultâneas são permitidas, mas não são permitidas duas operações de gravação simultâneas ou uma leitura e uma gravação, pois isso leva à inconsistência dos dados).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O &lt;strong&gt;algoritmo de exclusão&lt;/strong&gt; garante, portanto, que, se um processo já estiver executando a operação de gravação em um objeto de dados, nenhum outro tem permissão para acessar e modificar o mesmo objeto ou seção crítica até que o primeiro tenha concluído a gravação e liberado o objeto para outros processos lerem e escreverem. Em outras palavras, a seção crítica passa a ser de uso exclusivo do processo que a acessou inicialmente.&lt;/p&gt;

&lt;p&gt;Um exemplo simples de porque a exclusão mútua é importante na prática pode ser visualizado usando uma lista unida de quatro itens, na qual o segundo e o terceiro devem ser removidos, como pode ser exemplificado na imagem a seguir: &lt;code&gt;Lista unida de quatro itens&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyh1iyzjr1nzrixfmaxh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyh1iyzjr1nzrixfmaxh.jpg" alt="img4-1" width="559" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A remoção de um nó que fica entre dois outros é realizada mudando o ponteiro próximo do nó anterior para apontar para o próximo nó. Em outras palavras, se o nó está sendo removido, então o ponteiro próximo de nó é alterado para apontar para o nó , removendo assim da lista encadeada qualquer referência ao nó . Observe a imagem a seguir: &lt;code&gt;Lista unida após movimentação do ponteiro próximo de n-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbzbj753ig61tu68poaf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbzbj753ig61tu68poaf.jpg" alt="img5" width="571" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando tal lista encadeada está sendo compartilhada entre vários threads de execução, dois threads de execução podem tentar remover dois nós diferentes simultaneamente − um thread de execução mudando o ponteiro próximo do nó &lt;code&gt;i - 1&lt;/code&gt; para apontar para o nó &lt;code&gt;i + 1&lt;/code&gt;, enquanto outro thread de execução muda o ponteiro próximo do nó &lt;code&gt;i&lt;/code&gt; para apontar para o nó &lt;code&gt;i + 2&lt;/code&gt;. Embora ambas as operações de remoção sejam concluídas com sucesso, o estado desejado da lista vinculada não é alcançado: nó &lt;code&gt;i + 1&lt;/code&gt; permanece na lista, porque o ponteiro próximo do nó &lt;code&gt;i - 1&lt;/code&gt; aponta para o nó &lt;code&gt;i + 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esse problema (chamado de condição de corrida) pode ser evitado usando o requisito de exclusão mútua para garantir que atualizações simultâneas na mesma parte da lista não ocorram.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Saiba Mais&lt;/strong&gt;: O termo exclusão mútua também é usado em referência à gravação simultânea de um endereço de memória por um thread/processo, enquanto o endereço de memória mencionado anteriormente está sendo manipulado ou lido por um ou mais threads/processos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O problema que a exclusão mútua aborda é de compartilhamento de recursos:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Como um sistema de software pode controlar o acesso de vários processos a um recurso compartilhado, quando cada processo precisa do controle exclusivo desse recurso enquanto faz seu trabalho?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para isso, a solução de exclusão mútua torna o recurso compartilhado disponível apenas enquanto o processo está em um segmento de código específico (seção crítica), com acesso exclusivo, impedindo que outros processos acessem essa área de código. Ele controla o acesso ao recurso compartilhado controlando cada execução mútua daquela parte do programa na qual o recurso seria usado.&lt;/p&gt;

&lt;p&gt;Uma solução bem-sucedida para esse problema deve ter pelo menos duas propriedades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deve implementar a exclusão mútua&lt;/strong&gt;: Apenas um processo pode estar na seção crítica de cada vez.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deve estar livre de deadlocks&lt;/strong&gt;: Se os processos estão tentando entrar na seção crítica, um deles deve ser capaz de fazê-lo com sucesso, desde que nenhum processo permaneça na seção crítica permanentemente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A liberdade de deadlock pode ser expandida para implementar uma ou ambas as propriedades. A liberdade de bloqueio garante que qualquer processo que deseje entrar na seção crítica será capaz de fazê-lo eventualmente. Isso é diferente da prevenção de deadlock, que requer que algum processo em espera seja capaz de obter acesso à seção crítica, mas não requer que cada processo tenha sua vez. Se dois processos trocarem continuamente um recurso entre eles, um terceiro processo pode ser bloqueado e ficar sem recursos, mesmo que o sistema não esteja em um impasse. Se um sistema estiver livre de bloqueios, ele garante que todos os processos possam ser revertidos em algum ponto no futuro.&lt;/p&gt;

&lt;p&gt;Uma propriedade de espera limitada por k fornece um compromisso mais preciso do que a liberdade de bloqueio. Isso porque, na liberdade de bloqueio, não dá nenhuma garantia sobre o tempo de espera. Um processo pode ser ultrapassado um número arbitrário ou ilimitado de vezes por outros de prioridade mais alta antes de chegar a sua vez. Sob uma propriedade de espera limitada por k, cada processo tem um tempo de espera máximo finito. Isso funciona estabelecendo um limite para o número de vezes que outros processos podem interromper a fila, de modo que nenhum deles possa entrar na seção crítica mais de k vezes enquanto outro está esperando.&lt;/p&gt;

&lt;p&gt;O programa de cada processo pode ser dividido em quatro seções, resultando em quatro estados. A execução do programa percorre esses quatro estados, em ordem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Seção não crítica&lt;/strong&gt;: A operação está fora da seção crítica; o processo não está usando ou solicitando o recurso compartilhado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tentando&lt;/strong&gt;: A operação está fora da seção crítica; o processo não está usando ou solicitando o recurso compartilhado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seção crítica&lt;/strong&gt;: O processo tem permissão para acessar o recurso compartilhado nessa seção.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saída&lt;/strong&gt;: O processo sai da seção crítica e disponibiliza o recurso compartilhado para outros processos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se um processo deseja entrar na seção crítica, ele deve primeiro executar a seção de tentativa e esperar até obter acesso à seção crítica. Após ter executado sua seção crítica e finalizado com os recursos compartilhados, ele precisa executar a seção de saída para liberá-los para uso de outros processos. O processo então retorna à sua seção não crítica.&lt;/p&gt;

&lt;h1&gt;
  
  
  🆘 SEÇÃO CRÍTICA (Região)
&lt;/h1&gt;

&lt;p&gt;Conforme vimos, na programação simultânea, os acessos simultâneos a recursos compartilhados podem levar a um comportamento inesperado ou errôneo. Portanto, partes do programa onde o recurso compartilhado é acessado precisam ser protegidas de maneiras que evitem o acesso simultâneo. Essa seção protegida − chamada de &lt;strong&gt;região&lt;/strong&gt; ou &lt;strong&gt;seção crítica&lt;/strong&gt; − não pode ser executada por mais de um processo por vez.&lt;/p&gt;

&lt;p&gt;Normalmente, a seção crítica acessa um recurso compartilhado, como uma estrutura de dados, um dispositivo periférico ou uma conexão de rede, que não operaria corretamente no contexto de vários acessos simultâneos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Códigos ou processos diferentes podem consistir na mesma variável ou em outros recursos que precisam ser lidos ou escritos, mas cujos resultados dependem da ordem em que as ações ocorrem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por exemplo, se uma variável &lt;code&gt;x&lt;/code&gt; deve ser lida pelo processo &lt;code&gt;A&lt;/code&gt; e o processo &lt;code&gt;B&lt;/code&gt; precisa gravar na mesma variável &lt;code&gt;x&lt;/code&gt; ao mesmo tempo, o processo &lt;code&gt;A&lt;/code&gt; pode obter o valor antigo ou o novo valor de &lt;code&gt;x&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Processo a&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;// Instrução executada em Tx&lt;/span&gt;
&lt;span class="c1"&gt;//Processo b&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="c1"&gt;// Instrução executada em Tx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em casos como esses, uma seção crítica é importante. No exemplo anterior, se &lt;code&gt;A&lt;/code&gt; precisar ler o valor atualizado de &lt;code&gt;x&lt;/code&gt;, executar o Processo &lt;code&gt;A&lt;/code&gt; e o Processo &lt;code&gt;B&lt;/code&gt; ao mesmo tempo pode não dar os resultados necessários. Para evitar isso, a variável &lt;code&gt;x&lt;/code&gt; é protegida por uma seção crítica. Primeiramente, &lt;code&gt;B&lt;/code&gt; obtém o acesso à seção. Assim que &lt;code&gt;B&lt;/code&gt; terminar de escrever o valor, &lt;code&gt;A&lt;/code&gt; terá acesso à seção crítica e a variável &lt;code&gt;x&lt;/code&gt; poderá ser lida.&lt;/p&gt;

&lt;p&gt;Controlando cuidadosamente quais variáveis são modificadas dentro e fora da seção crítica, o acesso simultâneo à variável compartilhada é evitado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uma seção crítica é normalmente usada quando um programa multithreaded deve atualizar várias variáveis relacionadas sem que um thread separado faça alterações conflitantes nesses dados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em uma situação relacionada, uma seção crítica pode ser usada para garantir que um recurso compartilhado − por exemplo, uma impressora − só possa ser acessado por um processo por vez.&lt;/p&gt;

&lt;h1&gt;
  
  
  🚘🚙 DEADLOCK (impasse)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.javatpoint.com%2Foperating-system%2Fimages%2Fdeadlock-vs-starvation2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.javatpoint.com%2Foperating-system%2Fimages%2Fdeadlock-vs-starvation2.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como vimos, na computação simultânea, um &lt;strong&gt;deadlock&lt;/strong&gt; é um estado em que cada membro de um grupo espera que outro membro, incluindo ele mesmo, execute uma ação − como enviar uma mensagem ou, mais comumente, liberar um bloqueio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Deadlock são problemas comuns em sistemas de multiprocessamento (sistemas operacionais), banco de dados, computação paralela e sistemas distribuídos, em que bloqueios de software e hardware são usados para arbitrar recursos compartilhados e implementar sincronização de processos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um sistema operacional, um deadlock ocorre quando um processo ou thread entra em um estado de espera porque um recurso de sistema solicitado é mantido por outro processo em espera − que, por sua vez, está esperando por outro recurso mantido por outro processo em espera.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Se um processo é incapaz de mudar seu estado indefinidamente porque os recursos solicitados por ele estão sendo usados por outro processo em espera, então o sistema é considerado um deadlock.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um sistema de comunicação, os deadlock ocorrem principalmente devido a sinais perdidos ou corrompidos, em vez de contenção de recursos. Uma situação de deadlock em um recurso pode surgir se e somente se todas as seguintes condições, conhecidas como as quatro condições de Coffman et al. 1971, forem mantidas simultaneamente em um sistema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exclusão mútua&lt;/strong&gt;: Como vimos anteriormente, pelo menos um recurso deve ser mantido em um modo não compartilhável. Caso contrário, os processos não seriam impedidos de usar o recurso quando necessário. Apenas um processo pode usar o recurso em um determinado instante de tempo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reter e aguardar ou retenção de recurso&lt;/strong&gt;: Um processo está atualmente retendo pelo menos um recurso e solicitando recursos adicionais que estão sendo retidos por outros processos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sem preempção&lt;/strong&gt;: Um recurso só pode ser liberado voluntariamente pelo processo que o detém.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Espera circular&lt;/strong&gt;: Cada processo deve estar esperando por um recurso que está sendo retido por outro processo, que, por sua vez, está aguardando que o primeiro processo libere o recurso. Em geral, existe um conjunto de processos de espera, &lt;code&gt;P = {P1, P2, ..., PN}&lt;/code&gt;, tal que &lt;code&gt;P1&lt;/code&gt; está esperando por um recurso mantido por &lt;code&gt;P2&lt;/code&gt;, &lt;code&gt;P2&lt;/code&gt; está esperando por um recurso mantido por &lt;code&gt;P3&lt;/code&gt; e assim por diante, até que &lt;code&gt;PN&lt;/code&gt; seja esperando por um recurso mantido por &lt;code&gt;P1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Um deadlock ocorre se e somente se as quatro condições de Coffman forem satisfeitas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exclusão mútua.&lt;/li&gt;
&lt;li&gt;Posse e espera.&lt;/li&gt;
&lt;li&gt;Não preempção.&lt;/li&gt;
&lt;li&gt;Espera circular.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Embora essas condições sejam suficientes para produzir um conflito em sistemas de recursos de instância única, elas indicam apenas a possibilidade de conflito em sistemas com várias instâncias de recursos.&lt;/p&gt;

&lt;p&gt;A maioria dos sistemas operacionais atuais não pode evitar bloqueios. Quando ocorre um deadlock, diferentes sistemas operacionais respondem a eles de maneiras diferentes e fora do padrão. A maioria das abordagens funciona evitando que uma das quatro condições de Coffman ocorra, especialmente a espera circular.&lt;/p&gt;

&lt;p&gt;As principais abordagens são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IGNORANDO IMPASSE&lt;/strong&gt;: Nessa abordagem, presume-se que nunca ocorrerá um deadlock. É usada quando os intervalos de tempo entre as ocorrências de deadlocks são grandes e a perda de dados incorrida a cada vez é tolerável. Ignorar deadlocks pode ser feito com segurança se estes forem formalmente comprovados como nunca ocorrendo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DETECÇÃO&lt;/strong&gt;: Na detecção de deadlocks, presumimos que estes podem ocorrer. Em seguida, o estado do sistema é examinado para detectar se ocorreu um conflito e, posteriormente, corrigi-lo. É empregado um algoritmo que rastreia a alocação de recursos e os estados do processo, reverte e reinicia um ou mais processos para remover o impasse detectado. Detectar um deadlock que já ocorreu é facilmente possível, uma vez que os recursos que cada processo bloqueou e/ou solicitou atualmente são conhecidos pelo escalonador de recursos do sistema operacional.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depois que um deadlock é detectado, ele pode ser corrigido usando um dos seguintes métodos:&lt;/p&gt;

&lt;h2&gt;
  
  
  Encerramento do processo
&lt;/h2&gt;

&lt;p&gt;Um ou mais processos envolvidos no deadlock podem ser abortados. Pode-se optar por abortar todos os processos concorrentes envolvidos no impasse, garantindo que o impasse seja resolvido com certeza e velocidade. Entretanto, eventuais processamentos anteriores podem ser perdidos.&lt;/p&gt;

&lt;p&gt;O encerramento de processos pode seguir uma sequência, até que o impasse seja resolvido. Essa abordagem, porém, tem alto custo, porque após cada encerramento de processo/thread, um algoritmo deve determinar se o sistema ainda está em deadlock.&lt;/p&gt;

&lt;p&gt;Vários fatores devem ser considerados ao escolher um candidato para o encerramento, como prioridade e tempo de execução do processo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preempção de recursos
&lt;/h2&gt;

&lt;p&gt;Os recursos alocados a vários processos podem ser sucessivamente eliminados e alocados a outros processos até que o impasse seja resolvido.&lt;/p&gt;

&lt;p&gt;A prevenção de deadlock funciona evitando que uma das quatro condições de Coffman ocorra. Remover a condição de exclusão mútua significa que nenhum processo terá acesso exclusivo a um recurso. Isso é impossível para recursos que não podem ser armazenados em &lt;strong&gt;spool&lt;/strong&gt;. Mas, mesmo com recursos em spool, o impasse ainda pode ocorrer. Os algoritmos que evitam a exclusão mútua são chamados de &lt;strong&gt;algoritmos de sincronização sem bloqueio&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Spool&lt;/strong&gt; é o processo que transfere dados colocando-os em uma área de trabalho temporária, na qual outro programa pode acessá-lo para processá-lo em um tempo futuro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: As condições de retenção e espera ou retenção de recurso podem ser removidas exigindo que os processos solicitem todos os recursos de que precisarão antes de iniciar (ou antes de iniciar um determinado conjunto de operações). Esse conhecimento prévio é frequentemente difícil de satisfazer e, em qualquer caso, é um uso ineficiente de recursos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Outra maneira é exigir que os processos solicitem recursos apenas quando não houver nenhum. Primeiro, eles devem liberar todos os seus recursos atualmente mantidos antes de solicitar todos os recursos de que precisarão do zero. Muitas vezes, isso também é impraticável, porque os recursos podem ser alocados e permanecer sem uso por longos períodos. Além disso, um processo que requer um recurso popular pode ter que esperar indefinidamente, já que este pode sempre ser alocado para algum processo, resultando em escassez de recursos. Esses algoritmos, como tokens de serialização, são conhecidos como &lt;strong&gt;algoritmos tudo ou nada&lt;/strong&gt;. Eles devem liberar todos os seus recursos atualmente mantidos antes de solicitar todos os recursos de que precisarão do zero. Muitas vezes, isso também é impraticável, porque os recursos podem ser alocados e permanecer sem uso por longos períodos. Além disso, um processo que requer um recurso popular pode ter que esperar indefinidamente, já que este pode sempre ser alocado para algum processo, resultando em escassez de recursos. Esses algoritmos, como tokens de serialização, são conhecidos como algoritmos tudo ou nada.&lt;/p&gt;

&lt;p&gt;A condição de ausência de preempção também pode ser difícil ou impossível de evitar, pois um processo deve ser capaz de ter um recurso por um determinado período de tempo, ou o resultado do processamento pode ser inconsistente. No entanto, a incapacidade de impor a preempção pode interferir com um algoritmo de prioridade.&lt;/p&gt;

&lt;p&gt;A preempção de um recurso "bloqueado" geralmente implica uma reversão e deve ser evitada, uma vez que é muito cara em despesas gerais. Os algoritmos que permitem a preempção incluem algoritmos sem bloqueio e sem espera e controle de simultaneidade otimista. Se um processo retém alguns recursos e solicita algum outro que não pode ser alocado imediatamente a eles, a condição pode ser removida liberando todos os recursos retidos atualmente desse processo.&lt;/p&gt;

&lt;p&gt;A condição final é a condição de espera circular. Abordagens que evitam esperas circulares incluem desabilitar interrupções durante seções críticas e usar uma hierarquia para determinar uma ordenação parcial de recursos. Se nenhuma hierarquia óbvia existe, até mesmo o endereço de memória dos recursos será usado para determinar a ordem, e os recursos serão solicitados na ordem crescente da enumeração.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deadlocks distribuídos&lt;/strong&gt; podem ocorrer em sistemas distribuídos quando transações distribuídas ou controle de simultaneidade estão sendo usados. Eles podem ser detectados pela construção de um gráfico de espera global a partir de gráficos de espera locais em um detector de deadlock ou por um algoritmo distribuído como &lt;strong&gt;perseguição de borda&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Os sistemas distribuídos podem ter três tipos de deadlocks: &lt;strong&gt;fantasma&lt;/strong&gt;, de &lt;strong&gt;recurso&lt;/strong&gt; e de &lt;strong&gt;comunicação&lt;/strong&gt;. Veja-os a seguir:&lt;/p&gt;

&lt;h3&gt;
  
  
  Deadlocks fantasmas
&lt;/h3&gt;

&lt;p&gt;São deadlocks falsamente detectados em um sistema distribuído devido a atrasos internos do sistema, mas não existem de fato.&lt;/p&gt;

&lt;p&gt;Por exemplo, se um processo libera um recurso R1 e emite uma solicitação de R2, e a primeira mensagem é perdida ou atrasada, um coordenador (detector de deadlocks) pode concluir falsamente um deadlock (a solicitação de R2 enquanto tem R1 causaria um impasse). Em uma possível situação de deadlock fantasma, é muito difícil detectá-lo, porque vários processos podem liberar alguns recursos ou solicitar outros recursos ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Em alguns casos, as mensagens de liberação chegam depois das mensagens de solicitação para alguns recursos específicos. O &lt;strong&gt;algoritmo de detecção&lt;/strong&gt; trata a situação como um deadlock, e pode abortar alguns processos para quebrá-lo. Mas, na realidade, nenhum deadlock estava presente − os algoritmos o detectaram com base em mensagens desatualizadas dos processos devido a atrasos na comunicação. Esse impasse é chamado de &lt;strong&gt;impasse fantasma&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deadlocks de recurso
&lt;/h3&gt;

&lt;p&gt;Os processos podem esperar simultaneamente por vários recursos, e não podem prosseguir até que tenham adquirido todos eles. Um conjunto de processos fica em deadlock se cada processo no conjunto solicitar recursos mantidos por outro processo no conjunto. E deve receber todos os recursos solicitados antes que possa ser desbloqueado. Esse tipo de deadlock é muito parecido com os que observamos anteriormente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deadlocks de comunicação
&lt;/h3&gt;

&lt;p&gt;Os processos esperam para se comunicar com outros em um conjunto. Um processo de espera pode ser desbloqueado ao receber uma comunicação de um desses processos.&lt;/p&gt;

&lt;p&gt;Há conflito se cada processo no conjunto estiver esperando para se comunicar com outro e nenhum deles iniciar qualquer comunicação adicional até que receba a comunicação pela qual está esperando.&lt;/p&gt;

&lt;p&gt;Assista ao vídeo a seguir e conheça as quatro condições necessárias para que ocorra o &lt;a href="https://play.yduqs.videolib.live/player?token=78bc0e2ebd58471eb8361143f9196d64" rel="noopener noreferrer"&gt;problema de deadlock&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  🚦 Semáforo
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fem-content.zobj.net%2Fsource%2Fmicrosoft-teams%2F363%2Fvertical-traffic-light_1f6a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fem-content.zobj.net%2Fsource%2Fmicrosoft-teams%2F363%2Fvertical-traffic-light_1f6a6.png" width="256" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na ciência da computação, um &lt;strong&gt;semáforo&lt;/strong&gt; é um tipo de dado variável ou abstrato empregado para controlar o acesso a um recurso comum por vários processos e evitar problemas de seção crítica em um sistema simultâneo, como um sistema operacional multitarefa. Um &lt;strong&gt;semáforo trivial&lt;/strong&gt; é uma variável simples que é alterada (por exemplo, incrementada ou decrementada ou alternada), dependendo das condições definidas pelo programador.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em ciência da computação, semáforo é uma variável especial protegida que tem como função o controle de acesso a recursos compartilhados num ambiente multitarefa. A invenção desse tipo de variável é atribuída a Edsger Dijkstra, em 1965 e foi utilizado inicialmente no sistema operacional THEOS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Os semáforos são uma ferramenta útil na prevenção de condições de corrida; entretanto, seu uso não é de forma alguma uma garantia de que um programa esteja livre desses problemas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os semáforos que permitem uma contagem arbitrária de recursos são chamados de &lt;strong&gt;semáforos de contagem&lt;/strong&gt;, enquanto os que são restritos aos valores 0 e 1 (ou bloqueado/desbloqueado, indisponível/disponível) são chamados de &lt;strong&gt;semáforos binários&lt;/strong&gt; e são usados para implementar bloqueios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Suponha que uma biblioteca tenha dez salas de estudo idênticas, para serem usadas por um aluno por vez. Os alunos devem solicitar na recepção, caso desejem usar uma sala de estudo e, se nenhuma estiver disponível, eles esperam na mesa. Quando um aluno terminar de usar uma sala, ele deve retornar à carteira e indicar que uma das salas ficou livre.&lt;/p&gt;

&lt;p&gt;Na implementação mais simples, o funcionário da recepção sabe apenas o número de salas livres disponíveis. Quando um aluno solicita uma sala, o funcionário diminui esse número. Quando um aluno libera uma sala, o secretário aumenta esse número. As salas podem ser usadas por tempo indeterminado, por isso não é possível reservá-las com antecedência.&lt;/p&gt;

&lt;p&gt;Nesse cenário, o contador da recepção representa um semáforo de contagem, as salas são o recurso e os alunos representam processos/threads. O valor do semáforo é inicialmente 10, com todas as salas vazias. Quando um aluno solicita uma sala, o valor do semáforo é alterado para 9. Depois que o próximo aluno chega, ele cai para 8, depois para 7 e assim por diante. Se alguém solicita uma sala e o valor atual do semáforo é 0, eles são forçados a esperar até que uma delas esteja disponível (quando a contagem é aumentada de 0).&lt;/p&gt;

&lt;p&gt;Se uma das salas foi liberada, mas há vários alunos esperando, então qualquer método pode ser usado para selecionar aquele que irá ocupá-la. E os alunos precisam informar ao balconista sobre a liberação de sua sala somente depois de realmente deixá-la; caso contrário, pode haver uma situação embaraçosa quando este está em processo de deixar a sala (está empacotando seus livros etc.) e outro aluno entra antes de ele sair.&lt;/p&gt;

&lt;p&gt;Os semáforos são muito úteis na sincronização de processos e multithreading. Temos a biblioteca de semáforo &lt;strong&gt;POSIX&lt;/strong&gt; em sistemas Linux, e vamos aprender a usá-lo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Salientamos que semáforos existem nas mais diversas linguagens que permitem programação paralela, como por exemplo Java, bem como em diferentes sistemas operacionais.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O código básico de um semáforo é simples, conforme apresentado em nosso estudo. Mas esse código não pode ser escrito diretamente, pois as funções precisam ser atômicas, e escrever o código diretamente levaria a uma troca de contexto sem a conclusão da função e resultaria em uma bagunça.&lt;/p&gt;

&lt;p&gt;Para bloquear um semáforo ou esperar, podemos usar a função &lt;code&gt;sem_wait&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sem_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para liberar ou sinalizar um semáforo, usamos a função &lt;code&gt;sem_post&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sem_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um semáforo é inicializado usando &lt;code&gt;sem_init&lt;/code&gt; (para processos ou threads) ou &lt;code&gt;sem_open&lt;/code&gt; (para IPC).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;sem_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pshared&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  SEÇÃO CRÍTICA: TÉCNICAS DE SINCRONIZAÇÃO
&lt;/h1&gt;

&lt;p&gt;Como vimos no módulo anterior, o acesso dos processos à seção crítica (segmento serializado do programa) é controlado pelo uso de técnicas de sincronização. Quando um thread começa a executar a seção crítica, o outro thread deve esperar até que o primeiro thread termine.&lt;/p&gt;

&lt;p&gt;Se as técnicas de sincronização adequadas não forem aplicadas, isso pode causar uma condição de corrida em que os valores das variáveis podem ser imprevisíveis e variam dependendo dos tempos de alternância de contexto dos processos ou threads.&lt;/p&gt;

&lt;p&gt;Vejamos um exemplo de código para estudar problemas de sincronização por meio de uma seção crítica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="n"&gt;pthread_t&lt;/span&gt; &lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;pthread_mutex_t&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;trythis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; Job %d has started&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; Job %d has finished&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pthread_mutex_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; mutex init has failed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;trythis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Thread can't be created :[%s]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;strerror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pthread_mutex_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código anterior, percebemos que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Um mutex é inicializado no início da função principal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O mesmo mutex está bloqueado na função &lt;code&gt;trythis ()&lt;/code&gt; ao usar o recurso compartilhado ‘contador’.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No final da função &lt;code&gt;trythis ()&lt;/code&gt;, o mesmo mutex é desbloqueado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No final da função principal, quando ambas os threads estão concluídos, o mutex é destruído.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resultado:&lt;/p&gt;

&lt;pre&gt;
Job 1 started
Job 1 finished
Job 2 started
Job 2 finished
&lt;/pre&gt;

&lt;h1&gt;
  
  
  🚨 MONITOR
&lt;/h1&gt;

&lt;p&gt;Para superar os erros de tempo que ocorrem ao usar o semáforo para sincronização de processos, foi introduzida uma construção de sincronização de alto nível denominada monitor. Um tipo de monitor é um tipo de dados abstrato usado para sincronização de processos.&lt;/p&gt;

&lt;p&gt;Sendo um tipo de dados abstrato, o tipo de monitor contém as variáveis de dados que devem ser compartilhados por todos os processos e algumas operações definidas pelo programador, que permitem que os processos sejam executados em exclusão mútua dentro do monitor.&lt;/p&gt;

&lt;p&gt;Um processo não pode acessar diretamente a variável de dados compartilhados no monitor. Ele deve acessá-lo por meio de procedimentos definidos no monitor que permitem que apenas um processo acesse as variáveis compartilhadas em um monitor por vez. Ou seja, um monitor é uma construção em que apenas um processo está ativo por vez. Se outro processo tentar acessar a variável compartilhada no monitor, ele será bloqueado e será alinhado na fila para obter o acesso.&lt;/p&gt;

&lt;p&gt;A sintaxe do monitor é a seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;monitor&lt;/span&gt; &lt;span class="n"&gt;monitor_name&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//shared variable declarations&lt;/span&gt;
    &lt;span class="n"&gt;procedure&lt;/span&gt; &lt;span class="n"&gt;P1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;procedure&lt;/span&gt; &lt;span class="nf"&gt;P2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;procedure&lt;/span&gt; &lt;span class="nf"&gt;Pn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;initialization&lt;/span&gt; &lt;span class="nf"&gt;code&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos monitores, há a introdução do conceito de variáveis condicionais como um mecanismo de sincronização adicional. A variável condicional permite que um processo aguarde dentro do monitor e que um processo de espera seja retomado imediatamente quando o outro libera os recursos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: A variável condicional pode invocar apenas duas operações, &lt;code&gt;wait ()&lt;/code&gt; e &lt;code&gt;signal ()&lt;/code&gt;. Se um processo &lt;code&gt;P&lt;/code&gt; invocar uma operação &lt;code&gt;wait ()&lt;/code&gt;, ele é suspenso no monitor até que outro processo &lt;code&gt;Q&lt;/code&gt; invoque a operação &lt;code&gt;signal ()&lt;/code&gt;; ou seja, uma operação &lt;code&gt;signal ()&lt;/code&gt; invocada por um processo retoma o processo suspenso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  DIFERENÇA ENTRE SEMÁFORO E MONITOR
&lt;/h2&gt;

&lt;p&gt;Veja no quadro abaixo algumas diferenças entre semáforo e monitor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Semáforos&lt;/th&gt;
    &lt;th&gt;Monitores&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;O semáforo é uma variável inteira S que indica o número de recursos disponíveis no sistema&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;O monitor é o tipo de dado abstrato que permite que apenas um processo seja executado na seção crítica por vez.&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;O valor do semáforo pode ser modificado apenas pelas operações &lt;code&gt;wait()&lt;/code&gt; e &lt;code&gt;shmget()&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Um monitor, por sua vez, possui as variáveis compartilhadas e os procedimentos apenas por meio dos quais as variáveis compartilhadas podem ser acessadas pelos processos.&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;p&gt;No semáforo, quando um processo deseja acessar recursos compartilhados, o processo executa a operação &lt;code&gt;wait()&lt;/code&gt; e bloqueia os recursos e, quando libera os recursos, executa a operação &lt;code&gt;signal()&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
    &lt;td&gt;&lt;p&gt;Em monitores, quando um processo precisa acessar recursos compartilhados, ele deve acessá-los por meio de procedimentos no monitor.&lt;/p&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Além disso, o tipo de monitor possui variáveis de condição que o semáforo não possui.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-semaforo.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="99" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;// Programa em C para demonstrar como os Semaforos trabalham&lt;/span&gt;
&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;semaphore.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="cp"&gt;#define SemaforoLigado 1 // constante com o semáforo ligado
&lt;/span&gt;&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// estrutura de dados para identificar o estado do semáforo&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;identificador&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;thread_arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr_thread_arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="n"&gt;sem_t&lt;/span&gt; &lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;//semaforo nao-binario&lt;/span&gt;
&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//wait&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SemaforoLigado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sem_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Entrando na Regiao Critica..&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;ptr_thread_arg&lt;/span&gt; &lt;span class="n"&gt;targ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr_thread_arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A - Thread:  [%d]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targ&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;identificador&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//dormir 5 segundos&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B - Thread:  [%d]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targ&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;identificador&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;//signal&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Saindo da Regiao Critica...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SemaforoLigado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sem_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;thread_arg&lt;/span&gt; &lt;span class="n"&gt;argumentos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SemaforoLigado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sem_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;//Iniciar semaforo&lt;/span&gt;

    &lt;span class="n"&gt;pthread_t&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;argumentos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;identificador&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;argumentos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;identificador&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argumentos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt; &lt;span class="c1"&gt;//Criar a Thread 1&lt;/span&gt;
    &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                                           &lt;span class="c1"&gt;//dormir 2 segundos&lt;/span&gt;
    &lt;span class="n"&gt;pthread_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argumentos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt; &lt;span class="c1"&gt;//Criar a Thread 2&lt;/span&gt;
    &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                            &lt;span class="c1"&gt;//Esperar por um Thread 1&lt;/span&gt;
    &lt;span class="n"&gt;pthread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                            &lt;span class="c1"&gt;//Esperar por um Thread 2  &lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SemaforoLigado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sem_destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//---------------------------------------------------------------------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  ↕️ CORROTINAS (co-rotinas)
&lt;/h1&gt;

&lt;p&gt;As &lt;strong&gt;corrotinas&lt;/strong&gt; são componentes de programas de computador que generalizam sub-rotinas para multitarefa não preemptiva, permitindo que a execução seja suspensa e reiniciada. Os sistemas Windows iniciais não eram preemptivos, e o uso de corrotinas permitia que se alternassem dentro dos processos em execução. O uso de corrotinas permite, por exemplo, a não utilização de mecanismos de primitivas de sincronização, como semáforos e mutex.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As corrotinas foram uma das primeiras formas de permitir a simulação de um ambiente multitarefa, em especial nos sistemas operacionais não preemptivos, sendo ainda bastante úteis e simples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Elas também são componentes de programas de computador, onde os valores dos dados locais para uma co-rotina persistem em chamadas sucessivas e a execução de uma corrotina é suspensa quando o controle a deixa.&lt;/p&gt;

&lt;p&gt;As sub-rotinas são casos especiais de corrotinas. Quando são chamadas, a execução começa no início e, quando uma sub-rotina for encerrada, ela é concluída. Uma instância de uma sub-rotina só retorna uma vez, e não mantém o estado entre as invocações.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As corrotinas são úteis para implementar máquinas de estado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As corrotinas, por sua vez, podem sair chamando outras corrotinas, que podem posteriormente retornar ao ponto onde foram chamadas na corrotina original. Do seu ponto de vista, ela não está saindo, mas chamando outra corrotina. Assim, uma instância de corrotina mantém o estado e varia entre as invocações − pode haver várias instâncias de uma determinada corrotina de uma vez.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A diferença entre chamar outra corrotina por meio de "ceder" a ela e simplesmente chamar outra rotina (que então, também, voltaria ao ponto original), é que a relação entre duas corrotinas que cedem uma à outra não é a do chamador, mas simétrica.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma aplicação de corrotina seria na industria de videogames, onde cada ator tem seus proprios procedimentos, mas eles cedem controle ao escalonador central, que faz a execução dele sequencialmente.&lt;/p&gt;

&lt;p&gt;Vejamos um exemplo simples de como as corrotinas podem ser úteis: Suponha que você tenha um relacionamento consumidor-produtor em que uma rotina cria itens e os adiciona a uma fila e outra remove itens da fila e os usa. Por razões de eficiência, você deseja adicionar e remover vários itens de uma vez. O código pode ser assim:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-corrotina.c-4EAA25%3Fstyle%3Dsocial%26logo%3DC%26logoColor%3D5050" alt="C" width="97" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;queu&lt;/span&gt;
&lt;span class="n"&gt;coroutine&lt;/span&gt; &lt;span class="n"&gt;produce&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;produtora&lt;/span&gt;
    &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;preenchendo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;criando&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; &lt;span class="n"&gt;elementos&lt;/span&gt; &lt;span class="n"&gt;em&lt;/span&gt; &lt;span class="n"&gt;uma&lt;/span&gt; &lt;span class="n"&gt;fila&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;
            &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
            &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;
        &lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;consume&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Quando&lt;/span&gt; &lt;span class="n"&gt;ela&lt;/span&gt; &lt;span class="n"&gt;termina&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ela&lt;/span&gt; &lt;span class="n"&gt;manda&lt;/span&gt; &lt;span class="n"&gt;para&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;consumidora&lt;/span&gt;
&lt;span class="n"&gt;coroutine&lt;/span&gt; &lt;span class="n"&gt;consume&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;consumidora&lt;/span&gt;
    &lt;span class="n"&gt;loop&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;consumir&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; &lt;span class="n"&gt;elementos&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;remover&lt;/span&gt;
            &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;
            &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
        &lt;span class="n"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;produce&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Quando&lt;/span&gt; &lt;span class="n"&gt;ele&lt;/span&gt; &lt;span class="n"&gt;acabar&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;consumir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ele&lt;/span&gt; &lt;span class="n"&gt;envia&lt;/span&gt; &lt;span class="n"&gt;para&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;produtora&lt;/span&gt;
&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;produce&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Um exemplo clássico, seria o de produtor e consumidor, onde a corrotina cria itens e os coloca em uma fila e a outra rotina remove os itens da fila para usá-los e fazer a atividade dela. Perceba que há um processo colaborativo, onde ocorre as execuções e eles ficam se avisando quando ocorre essa execução.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-corrotina.py-3776AB%3Fstyle%3Dsocial%26logo%3DPython%26logoColor%3D5050" alt="python" width="103" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# -*- coding: utf-8 -*-
# Exemplo de co-rotina 
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;imprimir_nome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Procurando Nome:{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;texto_entrada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;texto_entrada&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;foi encontrado no texto: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;texto_entrada&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Chamando co-rotina. Nada irá acontecer.
&lt;/span&gt;&lt;span class="n"&gt;co_rotina&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;imprimir_nome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;teste&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Isso iniciará a execução da co-rotina e
# Imprime a primeira linha "Procurando Nome ..."
# e avançar a execução para "yield"
&lt;/span&gt;
&lt;span class="n"&gt;co_rotina&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Enviando entradas
&lt;/span&gt;&lt;span class="n"&gt;co_rotina&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;teste 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;co_rotina&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;teste 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;co_rotina&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;este 3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Temos um exemplo de corrotina implementada na linguagem de programação Python, diferente no programa anteriormente, esse tem uma função onde fazemos chamadas, e no resultado dela, foi achado o &lt;code&gt;teste 1&lt;/code&gt; e &lt;code&gt;teste 2&lt;/code&gt;, mas não o &lt;code&gt;este 3&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A fila é completamente preenchida ou esvaziada antes de ceder o controle para a outra corrotina usando o comando &lt;code&gt;yield&lt;/code&gt;. As chamadas de corrotinas adicionais começam logo após o rendimento, no &lt;code&gt;loop&lt;/code&gt; de corrotinas externo.&lt;/p&gt;

&lt;p&gt;Embora, esse exemplo seja frequentemente usado como uma introdução ao multithreading, dois threads não são necessários para isso: a instrução &lt;code&gt;yield&lt;/code&gt; pode ser implementada por um salto direto de uma rotina para a outra.&lt;/p&gt;

&lt;p&gt;As vantagens das corrotinas sobre os threads são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elas podem ser usadas em um contexto de tempo real rígido (alternar entre as corrotinas não precisa envolver nenhuma chamada do sistema ou qualquer chamada de bloqueio).&lt;/li&gt;
&lt;li&gt;Não há necessidade de primitivas de sincronização, como mutexes, semáforos etc. para proteger as seções críticas.&lt;/li&gt;
&lt;li&gt;Não há necessidade de suporte do sistema operacional.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;É possível implementar corrotinas usando encadeamentos de tarefas agendados preventivamente, de forma que seja transparente para o código de chamada, mas algumas das vantagens (particularmente a adequação para operação em tempo real e relativa economia de alternar entre eles) serão perdidas.&lt;/p&gt;

&lt;p&gt;As corrotinas são úteis para implementar o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MÁQUINAS DE ESTADO&lt;/strong&gt;: Dentro de uma única sub-rotina, em que o estado é determinado pelo ponto de entrada e de saída atual do procedimento. Isso pode resultar em um código mais legível em comparação com o uso da diretiva goto, e pode ser implementado por meio de recursão mútua com chamadas finais.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MODELO DE ATOR DE SIMULTANEIDADE&lt;/strong&gt;: Por exemplo, em videogames, cada ator tem seus próprios procedimentos (isso, novamente, separa logicamente o código), mas eles cedem de forma voluntária o controle ao escalonador central, que os executa sequencialmente (essa é uma forma de multitarefa cooperativa).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COMUNICAR PROCESSOS SEQUENCIAIS&lt;/strong&gt;: Ocorre quando cada subprocesso é uma corrotina. As entradas/saídas do canal e as operações de bloqueio geram corrotinas, e um planejador as desbloqueia em eventos de conclusão. Alternativamente, cada subprocesso pode ser o pai daquele que o segue no pipeline de dados (ou o precede, caso em que o padrão pode ser expresso como geradores aninhados).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COMUNICAÇÃO REVERSA&lt;/strong&gt;: Comumente usada em software matemático, no qual um procedimento como um solucionador, avaliador integral, precisa do processo de uso para fazer um cálculo, como avaliar uma equação ou integrando.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PTHREADS
&lt;/h2&gt;

&lt;p&gt;Um dos conceitos mais importantes relacionados a sistemas operacionais é denominado &lt;strong&gt;processo&lt;/strong&gt;. De modo geral, um processo é uma abstração de um programa em execução.&lt;/p&gt;

&lt;p&gt;Tal programa possui um espaço de endereçamento e, em sistemas tradicionais, apenas um thread (segmento ou fluxo de controle) de execução. Além disso, o processo contém toda informação relacionada ao seu contexto de execução, por exemplo, contador de programa, apontador de pilha e demais registradores. Ou seja, é um programa com sua função principal, denominada, sendo executado sequencialmente, instrução por instrução.&lt;/p&gt;

&lt;p&gt;No entanto, em muitos sistemas operacionais é possível criar mais de um thread no mesmo processo, isto é, no mesmo espaço de endereçamento. Nesse caso, mais de um fluxo de execução ocorre dentro do mesmo processo. Diante disso, é importante destacar algumas aplicações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tratar atividades que ocorrem “simultaneamente”.&lt;/li&gt;
&lt;li&gt;Dividir a aplicação em tarefas que acessam recursos compartilhados.&lt;/li&gt;
&lt;li&gt;Reduzir o tamanho de uma aplicação, uma vez que threads ocupam menos espaço em relação aos processos.&lt;/li&gt;
&lt;li&gt;São mais fáceis de criar e destruir.&lt;/li&gt;
&lt;li&gt;A sobreposição de tarefas pode acelerar a aplicação.&lt;/li&gt;
&lt;li&gt;Possibilitam paralelismo real em sistemas multicore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;É importante destacar que threads e processos são conceitos diferentes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt; 
    &lt;td&gt;&lt;b&gt;Processo&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;b&gt;Threads&lt;/b&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt; 
    &lt;td&gt;Como dito anteriormente, o processo é basicamente um agrupador de recursos (código e dados) e possui uma identidade.&lt;/td&gt;
    &lt;td&gt;Os threads são criados no contexto de um processo e compartilham o mesmo espaço de endereçamento.&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Em vista disso, threads não são independentes como os processos, pois, embora compartilhem o mesmo espaço de endereçamento dentro de um processo, cada thread possui os mecanismos para gerenciar seu contexto de execução. Assim, threads possuem seu próprio contador de programa, seu apontador de pilha e seus registradores.&lt;/p&gt;

&lt;p&gt;Os threads criados ocupam a CPU do mesmo modo que o processo criador, e são escalonados pelo próprio processo. Nesse contexto, quando uma aplicação multithread é executada, esses threads podem estar em qualquer um destes estados: em execução, bloqueado (aguardando), pronto para ser executado ou concluído (finalizado), conforme ilustrado na imagem a seguir:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F6e4d24c1-c805-416e-bffa-105a9de6b38e" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2F6e4d24c1-c805-416e-bffa-105a9de6b38e" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para padronizar a utilização de threads em diversos sistemas, o IEEE estabeleceu o padrão POSIX threads (IEEE 1003.1c), ou Pthreads. Esse padrão define mais de 60 funções − definidas na biblioteca &lt;strong&gt;pthreads.h&lt;/strong&gt; para criar e gerenciar threads.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Novo Thread&lt;/strong&gt;: Ela é criada, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pronto para ser executado&lt;/strong&gt;: pronta para ser executada,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em execução&lt;/strong&gt;: A thread pode passar pelo escalonador para ser executada,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aguardando&lt;/strong&gt;: A thread pode voltar para o estado de pronto, mas também para a operação de I/O,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pronto para ser executado&lt;/strong&gt;: Quando a operação anterior é resolvida, ela volta para o estado de pronto e volta para o ciclo em execução. Até que ela seja finalizada.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Além disso, a biblioteca define &lt;strong&gt;estruturas de dados&lt;/strong&gt; e &lt;strong&gt;atributos&lt;/strong&gt; para configurar os threads. De modo geral, esses atributos são passados como argumentos para os parâmetros das funções, por exemplo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pthread_t:&lt;/code&gt; Handle para pthread, isto é, um valor que permite identificar o thread.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pthread_attr_t:&lt;/code&gt; Atributos para configuração de thread.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  🔂 OPENMP &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FC%2FC%2B%2B-14.0.0-00599C%3Fstyle%3Dflat%26logo%3DCPlusPlus%26logoColor%3Dwhite" width="111" height="20"&gt;
&lt;/h1&gt;


&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fe%2Feb%2FOpenMP_logo.png" width="800" height="259"&gt;&lt;br&gt;

&lt;p&gt;&lt;strong&gt;OpenMP&lt;/strong&gt; é uma interface de programação de aplicativo (API) de memória compartilhada cujos recursos, como acabamos de ver, são baseados em esforços anteriores para facilitar a programação paralela de memória compartilhada.&lt;/p&gt;

&lt;p&gt;O OpenMP se destina à implementação em uma ampla gama de arquiteturas SMP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: À medida que máquinas multicore e processadores multithreading se espalham no mercado, eles podem ser cada vez mais usados para criar programas para computadores uniprocessadores.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como seus predecessores, OpenMP não é uma nova linguagem de programação. Em vez disso, é uma notação que pode ser adicionada a um programa sequencial em C ou C++ para descrever como o trabalho deve ser compartilhado entre threads que serão executados em diferentes processadores ou núcleos e para solicitar acessos a dados compartilhados conforme necessário.&lt;/p&gt;

&lt;p&gt;A inserção apropriada de recursos OpenMP em um programa sequencial permitirá que muitos, talvez a maioria, dos aplicativos se beneficiem de arquiteturas paralelas de memória compartilhada − geralmente com modificações mínimas no código. Na prática, muitos aplicativos têm um paralelismo considerável que pode ser explorado.&lt;/p&gt;

&lt;p&gt;O sucesso do OpenMP pode ser atribuído a vários fatores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sua forte ênfase na programação paralela estruturada.&lt;/li&gt;
&lt;li&gt;O fato de ser comparativamente simples de usar, uma vez que a responsabilidade de trabalhar os detalhes do programa paralelo é do compilador.&lt;/li&gt;
&lt;li&gt;A grande vantagem de ser amplamente adotado, de modo que um aplicativo OpenMP pode ser executado em muitas plataformas diferentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas, acima de tudo, o OpenMP é oportuno. Com o forte crescimento na implantação de SMPs pequenos e grandes e outros hardwares multithreading, a necessidade de um padrão de programação de memória compartilhada que seja fácil de aprender e aplicar é aceita em todo o setor. Os fornecedores por trás do OpenMP entregam coletivamente grande fração dos SMPs em uso nos dias atuais. Seu envolvimento com esse padrão de fato garante sua aplicabilidade contínua às suas arquiteturas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prós
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Código multithreading portátil (em C/C++ e outras linguagens, normalmente é necessário chamar primitivas específicas da plataforma para obter multithreading).&lt;/li&gt;
&lt;li&gt;Não precisa lidar com a passagem de mensagens como o MPI faz.&lt;/li&gt;
&lt;li&gt;O layout e a decomposição dos dados são controlados automaticamente por diretivas.&lt;/li&gt;
&lt;li&gt;Escalabilidade comparável ao MPI em sistemas de memória compartilhada.&lt;/li&gt;
&lt;li&gt;Paralelismo incremental: pode funcionar em uma parte do programa ao mesmo tempo, sendo que nenhuma mudança drástica no código é necessária.&lt;/li&gt;
&lt;li&gt;Código unificado para aplicativos seriais e paralelos: construções OpenMP são tratadas como comentários quando compiladores sequenciais são usados.&lt;/li&gt;
&lt;li&gt;As instruções de código original (serial) não precisam, em geral, ser modificadas quando paralelizadas com OpenMP. Isso reduz a chance de introduzir bugs inadvertidamente.&lt;/li&gt;
&lt;li&gt;Tanto o paralelismo de granulação grossa quanto o de granulação fina são possíveis.&lt;/li&gt;
&lt;li&gt;Em aplicações multifísicas irregulares que não aderem apenas ao modo de computação SPMD (Single Program Multiple Data), conforme encontrado em sistemas de partículas de fluido fortemente acoplados, a flexibilidade do OpenMP pode ter grande vantagem de desempenho sobre o MPI.&lt;/li&gt;
&lt;li&gt;Pode ser usado em vários aceleradores, como GPGPU (General Purpose Graphics Processing Unit) e FPGAs (Field Programmable Gate Array).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CONTRAS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Risco de introdução de bugs de sincronização difíceis de depurar e condições de corrida.&lt;/li&gt;
&lt;li&gt;A partir de 2017, funciona de forma eficiente somente em plataformas de multiprocessador de memória compartilhada.&lt;/li&gt;
&lt;li&gt;Requer um compilador que suporte OpenMP.&lt;/li&gt;
&lt;li&gt;A escalabilidade é limitada pela arquitetura da memória.&lt;/li&gt;
&lt;li&gt;Sem suporte para comparar e trocar.&lt;/li&gt;
&lt;li&gt;Falta um tratamento confiável de erros.&lt;/li&gt;
&lt;li&gt;Carece de mecanismos refinados para controlar o mapeamento do processador de thread.&lt;/li&gt;
&lt;li&gt;Alta chance de escrever código de compartilhamento falso acidentalmente.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Polling</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 20:51:23 +0000</pubDate>
      <link>https://forem.com/isaacalves7/polling-2kkl</link>
      <guid>https://forem.com/isaacalves7/polling-2kkl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205754710-bddc6a8a-cd5a-4785-abae-2ed4511d288d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F205754710-bddc6a8a-cd5a-4785-abae-2ed4511d288d.jpg" width="512" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Abordamos a &lt;strong&gt;arquitetura de polling&lt;/strong&gt; anteriormente, a agora passaremos a ver mais detalhes dessa implementação.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;polling&lt;/strong&gt; é um conceito que pode ser utilizado em diversas situações, tais como controle de acesso à rede, gerenciamento de impressora, entre outros. Seu mecanismo consiste no processo de um computador central, ou dispositivo de controle, interrogar cada estação ou recurso existente que compõe o sistema verificando sua prontidão ou estado.&lt;/p&gt;

&lt;p&gt;Em outras palavras, polling, ou operação com polling, na ciência da computação, refere-se à amostragem ativa do status de um dispositivo externo por um programa cliente como uma atividade síncrona.&lt;/p&gt;

&lt;p&gt;Esse sistema é mais frequentemente usado em termos de &lt;strong&gt;entrada/saída (E/S)&lt;/strong&gt;; também é conhecido como &lt;strong&gt;E/S com poll&lt;/strong&gt; ou &lt;strong&gt;E/S orientada por software&lt;/strong&gt;. A sondagem às vezes é usada como sinônimo de sondagem em espera ocupada.&lt;/p&gt;

&lt;p&gt;Nessa situação, quando uma operação de E/S é necessária, o computador não faz nada além de verificar o status do dispositivo de E/S até que ele esteja pronto, momento em que o dispositivo é acessado. Em outras palavras, o computador espera até que o dispositivo esteja pronto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: A sondagem também se refere à situação em que um recurso é testado continuamente quanto a sua prontidão. Caso não esteja, o computador retorna para uma tarefa diferente. Apesar de ser mais eficiente que a espera ocupada, não desperdiçando tantos ciclos de CPU, isso, geralmente, não é tão eficiente quanto a alternativa à E/S controlada por interrupção de polling, ou seja, com um dispositivo de hardware dedicado a esta tarefa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A grande desvantagem do mecanismo de polling é que se houverem muitos dispositivos no sistema ou rede, o tempo necessário para percorrer cada um dos dispositivos e voltar ao inicial será muito alto. A consequência é que pode exceder o tempo disponível para atender ao dispositivo de E/S.&lt;/p&gt;

&lt;p&gt;O mecanismo de polling pode ser descrito nas seguintes etapas:&lt;/p&gt;

&lt;h2&gt;
  
  
  Ações da estação
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A estação verifica continuamente o bit de ocupado até que ele se torne livre, por exemplo, quando o bit assumir o valor 0;&lt;/li&gt;
&lt;li&gt;Estando o bit marcado como livre, a estação escreve o comando no registro de comando. Caso o host esteja &lt;strong&gt;enviando dados para a saída&lt;/strong&gt;, ele irá marcar o bit de gravação e enviar um byte de dados para o registrador de saída de dados. Caso a estação esteja recebendo dados, ela irá ler o registrado de entrada de dados e define o bit de leitura para 0 como o próximo comando;&lt;/li&gt;
&lt;li&gt;A estação irá definir o bit de pronto para comando (command-ready) para 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Ações do controlador
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Quando o controlador verificar que o bit command-ready está definido, ele configura o bit ocupado como 1.&lt;/li&gt;
&lt;li&gt;O controlador irá ler o registro de comando. Caso o bit de gravação interno estiver definido, ele lê os dados do registrador de saída e executa as operações de E/S necessárias no dispositivo. Caso o bit de leitura esteja definido, os dados do dispositivo serão carregados no registro de entrada de dados para que a estação possa ler.&lt;/li&gt;
&lt;li&gt;Quando terminarem as operações, o controlador libera o bit command-ready, limpa o bit de erro para mostrar que a operação foi bem-sucedida e libera o bit ocupado.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O ciclo de &lt;em&gt;polling&lt;/em&gt; pode ser definido como o tempo que leva para, após ter sido consultado em dado momento, o ciclo receba uma nova consulta. O tempo ideal para cada ciclo depende de vários aspectos, tais como, retardo esperado para cada componente responder e a sobrecarga, por exemplo, tempo do processador e largura de banda da pesquisa.&lt;/p&gt;

&lt;p&gt;Na votação nominal (&lt;em&gt;roll call polling&lt;/em&gt;), o controlador irá consultar cada recurso em uma lista em uma sequência fixa. Neste tipo de polling, é necessário que seja configurado um mecanismo de temporização para aguardar a resposta de cada recurso que foi consultado, evitando travamentos do sistema caso ele não responda. Esse tipo de votação pode ser ineficiente caso haja muitos elementos a serem consultados, sendo poucos ativos e, também, caso a sobrecarga para as mensagens de consulta seja alta.&lt;/p&gt;

&lt;p&gt;No &lt;em&gt;hub polling&lt;/em&gt;, ou &lt;em&gt;token polling&lt;/em&gt;, cada recurso pesquisa pelo próximo recurso em uma determinada sequência fixa, até que o primeiro recurso dessa sequência seja alcançado. E quando isso ocorre, o ciclo de polling começa novamente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: O mecanismo de polling é empregado em diversas situações na área de computação, principalmente para controlar a execução ou a sequência de transmissão dos elementos envolvidos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por exemplo, em sistemas operacionais multitarefa, pode ser utilizado para que vários processos concorrentes possam disputar o uso do processador ou de dispositivos de E/S.&lt;/p&gt;

&lt;p&gt;Outro exemplo seria na área de redes, quando o canal de comunicação é compartilhado entre diversos dispositivos. Para que não ocorra colisão, é necessário que seja empregado um mecanismo de controle de acesso ao meio, dentre eles o polling. Uma estação mestre irá interrogar as estações escravas para que possam transmitir as informações por meio do canal.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Master-Slave</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 20:38:10 +0000</pubDate>
      <link>https://forem.com/isaacalves7/master-slave-2m27</link>
      <guid>https://forem.com/isaacalves7/master-slave-2m27</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.eplan.help%2Fen-us%2FInfoportal%2FContent%2FEECPro%2F2.9%2FContent%2FPictures%2F2010112601.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.eplan.help%2Fen-us%2FInfoportal%2FContent%2FEECPro%2F2.9%2FContent%2FPictures%2F2010112601.svg" width="108" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Embora o nome sugira certa semelhança com o modelo de cliente-servidor, na &lt;strong&gt;arquitetura mestre-escravo&lt;/strong&gt;, as funções se invertem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mestre-escravo (master-slave)&lt;/strong&gt; é um modelo de comunicação ou controle assimétrico onde um dispositivo ou processo (o "mestre") controla um ou mais outros dispositivos ou processos (os "escravos") e serve como seu hub de comunicação.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em alguns sistemas, &lt;strong&gt;um mestre&lt;/strong&gt; é selecionado a partir de um grupo de dispositivos elegíveis, com os outros dispositivos atuando na função de &lt;strong&gt;escravos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O processo de comunicação de um mestre com um escravo é denominado &lt;strong&gt;transação&lt;/strong&gt;. Existem dois tipos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pergunta-Resposta&lt;/strong&gt;: O mestre inicia uma transação com um de seus escravos. Todos os escravos o ouvem, mas apenas aquele a quem a comunicação é dirigida responde. A transação pode envolver a troca de várias mensagens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disseminação sem Resposta&lt;/strong&gt;: O mestre inicia uma transação para todos os escravos. Nenhum escravo responde explicitamente e o mestre presume que eles terminarão suas execuções em algum ponto. Pode ser que um ou mais escravos não recebam as informações corretamente e isso deve ser levado em consideração ao utilizar esse tipo de transação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em uma transação mestre-escravo, certos parâmetros são definidos para organizá-los e garanti-los, entre eles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocolo&lt;/strong&gt;: Para que dois componentes que estão trocando informações sejam compreendidos, é necessário que haja acordo sobre o conteúdo das informações trocadas. O conjunto de regras e convenções que governam a comunicação é chamado de &lt;em&gt;protocolo&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling&lt;/strong&gt;: O componente mestre interroga sob um esquema programado a sequência de escravos disponíveis; cada escravo pode receber diferentes tipos de transações correspondentes a uma ou mais tarefas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo esgotado (Timeout)&lt;/strong&gt;: Quando o mestre inicia a transação com um determinado escravo dentro do esquema de consulta-resposta, pode acontecer que o escravo seja incapaz de responder ao mestre. Portanto, o mestre deve lidar com um tempo limite para a resposta do escravo e, se não houver resposta, abortar a transação para tentar novamente ou para continuar com seu esquema de &lt;em&gt;polling&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Novas tentativas&lt;/strong&gt;: Quando um escravo não responde e o mestre aborta a transação, ele deve decidir o que fazer: continuar com o esquema de polling ou tentar novamente a transação abortada. O número de vezes que uma transação será repetida é chamado de &lt;em&gt;novas tentativas&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dentro desses modelos, há ainda algumas variações. No projeto de um sistema com arquitetura mestre-escravo, uma das decisões mais relevantes afeta a distribuição de responsabilidades, o que se denomina &lt;strong&gt;granularidade&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Granularidade&lt;/strong&gt; é a forma como o trabalho a ser executado é decomposto, ou seja, a carga computacional ou o tamanho das tarefas atribuídas aos escravos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dois tipos são distinguidos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Granularidade fina&lt;/strong&gt;: Consiste em distribuir o trabalho em muitas pequenas tarefas. Isso tem a vantagem de que, se um escravo morrer, o mestre atribui a tarefa a outro escravo, com uma penalidade de tempo muito pequena. Como desvantagem, você precisa de um número maior de escravos para realizar a tarefas específica;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Granularidade grossa&lt;/strong&gt;: Consiste em distribuir o trabalho em algumas tarefas grandes. Como vantagem, é apresentado que não serão necessários muitos escravos para realizar uma tarefa. Por outro lado, se um escravo morrer, a penalidade de tempo será significativa.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A implantação de um sistema com arquitetura mestre-escravo também permite a aplicação de diversas variantes dependendo da utilização de um ou mais mestres.&lt;/p&gt;

&lt;p&gt;São elas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mestre-escravo simples&lt;/strong&gt;: Estrutura clássica em que existe um único mestre que realiza a distribuição das tarefas entre os componentes escravos que as executam. Também pode ser responsável pelo gerenciamento dos próprios escravos (inicialização e parada, criação de mais instâncias em resposta ao aumento de solicitações ou carga do sistema, prisão de escravos ociosos ou com comportamentos anômalos etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mestre-escravo multinível&lt;/strong&gt;: Estrutura profunda na qual, ao invés de ter um único mestre supervisionando todos os escravos, um ou mais níveis de mestres são introduzidos para esse fim. Esses níveis de mestres então agrupam a supervisão de escravos ou outros mestres, de forma a conter o número de componentes supervisionados por cada componente de supervisão. Esta variante é comum em sistemas com grande número de escravos para evitar problemas de desempenho, ou seja, o mestre fica saturado com alta frequência de comunicações de escravos e para os escravos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Master sobressalente&lt;/strong&gt;: Estrutura que inclui um ou mais master sobressalentes, com o objetivo de aumentar a disponibilidade. Esta variante apresenta vários mestres secundários para que o esquema geral da arquitetura seja mantido. Se, durante a operação usual de monitoramento e controle o mestre morre, ele é imediatamente substituído por outro (usando pontos de verificação), minimizando o tempo em que o sistema deixa de estar operacional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mestre com redundância passiva&lt;/strong&gt;: Estrutura que inclui um ou mais masters sobressalentes, com o objetivo de aumentar a disponibilidade. Esta variante, como no caso anterior, introduziria um novo mestre, que seria constantemente atualizado em relação aos dados do mestre principal. Assim, se durante a operação usual de supervisão e controle o mestre morrer, ele é imediatamente substituído por outro que já está pronto para funcionar, reduzindo praticamente a zero o tempo em que o sistema deixa de estar operacional.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vantagens do Master-Slave
&lt;/h3&gt;

&lt;p&gt;Entre as &lt;strong&gt;vantagens&lt;/strong&gt; da arquitetura mestre-escravo está a alta tolerância a erros. Isso significa que caso um escravo morra, dificilmente o sistema será afetado e poderá continuar operando sem problemas. A tarefa incompleta pode ser atribuída a outro escravo pelo mestre, e o escravo com falha pode ser reiniciado ou substituído. Por outro lado, no caso de falecimento do mestre (que é o caso que mais afeta o sistema, pois envolve uma penalidade maior ou até mesmo faz com que pare totalmente) pode ser resolvido aplicando algumas das variantes que proporcionam um substituto para o mestre.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desvantagens do Master-Slave
&lt;/h3&gt;

&lt;p&gt;Entre as &lt;strong&gt;desvantagens&lt;/strong&gt; mais problemáticas está a necessidade de independência das tarefas a serem desempenhadas pelo sistema, de forma a distribuí-las entre os escravos. Além disso, tal distribuição deve fazer uso inteligente das capacidades dos escravos, para maximizar o desempenho geral do sistema.&lt;/p&gt;

&lt;p&gt;Assim, se uma arquitetura com muitos escravos e um único mestre for implantada, onde há muitas comunicações entre ela e estes, o mestre pode sofrer problemas de saturação, sendo o principal componente do sistema, isso resultaria em uma redução direta no desempenho. A saturação (ou baixo desempenho) do mestre é tanto mais provável quanto mais responsabilidades lhe forem atribuídas, portanto um sistema em que o mestre, além de distribuir tarefas entre os escravos, é responsável por processar os dados por eles retornados, fazendo algum tipo de computação global com esses dados, aumenta o risco de oferecer uma latência maior do que a esperada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em termos gerais, a arquitetura mestre-escravo é adequada para a construção de sistemas de tempo real, que precisam garantir o tempo de resposta. Também é frequentemente encontrado em sistemas embarcados, que podem ser construídos combinando arquitetura de repositório ou arquitetura de pipeline com mestre-escravo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comentário&lt;/strong&gt;: Essa arquitetura, às vezes, é usada para estruturar a parte dos sistemas que lida com a replicação de informações; portanto, na replicação do banco de dados, o banco de dados mestre é considerado a fonte autorizada, e os bancos de dados escravos são sincronizados com ele.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Além de organizar a relação entre componentes de software de sistemas computacionais, a organização mestre-escravo está presente nas camadas mais baixas dos níveis de rede, bem como nas caraterísticas de arquitetura de computadores.&lt;/p&gt;

&lt;p&gt;Os periféricos conectados a um barramento em equipamentos de informática geralmente funcionam como escravos de um mestre (controlador). Os discos rígidos que usam &lt;strong&gt;ATA&lt;/strong&gt; em paralelo também são organizados em um esquema mestre-escravo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ATA - Acrônimo de Advanced Technology Attachment&lt;/strong&gt; é uma tecnologia surgida nos anos 80, trazendo o inovador recurso de funcionamento do disco rígido com o driver (controlador) integrado, tendo o objetivo de homogeneizar os tipos de conectores do disco rígido à placa mãe e à fonte de energia.&lt;/p&gt;

&lt;p&gt;Os &lt;strong&gt;clusters&lt;/strong&gt; de computadores fazem uso dessa arquitetura, assim como ferramentas como o &lt;strong&gt;Jenkins&lt;/strong&gt; que utiliza essa arquitetura para realizar seu &lt;code&gt;build&lt;/code&gt; da instância master para as instâncias slaves.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>distributedsystems</category>
      <category>devops</category>
      <category>architecture</category>
      <category>networking</category>
    </item>
    <item>
      <title>Client-Server model</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 20:19:59 +0000</pubDate>
      <link>https://forem.com/isaacalves7/client-server-model-41pm</link>
      <guid>https://forem.com/isaacalves7/client-server-model-41pm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fc%2Fc9%2FClient-server-model.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fc%2Fc9%2FClient-server-model.svg" width="500" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;modelo cliente-servidor&lt;/strong&gt; (em inglês &lt;strong&gt;client-server model&lt;/strong&gt;), em computação, é uma estrutura/arquitetura de aplicação distribuída que distribui as tarefas e cargas de trabalho entre os fornecedores/provedores de um recurso e/ou serviço, designados como &lt;strong&gt;servidores&lt;/strong&gt;, e os solicitantes/requerentes dos serviços, designados como &lt;strong&gt;clientes&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Um &lt;strong&gt;servidor&lt;/strong&gt; é um dispositivo ou computador ou programa dedicado à prestação de serviços para outros programas, chamados de "clientes". Ou seja, um servidor é uma máquina centralizada que oferece serviços a um &lt;strong&gt;cliente&lt;/strong&gt; que é o computador do usuário, assim como o seu. É utilizado pelas pessoas para acessar sites ou sistemas a partir de um endereço no navegador (Google Chrome, Internet Explorer, Safari, Mozilla Firefox e etc).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois da etapa de UI/UX Design, vem a etapa de codificação. Na parte de codificação no modelo cliente-servidor, você consegue discernir quem é o requerente e o provedor, o aplicativo mobile do banco de seu celular é o requerente. E a forma como o requerente irá acessar e solicitar as informações dele no sistema, é necessário o provedor. Então, perceba que eles tem funções distintas, assim como também pode haver linguagens de programação distintas ou não.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O modelo cliente-servidor é a arquitetura mais frequentemente citada na literatura de sistemas distribuídos. Historicamente, é a mais importante e continua sendo a mais amplamente utilizada. A figura a seguir ilustra a estrutura simples na qual os processos assumem as funções de clientes ou servidores. Em particular, os processos do cliente interagem com os processos individuais do servidor em computadores host potencialmente separados para acessar os recursos compartilhados que eles gerenciam.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Geralmente os clientes e servidores comunicam através de uma rede de computadores em computadores distintos, mas tanto o cliente quanto o servidor podem residir no mesmo computador.&lt;/p&gt;

&lt;p&gt;Um servidor é um host que está executando um ou mais serviços ou programas que compartilham recursos com os clientes. Um cliente não compartilha qualquer de seus recursos, mas solicita um conteúdo ou função do servidor. Os clientes iniciam sessões de comunicação com os servidores que aguardam requisições de entrada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Frequentemente, clientes e servidores se comunicam em uma rede de computadores em hardware separado, mas tanto o cliente quanto o servidor podem residir no mesmo sistema. Um host de servidor executa um ou mais programas de servidor, que compartilham seus recursos com os clientes. &lt;/p&gt;

&lt;p&gt;Um cliente, geralmente, não compartilha nenhum de seus recursos, mas solicita conteúdo ou serviço de um servidor. Os clientes, portanto, iniciam sessões de comunicação com os servidores, que aguardam solicitações de entrada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O modelo cliente-servidor foi desenvolvido na Xerox PARC durante os anos 70. Este modelo é actualmente o predominante nas redes informáticas. Email, a World Wide Web e redes de impressão são exemplos comuns deste modelo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A arquitetura cliente-servidor descreve o relacionamento de programas cooperativos em um aplicativo. O componente do servidor fornece uma função ou serviço a um ou mais clientes, que iniciam solicitações para esses serviços. Nesse sentido, os servidores são classificados pelos serviços que fornecem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os tipos de servidores dessa arquitetura incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Servidor de Aplicação (Middleware)&lt;/li&gt;
&lt;li&gt;Servidor DNS&lt;/li&gt;
&lt;li&gt;Servidor Web (Web Server)&lt;/li&gt;
&lt;li&gt;Servidor de Fax&lt;/li&gt;
&lt;li&gt;Servidor de arquivos&lt;/li&gt;
&lt;li&gt;Servidor de email&lt;/li&gt;
&lt;li&gt;Servidor FTP&lt;/li&gt;
&lt;li&gt;Servidor de imagens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A arquitetura de um sistema de software é uma metáfora, análoga à arquitetura de um edifício. Funciona como um &lt;strong&gt;blueprint&lt;/strong&gt; do sistema e do projeto em desenvolvimento, que a gerência do projeto pode utilizar posteriormente para extrapolar as tarefas necessárias a serem executadas pelas equipes e pessoas envolvidas.&lt;/p&gt;

&lt;p&gt;A arquitetura de software trata de fazer escolhas estruturais fundamentais que custam caro mudar uma vez implementadas. As opções de arquitetura de software incluem opções estruturais específicas de possibilidades no design do software.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Um servidor web atende páginas web e um servidor de arquivos atende arquivos de computador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um recurso compartilhado pode ser qualquer software e componentes eletrônicos do computador servidor, desde programas e dados até processadores e dispositivos de armazenamento. O compartilhamento de recursos de um servidor constitui um serviço.&lt;/p&gt;

&lt;p&gt;Se um computador é um cliente, um servidor ou ambos, é determinado pela natureza do aplicativo que requer as funções de serviço.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Exemplo&lt;/strong&gt;: Um único computador pode executar um servidor web e um software servidor de arquivos ao mesmo tempo para servir dados diferentes a clientes que fazem diferentes tipos de solicitações. O software cliente também pode se comunicar com o software servidor no mesmo computador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em geral, um &lt;strong&gt;serviço&lt;/strong&gt; é uma abstração de recursos do computador, e um cliente não precisa se preocupar, em tese, com o desempenho do servidor enquanto atende a solicitação e entrega a resposta. O cliente só precisa entender a resposta com base no protocolo de aplicativo bem conhecido, ou seja, o conteúdo e a formatação dos dados para o serviço solicitado.&lt;/p&gt;

&lt;p&gt;Clientes e servidores trocam mensagens em um padrão de mensagem de solicitação-resposta. O cliente envia uma solicitação e o servidor retorna uma resposta. Essa troca de mensagens é um exemplo de comunicação entre processos. Para se comunicar, os computadores devem ter uma linguagem comum e devem seguir regras para que o cliente e o servidor saibam o que esperar.&lt;/p&gt;

&lt;p&gt;O idioma e as regras de comunicação são definidos em um protocolo de comunicação, sendo que estes protocolos operam na camada de aplicativo. O protocolo da camada de aplicação define os padrões básicos do diálogo.&lt;/p&gt;

&lt;p&gt;Para formalizar ainda mais a troca de dados, o servidor pode implementar uma interface de programação de aplicativos (Application Program Interface – API).&lt;/p&gt;

&lt;p&gt;A API é uma camada de abstração para acessar um serviço:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ao &lt;strong&gt;restringir a comunicação&lt;/strong&gt; a um formato de conteúdo específico, facilita a análise.&lt;/li&gt;
&lt;li&gt;Ao abstrair o acesso, facilita a troca de dados entre plataformas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um servidor pode receber solicitações de muitos clientes distintos em um curto período. Um computador só pode realizar um número limitado de tarefas a qualquer momento e conta com um sistema de agendamento para priorizar as solicitações de entrada dos clientes para acomodá-las.&lt;/p&gt;

&lt;p&gt;Para evitar sobrecarga e maximizar a disponibilidade, o software do servidor pode limitar a disponibilidade para os clientes. Aproveitando a eventual possibilidade de sobrecarga, podem ser feitos ataques de negação de serviço que são projetados para explorar a obrigação de um servidor de processar solicitações, sobrecarregando-o com taxas de solicitação excessivas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção&lt;/strong&gt;: Caso a segurança seja um fator importante, técnicas de criptografia podem ser aplicadas se as informações confidenciais forem comunicadas entre o cliente e o servidor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando um correntista de banco acessa serviços de banco on-line com um navegador da web (o cliente), este inicia uma solicitação ao servidor de web do banco. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As credenciais de login do correntista podem ser armazenadas em um banco de dados e o servidor da web acessa o servidor de banco de dados como um cliente. Um servidor de aplicativos (Middleware) interpreta os dados retornados aplicando a lógica de negócios do banco e fornece a saída para o servidor da web. Finalmente, o servidor da web retorna o resultado ao navegador da web do correntista para exibição.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por exemplo, os sistemas que controlavam o veículo de lançamento do ônibus espacial tinham o requisito de serem muito rápidos e muito confiáveis. Portanto, uma &lt;strong&gt;linguagem de computação de tempo real (RTC)&lt;/strong&gt; apropriada precisaria ser escolhida. Além disso, para satisfazer a necessidade de confiabilidade, pode-se optar por ter várias cópias redundantes e produzidas independentemente do programa e executar essas cópias em hardware independente enquanto verifica os resultados.&lt;/p&gt;

&lt;p&gt;A documentação da arquitetura de software facilita a comunicação entre as partes interessadas , captura decisões iniciais sobre o design de alto nível e permite a reutilização de componentes de design entre projetos.&lt;/p&gt;

&lt;p&gt;A característica do &lt;strong&gt;modelo cliente-servidor&lt;/strong&gt;, descreve a relação de programas numa aplicação. O componente de servidor fornece uma função ou serviço a um ou mais clientes, que iniciam os pedidos de serviço.&lt;/p&gt;

&lt;h2&gt;
  
  
  Servidor DNS
&lt;/h2&gt;

&lt;p&gt;Quando os usuários digitam nomes de domínio na barra de URL do navegador, os &lt;strong&gt;servidores de DNS&lt;/strong&gt; são responsáveis pela tradução desses nomes de domínio em endereços de IP numéricos, levando-os ao site correto. O &lt;strong&gt;Domain Name System&lt;/strong&gt; (DNS) é a lista telefônica da Internet. Quando os usuários digitam nomes de domínio como 'google.com' ou 'nytimes.com' nos navegadores da web, o DNS é responsável por encontrar o endereço de IP correto para esses sites. Os navegadores então usam esses endereços para se comunicar com os servidores de origem ou com os servidores de borda da CDN para acessar as informações do site. Tudo isso acontece graças aos servidores de DNS: máquinas dedicadas para responder às solicitações ao DNS.&lt;/p&gt;

&lt;p&gt;Os clientes DNS, que são integrados à maioria dos sistemas operacionais modernos dos desktops e de dispositivos móveis, permitem que os navegadores web interajam com os servidores de DNS. Para obter mais informações, veja O Modelo Cliente-Servidor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Server (Servidor web)
&lt;/h2&gt;

&lt;p&gt;Um "&lt;strong&gt;Servidor web&lt;/strong&gt; (&lt;strong&gt;web server&lt;/strong&gt;)" pode referir ao hardware ou ao software, ou ambos trabalhando juntos.&lt;/p&gt;

&lt;p&gt;As funcionalidades como a troca de e-mail, acesso à internet ou acesso a um banco de dados, são construídos com base no modelo cliente-servidor. Por exemplo, um navegador web é um programa cliente, em execução no computador do usuário, que acede às informações armazenadas num &lt;strong&gt;servidor web&lt;/strong&gt; (Web Server) na internet, onde seu objetivo é ouvir uma porta para responder requisições HTTP. Usuários de serviços bancários, acedendo do seu computador, usam um cliente web para enviar uma solicitação para um servidor web num banco. Esse programa pode, por sua vez, encaminhar o pedido para o seu próprio programa de banco de dados do cliente que envia uma solicitação para um servidor de banco de dados noutro computador do banco para recuperar as informações da conta. O saldo é devolvido ao cliente de banco de dados do banco, que por sua vez, serve de volta ao cliente navegador exibindo os resultados para o usuário.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mas como o &lt;strong&gt;servidor web&lt;/strong&gt; (&lt;strong&gt;Web Server&lt;/strong&gt;) e o computador sabem o que significa "localhost"? Através do &lt;strong&gt;arquivo de hosts&lt;/strong&gt;. Então, todo sistema operacional possui um arquivo de hosts. No Linux, por padrão fica em &lt;code&gt;/etc/hosts&lt;/code&gt;. No Mac, &lt;code&gt;/private/etc/hosts&lt;/code&gt;. Já no Windows, &lt;code&gt;C:\Windows\System32\Drivers\Etc\hosts&lt;/code&gt;. Esse arquivo informa ao sistema operacional que quando uma conexão for estabelecida usando algum nome, o IP correspondente deve ser usado. Para o nome localhost, temos o IP da nossa própria máquina (127.0.0.1).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;São exemplos de servidores web HTTP, junto com suas características abaixo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apache&lt;/strong&gt; (desenvolvimento/produção): O Servidor HTTP Apache ou Servidor Apache ou HTTP Daemon Apache ou somente Apache, é o servidor web livre criado em 1995 por um grupo de desenvolvedores da NCSA, tendo como base o servidor web NCSA HTTPd criado por Rob McCool. O Apache é um software de servidor da Web de código aberto usado para fornecer páginas da Web aos usuários. É um dos servidores da Web mais populares do mundo e é usado por muitos dos maiores sites. O Apache também é usado como um servidor de aplicativos, permitindo que os desenvolvedores criem e implantem aplicativos na web;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt; (desenvolvimento/produção): Nginx é um servidor leve de HTTP, proxy reverso, proxy de e-mail IMAP/POP3, feito por Igor Sysoev em 2005, sob licença BSD-like 2-clause. O Nginx consome menos memória que o Apache, pois lida com requisições Web do tipo “event-based web server”; e o Apache é baseado no “process-based server”, podendo trabalhar juntos;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IIS Express&lt;/strong&gt; (desenvolvimento): O IIS - Serviços de informação para internet (Internet Information Services) é um servidor web incluso no Visual Studio que permite você aproveitar ao máximo todos os recursos do servidor da Web (SSL, regras de regravação de URL, etc.). O IIS é um servidor web completo – o que significa que você terá uma experiência mais próxima de como funcionará quando implantar o aplicativo em um servidor de produção. O IIS Express é usado apenas para fins de desenvolvimento e teste e não tem suporte para uso em um ambiente de produção como um servidor Web de produção.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lighttpd&lt;/strong&gt; (desenvolvimento/produção): é um servidor web projetado para otimizar ambientes de alta performance. A utilização de memória é baixa se comparada a outros servidores web, possui um bom gerenciamento de carga da UCP e opções avançadas como CGI, FastCGI, SCGI, SSL, reescrita de URL, entre outras. Ele é projetado em um modelo assíncrono para lidar com solicitações e funciona em um único thread. Se você não deseja carregar os recursos do sistema, essa é a melhor opção para você. O Lighttpd é capaz de lidar com algumas centenas de solicitações por segundo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gunicorn&lt;/strong&gt; (desenvolvimento/produção): O Gunicorn "Green Unicorn" é um servidor HTTP Python Web Server Gateway Interface. É um modelo de trabalhador pré-fork, portado do projeto Unicorn de Ruby. O servidor Gunicorn é amplamente compatível com vários frameworks da web, implementado de forma simples, leve nos recursos do servidor e bastante rápido. O Gunicorn é, acima de tudo, um servidor de aplicativos Python WSGI e testado em batalha: é rápido, otimizado e projetado para produção. Ele oferece um controle mais refinado sobre o próprio servidor de aplicativos;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Puma&lt;/strong&gt; (desenvolvimento/produção): Puma é um servidor web HTTP derivado de Mongrel e escrito por Evan Phoenix. Ele enfatiza a velocidade e o uso eficiente da memória. Ele é ideal para aplicações Rails em produção;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apache Tomcat&lt;/strong&gt; (desenvolvimento/produção): O Tomcat é um servidor web Java, mais especificamente, um container de servlets. O Tomcat implementa, dentre outras de menor relevância, as tecnologias Java Servlet e JavaServer Pages e não é um container Enterprise JavaBeans. Desenvolvido pela Apache Software Foundation, é distribuído como software livre.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Glassfish&lt;/strong&gt; (desenvolvimento): GlassFish é um servidor de aplicação open source liderado pela Sun Microsystems para a plataforma Java EE. Sua versão proprietária é chamada Sun GlassFish Enterprise Server. GlassFish suporta todas as especificações da API Java EE, tais como JDBC, RMI, JavaMail, JMS, JMX etc. e define como coordená-las. GlassFish também suporta algumas especificações para componentes Java EE, como Enterprise JavaBeans, conectore, servlets, portlets, JSF e diversas tecnologias de web services. Isto permite que desenvolvedores criem aplicações corporativas portáveis, escaláveis e fáceis de integrar com código legado.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A base de GlassFish é o código-fonte liberado pela Sun e o sistema de persistência TopLink da Oracle. Ele utiliza uma variante do Apache Tomcat como container de servlets, com um componente adicional chamado Grizzly que utiliza nio para maior escalabilidade e eficiência.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Caddy&lt;/strong&gt; (desenvolvimento/produção): é um servidor HTTP de código aberto pronto para produção, mais produtivo, fácil de usar e rápido com HTTPS ativado por padrão. Foi lançado em 2015 e oferece suporte a uma variedade de tecnologias de sites. O Caddy é semelhante ao NGINX em sintaxe e em muitas outras coisas, mas é extremamente simplificado. Let's Encrypt (uma autoridade certificadora sem fins lucrativos que fornece certificados TLS) A integração SSL pode ser concluída usando três linhas de configuração.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Ff%2Ffb%2FServer-based-network.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Ff%2Ffb%2FServer-based-network.svg" width="119" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O modelo cliente-servidor, tornou-se uma das ideias centrais de computação de rede. Muitos aplicativos de negócios, escritos hoje, utilizam o modelo cliente-servidor. O termo também tem sido utilizado para distinguir a computação distribuída por computadores dispersos da "computação" monolítica centralizada em &lt;strong&gt;mainframe&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mainframe&lt;/strong&gt; é um computador de grande porte dedicado normalmente ao processamento de um volume enorme de informações. O termo mainframe era utilizado para se referir ao gabinete principal que alojava a CPU (unidade central de processamento) nos primeiros computadores.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cada instância de software do cliente pode enviar requisições a vários servidores (sendo clusters ou não). Por sua vez, os servidores podem aceitar esses pedidos, processá-los e retornar as informações solicitadas para o cliente. Embora este conceito possa ser aplicado por uma variedade de razões e para diversos tipos de aplicações, a arquitetura permanece fundamentalmente a mesma.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmadooei.github.io%2Fcs421_sp20_homepage%2Fassets%2Fclient-server-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmadooei.github.io%2Fcs421_sp20_homepage%2Fassets%2Fclient-server-1.png" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Curiosidade&lt;/strong&gt;: Nesse tipo de arquitetura que surgiu o Desenvolvimento Web com as terminologias de &lt;strong&gt;Front-End&lt;/strong&gt; (Lado do Cliente) e &lt;strong&gt;Back-End&lt;/strong&gt; (Lado do Servidor). Onde o &lt;strong&gt;front-end&lt;/strong&gt; se trata de toda a interface que o usuário interage com a Web com arquivos estáticos e o Back-end se trata do seu consumo e interação com as aplicações de servidores localizados na internet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Temos aqui o cliente e o servidor, então imagine que o &lt;strong&gt;cliente&lt;/strong&gt; é um navegador web (browser); e nós temos um servidor rodando, uma aplicação em &lt;strong&gt;Java&lt;/strong&gt;, em &lt;strong&gt;PHP&lt;/strong&gt;, &lt;strong&gt;C-Sharp (C#) - .NET&lt;/strong&gt;, &lt;strong&gt;Python&lt;/strong&gt;, &lt;strong&gt;Ruby&lt;/strong&gt; ou a linguagem que for. &lt;/p&gt;

&lt;p&gt;Então, o cliente vai digitar a URL do nosso site: “site.com.br”, por exemplo, e ele vai fazer uma requisição, utilizando o protocolo HTTP, para o computador que tem o nome “site.com.br”. Esse computador precisa saber/receber essa requisição (&lt;strong&gt;request&lt;/strong&gt;) web e fazer uma resposta (&lt;strong&gt;response&lt;/strong&gt;) que pode ser: exibir o HTML, a imagem, devolver o arquivo CSS - ou então mandar para uma aplicação processar essa requisição, uma aplicação em Java, em PHP, em Python ou no que for. Essa tarefa de receber a requisição e decidir o que vai fazer para enviar uma resposta, se vai mandar para uma aplicação, se vai devolver algum arquivo direto - essa é a tarefa de um &lt;strong&gt;servidor web&lt;/strong&gt; (&lt;strong&gt;Web Server&lt;/strong&gt;), e que ele vai fazer dentro de um servidor é ficar ouvindo a porta (Listener). &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O papel de um servidor web é ouvir conexões TCP em alguma porta configurada. Um servidor web vai ficar esperando uma conexão chegar. Quando ela chegar, o servidor web faz seu trabalho, garantindo que a mensagem recebida está no formato HTTP e depois fazendo o que deve fazer segundo suas configurações. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando falamos de HTTP, a porta padrão é a &lt;code&gt;80&lt;/code&gt;. Então, se você não digita uma porta e está utilizando HTTP, essa requisição vai cair na porta &lt;code&gt;80&lt;/code&gt;. Então um servidor web fica lá ouvindo, por exemplo, a porta 80 e ele fica esperando alguma requisição ou algum pedido entrar para chegar nesse computador. &lt;/p&gt;

&lt;h2&gt;
  
  
  Caching (Cacheamento)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F234577655-debc406d-1abc-4774-9b8f-463458722b7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F234577655-debc406d-1abc-4774-9b8f-463458722b7f.png" width="630" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na área da computação, cache é um dispositivo de acesso rápido, interno a um sistema, que serve de intermediário entre um operador de um processo e o dispositivo de armazenamento ao qual esse operador acede.&lt;/p&gt;

&lt;p&gt;Portanto, o &lt;strong&gt;caching&lt;/strong&gt; é uma técnica de armazenamento intermediário de dados da aplicação, que podem ser feitos através de hardware ou software. Ela serve para prover um acesso mais rápido a determinadas informações do que acessar diretamente a base de dados da aplicação.&lt;/p&gt;

&lt;p&gt;Uma das maiores causas da má performance em aplicações Web é a falta de cache. Nem todas as requests precisam gastar recursos computacionais do seu servidor para executarem alguma coisa. Grande parte das requisições que fazemos podem ocupar um total de 0 recursos computacionais usando técnicas de caching.&lt;/p&gt;

&lt;p&gt;Existem diversas formas de se fazer cache, a mais comum delas é utilizar o próprio servidor de proxy, como o Nginx ou o Apache para poder tratar e verificar se aquela requisição já foi feita no passado e evitar que ela sequer chegue no servidor da sua aplicação, já retornando o valor computado.&lt;/p&gt;

&lt;p&gt;Em outros casos, quando precisamos de uma requisição mais complexa, a gente pode usar bancos de dados chave-valor, como o Redis, para poder armazenar os resultados das nossas requisições e retornar uma resposta o mais rápido possível, utilizando o mínimo do nosso servidor.&lt;/p&gt;

&lt;p&gt;A grande maioria das empresas, principalmente as que lidam com dados que não se alteram tanto, usam caches para poder servir as páginas da forma mais rápida possível, ou você acha que o Twitter vai recalcular toda a sua linha do tempo todas as vezes? &lt;/p&gt;

&lt;h2&gt;
  
  
  Middleware (Servidor de Aplicação)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204110690-b71f040a-ee52-4719-89cb-c42ed5346809.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F204110690-b71f040a-ee52-4719-89cb-c42ed5346809.png" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando chega, esse servidor web tem que saber o que fazer, ou seja, ele vai analisar e se o que você está pedindo parece ser um arquivo de imagem, então não preciso fazer nada com mais ninguém. Eu só vou te devolver essa imagem e o navegador vai exibir para você. Se você está me pedindo um arquivo estático, um arquivo de CSS? Então só vou te devolver, não preciso envolver ninguém nesse processo. Agora, o que você está me pedindo aqui parece ser uma rota, uma URL, que precisa ser executada por uma aplicação, em PHP, Python ou Java, então o que ele faz é poder transferir a responsabilidade para algum &lt;strong&gt;servidor de aplicação&lt;/strong&gt;, também conhecido como &lt;strong&gt;middleware&lt;/strong&gt;, cujo é um servidor que disponibiliza um ambiente para a instalação e execução de aplicações de informática, centralizando e dispensando a instalação em computadores clientes. Esse servidor de aplicação pode estar, por exemplo, aberto ouvindo uma outra porta.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Middleware&lt;/strong&gt; é um software que permite um ou mais tipos de comunicação ou conectividade entre dois ou mais aplicativos e/ou componentes de aplicativos em uma rede distribuída. Ao tornar mais fácil conectar aplicativos que não foram projetados para se conectar uns aos outros — e fornecer funcionalidade para conectá-los de maneiras inteligentes — o middleware otimiza o desenvolvimento de aplicativos e acelera o tempo de lançamento no mercado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E esse servidor web manda uma outra requisição (não utilizando o protocolo HTTP, necessariamente, pode ser usando outro formato), mas ele manda esse pedido para o servidor de aplicação. O servidor de aplicação processa, devolve para o servidor web, e o servidor web vai devolver para o cliente o que ele recebeu. Essa comunicação entre um servidor web e um servidor de aplicação pode ser feita de diversas formas. Então vamos focar, pelo menos no início, só nessa tarefa individual do servidor web tratando o que ele tem que tratar, de forma isolada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F112913158-880b3d00-90cf-11eb-9691-786c2e875179.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F112913158-880b3d00-90cf-11eb-9691-786c2e875179.png" width="681" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após vários modelos estudados de cliente-servidor caracterizou-se chamar tecnicamente de &lt;strong&gt;arquitetura multicamada&lt;/strong&gt;, inspirado nas camadas no &lt;strong&gt;Modelo OSI&lt;/strong&gt;, o processo de dividir a arquitetura de cliente-servidor em várias camadas lógicas (logic layers) facilitando o processo de programação distribuída, existe desde o modelo mais simples de duas camadas, e o mais utilizado atualmente que é o modelo de três camadas que é paralelo ao modelo de arquitetura de software denominado &lt;strong&gt;MVC (Model-view-controller)&lt;/strong&gt;, onde a troca de mensagens entre o cliente e o servidor é feita através de uma chamada de API: &lt;strong&gt;REST&lt;/strong&gt;, &lt;strong&gt;SOAP&lt;/strong&gt; ou &lt;strong&gt;RPC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O resumo a seguir mostra a sequência de ações tanto do lado do cliente como do lado do servidor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Características do Cliente
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Inicia pedidos/solicitações para servidores;&lt;/li&gt;
&lt;li&gt;Espera/aguarda por respostas;&lt;/li&gt;
&lt;li&gt;Recebe respostas;&lt;/li&gt;
&lt;li&gt;Conecta-se a um pequeno/reduzido número de servidores por vez;&lt;/li&gt;
&lt;li&gt;Normalmente/usualmente, interage diretamente com os servidores através/por meio de seu software de aplicação específico para a tarefa de estabelecer/possibilitar a comunicação entre cliente e servidor;&lt;/li&gt;
&lt;li&gt;Utiliza recursos da rede.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthefloppydisk.files.wordpress.com%2F2013%2F05%2Fweb20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthefloppydisk.files.wordpress.com%2F2013%2F05%2Fweb20.png" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Características do Servidor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sempre aguarda/espera por um pedido/solicitação de um cliente;&lt;/li&gt;
&lt;li&gt;Atende os pedidos/solicitações e, em seguida, responde aos clientes com os dados solicitados/requisitados;&lt;/li&gt;
&lt;li&gt;Podem se conectar com outros servidores para atender uma solicitação específica do cliente; jamais podem se comunicar.&lt;/li&gt;
&lt;li&gt;Fornece recursos adicionais de rede, além da infraestrutura de rede propriamente dita.&lt;/li&gt;
&lt;li&gt;Normalmente interage por meio de interfaces diretamente com os usuários finais através de qualquer interface com o usuário;&lt;/li&gt;
&lt;li&gt;Estrutura o sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vantagens do modelo Cliente-Servidor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Na maioria dos casos, a arquitetura cliente-servidor permite que os papéis e responsabilidades de um sistema de computação possam ser distribuídos entre vários computadores independentes que são conhecidos por si só através de uma rede. Isso cria uma vantagem adicional para essa arquitetura: maior facilidade de manutenção. Por exemplo, é possível substituir, reparar, atualizar ou mesmo realocar um servidor de seus clientes, enquanto continuam a ser a consciência e não afetado por essa mudança. A arquitetura cliente-servidor permite que as responsabilidades de um sistema de computação possam ser distribuídas entre vários computadores independentes interconectados por meio de uma rede, o que resulta em maior facilidade de manutenção;&lt;/li&gt;
&lt;li&gt;Todos os dados são armazenados nos servidores, que geralmente possuem controles de segurança muito maiores do que a maioria dos clientes. Os servidores podem controlar melhor o acesso a recursos, para garantir que apenas os clientes com credenciais válidas possam aceder e alterar os dados;&lt;/li&gt;
&lt;li&gt;Como o armazenamento de dados é centralizado, as atualizações dos dados são muito mais fáceis de administrar em comparação com o paradigma P2P. Em uma arquitetura P2P, atualizações de dados podem precisar ser distribuídas e aplicadas a cada nó na rede, o que consome tempo e é passível de erro, já que pode haver milhares ou mesmo milhões de nós. O gerenciamento das atualizações dos dados é mais fácil de ser feita nesse modelo do que no paradigma peer-to-peer (P2P), onde as atualizações de dados podem necessitar ser distribuídas e aplicadas a cada nó na rede, o que consome tempo e torna-se passível de erro;&lt;/li&gt;
&lt;li&gt;Muitas tecnologias avançadas de cliente-servidor estão disponíveis e foram projetadas para garantir a segurança, facilidade de interface do usuário e facilidade de uso;&lt;/li&gt;
&lt;li&gt;Os dados principais são armazenados nos servidores, que por regra possuem controles de segurança mais robustos do que o da maioria dos clientes.&lt;/li&gt;
&lt;li&gt;Muitas tecnologias avançadas de cliente-servidor foram projetadas para garantir a segurança, facilidade de interface do usuário e facilidade de uso encontram-se disponíveis.&lt;/li&gt;
&lt;li&gt;Funciona com vários clientes diferentes, sendo que os clientes podem ter capacidades diferentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Entretanto, o modelo apresenta diversos problemas. Visto que a capacidade de oferecer serviços ou recursos fica centralizada na figura do servidor, surge um problema:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O que fazer quando o número de requisições dos clientes ultrapassa a capacidade computacional do servidor?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essa pergunta não tem uma resposta de alta eficiência para aplicações em redes de computadores. A sobrecarga de servidores é um problema real apesar de a capacidade computacional dos servidores crescer consideravelmente ano após ano.&lt;/p&gt;

&lt;p&gt;Além do fato de algumas requisições não serem atendidas, pela sobrecarga do servidor, no modelo cliente-servidor, ainda há o fato de que o modelo não é robusto, ou seja, se um servidor crítico falha, as requisições já feitas pelos clientes não poderão ser atendidas.&lt;/p&gt;

&lt;p&gt;Esses motivos são a base para a concepção das &lt;strong&gt;redes peer-to-peer (P2P)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desvantagens do modelo Cliente-Servidor
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clientes podem solicitar serviços, mas não podem oferecê-los para outros clientes, sobrecarregando o servidor, pois quanto mais clientes, mais informações que irão demandar mais banda.&lt;/li&gt;
&lt;li&gt;Um servidor poderá ficar sobrecarregado caso receba mais solicitações simultâneas dos clientes do que pode suportar;&lt;/li&gt;
&lt;li&gt;Este modelo não possui a robustez de uma rede baseada em P2P. Na arquitetura cliente-servidor, se um servidor crítico falha, os pedidos dos clientes não poderão ser cumpridos. Já no P2P, os recursos são normalmente distribuídos entre vários nós. Mesmo se uma ou mais máquinas falharem no momento de download de um arquivo, por exemplo, as demais ainda terão os dados necessários para completar a referida operação.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Protocolos de transporte e aplicações de rede
&lt;/h2&gt;

&lt;p&gt;Os protocolos do nível de transporte fornecem serviços que garantem uma transferência confiável de dados e aplicativos entre computadores (ou outros equipamentos) remotos. Os programas na camada de aplicação usam os protocolos de transporte para contactar outras aplicações. Para isso, a aplicação interage com o software do protocolo antes de ser feito o contacto. A aplicação que aguarda a conexão informa ao software do protocolo local que está pronta a aceitar mensagem. A aplicação que estabelece a conexão usa os protocolos de transporte e rede para contactar o sistema que aguarda. As mensagens entre as duas aplicações são trocadas através da conexão resultante.&lt;/p&gt;

&lt;p&gt;Existem duas formas para que se estabeleça uma ligação cliente-servidor: enquanto uma delas é orientada à conexão, a outra não é. O TCP, por exemplo, é um protocolo de transporte orientado à conexão em que o cliente estabelece uma conexão com o servidor e ambos trocam múltiplas mensagens de tamanhos variados, sendo a aplicação do cliente quem termina a sessão. Já o protocolo UDP não é orientado à conexão, nele o cliente constrói uma mensagem e a envia num pacote UDP para o servidor, que responde porém, sem garantia de entrega em uma conexão permanente com o cliente.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>nginx</category>
      <category>architecture</category>
      <category>networking</category>
    </item>
    <item>
      <title>Cluster</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 19:23:02 +0000</pubDate>
      <link>https://forem.com/isaacalves7/cluster-5ghj</link>
      <guid>https://forem.com/isaacalves7/cluster-5ghj</guid>
      <description>&lt;p&gt;A palavra "&lt;strong&gt;cluster&lt;/strong&gt;", em inglês, significa “aglomerar” ou “agrupar”, dentro da Tecnologia da Informação (TI), cluster também significa integrar dois ou mais computadores para que eles trabalhem simultaneamente no processamento de uma determinada tarefa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No entanto, os clusters não necessariamente precisam ter dois ou mais servidores, podemos ter um cluster com apenas um servidor. Então, para ter um cluster com Docker ou Kubernetes, você não precisa ter dois servidores. Entretanto, é importante ter, dentro do cluster, mais de um servidor porque caso ocorra uma falha no primeiro servidor o outro pode assumir o papel, caso seja pré-configurado dessa maneira.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um &lt;strong&gt;cluster de computador&lt;/strong&gt; é um conjunto de computadores fracamente ou fortemente conectados que funcionam juntos para que, em muitos aspectos, possam ser vistos como um único sistema. Os clusters de computador têm cada nó definido para executar a mesma tarefa, controlado e programado por software.&lt;/p&gt;

&lt;p&gt;Os componentes de um cluster geralmente são conectados uns aos outros por meio de redes locais rápidas, com cada nó (computador usado como servidor) executando sua própria instância de sistema operacional. Na maioria das circunstâncias, todos os nós usam o mesmo hardware e o mesmo sistema operacional, embora em algumas configurações, diferentes sistemas operacionais podem ser usados em cada computador ou hardware diferente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Os clusters são, geralmente, implantados para melhorar o desempenho e a disponibilidade em relação a um único computador, embora sejam, normalmente, muito mais econômicos do que computadores únicos de velocidade ou disponibilidade comparáveis.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os clusters de computador surgiram como resultado da convergência de uma série de tendências de computação, incluindo a disponibilidade de microprocessadores de baixo custo, redes de alta velocidade e software para computação distribuída de alto desempenho.&lt;/p&gt;

&lt;p&gt;Um dos problemas ao projetar um cluster é o quão fortemente acoplados os nós individuais podem ser. Por exemplo, um único trabalho de computador pode exigir comunicação frequente entre os nós. Isso implica que o cluster compartilha uma rede dedicada, está densamente localizado e provavelmente tem nós homogêneos. O outro extremo é quando um trabalho de computador usa um ou poucos nós e precisa de pouca ou nenhuma comunicação entre nós, aproximando-se da &lt;strong&gt;computação em grade&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A &lt;strong&gt;computação em grade&lt;/strong&gt; é um grupo de computadores em rede que trabalham em conjunto, como um super computador virtual, para executar tarefas grandes, como analisar grandes conjuntos de dados e modelagem do clima.” - Fonte: Microsoft Azure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um cluster, os programas aplicativos nunca veem os nós computacionais (também chamados de &lt;strong&gt;computadores escravos&lt;/strong&gt;), mas apenas interagem com o &lt;strong&gt;mestre&lt;/strong&gt;, que é um computador específico que cuida do agendamento e gerenciamento dos escravos. Em uma implementação típica, o mestre tem duas interfaces de rede, &lt;strong&gt;uma que se comunica com a rede privada para os escravos&lt;/strong&gt; e a &lt;strong&gt;outra para a rede de uso geral da organização (pública)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Os clusters de computador são historicamente executados em computadores físicos separados com o mesmo sistema operacional. Com o advento da virtualização, os nós do cluster podem ser executados em computadores físicos separados com diferentes sistemas operacionais, mas é adicionada uma camada virtual acima deles a fim de parecerem semelhantes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dentro do conceito sobre o que é cluster, o &lt;strong&gt;cluster de servidores&lt;/strong&gt; é a junção de várias máquinas (computadores/servidores) que, quando interligadas, elevam o seu potencial de disponibilidade e de capacidade de atuação.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No cluster, cada computador é denominado “nodo” ou “nó”, sendo que não há limites de quantos nodos podem ser interligados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lembrando&lt;/strong&gt;: Um &lt;strong&gt;nodo&lt;/strong&gt; ou &lt;strong&gt;nó&lt;/strong&gt; (node) representa cada ponto de interconexão com uma estrutura ou rede, independente da função do equipamento representado por ele, seja um ponto de redistribuição ou um terminal de comunicação. A definição de um nó depende da rede e da camada de protocolo referida.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Com isso, os computadores passam a atuar dentro de um único sistema, trabalhando em conjunto no processamento, análise e interpretação de dados, na mesma conexão de rede, informações e/ou realização de tarefas simultâneas.&lt;/p&gt;

&lt;p&gt;A função de um cluster é combinar o funcionamento de vários computadores dentro de um mesmo sistema, a fim de potencializar o seu desempenho.&lt;/p&gt;

&lt;p&gt;Muitas vezes, a computação em cluster permite o uso de hardwares simples, evitando a necessidade de utilização de servidores complexos ou dos chamados “supercomputadores” para realizar a mesma tarefa, reduzindo, assim, os investimentos.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;cluster&lt;/strong&gt; consiste em computadores fracamente ou fortemente ligados que trabalham em conjunto, de modo que, em muitos aspectos, podem ser considerados como um único sistema. Diferentemente dos computadores em &lt;strong&gt;grade&lt;/strong&gt; (grid), computadores em cluster têm cada conjunto de &lt;strong&gt;nós&lt;/strong&gt; (nodes), para executar a mesma tarefa, controlado e programado por software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tipos de clusters
&lt;/h2&gt;

&lt;p&gt;Existem vários tipos de cluster. Os mais conhecidos são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;High Performance Computing Cluster (&lt;strong&gt;cluster de alto desempenho&lt;/strong&gt;): também conhecido como cluster de alta performance, ele funciona permitindo que ocorra uma grande carga de processamento com um volume baixo de gigaflops em computadores comuns e utilizando sistema operacional gratuito, o que diminui seu custo. Ou seja, esse tipo de cluster é utilizado para desempenhar tarefas de alto desempenho, de modo que garantam a máxima performance da atuação. Também conhecido como cluster de alta performance, funciona permitindo que ocorra uma grande carga de processamento com um volume em computadores comuns e utilizando sistema operacional gratuito, o que diminui seu custo.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failover ou High Availability Computing Cluster (&lt;strong&gt;cluster de alta disponibilidade&lt;/strong&gt;): são clusters cujos sistemas conseguem permanecer ativos por um longo período de tempo e em plena condição de uso; sendo assim, podemos dizer que eles nunca param seu funcionamento; além disso, conseguem detectar erros se protegendo de possíveis falhas. Ou seja, garante que uma rede permaneça sempre ativa. Para isso, caso um computador apresente falha e fique fora do ar, outro continua mantendo a rede operante. É aquele que consegue permanecer ativo por um longo período e em plena condição de uso. Além disso, consegue detectar erros se protegendo de possíveis falhas.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Load Balancing (&lt;strong&gt;cluster para balanceamento de carga&lt;/strong&gt;): esse tipo de cluster tem como função controlar a distribuição equilibrada do processamento. Requer um monitoramento constante na sua comunicação e em seus mecanismos de redundância, pois, se ocorrer alguma falha, haverá uma interrupção no seu funcionamento. Ou seja, o tipo de cluster load balancing é uma estrutura na qual todos os computadores são responsáveis pela execução de uma determinada tarefa. Assim, caso um dos equipamentos apresente algum problema, ele é automaticamente retirado do sistema e a função inicial atribuída a ele é dividida entre os demais nós. Tem como função controlar a distribuição equilibrada do processamento. Requer um monitoramento constante na sua comunicação e em seus mecanismos de redundância, pois, se ocorrer alguma falha, seu funcionamento será interrompido.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Processamento paralelo&lt;/strong&gt;: Esse tipo de cluster transforma uma tarefa complexa em várias simples e as distribui entre os nós integrados ao sistema.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não existe um tipo de cluster mais adequado, por isso, é possível utilizar diferentes tipos paralelamente. A escolha de qual, ou quais, usar depende do objetivo que se pretende alcançar.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que significa clusterizar?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Clusterizar&lt;/strong&gt; significa promover o agrupamento de algo. Dentro da Tecnologia da Informação (TI), consiste em integrar um dois ou mais computadores com o objetivo de potencializar a sua eficiência.&lt;/p&gt;

&lt;p&gt;No meio corporativo, clusterizar quer dizer unir duas ou mais empresas com o propósito de melhorar suas atuações, aumentar o poder competitivo, permitir acesso a inovações, entre outras funções.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é cluster físico e o que é cluster virtual?
&lt;/h2&gt;

&lt;p&gt;Para deixar o conceito do que é cluster mais completo, é importante que você entenda também a diferença entre &lt;strong&gt;cluster físico&lt;/strong&gt; e &lt;strong&gt;cluster virtual&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;cluster físico&lt;/strong&gt; consiste em uma integração presencial entre dois ou mais computadores.&lt;/p&gt;

&lt;p&gt;Já o &lt;strong&gt;cluster virtual&lt;/strong&gt; segue o mesmo princípio, ou seja, de integrar computadores em um mesmo sistema, porém por meio de uma rede online.&lt;/p&gt;

&lt;p&gt;Esse processo acaba sendo mais dinâmico e garante que mesmo máquinas que estejam distantes fisicamente possam ser conectadas para aumentar o seu desempenho.&lt;/p&gt;

</description>
      <category>node</category>
      <category>kubernetes</category>
      <category>docker</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Load Balancer</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 19:06:09 +0000</pubDate>
      <link>https://forem.com/isaacalves7/load-balancer-44e2</link>
      <guid>https://forem.com/isaacalves7/load-balancer-44e2</guid>
      <description>&lt;p&gt;Um &lt;strong&gt;Load Balancer&lt;/strong&gt; (balanceador de carga), abreviado como &lt;strong&gt;LB&lt;/strong&gt;, é um método de distribuição de tráfego de protocolos de redes entre vários computadores e, geralmente, ele fica na frente da aplicação, ou seja, na frente das máquinas (servidores) que rodam seu back-end, enquanto seu back-end consome sua aplicação e as requisições que ele está recebendo, onde, o Load Balancer fica encarregado de distribuir tudo e manter tudo organizado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As grandes empresas como Google, Microsoft, Amazon, Netflix, Apple e entre outras são capazes de receber muitas informações e muitos clientes online em um site ou aplicativo, e isso sem que o servidor acabe caindo e nisso sem ter algum problema de performance, então, obviamente, há um &lt;strong&gt;load balancer&lt;/strong&gt; (balanceador de carga) configurado nesse servidor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Então, todo o hardware tem o seu limite, e muitas vezes o mesmo serviço tem que ser repartido por várias máquinas, sob pena de se tornar congestionado. Estas soluções podem-se especializar em pequenos grupos sobre os quais se faz um balanceamento de carga: utilização do CPU, de armazenamento, ou de rede. Qualquer uma delas introduz o conceito de clustering, ou server farm, já que o balanceamento será, provavelmente, feito para vários servidores.&lt;/p&gt;

&lt;p&gt;Em rede de computadores, o balanceamento de carga é uma técnica para distribuir a carga de trabalho uniformemente entre dois ou mais computadores, enlaces de rede, UCPs, discos rígidos ou outros recursos, a fim de otimizar a utilização de recursos, maximizar o desempenho, escalabilidade, minimizar o tempo de resposta e evitar sobrecarga. Utilizando múltiplos componentes com o balanceamento de carga, em vez de um único componente, pode aumentar a confiabilidade através da redundância.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgridscale.io%2Fwp-content%2Fuploads%2Floadbalancer.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgridscale.io%2Fwp-content%2Fuploads%2Floadbalancer.svg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Além disso, se houver problema com alguma máquina, ele será capaz de direcionar o tráfego para outra máquina, sem que o usuário perceba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dentro de um Load Balancer, quando ele está rodando na aplicação, existem algoritmos responsáveis por fazer essa distribuição e o melhor disso é que você pode configurar essa distribuição, e não existe somente um algoritmo, mas sim vários algoritmos: com menas conexões, menor tempo de resposta, IP Hash, de duas escolhas aleatórias e entre outros tipos de algoritmos dependendo da maneira que você configurar na sua aplicação e isso é bem customizável. O algoritmo mais comum de todos é o &lt;strong&gt;RR - Round Robin&lt;/strong&gt; que é o algoritmo padrão que roda na maioria dos Load Balancers, veja abaixo como esse algoritmo funciona em um balanceador de carga:&lt;/p&gt;

&lt;h3&gt;
  
  
  RR - Round Robin
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F7%2F76%2FRound_Robin_Schedule_Example.jpg%2F700px-Round_Robin_Schedule_Example.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F7%2F76%2FRound_Robin_Schedule_Example.jpg%2F700px-Round_Robin_Schedule_Example.jpg" width="700" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Round Robin&lt;/strong&gt;, abreviado como &lt;strong&gt;RR&lt;/strong&gt;, é um dos algoritmos mais simples de agendamento de processos em um sistema operacional e é padrão para a maioria dos balanceadores de carga pela simplicidade da sua funcionalidade e processamento, que atribui frações de tempo para cada processo em partes iguais e de forma circular, manipulando todos os processos sem prioridades. O escalonamento Round Robin é simples e fácil de implementar.&lt;/p&gt;

&lt;p&gt;O algoritmo de escalonamento Round-Robin é um dos mais antigos e simples algoritmos, além de ser totalmente imune a problemas de &lt;strong&gt;starvation&lt;/strong&gt; que são tarefas que nunca são executadas em função de ter prioridade inferior as demais.&lt;/p&gt;

&lt;p&gt;É usado em projetos de sistemas operacionais multitarefa, e foi projetado especialmente para sistemas time-sharing (tempo compartilhado), pois este algoritmo depende de um temporizador (Timer).&lt;/p&gt;

&lt;p&gt;Uma unidade de tempo, denominada quantum, é definida pelo sistema operacional, que determina o período de tempo entre cada sinal de interrupção. Todos os processos são armazenados em uma &lt;strong&gt;fila circular&lt;/strong&gt; (circular queue, data structure - estrutura de dados).&lt;/p&gt;

&lt;p&gt;Se o quantum é 100 milisegundos e a tarefa leva 250 milisegundos para completar, o agendamento round-robin suspenderá a tarefa após os primeiros 100 milisegundos e dará a outra tarefa da fila, o mesmo tempo. Essa tarefa será executa portanto após 3 agendamentos a saber (100 ms + 100 ms + 50 ms). A interrupção da tarefa é conhecida como preempção.&lt;/p&gt;

&lt;p&gt;Tarefa1 = Tempo de execução igual a 250 ms (quantum 100 ms).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Primeiro agendamento = executa tarefa durante 100 ms.&lt;/li&gt;
&lt;li&gt;Segundo agendamento = mais 100 ms de execução da tarefa.&lt;/li&gt;
&lt;li&gt;Terceiro agendamento = 100 ms, mas a tarefa termina após os primeiros 50 ms.&lt;/li&gt;
&lt;li&gt;Total de tempo que a CPU levou para a tarefa1 = 250 ms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Um melhoramento desse agendamento é dividir todos os processos em números iguais de frações de tempo e proporcionais ao tamanho da tarefa, assim todos os processos terminam ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203871587-807180e8-c77c-43d3-9c1a-eee60983e8bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F203871587-807180e8-c77c-43d3-9c1a-eee60983e8bd.png" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse exemplo, possuimos os clientes no lado esquerdo (C1, C2, C3, C4), o Load Balancer no meio delas, e as máquinas no lado direito (M1, M2, M3). Então, vamos imaginar que esses clientes estão enviando requisição para um &lt;strong&gt;endpoint&lt;/strong&gt; (ponto-final) que vai cair lá no nosso LB, não vamos somente imaginar que 4, mas sim vários clientes enviando requisição para esse endpoint.&lt;/p&gt;

&lt;p&gt;E o nosso LB está configurado com o algoritmo de R.R - Round Robin, então esse algoritmo vai sequencialmente distribuir essa carga de tráfego de requisições para cada uma dessas máquinas, ou seja, a primeira que ele vai receber vai distribuir para a máquina 1 (M1), a máquina 2 (M2) e a máquina 3 (M3).&lt;/p&gt;

&lt;p&gt;E, assim por diante, para a quantidade de máquinas que ele conseguir enxergar e enviar essa requisição. E, assim que ele acabar, ele vai voltar para a primeira máquina, segunda máquina, terceira máquina e assim por diante. No qual, ele armazena para onde foi enviada a ultima conexão.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sticky Round Robin
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Weighted Round Robin
&lt;/h3&gt;

&lt;h3&gt;
  
  
  IP/URL Hash
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Least Time
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Menor número de conexões
&lt;/h3&gt;

&lt;p&gt;O algoritmo de menor número de conexões é especifico para o determinado propósito a qual foi atribuido pelo seu próprio nome, ou seja, ele verifica quantas conexões possuem em cada máquina aberta.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Least Connections
&lt;/h3&gt;

&lt;p&gt;Verifica quantas conexões há abertas com cada servidor para decidir para onde enviar a próxima requisição.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>distributedsystems</category>
      <category>nginx</category>
      <category>node</category>
    </item>
    <item>
      <title>EJS - Embedded JavaScript Templating</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 19:05:03 +0000</pubDate>
      <link>https://forem.com/isaacalves7/messaging-brokers-38om</link>
      <guid>https://forem.com/isaacalves7/messaging-brokers-38om</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F231615336-cf2c103c-a9b0-42be-a356-d2c0ccefeb74.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F231615336-cf2c103c-a9b0-42be-a356-d2c0ccefeb74.svg" width="196" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;Template Engine&lt;/strong&gt; é um programa responsável por compilar um template (que pode ser escrito usando qualquer uma das várias linguagens) em HTML. O Template Engine normalmente receberá dados de uma fonte externa, que injetará no template que está compilando.&lt;/p&gt;

&lt;p&gt;O PHP não é um template engine, mas uma linguagem de programação que pode ser usada para escrever templates ou templates engine. Um template engine não é apenas uma linguagem, mas também a API de programação que permite que os scripts localizem, organizem templates ou atribuam os dados do script a eles. &lt;/p&gt;

&lt;p&gt;Os Templates Engine compilam para php nativo, portanto, não há nada a perder e muito a ganhar usando um template engine. Se você olhar para qualquer Template Engine moderno, como smarty ou twig, verá que eles compilam os modelos para fonte php, de modo que a saída seja a mesma como se você tivesse feito a página em php manualmente. Mas os templates engine sabem como compilar a página php melhor do que uma pessoa, pois os templates engine são mantidos por milhares de pessoas.&lt;/p&gt;

&lt;p&gt;Essa abordagem permite que você reutilize elementos estáticos da página da Web, enquanto define elementos dinâmicos com base em seus dados. Também facilita a separação de preocupações, mantendo a lógica do aplicativo isolada da lógica de exibição. É mais provável que você se beneficie de um Template Engine se seu site ou aplicativo da Web for orientado a dados - como um diretório de equipe para funcionários administrativos, uma loja da Web que lista vários produtos para os usuários comprarem ou um site com funcionalidade de pesquisa dinâmica. Você não precisará de um Template Engine se estiver buscando uma pequena quantidade de dados de uma API (nesse caso, você pode usar apenas as strings de modelo nativo do JavaScript) ou se estiver criando um pequeno site estático.&lt;/p&gt;

&lt;p&gt;Portanto, uma das vantagens do Template Engine é a segurança adicional para personalização do usuário final. Os temas em PHP puro têm capacidade irrestrita de causar danos a um usuário e sua instalação. Assim, um template engine remove esse risco, se for bom e a facilidade de uso para não programadores, como artistas gráficos ou web designers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Next.js, Astro, EJS, Pug e PHP compartilham a mesma raiz conceitual: gerar HTML no servidor. A diferença está em como, quando e por que fazem isso, e no nível de controle e abstração oferecido.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://ejs.co/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.svgrepo.com%2Fshow%2F373574%2Fejs.svg" title="Site do Node.js" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;EJS&lt;/strong&gt; (Embedded JavaScript Templating) é uma Template Engine que podemos utilizar com Node.js. Assim como vimos sobre o PUG, com a template engine nós podemos criar as páginas das nossas aplicações em Node.js de forma dinâmica sem depender das limitações do HTML.&lt;/p&gt;

&lt;p&gt;A grande diferença entre o EJS e o PUG é que o EJS segue uma sintaxe muito semelhante ao HTML, desta forma qualquer desenvolvedor que já conhece HTML não terá nenhuma dificuldade de trabalhar com o EJS, ao contrário do PUG que possuí algumas particularidades e que pode, no início, afetar a produtividade do desenvolvedor. Além disso, o PHP e EJS compartilham o objetivo comum de facilitar a renderização de conteúdo dinâmico em páginas web, eles diferem em suas abordagens, sintaxe e ecossistemas subjacentes.&lt;/p&gt;

&lt;p&gt;Um bom cenário para se usar Templates Engine seria nas áreas de login, cadastro de usuários, cadastro de admins, áreas de usuários e áreas de admin. Isso tudo com arquitetura monolítica e MVC (Model View Controller).&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-index.js-fff%3Fstyle%3Dsocial%26logo%3Djavascript%26logoColor%3DECD53F" alt="index.js" width="81" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Setting up EJS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view engine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App rodando&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obrigatoriamente, o EJS trabalha com o padrão de servir o HTML do nosso projeto através da pasta &lt;code&gt;./views/&lt;/code&gt;, só que não estamos utilizando HTML básico, mas sim com EJS, a extensão &lt;code&gt;.ejs&lt;/code&gt;. E o Express renderiza esse arquivo com &lt;code&gt;res.render()&lt;/code&gt; onde ele reconhece os arquivos de forma automática, mas se você quer processar todos os arquivos, basta criar uma pasta: &lt;code&gt;"principal/home"&lt;/code&gt;, que ele irá interpretar esse diretório dentro da pasta &lt;code&gt;views&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Dentro do arquivo EJS, a tag &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt; significa exibir o valor da variável.&lt;/p&gt;

&lt;p&gt;Podemos também exibir variáveis no nosso HTML:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-index.js-fff%3Fstyle%3Dsocial%26logo%3Djavascript%26logoColor%3DECD53F" alt="index.js" width="81" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Setting up EJS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view engine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Isaac&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;português brasileiro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;empresa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Globo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App rodando&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-index.ejs-crimson%3Fstyle%3Dsocial%26logo%3Dhtml5%26logoColor%3DECD53F" alt="index.ejs" width="87" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="pt-BR"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8" /&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&amp;gt;
    &amp;lt;meta name="description" content="Exemplo de documento HTML5 básico." /&amp;gt;
    &amp;lt;title&amp;gt;EJS&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Dados do colaborador:&amp;lt;/h1&amp;gt;

    &amp;lt;%= nome %&amp;gt;
    &amp;lt;%= empresa %&amp;gt;
    &amp;lt;%= lang %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemplo 2: Passando parâmetros na nossa rota&lt;/p&gt;

&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-index.js-fff%3Fstyle%3Dsocial%26logo%3Djavascript%26logoColor%3DECD53F" alt="index.js" width="81" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Setting up EJS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view engine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/:nome/:lang&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;empresa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Globo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App rodando&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F-index.ejs-crimson%3Fstyle%3Dsocial%26logo%3Dhtml5%26logoColor%3DECD53F" alt="index.ejs" width="87" height="20"&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="pt-BR"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8" /&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&amp;gt;
    &amp;lt;meta name="description" content="Exemplo de documento HTML5 básico." /&amp;gt;
    &amp;lt;title&amp;gt;EJS&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Dados do colaborador:&amp;lt;/h1&amp;gt;

    &amp;lt;%= nome %&amp;gt;
    &amp;lt;%= lang %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>node</category>
      <category>ejs</category>
      <category>javascript</category>
      <category>express</category>
    </item>
    <item>
      <title>MVC (Model View Controller)</title>
      <dc:creator>Isaac Alves Pinheiro</dc:creator>
      <pubDate>Wed, 24 May 2023 18:14:20 +0000</pubDate>
      <link>https://forem.com/isaacalves7/mvc-model-view-controller-4d9b</link>
      <guid>https://forem.com/isaacalves7/mvc-model-view-controller-4d9b</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F539%2F1%2Acawy7bN4_XKkSbujWQvaPQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F539%2F1%2Acawy7bN4_XKkSbujWQvaPQ.png" width="539" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;MVC&lt;/strong&gt; é o acrônimo de &lt;strong&gt;Model-View-Controller&lt;/strong&gt; (em português: Arquitetura Modelo-Visão-Controle - MVC) é um padrão de projeto de software, ou padrão de arquitetura de software formulado na década de 1970, focado no reuso de código e a separação de conceitos em três camadas interconectadas, onde a apresentação dos dados e interação dos usuários (front-end) são separados dos métodos que interagem com o banco de dados (back-end).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A arquitetura MVC (Model View Controller) é um padrão de arquitetura de projeto de software adotado para sistemas e aplicações web, que foi muito usado no modelo cliente-servidor. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normalmente usado para o desenvolvimento de interfaces de usuário que divide uma aplicação em partes (camadas/componentes) interconectadas. Isto é feito para separar representações de informação internas dos modos como a informação é apresentada para e aceita pelo usuário, levando ao desenvolvimento paralelo de maneira eficiente.&lt;/p&gt;

&lt;p&gt;Antigamente, o cliente acessava somente um arquivo do sistema dentro de um servidor, isso é possível, porém digamos que seu sistema está em fase de crescimento, e dessa forma seu arquivo vai ganhando um grande volume de dados sendo contidos e processados ao mesmo tempo de maneira congestionada, gerando assim uma sobrecarga, ainda mais se ele estiver desorganizado. Então, o MVC é ideal, justamente, para separar as funcionalidades (Model, View e Controller) tornando seu sistema mais fácil de manutenção, performático e organizado.&lt;/p&gt;

&lt;p&gt;A arquitetura MVC (Model-View-Controller) foi criada nos anos 80 na Xerox Parc, por Trygve Reenskaug, que iniciou em 1979 o que viria a ser o nascimento do padrão de projeto MVC. A implementação original foi descrita no artigo “Applications Programming in Smalltalk-80: How to use Model-View-Controller”.&lt;/p&gt;

&lt;p&gt;Tradicionalmente usado para interfaces gráficas de usuário (GUIs), esta arquitetura tornou-se popular para projetar aplicações web e até mesmo para aplicações móveis, para desktop e para outros clientes. Linguagens de programação populares como Java, C#, Object Pascal/Delphi, Ruby, PHP, JavaScript e outras possuem frameworks MVC populares que são atualmente usados no desenvolvimentos de aplicações web.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;É comum esse tipo de padrão de arquitetura possuir o padrão estrutural de aplicações monolíticas, mas nada impede você de implementar sua aplicação MVC para a arquitetura de microsserviços, então você pode fazer, dessa forma, uma migração do monolítico para microservices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A popularidade dessa arquitetura pode ser vista principalmente no desenvolvimento de aplicações WEB. Isso é uma consequência do ambiente ter um alcance ilimitado e com constante crescimento, onde a escalabilidade é um dos fatores mais importantes.&lt;/p&gt;

&lt;p&gt;Com o aumento da complexidade das aplicações desenvolvidas, sempre visando a programação orientada a objeto, torna-se relevante a separação entre os dados e a apresentação das aplicações. Desta forma, alterações feitas no layout não afetam a manipulação de dados, e estes poderão ser reorganizados sem alterar o layout.&lt;/p&gt;

&lt;p&gt;Esse padrão resolve tal problema através da separação das tarefas de acesso aos dados e lógica de negócio, lógica de apresentação e de interação com o utilizador, introduzindo um componente entre os dois: o controlador.&lt;/p&gt;

&lt;p&gt;A separação de propósitos que o paradigma MVC propõem ajuda na escalabilidade e padronização de um produto. Manter um código que cresce constantemente em grandes corporações é uma tarefa árdua, e pequenas equipes também podem sofrer para aumentar a escalabilidade de um produto se não houver um preparo.&lt;/p&gt;

&lt;p&gt;Essa divisão de preocupações, ajuda na separação de tarefas e torna-as mais específicas, uma consequência disso é que os códigos possuem um propósito melhor definido, o que facilita no teste e no contexto de seu desenvolvimento e na reutilização do mesmo.&lt;/p&gt;

&lt;p&gt;Além de dividir a aplicação em três tipos de componentes, o desenho MVC define as interações entre eles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2Fce1203ee-3b5f-461e-8f23-443a96863841" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FIsaacAlves7%2FDevSecOps%2Fassets%2F61624336%2Fce1203ee-3b5f-461e-8f23-443a96863841" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;Controlador&lt;/strong&gt; (controller) envia comandos para o modelo para atualizar o seu estado (por exemplo, editando um documento). O controlador também pode enviar comandos para a visão associada para alterar a apresentação da visão do modelo (por exemplo, percorrendo um documento).&lt;/li&gt;
&lt;li&gt;Um &lt;strong&gt;modelo&lt;/strong&gt; (model) armazena dados e notifica suas visões e controladores associados quando há uma mudança em seu estado. Estas notificações permitem que as visões produzam saídas atualizadas e que os controladores alterem o conjunto de comandos disponíveis. Uma implementação passiva do MVC monta estas notificações, devido a aplicação não necessitar delas ou a plataforma de software não suportá-las.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;visão&lt;/strong&gt; (view) gera uma representação (Visão) dos dados presentes no modelo solicitado, fazendo a exibição dos dados, sendo ela por meio de um html ou xml.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Camada de modelo ou da lógica da aplicação (Model)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Fa0%2FMVC-Process.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fa%2Fa0%2FMVC-Process.svg" width="500" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modelo&lt;/strong&gt; (Model) é a ponte entre as camadas Visão (View) e Controle (Controller), consiste na parte lógica da aplicação, que gerencia o comportamento dos dados através de regras de negócios, lógica e funções. Esta fica apenas esperando a chamada das funções, que permite o acesso para os dados serem coletados, gravados e, exibidos.&lt;/p&gt;

&lt;p&gt;É o coração da execução, responsável por tudo que a aplicação vai fazer a partir dos comandos da camada de controle em um ou mais elementos de dados, respondendo a perguntas sobre o sua condição e a instruções para mudá-las. O modelo sabe o que o aplicativo quer fazer e é a principal estrutura computacional da arquitetura, pois é ele quem modela o problema que está se tentando resolver. Modela os dados e o comportamento por trás do processo de negócios. Se preocupa apenas com o armazenamento, manipulação e geração de dados. É um encapsulamento de dados e de comportamento independente da apresentação.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lida diretamente com os dados contidos dentro do banco de dados via ORM ou ODM.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Camada de apresentação ou visualização (View)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F169295947-65858769-5b31-442f-8384-3bfb8f9b6899.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F61624336%2F169295947-65858769-5b31-442f-8384-3bfb8f9b6899.png" width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visão&lt;/strong&gt; (View) pode ser qualquer saída de representação dos dados, como uma tabela ou um diagrama. É onde os dados solicitados do Modelo (Model) são exibidos. É possível ter várias visões do mesmo dado, como um gráfico de barras para gerenciamento e uma visão tabular para contadores. A Visão também provoca interações com o usuário, que interage com o Controle (Controller). O exemplo básico disso é um botão gerado por uma Visão, no qual um usuário clica e aciona uma ação no Controle.&lt;/p&gt;

&lt;p&gt;Não se dedica em saber como o conhecimento foi retirado ou de onde ela foi obtida, apenas mostra a referência. Segundo Gamma et al (2006), ”A abordagem MVC separa a View e Model por meio de um protocolo inserção/notificação (subscribe/notify). Uma View deve garantir que sua expressão reflita o estado do Model. Sempre que os dados do Model mudam, o Model altera as Views que dependem dele. Em resposta, cada View tem a oportunidade de modificar-se”. Adiciona os elementos de exibição ao usuário: HTML, ASP, XML, Applets. É a camada de interface com o usuário. É utilizada para receber a entrada de dados e apresentar visualmente o resultado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camada de controle ou controlador (Controller)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F539%2F1%2Acawy7bN4_XKkSbujWQvaPQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F539%2F1%2Acawy7bN4_XKkSbujWQvaPQ.png" width="539" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controle&lt;/strong&gt; (Controller) é o componente final da tríade, faz a mediação da entrada e saída, comandando a visão e o modelo para serem alterados de forma apropriada conforme o usuário solicitou através do mouse e teclado. O foco do Controle é a ação do usuário, onde são manipulados os dados que o usuário insere ou atualiza, chamando em seguida o Modelo.&lt;/p&gt;

&lt;p&gt;O Controle (Controller) envia essas ações para o Modelo (Model) e para a janela de visualização (View) onde serão realizadas as operações necessárias.&lt;/p&gt;

&lt;p&gt;Podemos dizer que o &lt;strong&gt;Controller&lt;/strong&gt; é a principal funcionalidade que controla esse sistema, pois ele fica encarregado de obter os dados do Model, realizar responses e requests por meio de protocolos HTTP, configuração de APIs e Middlewares e renderizar todos os dados para a View processar para o cliente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Então, a sigla correta deveria ser, na verdade, CMV ou CVM.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Então, para ocorrer o funcionamento é acompanhado do seguinte fluxo: o usuário (cliente) acessa a aplicação web pelo browser e faz um request (Controller) e assim pegando os dados (Model) do banco de dados e liberando assim esses dados para o View que envia as responses para o cliente (browser), e assim o sistema estará funcionando perfeitamente para o usuário.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vantagens do modelo MVC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Como o modelo MVC gerencia múltiplos views usando o mesmo modelo é fácil manter, testar e atualizar sistemas compostos;&lt;/li&gt;
&lt;li&gt;É muito simples adicionar novos clientes apenas incluindo seus views e controles;&lt;/li&gt;
&lt;li&gt;Torna a aplicação escalável;&lt;/li&gt;
&lt;li&gt;É possível ter desenvolvimento em paralelo para o modelo, visualizador e controle pois são independentes;&lt;/li&gt;
&lt;li&gt;Facilita o reuso do código;&lt;/li&gt;
&lt;li&gt;Melhor nível de sustentabilidade, pois facilita a manutenção da aplicação;&lt;/li&gt;
&lt;li&gt;Fácil transformação da interface, sem que haja necessidade de modificar a camada de negócio;&lt;/li&gt;
&lt;li&gt;Melhor desempenho e produtividade, graças a estrutura de pacotes modulares;&lt;/li&gt;
&lt;li&gt;A arquitetura modular permite aos desenvolvedores e designers desenvolverem em paralelo;&lt;/li&gt;
&lt;li&gt;Partes da aplicação podem ser alteradas sem a necessidade de alterar outras.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Desvantagens do modelo MVC
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Necessita de um tempo maior para explorar e modelar o sistema;&lt;/li&gt;
&lt;li&gt;Requer mão-de-obra especializada;&lt;/li&gt;
&lt;li&gt;À medida que o tamanho e a complexidade do projeto crescem, a quantidade de arquivos e pastas continuará aumentando também. Os interesses de UI (interface do usuário) (modelos, exibições, controladores) se localizam em várias pastas, que não são formadas em grupos por ordem alfabética.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>projectpattern</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
