In questo tutorial imparerai a eseguire il deployment di un cluster Memcached server su Google Kubernetes Engine (GKE) utilizzando Kubernetes, Helm e Mcrouter. Memcached è un popolare sistema di memorizzazione nella cache multiuso open source. Di solito funge da archivio temporaneo per i dati utilizzati di frequente al fine di velocizzare il applicazioni e alleggerisci i carichi del database.
Caratteristiche di Memcached
Memcached ha due obiettivi di progettazione principali:
- Semplicità: Memcached funziona come una grande tabella hash e offre un'API semplice per memorizzare e recuperare oggetti di forma arbitraria per chiave.
- Velocità: Memcached conserva i dati della cache esclusivamente in una memoria ad accesso casuale (RAM), rendendo l'accesso ai dati estremamente rapido.
Memcached è un sistema distribuito che consente di scalare la capacità della tabella hash in modo orizzontale in un pool di server. Ogni server Memcached completamente isolata dagli altri server nel pool. Pertanto, il routing e il bilanciamento del carico tra i server devono essere eseguiti a livello di client. I client Memcached applicano un schema di hashing coerente per selezionare in modo appropriato i server di destinazione. Questo schema garantisce le seguenti condizioni:
- Viene sempre selezionato lo stesso server per la stessa chiave.
- L'utilizzo della memoria è bilanciato uniformemente tra i server.
- Un numero minimo di chiavi viene spostato quando il pool di server viene ridotto o ampliato.
Il seguente diagramma illustra a grandi linee l'interazione tra un client Memcached e un pool distribuito di server Memcached.
Obiettivi
- Scopri alcune caratteristiche dell'architettura distribuita di Memcached.
- Eseguire il deployment di un servizio Memcached in GKE utilizzando Kubernetes Helm.
- Esegui il deployment di Mcrouter, un proxy Memcached open source, per migliorare le prestazioni del sistema.
Costi
In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:
- Compute Engine
Per generare una stima dei costi basata sull'utilizzo previsto,
utilizza il Calcolatore prezzi.
Prima di iniziare
- 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.
- Avvia un'istanza di Cloud Shell.
Apri Cloud Shell
Deployment di un servizio Memcached
Un modo semplice per eseguire il deployment di un servizio Memcached in GKE è usa un Helm grafico. Per procedere con il deployment, segui questi passaggi in Cloud Shell:
Crea un nuovo cluster GKE di tre nodi:
gcloud container clusters create demo-cluster --num-nodes 3 --zone us-central1-f
Scarica l'archivio binario
helm
:HELM_VERSION=3.7.1 cd ~ wget https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz
Decomprimi il file di archivio sul tuo sistema locale:
mkdir helm-v${HELM_VERSION} tar zxfv helm-v${HELM_VERSION}-linux-amd64.tar.gz -C helm-v${HELM_VERSION}
Aggiungi la directory del programma binario
helm
alla variabile di ambientePATH
:export PATH="$(echo ~)/helm-v${HELM_VERSION}/linux-amd64:$PATH"
Questo comando rende il programma binario
helm
rilevabile da qualsiasi directory durante dell'attuale sessione di Cloud Shell. Per rendere permanente questa configurazione in più sessioni, aggiungi il comando a Cloud Shell il file~/.bashrc
dell'utente.Installa una nuova release del grafico Helm Memcached con l'architettura ad alta disponibilità:
helm repo add bitnami https://charts.bitnami.com/bitnami helm install mycache bitnami/memcached --set architecture="high-availability" --set autoscaling.enabled="true"
Il grafico Helm di Memcached utilizza un controller StatefulSet. Uno dei vantaggi dell'utilizzo di un controller StatefulSet è che i nomi dei pod sono ordinati e prevedibili. In questo caso, i nomi vengono
mycache-memcached-{0..2}
. Questo ordinamento semplifica la gestione di Memcached per fare riferimento ai server.Per vedere i pod in esecuzione, esegui questo comando:
kubectl get pods
L'output della console Google Cloud è simile al seguente:
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
Rilevamento degli endpoint di servizio Memcached
Il grafico Helm Memcached utilizza un servizio headless. Un servizio headless espone gli indirizzi IP di tutti i suoi pod in modo che possano essere rilevati singolarmente.
Verifica che il servizio di cui è stato eseguito il deployment sia headless:
kubectl get service mycache-memcached -o jsonpath="{.spec.clusterIP}"
L'output
None
conferma che il servizio non haclusterIP
e che è quindi headless.Il servizio crea un record DNS per un nome host nel formato:
[SERVICE_NAME].[NAMESPACE].svc.cluster.local
In questo tutorial, il nome del servizio è
mycache-memcached
. Poiché non è stato definito esplicitamente uno spazio dei nomi, viene utilizzato lo spazio dei nomi predefinito e quindi l'intero nome host èmycache-memcached.default.svc.cluster.local
. Questo nome host risolve in un insieme di indirizzi IP e domini per tutti e tre i pod esposti dal servizio. Se in futuro verranno aggiunti al pool alcuni pod o quelli vecchi verranno rimossi,kube-dns
aggiorna automaticamente il record DNS.È responsabilità del client rilevare gli endpoint del servizio Memcached, come descritto nei passaggi successivi.
Recupera gli indirizzi IP degli endpoint:
kubectl get endpoints mycache-memcached
L'output è simile al seguente:
NAME ENDPOINTS AGE mycache-memcached 10.36.0.32:11211,10.36.0.33:11211,10.36.1.25:11211 3m
Nota che ogni pod Memcached ha, rispettivamente, un indirizzo IP separato
10.36.0.32
,10.36.0.33
e10.36.1.25
. Questi indirizzi IP potrebbero essere diversi per le tue istanze server. Ogni pod rimane in ascolto della porta11211
, che è la porta predefinita di Memcached.In alternativa al passaggio 2, esegui un'ispezione DNS utilizzando un un linguaggio di programmazione come Python:
Avvia una console interattiva Python all'interno del cluster:
kubectl run -it --rm python --image=python:3.10-alpine --restart=Never python
Nella console Python, esegui questi comandi:
import socket print(socket.gethostbyname_ex('mycache-memcached.default.svc.cluster.local')) exit()
L'output è simile al seguente:
('mycache-memcached.default.svc.cluster.local', ['mycache-memcached.default.svc.cluster.local'], ['10.36.0.32', '10.36.0.33', '10.36.1.25'])
Testa il deployment aprendo una sessione
telnet
con una delle Server Memcached sulla porta11211
:kubectl run -it --rm busybox --image=busybox:1.33 --restart=Never telnet mycache-memcached-0.mycache-memcached.default.svc.cluster.local 11211
Al prompt
telnet
, esegui questi comandi utilizzando Protocollo ASCII Memcached:set mykey 0 0 5 hello get mykey quit
L'output risultante è mostrato qui in grassetto:
set mykey 0 0 5 hello STORED get mykey VALUE mykey 0 5 hello END quit
Implementazione della logica di Service Discovery
Ora è tutto pronto per implementare la logica di rilevamento dei servizi di base mostrata nel diagramma seguente.
A livello generale, la logica di rilevamento dei servizi è costituita dai seguenti passaggi:
- L'applicazione esegue una query su
kube-dns
per trovare il record DNS dimycache-memcached.default.svc.cluster.local
. - L'applicazione recupera gli indirizzi IP associati a quel record.
- L'applicazione crea un'istanza per un nuovo client Memcached e gli fornisce di indirizzi IP recuperati.
- Il bilanciatore del carico integrato del client Memcached si connette a Memcached disponibili agli indirizzi IP indicati.
Ora implementi questa logica di Service Discovery utilizzando Python:
Esegui il deployment di un nuovo pod abilitato per Python nel tuo cluster e avvia una shell sessione all'interno del pod:
kubectl run -it --rm python --image=python:3.10-alpine --restart=Never sh
Installa il Raccolta
pymemcache
:pip install pymemcache
Avvia una console interattiva Python eseguendo il comando
python
.Nella console Python, esegui questi comandi:
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')
L'output è il seguente:
b'hello'
Il prefisso
b
indica bytes letterale, che è il formato in cui Memcached archivia i dati.Esci dalla console Python:
exit()
Per uscire dalla sessione shell del pod, premi
Control
+D
.
Attivazione del pool di connessioni
Man mano che le tue esigenze di memorizzazione nella cache aumentano e il pool si espande fino a decine, centinaia o persino migliaia di server Memcached, potresti riscontrare alcuni limiti. In particolare, il numero elevato di connessioni aperte dei client Memcached potrebbe comportare un carico elevato sui server, come mostrato nel seguente diagramma.
Per ridurre il numero di connessioni aperte, devi introdurre un proxy per abilitare il pooling delle connessioni, come nel seguente diagramma.
Mcrouter (pronunciato "mick router"), un potente proxy Memcached open source, consente il pooling delle connessioni. L'integrazione di Mcrouter è semplice, perché utilizza il protocollo ASCII Memcached standard. Per un client Memcached, Mcrouter si comporta come un normale server Memcached. Per un server Memcached, Mcrouter si comporta come un Memcached.
Per eseguire il deployment di Mcrouter, esegui questi comandi in Cloud Shell.
Elimina la release del grafico Helm
mycache
installata in precedenza:helm delete mycache
Esegui il deployment di nuovi pod Memcached e Mcrouter installando una nuova release del grafico Helm Mcrouter:
helm repo add stable https://charts.helm.sh/stable helm install mycache stable/mcrouter --set memcached.replicaCount=3
I pod proxy sono ora pronti per accettare le richieste dalle applicazioni client.
Testa questa configurazione connettendoti a uno dei pod del proxy. Utilizza il comando
telnet
sulla porta5000
, che è la porta predefinita di 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
Nel prompt
telnet
, esegui questi comandi:set anotherkey 0 0 15 Mcrouter is fun get anotherkey quit
I comandi impostano ed emettono il valore della chiave.
Ora hai implementato un proxy che abilita il pooling delle connessioni.
Riduzione della latenza
Per aumentare la resilienza, è prassi comune utilizzare un cluster con più nodi. Questo tutorial utilizza un cluster con tre nodi. Tuttavia, l'uso di più nodi comportano anche il rischio di aumento della latenza causato da una rete più pesante il traffico tra nodi.
Colocation dei pod proxy
Puoi ridurre questo rischio collegando i pod delle applicazioni client solo a un pod proxy Memcached nello stesso nodo. Il seguente diagramma che illustra questa configurazione.
Esegui questa configurazione come segue:
- Assicurati che ogni nodo contenga un pod proxy in esecuzione. Un approccio comune è di eseguire il deployment dei pod del proxy Controller DaemonSet. Man mano che i nodi vengono aggiunti al cluster, vengono aggiunti automaticamente nuovi pod proxy. Quando i nodi vengono rimossi dal cluster, questi pod vengono garbage-collect. In questo tutorial, il grafico Mcrouter Helm di cui è stato eseguito il deployment in precedenza utilizza un controller DaemonSet per impostazione predefinita. Quindi, questo passaggio è già stato completato.
- Imposta un valore
hostPort
nei parametri Kubernetes del container proxy su fare in modo che il nodo ascolti quella porta e reindirizzi il traffico al proxy. In questo tutorial, il grafico Mcrouter Helm utilizza questo parametro per impostazione predefinita per la porta5000
. Quindi anche questo passaggio è già stato completato. Esponi il nome del nodo come variabile di ambiente all'interno dei pod dell'applicazione utilizzando la voce
spec.env
e selezionando il valorespec.nodeName
fieldRef
. Scopri di più su questo metodo nella documentazione di Kubernetes.Esegui il deployment di alcuni pod di applicazioni di esempio:
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
Verifica che il nome del nodo sia esposto, cercando all'interno di uno dei di esempio di pod di applicazioni:
POD=$(kubectl get pods -l app=sample-application -o jsonpath="{.items[0].metadata.name}") kubectl exec -it $POD -- sh -c 'echo $NODE_NAME'
Questo comando restituisce il nome del nodo nel seguente formato:
gke-demo-cluster-default-pool-XXXXXXXX-XXXX
Collegamento dei pod
I pod dell'applicazione di esempio sono ora pronti per connettersi al pod Mcrouter che
viene eseguito sui rispettivi nodi reciproci sulla porta 5000
, che è quella di Mcrouter
predefinita.
Avvia una connessione per uno dei pod aprendo una sessione
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'
Nel prompt
telnet
, esegui questi comandi:get anotherkey quit
Output risultante:
Mcrouter is fun
Infine, come illustrazione, il seguente codice Python è un programma di esempio
che esegue questa connessione recuperando la variabile NODE_NAME
da
l'ambiente e utilizzando la libreria 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')
Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.
Esegui questo comando per eliminare il cluster GKE:
gcloud container clusters delete demo-cluster --zone us-central1-f
Se vuoi, elimina il file binario Helm:
cd ~ rm -rf helm-v3.7.1 rm helm-v3.7.1-linux-amd64.tar.gz
Passaggi successivi
- Esplora i tanti altri che Mcrouter offre al di là del semplice pooling di connessioni, come il failover repliche, eliminazione di flussi di dati affidabili, riscaldamento della cache fredda, cluster multipli la trasmissione.
- Esplora i file di origine del grafico Memcached e del grafico Mcrouter per ulteriori dettagli sulle rispettive configurazioni di Kubernetes.
- Informazioni tecniche efficaci per l'uso di Memcached su App Engine. Alcune si applicano ad altre piattaforme, come GKE.