One place for hosting & domains

      Monitoramento para Deployments Distribuídos e de Microsserviços


      Introdução

      O monitoramento de sistemas e da infraestrutura é uma responsabilidade central de equipes de operações de todos os tamanhos. A indústria desenvolveu coletivamente muitas estratégias e ferramentas para ajudar a monitorar servidores, coletar dados importantes e responder a incidentes e condições em alteração em ambientes variados. No entanto, à medida que as metodologias de software e os projetos de infraestrutura evoluem, o monitoramento deve se adaptar para atender a novos desafios e fornecer insights em um território relativamente desconhecido.

      Até agora, nesta série, discutimos o que são métricas, monitoramento e alertas, e as qualidades de bons sistemas de monitoramento. Conversamos sobre coletar métricas de sua infraestrutura e aplicações e os sinais importantes para monitorar toda a sua infraestrutura. Em nosso último guia, cobrimos como colocar em prática métricas e alertas entendendo os componentes individuais e as qualidades do bom projeto de alertas.

      Neste guia, vamos dar uma olhada em como o monitoramento e a coleta de métricas são alterados para arquiteturas e microsserviços altamente distribuídos. A crescente popularidade da computação em nuvem, dos clusters de big data e das camadas de orquestração de instâncias forçou os profissionais de operações a repensar como projetar o monitoramento em escala e a enfrentar problemas específicos com uma melhor instrumentação. Vamos falar sobre o que diferencia os novos modelos de deployment e quais estratégias podem ser usadas para atender a essas novas demandas.

      Quais Desafios Criam as Arquiteturas Altamente Distribuídas?

      Para modelar e espelhar os sistemas monitorados, a infraestrutura de monitoramento sempre foi um pouco distribuída. No entanto, muitas práticas modernas de desenvolvimento — incluindo projetos em torno de microsserviços, containers e instâncias de computação intercambiáveis e efêmeras — alteraram drasticamente o cenário de monitoramento. Em muitos casos, os principais recursos desses avanços são os fatores que tornam o monitoramento mais difícil. Vamos analisar algumas das maneiras pelas quais elas diferem dos ambientes tradicionais e como isso afeta o monitoramento.

      O Trabalho é Dissociado dos Recursos Subjacentes

      Algumas das mudanças mais fundamentais na forma como muitos sistemas se comportam são devido a uma explosão em novas camadas de abstração em torno das quais o software pode ser projetado. A tecnologia de containers mudou o relacionamento entre o software deployado e o sistema operacional subjacente. Os aplicações com deploy em containers têm relacionamentos diferentes com o mundo externo, com outros programas e com o sistema operacional do host, do que com as aplicações cujo deploy foi feito por meios convencionais. As abstrações de kernel e rede podem levar a diferentes entendimentos do ambiente operacional, dependendo de qual camada você verificar.

      Esse nível de abstração é incrivelmente útil de várias maneiras, criando estratégias de deployment consistentes, facilitando a migração do trabalho entre hosts e permitindo que os desenvolvedores controlem de perto os ambientes de runtime de suas aplicações. No entanto, esses novos recursos surgem às custas do aumento da complexidade e de um relacionamento mais distante com os recursos que suportam cada processo.

      Aumento na Comunicação Baseada em Rede

      Uma semelhança entre paradigmas mais recentes é uma dependência crescente da comunicação de rede interna para coordenar e realizar tarefas. O que antes era o domínio de uma única aplicação, agora pode ser distribuído entre muitos componentes que precisam coordenar e compartilhar informações. Isso tem algumas repercussões em termos de infraestrutura de comunicação e monitoramento.

      Primeiro, como esses modelos são construídos na comunicação entre serviços pequenos e discretos, a saúde da rede se torna mais importante do que nunca. Em arquiteturas tradicionais, mais monolíticas, tarefas de coordenação, compartilhamento de informações e organização de resultados foram amplamente realizadas em aplicações com lógica de programação regular ou através de uma quantidade comparativamente pequena de comunicação externa. Em contraste, o fluxo lógico de aplicações altamente distribuídas usa a rede para sincronizar, verificar a integridade dos pares e passar informações. A saúde e o desempenho da rede impactam diretamente mais funcionalidades do que anteriormente, o que significa que é necessário um monitoramento mais intensivo para garantir a operação correta.

      Embora a rede tenha se tornado mais crítica do que nunca, a capacidade de monitorá-la é cada vez mais desafiadora devido ao número estendido de participantes e linhas de comunicação individuais. Em vez de rastrear interações entre algumas aplicações, a comunicação correta entre dezenas, centenas ou milhares de pontos diferentes torna-se necessária para garantir a mesma funcionalidade. Além das considerações de complexidade, o aumento do volume de tráfego também sobrecarrega os recursos de rede disponíveis, aumentando ainda mais a necessidade de um monitoramento confiável.

      Funcionalidade e Responsabilidade Particionada para um Nível Maior

      Acima, mencionamos de passagem a tendência das arquiteturas modernas de dividir o trabalho e a funcionalidade entre muitos componentes menores e discretos. Esses projetos podem ter um impacto direto no cenário de monitoramento porque tornam a clareza e a compreensão especialmente valiosas, mas cada vez mais evasivas.

      Ferramentas e instrumentação mais robustas são necessárias para garantir um bom funcionamento. No entanto, como a responsabilidade de concluir qualquer tarefa é fragmentada e dividida entre diferentes workers (possivelmente em muitos hosts físicos diferentes), entender onde a responsabilidade reside em questões de desempenho ou erros pode ser difícil. Solicitações e unidades de trabalho que tocam dezenas de componentes, muitos dos quais são selecionados de um pool de possíveis candidatos, podem tornar impraticável a visualização do caminho da solicitação ou a análise da causa raiz usando mecanismos tradicionais.

      Unidades de Vida Curta e Efêmera

      Uma batalha adicional na adaptação do monitoramento convencional é monitorar sensivelmente as unidades de vida curta ou efêmeras. Independentemente de as unidades de interesse serem instâncias de computação em nuvem, instâncias de container ou outras abstrações, esses componentes geralmente violam algumas das suposições feitas pelo software de monitoramento convencional.

      Por exemplo, para distinguir entre um node problemático e uma instância intencionalmente destruída para reduzir a escala, o sistema de monitoramento deve ter um entendimento mais íntimo de sua camada de provisionamento e gerenciamento do que era necessário anteriormente. Para muitos sistemas modernos, esses eventos ocorrem com muito mais frequência, portanto, ajustar manualmente o domínio de monitoramento a cada vez não é prático. O ambiente de deployment muda mais rapidamente com esses projetos, portanto, a camada de monitoramento deve adotar novas estratégias para permanecer valiosa.

      Uma questão que muitos sistemas devem enfrentar é o que fazer com os dados das instâncias destruídas. Embora as work units possam ser aprovisionadas e desprovisionadas rapidamente para acomodar demandas variáveis, é necessário tomar uma decisão sobre o que fazer com os dados relacionados às instâncias antigas. Os dados não perdem necessariamente seu valor imediatamente porque o worker subjacente não está mais disponível. Quando centenas ou milhares de nodes podem entrar e sair todos os dias, pode ser difícil saber como melhorar a construção de uma narrativa sobre a integridade operacional geral de seu sistema a partir dos dados fragmentados de instâncias de vida curta.

      Quais Alterações são Necessárias para Escalar seu Monitoramento?

      Agora que identificamos alguns dos desafios únicos das arquiteturas e microsserviços distribuídos, podemos falar sobre como os sistemas de monitoramento podem funcionar dentro dessas realidades. Algumas das soluções envolvem reavaliar e isolar o que é mais valioso sobre os diferentes tipos de métricas, enquanto outras envolvem novas ferramentas ou novas formas de entender o ambiente em que elas habitam.

      Granularidade e Amostragem

      O aumento no volume total de tráfego causado pelo elevado número de serviços é um dos problemas mais simples de se pensar. Além do aumento nos números de transferência causados por novas arquiteturas, a própria atividade de monitoramento pode começar a atolar a rede e roubar recursos do host. Para lidar melhor com o aumento de volume, você pode expandir sua infraestrutura de monitoramento ou reduzir a resolução dos dados com os quais trabalha. Vale à pena olhar ambas as abordagens, mas vamos nos concentrar na segunda, pois representa uma solução mais extensível e amplamente útil.

      Alterar suas taxas de amostragem de dados pode minimizar a quantidade de dados que seu sistema precisa coletar dos hosts. A amostragem é uma parte normal da coleção de métricas que representa com que frequência você solicita novos valores para uma métrica. Aumentar o intervalo de amostragem reduzirá a quantidade de dados que você precisa manipular, mas também reduzirá a resolução — o nível de detalhes — de seus dados. Embora você deva ter cuidado e compreender sua resolução mínima útil, ajustar as taxas de coleta de dados pode ter um impacto profundo em quantos clientes de monitoramento seu sistema pode atender adequadamente.

      Para diminuir a perda de informações resultante de resoluções mais baixas, uma opção é continuar a coletar dados em hosts na mesma frequência, mas compilá-los em números mais digeríveis para transferência pela rede. Computadores individuais podem agregar e calcular valores médios de métricas e enviar resumos para o sistema de monitoramento. Isso pode ajudar a reduzir o tráfego da rede, mantendo a precisão, já que um grande número de pontos de dados ainda é levado em consideração. Observe que isso ajuda a reduzir a influência da coleta de dados na rede, mas não ajuda, por si só, com a pressão envolvida na coleta desses números no host.

      Tome Decisões com Base em Dados Agregados de Várias Unidades

      Como mencionado acima, um dos principais diferenciais entre sistemas tradicionais e arquiteturas modernas é a quebra de quais componentes participam no processamento de solicitações. Em sistemas distribuídos e microsserviços, é muito mais provável que uma unidade de trabalho ou worker seja dado a um grupo de workers por meio de algum tipo de camada de agendamento ou arbitragem. Isso tem implicações em muitos dos processos automatizados que você pode construir em torno do monitoramento.

      Em ambientes que usam grupos de workers intercambiáveis, as políticas de verificação de integridade e de alerta podem ter relações complexas com a infraestrutura que eles monitoram. As verificações de integridade em workers individuais podem ser úteis para desativar e reciclar unidades defeituosas automaticamente. No entanto, se você tiver a automação em funcionamento, em escala, não importa muito se um único servidor web falhar em um grande pool ou grupo. O sistema irá se auto-corrigir para garantir que apenas as unidades íntegras estejam no pool ativo recebendo solicitações.

      Embora as verificações de integridade do host possam detectar unidades defeituosas, a verificação da integridade do pool em si é mais apropriada para alertas. A capacidade do pool de satisfazer a carga de trabalho atual tem maior importância na experiência do usuário do que os recursos de qualquer worker individual. Os alertas com base no número de membros íntegros, na latência do agregado do pool ou na taxa de erros do pool podem notificar os operadores sobre problemas mais difíceis de serem mitigados automaticamente e mais propensos a causar impacto nos usuários.

      Integração com a Camada de Provisionamento

      Em geral, a camada de monitoramento em sistemas distribuídos precisa ter um entendimento mais completo do ambiente de deploy e dos mecanismos de provisionamento. O gerenciamento automatizado do ciclo de vida se torna extremamente valioso devido ao número de unidades individuais envolvidas nessas arquiteturas. Independentemente de as unidades serem containers puros, containers em uma estrutura de orquestração ou nodes de computação em um ambiente de nuvem, existe uma camada de gerenciamento que expõe informações de integridade e aceita comandos para dimensionar e responder a eventos.

      O número de peças em jogo aumenta a probabilidade estatística de falha. Com todos os outros fatores sendo iguais, isso exigiria mais intervenção humana para responder e mitigar esses problemas. Como o sistema de monitoramento é responsável por identificar falhas e degradação do serviço, se ele puder conectar-se às interfaces de controle da plataforma, isso pode aliviar uma grande classe desses problemas. Uma resposta imediata e automática desencadeada pelo software de monitoramento pode ajudar a manter a integridade operacional do seu sistema.

      Essa relação estreita entre o sistema de monitoramento e a plataforma de deploy não é necessariamente obrigatória ou comum em outras arquiteturas. Mas os sistemas distribuídos automatizados visam ser auto-reguláveis, com a capacidade de dimensionar e ajustar com base em regras pré-configuradas e status observado. O sistema de monitoramento, neste caso, assume um papel central no controle do ambiente e na decisão sobre quando agir.

      Outro motivo pelo qual o sistema de monitoramento deve ter conhecimento da camada de provisionamento é lidar com os efeitos colaterais de instâncias efêmeras. Em ambientes onde há rotatividade frequente nas instâncias de trabalho, o sistema de monitoramento depende de informações de um canal paralelo para entender quando as ações foram intencionais ou não. Por exemplo, sistemas que podem ler eventos de API de um provisionador podem reagir de maneira diferente quando um servidor é destruído intencionalmente por um operador do que quando um servidor repentinamente não responde sem nenhum evento associado. A capacidade de diferenciar esses eventos pode ajudar seu monitoramento a permanecer útil, preciso e confiável, mesmo que a infraestrutura subjacente possa mudar com frequência.

      Rastreio Distribuído

      Um dos aspectos mais desafiadores de cargas de trabalho altamente distribuídas é entender a interação entre os diferentes componentes e isolar a responsabilidade ao tentar a análise da causa raiz. Como uma única solicitação pode afetar dúzias de pequenos programas para gerar uma resposta, pode ser difícil interpretar onde os gargalos ou alterações de desempenho se originam. Para fornecer melhores informações sobre como cada componente contribui para a latência e sobrecarga de processamento, surgiu uma técnica chamada rastreamento distribuído.

      O rastreamento distribuído é uma abordagem dos sistemas de instrumentação que funciona adicionando código a cada componente para iluminar o processamento da solicitação à medida que ela percorre seus serviços. Cada solicitação recebe um identificador exclusivo na borda de sua infraestrutura que é transmitido conforme a tarefa atravessa sua infraestrutura. Cada serviço usa essa ID para relatar erros e os registros de data e hora de quando viu a solicitação pela primeira vez e quando ela foi entregue para a próxima etapa. Ao agregar os relatórios dos componentes usando o ID da solicitação, um caminho detalhado com dados de tempo precisos pode ser rastreado através de sua infraestrutura.

      Esse método pode ser usado para entender quanto tempo é gasto em cada parte de um processo e identificar claramente qualquer aumento sério na latência. Essa instrumentação extra é uma maneira de adaptar a coleta de métricas a um grande número de componentes de processamento. Quando mapeado visualmente com o tempo no eixo x, a exibição resultante mostra o relacionamento entre diferentes estágios, por quanto tempo cada processo foi executado e o relacionamento de dependência entre os eventos que devem ser executados em paralelo. Isso pode ser incrivelmente útil para entender como melhorar seus sistemas e como o tempo está sendo gasto.

      Melhorando a Capacidade de Resposta Operacional para Sistemas Distribuídos

      Discutimos como as arquiteturas distribuídas podem tornar a análise da causa raiz e a clareza operacional difíceis de se obter. Em muitos casos, mudar a forma como os humanos respondem e investigam questões é parte da resposta a essas ambiguidades. Configurar as ferramentas para expor as informações de uma maneira que permita analisar a situação metodicamente pode ajudar a classificar as várias camadas de dados disponíveis. Nesta seção, discutiremos maneiras de se preparar para o sucesso ao solucionar problemas em ambientes grandes e distribuídos.

      Definindo Alertas para os Quatro Sinais de Ouro em Todas as Camadas

      O primeiro passo para garantir que você possa responder a problemas em seus sistemas é saber quando eles estão ocorrendo. Em nosso guia Coletando Métricas de sua Infraestrutura e Aplicações, apresentamos os quatro sinais de ouro – indicadores de monitoramento identificados pela equipe de SRE do Google como os mais vitais para rastrear. Os quatro sinais são:

      • latência
      • tráfego
      • taxa de erro
      • saturação

      Esses ainda são os melhores locais para começar quando estiver instrumentando seus sistemas, mas o número de camadas que devem ser observadas geralmente aumenta para sistemas altamente distribuídos. A infraestrutura subjacente, o plano de orquestração e a camada de trabalho precisam de um monitoramento robusto com alertas detalhados definidos para identificar alterações importantes.

      Obtendo uma Visão Completa

      Depois que seus sistemas identificarem uma anomalia e notificarem sua equipe, esta precisa começar a coletar dados. Antes de continuar a partir desta etapa, eles devem ter uma compreensão de quais componentes foram afetados, quando o incidente começou e qual condição de alerta específica foi acionada.

      A maneira mais útil de começar a entender o escopo de um incidente é começar em um nível alto. Comece a investigar verificando dashboards e visualizações que coletam e generalizam informações de seus sistemas. Isso pode ajudá-lo a identificar rapidamente os fatores correlacionados e a entender o impacto imediato que o usuário enfrenta. Durante esse processo, você deve conseguir sobrepor informações de diferentes componentes e hosts.

      O objetivo deste estágio é começar a criar um inventário mental ou físico de itens para verificar com mais detalhes e começar a priorizar sua investigação. Se você puder identificar uma cadeia de problemas relacionados que percorrem diferentes camadas, a camada mais baixa deve ter precedência: as correções para as camadas fundamentais geralmente resolvem os sintomas em níveis mais altos. A lista de sistemas afetados pode servir como uma lista de verificação informal de locais para validar as correções posteriormente quando a mitigação é implementada.

      Detalhando Problemas Específicos

      Quando você perceber que tem uma visão razoável do incidente, faça uma pesquisa detalhada sobre os componentes e sistemas da sua lista em ordem de prioridade. As métricas detalhadas sobre unidades individuais ajudarão você a rastrear a rota da falha até o recurso responsável mais baixo. Ao examinar painéis de controle e entradas de log mais refinados, consulte a lista de componentes afetados para tentar entender melhor como os efeitos colaterais estão sendo propagados pelo sistema. Com microsserviços, o número de componentes interdependentes significa que os problemas se espalham para outros serviços com mais frequência.

      Este estágio é focado em isolar o serviço, componente ou sistema responsável pelo incidente inicial e identificar qual problema específico está ocorrendo. Isso pode ser um código recém-implantado, uma infraestrutura física com defeito, um erro ou bug na camada de orquestração ou uma alteração na carga de trabalho que o sistema não pôde manipular normalmente. Diagnosticar o que está acontecendo e porquê permite descobrir como mitigar o problema e recuperar a saúde operacional. Entender até que ponto a resolução deste problema pode corrigir problemas relatados em outros sistemas pode ajudá-lo a continuar priorizando as tarefas de mitigação.

      Mitigando e Resolvendo os Problemas

      Depois que os detalhes forem identificados, você poderá resolver ou mitigar o problema. Em muitos casos, pode haver uma maneira óbvia e rápida de restaurar o serviço fornecendo mais recursos, revertendo ou redirecionando o tráfego para uma implementação alternativa. Nestes cenários, a resolução será dividida em três fases:

      • Execução de ações para contornar o problema e restaurar o serviço imediato
      • Resolução do problema subjacente para recuperar a funcionalidade total e a integridade operacional
      • Avaliação completa do motivo da falha e implementação de correções de longo prazo para evitar recorrência

      Em muitos sistemas distribuídos, a redundância e os componentes altamente disponíveis garantirão que o serviço seja restaurado rapidamente, embora seja necessário mais trabalho em segundo plano para restaurar a redundância ou tirar o sistema de um estado degradado. Você deve usar a lista de componentes impactados compilados anteriormente como uma base de medição para determinar se a mitigação inicial resolve problemas de serviço em cascata. À medida que a sofisticação dos sistemas de monitoramento evolui, ele também pode automatizar alguns desses processos de recuperação mais completos enviando comandos para a camada de provisionamento para lançar novas instâncias de unidades com falha ou para eliminar unidades que não se comportam corretamente.

      Dada a automação possível nas duas primeiras fases, o trabalho mais importante para a equipe de operações geralmente é entender as causas-raiz de um evento. O conhecimento obtido a partir desse processo pode ser usado para desenvolver novos gatilhos e políticas para ajudar a prever ocorrências futuras e automatizar ainda mais as reações do sistema. O software de monitoramento geralmente obtém novos recursos em resposta a cada incidente para proteger contra os cenários de falha recém-descobertos. Para sistemas distribuídos, rastreamentos distribuídos, entradas de log, visualizações de séries temporais e eventos como deploys recentes podem ajudá-lo a reconstruir a sequência de eventos e identificar onde o software e os processos humanos podem ser aprimorados.

      Devido à complexidade específica inerente aos grandes sistemas distribuídos, é importante tratar o processo de resolução de qualquer evento significativo como uma oportunidade para aprender e ajustar seus sistemas. O número de componentes separados e os caminhos de comunicação envolvidos forçam uma grande dependência da automação e das ferramentas para ajudar a gerenciar a complexidade. A codificação de novas lições nos mecanismos de resposta e conjuntos de regras desses componentes (bem como nas políticas operacionais que sua equipe segue) é a melhor maneira de seu sistema de monitoramento manter a pegada de gerenciamento de sua equipe sob controle.

      Conclusão

      Neste guia, falamos sobre alguns dos desafios específicos que as arquiteturas distribuídas e os projetos de microsserviço podem introduzir para o software de monitoramento e visibilidade. As maneiras modernas de se construir sistemas quebram algumas suposições dos métodos tradicionais, exigindo abordagens diferentes para lidar com os novos ambientes de configuração. Exploramos os ajustes que você precisará considerar ao passar de sistemas monolíticos para aqueles que dependem cada vez mais de workers efêmeros, baseados em nuvem ou em containers e alto volume de coordenação de rede. Posteriormente, discutimos algumas maneiras pelas quais a arquitetura do sistema pode afetar a maneira como você responde a incidentes e a resolução.



      Source link

      How to Deploy a Resilient Go Application to DigitalOcean Kubernetes


      The author selected Girls Who Code to receive a donation as part of the Write for DOnations program.

      Introduction

      Docker is a containerization tool used to provide applications with a filesystem holding everything they need to run, ensuring that the software will have a consistent run-time environment and will behave the same way regardless of where it is deployed. Kubernetes is a cloud platform for automating the deployment, scaling, and management of containerized applications.

      By leveraging Docker, you can deploy an application on any system that supports Docker with the confidence that it will always work as intended. Kubernetes, meanwhile, allows you to deploy your application across multiple nodes in a cluster. Additionally, it handles key tasks such as bringing up new containers should any of your containers crash. Together, these tools streamline the process of deploying an application, allowing you to focus on development.

      In this tutorial, you will build an example application written in Go and get it up and running locally on your development machine. Then you’ll containerize the application with Docker, deploy it to a Kubernetes cluster, and create a load balancer that will serve as the public-facing entry point to your application.

      Prerequisites

      Before you begin this tutorial, you will need the following:

      • A development server or local machine from which you will deploy the application. Although the instructions in this guide will largely work for most operating systems, this tutorial assumes that you have access to an Ubuntu 18.04 system configured with a non-root user with sudo privileges, as described in our Initial Server Setup for Ubuntu 18.04 tutorial.
      • The docker command-line tool installed on your development machine. To install this, follow Steps 1 and 2 of our tutorial on How to Install and Use Docker on Ubuntu 18.04.
      • The kubectl command-line tool installed on your development machine. To install this, follow this guide from the official Kubernetes documentation.
      • A free account on Docker Hub to which you will push your Docker image. To set this up, visit the Docker Hub website, click the Get Started button at the top-right of the page, and follow the registration instructions.
      • A Kubernetes cluster. You can provision a DigitalOcean Kubernetes cluster by following our Kubernetes Quickstart guide. You can still complete this tutorial if you provision your cluster from another cloud provider. Wherever you procure your cluster, be sure to set up a configuration file and ensure that you can connect to the cluster from your development server.

      Step 1 — Building a Sample Web Application in Go

      In this step, you will build a sample application written in Go. Once you containerize this app with Docker, it will serve My Awesome Go App in response to requests to your server’s IP address at port 3000.

      Get started by updating your server’s package lists if you haven’t done so recently:

      Then install Go by running:

      Next, make sure you're in your home directory and create a new directory which will contain all of your project files:

      Then navigate to this new directory:

      Use nano or your preferred text editor to create a file named main.go which will contain the code for your Go application:

      The first line in any Go source file is always a package statement that defines which code bundle the file belongs to. For executable files like this one, the package statement must point to the main package:

      go-app/main.go

      package main
      

      Following that, add an import statement where you can list all the libraries the application will need. Here, include fmt, which handles formatted text input and output, and net/http, which provides HTTP client and server implementations:

      go-app/main.go

      package main
      
      import (
        "fmt"
        "net/http"
      )
      

      Next, define a homePage function which will take in two arguments: http.ResponseWriter and a pointer to http.Request. In Go, a ResponseWriter interface is used to construct an HTTP response, while http.Request is an object representing an incoming request. Thus, this block reads incoming HTTP requests and then constructs a response:

      go-app/main.go

      . . .
      
      import (
        "fmt"
        "net/http"
      )
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      

      After this, add a setupRoutes function which will map incoming requests to their intended HTTP handler functions. In the body of this setupRoutes function, add a mapping of the / route to your newly defined homePage function. This tells the application to print the My Awesome Go App message even for requests made to unknown endpoints:

      go-app/main.go

      . . .
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      

      And finally, add the following main function. This will print out a string indicating that your application has started. It will then call the setupRoutes function before listening and serving your Go application on port 3000.

      go-app/main.go

      . . .
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      
      func main() {
        fmt.Println("Go Web App Started on Port 3000")
        setupRoutes()
        http.ListenAndServe(":3000", nil)
      }
      

      After adding these lines, this is how the final file will look:

      go-app/main.go

      package main
      
      import (
        "fmt"
        "net/http"
      )
      
      func homePage(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "My Awesome Go App")
      }
      
      func setupRoutes() {
        http.HandleFunc("/", homePage)
      }
      
      func main() {
        fmt.Println("Go Web App Started on Port 3000")
        setupRoutes()
        http.ListenAndServe(":3000", nil)
      }
      

      Save and close this file. If you created this file using nano, do so by pressing CTRL + X, Y, then ENTER.

      Next, run the application using the following go run command. This will compile the code in your main.go file and run it locally on your development machine:

      Output

      Go Web App Started on Port 3000

      This output confirms that the application is working as expected. It will run indefinitely, however, so close it by pressing CTRL + C.

      Throughout this guide, you will use this sample application to experiment with Docker and Kubernetes. To that end, continue reading to learn how to containerize your application with Docker.

      Step 2 — Dockerizing Your Go Application

      In its current state, the Go application you just created is only running on your development server. In this step, you'll make this new application portable by containerizing it with Docker. This will allow it to run on any machine that supports Docker containers. You will build a Docker image and push it to a central public repository on Docker Hub. This way, your Kubernetes cluster can pull the image back down and deploy it as a container within the cluster.

      The first step towards containerizing your application is to create a special script called a Dockerfile. A Dockerfile typically contains a list of instructions and arguments that run in sequential order so as to automatically perform certain actions on a base image or create a new one.

      Note: In this step, you will configure a simple Docker container that will build and run your Go application in a single stage. If, in the future, you want to reduce the size of the container where your Go applications will run in production, you may want to look into mutli-stage builds.

      Create a new file named Dockerfile:

      At the top of the file, specify the base image needed for the Go app:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      

      Then create an app directory within the container that will hold the application's source files:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      

      Below that, add the following line which copies everything in the root directory into the app directory:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      

      Next, add the following line which changes the working directory to app, meaning that all the following commands in this Dockerfile will be run from that location:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      

      Add a line instructing Docker to run the go build -o main command, which compiles the binary executable of the Go app:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      RUN go build -o main .
      

      Then add the final line, which will run the binary executable:

      go-app/Dockerfile

      FROM golang:1.12.0-alpine3.9
      RUN mkdir /app
      ADD . /app
      WORKDIR /app
      RUN go build -o main .
      CMD ["/app/main"]
      

      Save and close the file after adding these lines.

      Now that you have this Dockerfile in the root of your project, you can create a Docker image based off of it using the following docker build command. This command includes the -t flag which, when passed the value go-web-app, will name the Docker image go-web-app and tag it.

      Note: In Docker, tags allow you to convey information specific to a given image, such as its version number. The following command doesn't provide a specific tag, so Docker will tag the image with its default tag: latest. If you want to give an image a custom tag, you would append the image name with a colon and the tag of your choice, like so:

      • docker build -t sammy/image_name:tag_name .

      Tagging an image like this can give you greater control over your images. For example, you could deploy an image tagged v1.1 to production, but deploy another tagged v1.2 to your pre-production or testing environment.

      The final argument you'll pass is the path: .. This specifies that you wish to build the Docker image from the contents of the current working directory. Also, be sure to update sammy to your Docker Hub username:

      • docker build -t sammy/go-web-app .

      This build command will read all of the lines in your Dockerfile, execute them in order, and then cache them, allowing future builds to run much faster:

      Output

      . . . Successfully built 521679ff78e5 Successfully tagged go-web-app:latest

      Once this command finishes building it, you will be able to see your image when you run the docker images command like so:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE sammy/go-web-app latest 4ee6cf7a8ab4 3 seconds ago 355MB

      Next, use the following command create and start a container based on the image you just built. This command includes the -it flag, which specifies that the container will run in interactive mode. It also has the -p flag which maps the port on which the Go application is running on your development machine — port 3000 — to port 3000 in your Docker container:

      • docker run -it -p 3000:3000 sammy/go-web-app

      Output

      Go Web App Started on Port 3000

      If there is nothing else running on that port, you'll be able to see the application in action by opening up a browser and navigating to the following URL:

      http://your_server_ip:3000
      

      Note: If you're following this tutorial from your local machine instead of a server, visit the application by instead going to the following URL:

      http://localhost:3000
      

      Your containerized Go App

      After checking that the application works as expected in your browser, stop it by pressing CTRL + C in your terminal.

      When you deploy your containerized application to your Kubernetes cluster, you'll need to be able to pull the image from a centralized location. To that end, you can push your newly created image to your Docker Hub image repository.

      Run the following command to log in to Docker Hub from your terminal:

      This will prompt you for your Docker Hub username and password. After entering them correctly, you will see Login Succeeded in the command's output.

      After logging in, push your new image up to Docker Hub using the docker push command, like so:

      • docker push sammy/go-web-app

      Once this command has successfully completed, you will be able to open up your Docker Hub account and see your Docker image there.

      Now that you've pushed your image to a central location, you're ready to deploy it to your Kubernetes cluster. First, though, we will walk through a brief process that will make it much less tedious to run kubectl commands.

      Step 3 — Improving Usability for kubectl

      By this point, you've created a functioning Go application and containerized it with Docker. However, the application still isn't publicly accessible. To resolve this, you will deploy your new Docker image to your Kubernetes cluster using the kubectl command line tool. Before doing this, though, let's make a small change to the Kubernetes configuration file that will help to make running kubectl commands less laborious.

      By default, when you run commands with the kubectl command-line tool, you have to specify the path of the cluster configuration file using the --kubeconfig flag. However, if your configuration file is named config and is stored in a directory named ~/.kube, kubectl will know where to look for the configuration file and will be able pick it up without the --kubeconfig flag pointing to it.

      To that end, if you haven't already done so, create a new directory called ~/.kube:

      Then move your cluster configuration file to this directory, and rename it config in the process:

      • mv clusterconfig.yaml ~/.kube/config

      Moving forward, you won't need to specify the location of your cluster's configuration file when you run kubectl, as the command will be able to find it now that it's in the default location. Test out this behavior by running the following get nodes command:

      This will display all of the nodes that reside within your Kubernetes cluster. In the context of Kubernetes, a node is a server or a worker machine on which one or more pods can be deployed:

      Output

      NAME STATUS ROLES AGE VERSION k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfd Ready <none> 1m v1.13.5 k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfi Ready <none> 1m v1.13.5 k8s-1-13-5-do-0-nyc1-1554148094743-1-7lfv Ready <none> 1m v1.13.5

      With that, you're ready to move on and deploy your application to your Kubernetes cluster. You will do this by creating two Kubernetes objects: one that will deploy the application to some pods in your cluster and another that will create a load balancer, providing an access point to your application.

      Step 4 — Creating a Deployment

      RESTful resources make up all the persistent entities wihtin a Kubernetes system, and in this context they're commonly referred to as Kubernetes objects. It's helpful to think of Kubernetes objects as the work orders you submit to Kubernetes: you list what resources you need and how they should work, and then Kubernetes will constantly work to ensure that they exist in your cluster.

      One kind of Kubernetes object, known as a deployment, is a set of identical, indistinguishable pods. In Kubernetes, a pod is a grouping of one or more containers which are able to communicate over the same shared network and interact with the same shared storage. A deployment runs more than one replica of the parent application at a time and automatically replaces any instances that fail, ensuring that your application is always available to serve user requests.

      In this step, you'll create a Kubernetes object description file, also known as a manifest, for a deployment. This manifest will contain all of the configuration details needed to deploy your Go app to your cluster.

      Begin by creating a deployment manifest in the root directory of your project: go-app/. For small projects such as this one, keeping them in the root directory minimizes the complexity. For larger projects, however, it may be beneficial to store your manifests in a separate subdirectory so as to keep everything organized.

      Create a new file called deployment.yml:

      Different versions of the Kubernetes API contain different object definitions, so at the top of this file you must define the apiVersion you're using to create this object. For the purpose of this tutorial, you will be using the apps/v1 grouping as it contains many of the core Kubernetes object definitions that you'll need in order to create a deployment. Add a field below apiVersion describing the kind of Kubernetes object you're creating. In this case, you're creating a Deployment:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      

      Then define the metadata for your deployment. A metadata field is required for every Kubernetes object as it contains information such as the unique name of the object. This name is useful as it allows you to distinguish different deployments from one another and identify them using names that are human-readable:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
          name: go-web-app
      

      Next, you'll build out the spec block of your deployment.yml. A spec field is a requirement for every Kubernetes object, but its precise format differs for each type of object. In the case of a deployment, it can contain information such as the number of replicas of you want to run. In Kubernetes, a replica is the number of pods you want to run in your cluster. Here, set the number of replicas to 5:

      go-app/deployment.yml

      . . .
      metadata:
          name: go-web-app
      spec:
        replicas: 5
      

      Next, create a selector block nested under the spec block. This will serve as a label selector for your pods. Kubernetes uses label selectors to define how the deployment finds the pods which it must manage.

      Within this selector block, define matchLabels and add the name label. Essentially, the matchLabels field tells Kubernetes what pods the deployment applies to. In this example, the deployment will apply to any pods with the name go-web-app:

      go-app/deployment.yml

      . . .
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
      

      After this, add a template block. Every deployment creates a set of pods using the labels specified in a template block. The first subfield in this block is metadata which contains the labels that will be applied to all of the pods in this deployment. These labels are key/value pairs that are used as identifying attributes of Kubernetes objects. When you define your service later on, you can specify that you want all the pods with this name label to be grouped under that service. Set this name label to go-web-app:

      go-app/deployment.yml

      . . .
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
        template:
          metadata:
            labels:
              name: go-web-app
      

      The second part of this template block is the spec block. This is different from the spec block you added previously, as this one applies only to the pods created by the template block, rather than the whole deployment.

      Within this spec block, add a containers field and once again define a name attribute. This name field defines the name of any containers created by this particular deployment. Below that, define the image you want to pull down and deploy. Be sure to change sammy to your own Docker Hub username:

      go-app/deployment.yml

      . . .
        template:
          metadata:
            labels:
              name: go-web-app
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
      

      Following that, add an imagePullPolicy field set to IfNotPresent which will direct the deployment to only pull an image if it has not already done so before. Then, lastly, add a ports block. There, define the containerPort which should match the port number that your Go application listens on. In this case, the port number is 3000:

      go-app/deployment.yml

      . . .
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 3000
      

      The full version of your deployment.yml will look like this:

      go-app/deployment.yml

      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: go-web-app
      spec:
        replicas: 5
        selector:
          matchLabels:
            name: go-web-app
        template:
          metadata:
            labels:
              name: go-web-app
          spec:
            containers:
            - name: application
              image: sammy/go-web-app
              imagePullPolicy: IfNotPresent
              ports:
                - containerPort: 3000
      

      Save and close the file.

      Next, apply your new deployment with the following command:

      • kubectl apply -f deployment.yml

      Note: For more information on all of the configuration available to you for deployments, please check out the official Kubernetes documentation here: Kubernetes Deployments

      In the next step, you'll create another kind of Kubernetes object which will manage how you access the pods that exist in your new deployment. This service will create a load balancer which will then expose a single IP address, and requests to this IP address will be distributed to the replicas in your deployment. This service will also handle port forwarding rules so that you can access your application over HTTP.

      Step 5 — Creating a Service

      Now that you have a successful Kubernetes deployment, you're ready to expose your application to the outside world. In order to do this, you'll need to define another kind of Kubernetes object: a service. This service will expose the same port on all of your cluster's nodes. Your nodes will then forward any incoming traffic on that port to the pods running your application.

      Note: For clarity, we will define this service object in a separate file. However, it is possible to group multiple resource manifests in the same YAML file, as long as they're separated by ---. See this page from the Kubernetes documentation for more details.

      Create a new file called service.yml:

      Start this file off by again defining the apiVersion and the kind fields in a similar fashion to your deployment.yml file. This time, point the apiVersion field to v1, the Kubernetes API commonly used for services:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      

      Next, add the name of your service in a metadata block as you did in deployment.yml. This could be anything you like, but for clarity we will call it go-web-service:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      

      Next, create a spec block. This spec block will be different than the one included in your deployment, and it will contain the type of this service, as well as the port forwarding configuration and the selector.

      Add a field defining this service's type and set it to LoadBalancer. This will automatically provision a load balancer that will act as the main entry point to your application.

      Warning: The method for creating a load balancer outlined in this step will only work for Kubernetes clusters provisioned from cloud providers that also support external load balancers. Additionally, be advised that provisioning a load balancer from a cloud provider will incur additional costs. If this is a concern for you, you may want to look into exposing an external IP address using an Ingress.

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
      

      Then add a ports block where you'll define how you want your apps to be accessed. Nested within this block, add the following fields:

      • name, pointing to http
      • port, pointing to port 80
      • targetPort, pointing to port 3000

      This will take incoming HTTP requests on port 80 and forward them to the targetPort of 3000. This targetPort is the same port on which your Go application is running:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
        ports:
        - name: http
          port: 80
          targetPort: 3000
      

      Lastly, add a selector block as you did in the deployments.yml file. This selector block is important, as it maps any deployed pods named go-web-app to this service:

      go-app/service.yml

      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-web-service
      spec:
        type: LoadBalancer
        ports:
        - name: http
          port: 80
          targetPort: 3000
        selector:
          name: go-web-app
      

      After adding these lines, save and close the file. Following that, apply this service to your Kubernetes cluster by once again using the kubectl apply command like so:

      • kubectl apply -f service.yml

      This command will apply the new Kubernetes service as well as create a load balancer. This load balancer will serve as the public-facing entry point to your application running within the cluster.

      To view the application, you will need the new load balancer's IP address. Find it by running the following command:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE go-web-service LoadBalancer 10.245.107.189 203.0.113.20 80:30533/TCP 10m kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 3h4m

      You may have more than one service running, but find the one labeled go-web-service. Find the EXTERNAL-IP column and copy the IP address associated with the go-web-service. In this example output, this IP address is 203.0.113.20. Then, paste the IP address into the URL bar of your browser to the view the application running on your Kubernetes cluster.

      Note: When Kubernetes creates a load balancer in this manner, it does so asynchronously. Consequently, the kubectl get services command's output may show the EXTERNAL-IP address of the LoadBalancer remaining in a <pending> state for some time after running the kubectl apply command. If this the case, wait a few minutes and try re-running the command to ensure that the load balancer was created and is functioning as expected.

      The load balancer will take in the request on port 80 and forward it to one of the pods running within your cluster.

      Your working Go App!

      With that, you've created a Kubernetes service coupled with a load balancer, giving you a single, stable entry point to application.

      Conclusion

      In this tutorial, you've built Go application, containerized it with Docker, and then deployed it to a Kubernetes cluster. You then created a load balancer that provides a resilient entry point to this application, ensuring that it will remain highly available even if one of the nodes in your cluster fails. You can use this tutorial to deploy your own Go application to a Kubernetes cluster, or continue learning other Kubernetes and Docker concepts with the sample application you created in Step 1.

      Moving forward, you could map your load balancer's IP address to a domain name that you control so that you can access the application through a human-readable web address rather than the load balancer IP. Additionally, the following Kubernetes tutorials may be of interest to you:

      Finally, if you'd like to learn more about Go, we encourage you to check out our series on How To Code in Go.



      Source link

      12 Reasons Why Your Website Is Slow (And How to Fix Them)


      Site speed plays a crucial role in the success of your website. It affects a variety of key metrics, for example, including your site’s visibility and conversion rate. Optimizing your website’s speed is clearly a necessity, but figuring out how to do it can be tricky.

      Fortunately, there are several easily-accessible speed tests you can use to determine how your site’s performance measures up. Although there are several reasons your site may be slow, you can resolve many of them with free WordPress plugins and quality web hosting.

      In this post, we’ll explain why site speed is so vital to your website. Then we’ll share solutions to 12 common issues that can lead to poor website performance. Let’s dive right in!

      Shared Hosting That Powers Your Purpose

      We make sure your website is fast, secure, and always up so your visitors trust you. Plans start at $2.59/mo.

      Why Your Website’s Loading Speed Matters

      These days, users expect websites to be fast. When pages take longer than expected to load, it negatively impacts your site’s User Experience (UX). This matters because any time your UX takes a hit, so does your conversion rate.

      You’ll likely see higher page abandonment and bounce rates as well. To be more specific, studies show that an additional two seconds of loading time can increase your site’s bounce rate by 103 percent. Plus, just 100 milliseconds of extra loading time can cause a 7 percent drop in conversion rates.

      Even fractions of a second count, so optimizing your site’s performance as fully as you can is crucial. What’s more, website speed not only influences whether users stay on your site and convert; it also affects whether or not they can find it in the first place.

      Site speed is now a Google ranking factor for both desktop and mobile sites. If you don’t maintain decent website performance, your site’s visibility on Search Engine Results Pages (SERPs) may decrease, leading to lower traffic levels.

      With your website’s success on the line, speed can’t be ignored. If you’re feeling overwhelmed, a smart place to start is by testing to determine where your site stands now. You can run load time tests to see how long your users are waiting and then get to work on decreasing those numbers.

      12 Reasons Your Website Is Slow (And How to Fix Them)

      Once you know the current state of your site’s performance, you can start optimizing key factors that influence site speed. Let’s look at 12 of the most common problems that contribute to slow websites and discuss how to resolve them.

      1. Render-Blocking JavaScript Is Delaying Page Loads

      JavaScript is the code that makes your website functional and interactive for users. Without it, your site would be pretty dull. However, if left unoptimized, JavaScript can delay your pages when they try to load in users’ browsers.

      When a browser tries to display a webpage, it has to stop and fully load any JavaScript files it encounters first. This results in what’s called ‘render-blocking JavaScript’ or JavaScript that prevents the page from loading quickly.

      There are three solutions for dealing with render-blocking JavaScript:

      • Remove external JavaScript files, and use inline JavaScript instead.
      • Use asynchronous loading so JavaScript can load separately from the rest of the page.
      • Defer JavaScript loading until the rest of the page is visible to the user.

      Each method has its pros and cons. Generally speaking, inline JavaScript will only improve page speed when used sparingly. Asynchronous loading can cause issues as files are not loaded in any particular order. Therefore, deferring JavaScript is usually the recommended method.

      2. You’re Not Using a Content Delivery Network (CDN)

      A Content Delivery Network (CDN) consists of several servers that are placed in strategic geographic locations. You can store copies of your website on them so its pages can be quickly loaded by users who are located far away from your main server.

      There are several CDN options for your WordPress site. Cloudflare is one of the most popular solutions, as is the Jetpack CDN for images and videos. For customers on our DreamPress Plus and Pro plans, you’ll get unlimited CDN usage powered by Jetpack.

      Additionally, if your website uses jQuery, you can load it from a CDN instead of your web server. Since jQuery uses far fewer lines of code than JavaScript to accomplish the same outcomes, it can be especially useful for boosting your site’s speed. Google and Microsoft are the two most popular jQuery CDN options.

      3. There’s Excessive Overhead in Your Database

      ‘Overhead’ refers to extraneous items in your site’s database — things like logs, transients, and other entries from plugins or themes can build up over time. Too much of this ‘overhead’ can cause database queries to take longer than necessary. In some cases, it can even cause your web server to time out while waiting for a response from your database.

      Optimizing your database by removing overhead will help prevent this. Most web hosts allow you to access the database management platform phpMyAdmin via your hosting account. If you aren’t able to optimize your tables in phpMyAdmin, you can use the WordPress Command Line interface (WP-CLI).

      4. Your Site’s CSS Isn’t Optimized

      Like JavaScript, your site’s CSS — the code responsible for styling its pages — can delay loading if left unoptimized. There are a few solutions you can implement to get your CSS into shape:

      • If you have several external CSS files, combine them into one or a few files.
      • Remove external CSS and use inline CSS instead.
      • Use ‘media types’ to specify when certain CSS files should be loaded.

      Like inline JavaScript, inline CSS is only useful for small portions of code. If you have several large CSS files, you shouldn’t try to add all of them to your HTML file. Specifying media types and combining your external CSS files (if you have more than one) should make a more significant impact.

      Be Awesome on the Internet

      Join our monthly newsletter for tips and tricks to build your dream website!

      5. OPcache Isn’t Enabled

      OPcache is a built-in caching engine for the coding language PHP. If you use PHP on your site, having OPcache enabled can speed up its loading and the loading of your pages as a result.

      If you host your website with one of our Shared WordPress or DreamPress plans, OPcache is enabled by default. If your site is hosted using one of our other plans or with another web host, you’ll likely need to enable it manually.

      6. Caching Issues Are Preventing Optimized Page Loading

      Caching is when browsers store static copies of your website’s files. Then when users access your site, their browsers can display the cached data instead of having to reload it.

      There are several caching solutions available for WordPress users, including using a caching plugin such as WP Super Cache.

      The WP Super Cache plugin.

      Our DreamPress customers have the advantage of built-in caching, which is included with your hosting account.

      DreamPress managed WordPress hosting plans

      This makes third-party caching plugins unnecessary. However, we do recommend using the Proxy Cache Purge plugin to manage your DreamPress cache.

      The Proxy Cache Purge plugin.

      The plugin automatically sends requests to delete cached data for a page or post after you’ve modified it. This can help prevent some caching issues that may result in slower site speeds.

      7. Large Media Files Are Increasing Loading Times

      Media files, such as images and videos, tend to be quite large. Optimizing them through compression can help to decrease their size and, therefore, improve your loading times.

      TinyJPG is a free online tool that compresses images. There are also several plugins you can use to compress media files within WordPress, including Smush Image Compression and Optimization.

      The Smush Image Optimization plugin.

      Compressing videos is a little trickier, so it’s usually better to host them externally on YouTube or another platform instead. You can then easily embed your videos on pages or posts.

      8. Poorly-Written Scripts Are Conflicting With Other Site Elements

      Poorly-written JavaScript can sometimes cause compatibility issues with other parts of your website, resulting in longer loading times. Running a speed test using tools such as Pingdom, Web Page Test, and GTmetrix can often point out scripts that are taking a long time to load.

      You can then investigate these files more closely to determine how you can improve them. It may also be useful to turn potentially problematic scripts off temporarily, to see how your performance scores change without them enabled.

      9. Your Site’s Code Is Too Bulky

      The more code your user’s web browser has to load, the longer it will take for your website to become visible. If your code is too ‘bulky’ or contains unnecessary characters and line breaks, your site may be slower. In response, you can ‘minify’ that code by removing the elements that aren’t needed.

      There are two popular plugins for carrying out this task. Autoptimize minifies code, in addition to inlining CSS and optimizing JavaScript files. It also integrates well with WP Super Cache.

      The Autoptimize plugin for WordPress.

      Fast Velocity Minify merges CSS and JavaScript files to reduce the number of requests needed for browsers to load your pages. It also minifies your code.

      The Fast Velocity Minify plugin for WordPress.

      Both plugins are solid choices. You might consider trying out each one and seeing which increases your performance test scores more.

      10. Missing Files Are Causing Errors

      In some instances, your WordPress installation may be missing files. If this happens, users will experience longer loading times as additional requests are made in an attempt to find the files. This process will eventually result in a 404 error if the files can’t be found.

      The causes behind this issue are numerous and varied. Instead of trying to track down the source of the problem, the fastest solution is to restore your site from your most recent backup. This should replace the missing files with the versions saved in your backup.

      11. Plugins Are Weighing Your Site Down

      Having too many plugins — or even a few very bulky ones — can weigh your website down and cause poor performance. It’s wise to always completely remove any plugins you’re not using to minimize the chance that this will happen.

      Additionally, some plugins can interfere with the caching of your site’s pages. If you’re using the Proxy Cache Purge plugin we mentioned earlier in this article, you can pinpoint which plugins are causing the problem by navigating to Proxy Cache > Check Caching.

      12. Internet Issues Are Hurting Specific Users’ Performance

      Finally, poor website performance can be due to an issue with a user’s Internet Service Provider (ISP), rather than with your site itself. Slow site speeds can result from network congestion, bandwidth throttling and restrictions, data discrimination and filtering, or content filtering.

      If you notice slow speeds when visiting your site, you can run a traceroute between your computer and your website to test the connection. This should give you an idea of whether or not the problem is related to your ISP or is a more significant site-wide concern.

      Lighten Your Website Load

      Your website’s performance and response time are closely tied to its success, so taking every available opportunity to improve it is worth the effort. Figuring out why your website has lagging load times can help boost both its Search Engine Optimization (SEO) and UX, resulting in better visibility and a higher conversion rate.

      We’ve covered twelve common causes of slow site speeds throughout this post. While ideally, you’ll want to optimize your site in all the ways we’ve mentioned, pinpointing specific areas for improvement — such as enabling caching or compressing your media files — can help you tackle the biggest issues first.

      Looking for a hosting service that can keep up with your site’s performance needs? Our Shared Hosting plans are a convenient, low-cost solution that’s optimized for WordPress and ideal for new users. Check them out today!



      Source link