Neste tutorial, você aprenderá a implantar um cluster de servidores distribuídos do Memcached no Google Kubernetes Engine (GKE) usando Kubernetes, Mcrouter e Mcrouter. O Memcached é um famoso sistema de armazenamento em cache de código aberto e multiuso. Ele normalmente funciona como um armazenamento temporário para os dados mais usados a fim de agilizar aplicativos da Web e diminuir cargas do banco de dados.
Características do Memcached
O Memcached tem duas metas de projeto principais:
- Simplicidade: o Memcached funciona como uma grande tabela de hash e oferece uma API simples para armazenar e recuperar objetos de maneira arbitrária por chave.
- Velocidade: o Memcached mantém dados de cache de maneira exclusiva em memória de acesso aleatório (RAM, na sigla em inglês), acelerando muito o acesso a dados.
Memcached é um sistema distribuído que permite que a capacidade da tabela de hash seja escalada horizontalmente em um grupo de servidores. Cada servidor do Memcached opera em completo isolamento dos outros servidores no grupo. Portanto, o roteamento e o balanceamento de carga entre os servidores precisam ser feitos no nível do cliente. Os clientes do Memcached aplicam um esquema de hash consistente para selecionar corretamente os servidores de destino. Esse esquema garante as seguintes condições:
- O mesmo servidor sempre é selecionado para a mesma chave.
- O uso da memória é equilibrado de maneira uniforme entre os servidores.
- Um número mínimo de chaves é realocado quando o grupo de servidores é reduzido ou expandido.
O diagrama a seguir ilustra detalhadamente a interação entre um cliente do Memcached e um grupo distribuído de servidores do Memcached.
Objetivos
- Saiba mais sobre algumas características da arquitetura distribuída do Memcached.
- Implante um serviço do Memcached para o GKE usando o Kubernetes e o Helm.
- Implante o Mcrouter, um proxy do Memcached de código aberto, para melhorar o desempenho do sistema.
Custos
Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:
- Compute Engine
Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.
Antes de começar
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine and GKE APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine and GKE APIs.
- Inicie uma instância do Cloud Shell.
Abra o Cloud Shell
Como implantar um serviço do Memcached
Uma maneira simples de implantar um serviço Memcached no GKE é usar um gráfico de Helm. Para continuar a implantação, siga estas etapas no Cloud Shell:
Crie um novo cluster GKE de três nós:
gcloud container clusters create demo-cluster --num-nodes 3 --zone us-central1-f
Faça o download do arquivo binário
helm
:HELM_VERSION=3.7.1 cd ~ wget https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz
Descompacte o arquivo no sistema local:
mkdir helm-v${HELM_VERSION} tar zxfv helm-v${HELM_VERSION}-linux-amd64.tar.gz -C helm-v${HELM_VERSION}
Adicione o diretório do binário
helm
à variável de ambientePATH
:export PATH="$(echo ~)/helm-v${HELM_VERSION}/linux-amd64:$PATH"
Esse comando torna o binário
helm
detectável a partir de qualquer diretório durante a sessão atual do Cloud Shell. Para tornar essa configuração persistente em várias sessões, adicione o comando ao arquivo~/.bashrc
do usuário do Cloud Shell.Instale um novo gráfico do Memcached Helm com a arquitetura de alta disponibilidade:
helm repo add bitnami https://charts.bitnami.com/bitnami helm install mycache bitnami/memcached --set architecture="high-availability" --set autoscaling.enabled="true"
O gráfico do Memcached Helm usa um controlador StatefulSet. Uma vantagem de usar um controlador StatefulSet é que os nomes dos pods são ordenados e previsíveis. Neste caso, os nomes são
mycache-memcached-{0..2}
. Essa ordem facilita a consulta aos servidores pelos clientes do Memcached.Para ver os pods em execução, execute o seguinte comando:
kubectl get pods
O resultado do Console do Google Cloud será como este:
NAME READY STATUS RESTARTS AGE mycache-memcached-0 1/1 Running 0 45s mycache-memcached-1 1/1 Running 0 35s mycache-memcached-2 1/1 Running 0 25s
Como descobrir endpoints do serviço Memcached
O gráfico do Memcached Helm usa um serviço sem cabeça. Um serviço sem cabeça expõe endereços IP de todos os pods, de maneira que eles possam ser detectados individualmente.
Verifique se o serviço implantado está sem cabeça:
kubectl get service mycache-memcached -o jsonpath="{.spec.clusterIP}"
O resultado
None
confirma que o serviço não temclusterIP
e que, portanto, é sem cabeça.O serviço cria um registro DNS para um nome do host do formulário:
[SERVICE_NAME].[NAMESPACE].svc.cluster.local
Neste tutorial, o nome do serviço é
mycache-memcached
. Como um namespace não foi definido explicitamente, o namespace padrão é usado e, portanto, todo o nome do host émycache-memcached.default.svc.cluster.local
. Esse nome de host é resolvido para um conjunto de endereços IP e domínios para todos os três pods expostos pelo serviço. Se, no futuro, alguns pods forem adicionados ao grupo ou os antigos forem removidos,kube-dns
atualizará automaticamente o registro DNS.É responsabilidade do cliente descobrir os endpoints do serviço Memcached, conforme descrito nas próximas etapas.
Recupere os endereços IP dos pontos de extremidade:
kubectl get endpoints mycache-memcached
O resultado será semelhante a:
NAME ENDPOINTS AGE mycache-memcached 10.36.0.32:11211,10.36.0.33:11211,10.36.1.25:11211 3m
Cada pod do Memcached tem um endereço IP separado, respectivamente
10.36.0.32
,10.36.0.33
, e10.36.1.25
. Esses endereços IP podem ser diferentes para as próprias instâncias de servidor. Cada pod escuta a porta11211
, que é a porta padrão do Memcached.Como alternativa à etapa 2, execute uma inspeção DNS usando uma linguagem de programação como Python:
Inicie um console interativo Python dentro do cluster:
kubectl run -it --rm python --image=python:3.10-alpine --restart=Never python
No console Python, execute estes comandos:
import socket print(socket.gethostbyname_ex('mycache-memcached.default.svc.cluster.local')) exit()
O resultado será semelhante a:
('mycache-memcached.default.svc.cluster.local', ['mycache-memcached.default.svc.cluster.local'], ['10.36.0.32', '10.36.0.33', '10.36.1.25'])
Teste a implantação abrindo uma sessão
telnet
com um dos servidores Memcached em execução na porta11211
:kubectl run -it --rm busybox --image=busybox:1.33 --restart=Never telnet mycache-memcached-0.mycache-memcached.default.svc.cluster.local 11211
No prompt
telnet
, execute esses comandos usando o protocolo Memcached ASCII:set mykey 0 0 5 hello get mykey quit
O resultado é mostrado aqui em negrito:
set mykey 0 0 5 hello STORED get mykey VALUE mykey 0 5 hello END quit
Como implementar a lógica de descoberta do serviço
Agora está tudo pronto para você implementar a lógica de descoberta do serviço básico mostrada no diagrama a seguir.
Em um nível mais detalhado, a lógica de descoberta de serviços consiste nas seguintes etapas:
- O aplicativo consulta
kube-dns
sobre o registro DNS demycache-memcached.default.svc.cluster.local
. - O aplicativo recupera os endereços IP associados a esse registro.
- O aplicativo instancia um novo cliente do Memcached e fornece a ele os endereços IP recuperados.
- O balanceador de carga integrado do cliente do Memcached se conecta aos servidores do Memcached nos endereços IP fornecidos.
Você agora implementa essa lógica de descoberta de serviço usando o Python:
Implante um novo pod ativado para Python no cluster e inicie uma sessão de shell dentro do pod:
kubectl run -it --rm python --image=python:3.10-alpine --restart=Never sh
Instale a biblioteca
pymemcache
:pip install pymemcache
Inicie um console interativo do Python executando o comando
python
.No console Python, execute estes comandos:
import socket from pymemcache.client.hash import HashClient _, _, ips = socket.gethostbyname_ex('mycache-memcached.default.svc.cluster.local') servers = [(ip, 11211) for ip in ips] client = HashClient(servers, use_pooling=True) client.set('mykey', 'hello') client.get('mykey')
A resposta é a seguinte:
b'hello'
O prefixo
b
indica um literal de bytes, formato de armazenamento de dados no Memcached.Saia do console Python:
exit()
Para sair da sessão de shell do pod, pressione
Control
+D
.
Como ativar o agrupamento de conexões
À medida que as necessidades de armazenamento em cache crescem e o grupo chega a dezenas, centenas ou milhares de servidores Memcached, você pode enfrentar algumas limitações. Em especial, o grande número de conexões abertas de clientes do Memcached pode colocar uma carga pesada sobre os servidores, como mostra o diagrama a seguir.
Para reduzir o número de conexões abertas, é preciso introduzir um proxy para ativar o agrupamento de conexões, como no diagrama a seguir.
O Mcrouter (pronuncia-se "mick router"), um proxy Memcached de código aberto eficiente, permite o agrupamento de conexões. A integração do Mcrouter é perfeita porque ele usa o protocolo padrão Memcached ASCII. Para um cliente do Memcached, o Mcrouter se comporta como um servidor do Memcached normal. Para um servidor do Memcached, o Mcrouter se comporta como um cliente do Memcached normal.
Para implantar o Mcrouter, execute os comandos a seguir no Cloud Shell.
Exclua a versão do gráfico do Helm
mycache
instalada anteriormente:helm delete mycache
Instale uma nova versão do gráfico do Mcrouter Helm para implantar novos pods do Memcached e do Mcrouter:
helm repo add stable https://charts.helm.sh/stable helm install mycache stable/mcrouter --set memcached.replicaCount=3
Os pods de proxy agora estão prontos para aceitar solicitações de aplicativos de cliente.
Teste essa configuração se conectando a um dos pods de proxy. Use o comando
telnet
na porta5000
, que é a porta padrão do Mcrouter.MCROUTER_POD_IP=$(kubectl get pods -l app=mycache-mcrouter -o jsonpath="{.items[0].status.podIP}") kubectl run -it --rm busybox --image=busybox:1.33 --restart=Never telnet $MCROUTER_POD_IP 5000
No prompt
telnet
, execute estes comandos:set anotherkey 0 0 15 Mcrouter is fun get anotherkey quit
Os comandos definem e reproduzem o valor da chave.
Você já implantou um proxy que permite o agrupamento de conexões.
Como reduzir a latência
Para aumentar a resiliência, é comum usar um cluster com vários nós. Este tutorial usa um cluster com três nós. No entanto, usar vários nós também oferece o risco de latência aumentada causada pelo tráfego de rede mais pesado entre nós.
Como colocar pods de proxy
Você pode reduzir esse risco conectando pods de aplicativo do cliente apenas a um pod de proxy do Memcached que esteja no mesmo nó. O diagrama a seguir ilustra essa configuração.
Realize essa configuração da seguinte maneira:
- Verifique se cada nó contém um pod de proxy em execução. Uma abordagem comum é implantar os pods de proxy com um controlador DaemonSet. À medida que nós são adicionados ao cluster, novos pods de proxy são adicionados automaticamente a eles. À medida que nós são removidos do cluster, o lixo desses pods é coletado. Neste tutorial, o gráfico do Mcrouter Helm que você implantou anteriormente usa um controlador DaemonSet por padrão. Por isso, esta etapa já está completa.
- Defina um valor
hostPort
nos parâmetros do Kubernetes do contêiner do proxy para que o nó escute essa porta e redirecione o tráfego para o proxy. Neste tutorial, o gráfico do Mcrouter Helm usa esse parâmetro por padrão para a porta5000
. Assim, esta etapa também já está completa. Exponha o nome do nó como uma variável de ambiente dentro dos pods do aplicativo usando a entrada
spec.env
e selecionando o valorspec.nodeName
fieldRef
. Saiba mais sobre esse método na documentação de Kubernetes.Implante alguns pods de aplicativos de amostra:
cat <<EOF | kubectl create -f - apiVersion: apps/v1 kind: Deployment metadata: name: sample-application spec: selector: matchLabels: app: sample-application replicas: 9 template: metadata: labels: app: sample-application spec: containers: - name: busybox image: busybox:1.33 command: [ "sh", "-c"] args: - while true; do sleep 10; done; env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName EOF
Verifique se o nome do nó está exposto, observando dentro de um dos pods de aplicativos de amostra:
POD=$(kubectl get pods -l app=sample-application -o jsonpath="{.items[0].metadata.name}") kubectl exec -it $POD -- sh -c 'echo $NODE_NAME'
Este comando produz o nome do nó na seguinte forma:
gke-demo-cluster-default-pool-XXXXXXXX-XXXX
Como conectar os pods
Os pods de aplicativos de amostra agora estão prontos para se conectar ao pod do Mcrouter executado nos respectivos nós mútuos na porta 5000
, que é a porta padrão do Mcrouter.
Inicie uma conexão para um dos pods abrindo uma sessão
telnet
:POD=$(kubectl get pods -l app=sample-application -o jsonpath="{.items[0].metadata.name}") kubectl exec -it $POD -- sh -c 'telnet $NODE_NAME 5000'
No prompt
telnet
, execute estes comandos:get anotherkey quit
Resultado:
Mcrouter is fun
Por fim, como ilustração, o código Python a seguir é um exemplo de um programa que realiza essa conexão recuperando a variável NODE_NAME
do ambiente e usando a biblioteca pymemcache
.
import os
from pymemcache.client.base import Client
NODE_NAME = os.environ['NODE_NAME']
client = Client((NODE_NAME, 5000))
client.set('some_key', 'some_value')
result = client.get('some_key')
Limpar
Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.
Execute o comando a seguir para excluir o cluster do GKE:
gcloud container clusters delete demo-cluster --zone us-central1-f
Se quiser, exclua o binário do Helm:
cd ~ rm -rf helm-v3.7.1 rm helm-v3.7.1-linux-amd64.tar.gz
A seguir
- Explore muitos outros recursos que o Mcrouter oferece além do agrupamento de conexões simples, como réplicas de failover, streams de exclusão confiáveis, aquecimento de cache a frio, transmissão multicluster.
- Explore os arquivos de origem do gráfico do Memcached e do gráfico do Mcrouter para ver mais detalhes sobre as respectivas configurações do Kubernetes.
- Leia mais sobre técnicas efetivas de uso do Memcached no App Engine. Algumas delas se aplicam a outras plataformas, como o GKE.