In questo tutorial imparerai a eseguire il deployment di un cluster di server distribuiti Memcached su Google Kubernetes Engine (GKE) utilizzando Kubernetes, Helm e Mcrouter. Memcached è un popolare sistema di memorizzazione nella cache open source e multifunzionale. Di solito funge da archivio temporaneo per i dati utilizzati di frequente, al fine di accelerare le applicazioni web e alleggerire i caricamenti dei database.
Caratteristiche di Memcached
Memcached ha due obiettivi di progettazione principali:
- Semplicità: Memcached funziona come una grande tabella con hash e offre un'API semplice per archiviare e recuperare oggetti di forma arbitraria in base alla chiave.
- Velocità: Memcached conserva i dati della cache esclusivamente nella memoria RAM ad accesso casuale, rendendo l'accesso ai dati estremamente veloce.
Memcached è un sistema distribuito che consente alla capacità della sua tabella hash di scalare orizzontalmente su un pool di server. Ogni server Memcached opera in completo isolamento dagli altri server del pool. Pertanto, il routing e il bilanciamento del carico tra i server devono essere eseguiti a livello di client. I client Memcached applicano uno schema di hashing coerente per selezionare in modo appropriato i server di destinazione. Questo schema garantisce le seguenti condizioni:
- Lo stesso server è sempre selezionato per la stessa chiave.
- La memoria utilizzata viene bilanciata uniformemente tra i server.
- Un numero minimo di chiavi viene spostato quando il pool di server viene ridotto o espanso.
Il seguente diagramma illustra a livello generale l'interazione tra un client Memcached e un pool distribuito di server Memcached.
Obiettivi
- Scopri alcune caratteristiche dell'architettura distribuita di Memcached.
- Esegui il deployment di un servizio Memcached su GKE utilizzando Kubernetes e Helm.
- Esegui il deployment di Mcrouter, un proxy Memcached open source, per migliorare le prestazioni del sistema.
Costi
In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:
- Compute Engine
Per generare una stima dei costi in base all'utilizzo previsto,
utilizza il Calcolatore prezzi.
Prima di iniziare
- Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
-
Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.
-
Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.
-
Abilita le API Compute Engine and GKE.
-
Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.
-
Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.
-
Abilita le API Compute Engine and GKE.
- Avviare 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 è utilizzare un grafico Helm. 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 di
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 la sessione di Cloud Shell corrente. Per rendere la configurazione persistente in più sessioni, aggiungi il comando al file~/.bashrc
dell'utente di Cloud Shell.Installa una nuova release di 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 Memcached utilizza un controller StatefulSet. Un vantaggio dell'uso di un controller StatefulSet è che i nomi dei pod sono ordinati e prevedibili. In questo caso, i nomi sono
mycache-memcached-{0..2}
. Questo ordinamento consente ai client Memcached di fare riferimento ai server più facilmente.Per visualizzare i pod in esecuzione, esegui questo comando:
kubectl get pods
L'output della console Google Cloud ha il seguente aspetto:
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
Scoprire gli endpoint del servizio Memcached
Il grafico Helm Memcached utilizza un servizio headless. Un servizio headless espone gli indirizzi IP per 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é uno spazio dei nomi non è stato definito esplicitamente, viene utilizzato lo spazio dei nomi predefinito, quindi l'intero nome host èmycache-memcached.default.svc.cluster.local
. Questo nome host si risolve in un insieme di indirizzi IP e domini per tutti e tre i pod esposti dal servizio. Se in futuro alcuni pod verranno aggiunti al pool o se quelli vecchi verranno rimossi,kube-dns
aggiornerà automaticamente il record DNS.È responsabilità del client individuare gli endpoint di 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
Tieni presente che ogni pod Memcached ha un indirizzo IP separato, rispettivamente
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 sulla porta11211
, che è la porta predefinita di Memcached.Per un'alternativa al passaggio 2, esegui un'ispezione DNS utilizzando 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 uno dei server Memcached in esecuzione 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 il 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 base di Service Discovery mostrata nel diagramma seguente.
A livello generale, la logica di Service Discovery prevede i seguenti passaggi:
- L'applicazione esegue una query su
kube-dns
per il record DNS dimycache-memcached.default.svc.cluster.local
. - L'applicazione recupera gli indirizzi IP associati al record.
- L'applicazione crea un'istanza per un nuovo client Memcached e gli fornisce gli indirizzi IP recuperati.
- Il bilanciatore del carico integrato del client Memcached si connette ai server Memcached agli indirizzi IP specificati.
Ora implementi questa logica di Service Discovery utilizzando Python:
Esegui il deployment di un nuovo pod abilitato per Python nel cluster e avvia una sessione shell all'interno del pod:
kubectl run -it --rm python --image=python:3.10-alpine --restart=Never sh
Installa la libreria
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 un valore letterale di byte, ovvero il formato in cui Memcached archivia i dati.Esci dalla console Python:
exit()
Per uscire dalla sessione shell del pod, premi
Control
+D
.
Abilitazione del pooling delle connessioni
Con l'aumento delle esigenze di memorizzazione nella cache e lo scale up del pool fino a decine, centinaia o migliaia di server Memcached, potresti incorrere in alcune limitazioni. In particolare, l'elevato numero di connessioni aperte dai client Memcached potrebbe sovraccaricare i server, come illustrato nel seguente diagramma.
Per ridurre il numero di connessioni aperte, devi introdurre un proxy per abilitare il pool di connessioni, come nel diagramma seguente.
Mcrouter (pronunciato "mick router"), un potente proxy Memcached open source, consente il pooling delle connessioni. L'integrazione di Mcrouter è semplice, poiché 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 normale client 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 Mcrouter Helm:
helm repo add stable https://charts.helm.sh/stable helm install mycache stable/mcrouter --set memcached.replicaCount=3
I pod proxy sono ora pronti ad accettare richieste dalle applicazioni client.
Verifica 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 eco il valore della chiave.
Hai eseguito il deployment di un proxy che consente il pooling delle connessioni.
Ridurre la latenza
Per aumentare la resilienza, è pratica comune utilizzare un cluster con più nodi. Questo tutorial utilizza un cluster con tre nodi. Tuttavia, l'utilizzo di più nodi comporta anche il rischio di un aumento della latenza causato da un traffico di rete più intenso tra i nodi.
Coallocazione dei pod proxy
Puoi ridurre questo rischio connettendo i pod delle applicazioni client solo a un pod proxy Memcached che si trova sullo stesso nodo. Il seguente diagramma illustra questa configurazione.
Esegui questa configurazione nel seguente modo:
- Assicurati che ogni nodo contenga un pod proxy in esecuzione. Un approccio comune consiste nell'eseguire il deployment dei pod proxy con un controller DaemonSet. Man mano che si aggiungono nodi al cluster, vengono aggiunti automaticamente nuovi pod proxy. Man mano che i nodi vengono rimossi dal cluster, i pod vengono raccolti inutili. In questo tutorial, il grafico Helm Mcrouter di cui hai eseguito il deployment in precedenza utilizza un controller DaemonSet per impostazione predefinita. Pertanto, questo passaggio è già stato completato.
- Imposta un valore
hostPort
nei parametri Kubernetes del container proxy per fare in modo che il nodo ascolti la porta e reindirizzi il traffico al proxy. In questo tutorial, il grafico Helm Mcrouter utilizza questo parametro per impostazione predefinita per la porta5000
. 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 valorefieldRef
spec.nodeName
. Scopri di più su questo metodo nella documentazione di Kubernetes.Esegui il deployment di alcuni pod dell'applicazione 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 osservando all'interno di uno dei pod dell'applicazione di esempio:
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 formato seguente:
gke-demo-cluster-default-pool-XXXXXXXX-XXXX
Connessione dei pod
I pod dell'applicazione di esempio sono ora pronti per la connessione al pod Mcrouter che viene eseguito sui rispettivi nodi reciproci alla porta 5000
, che è la porta predefinita di Mcrouter.
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 finale:
Mcrouter is fun
Infine, a titolo di illustrazione, il seguente codice Python è un programma di esempio che esegue questa connessione recuperando la variabile NODE_NAME
dall'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 programma binario Helm:
cd ~ rm -rf helm-v3.7.1 rm helm-v3.7.1-linux-amd64.tar.gz
Passaggi successivi
- Esplora le tante altre funzionalità offerte da Mcrouter oltre al semplice pool di connessioni, come repliche di failover, flussi di eliminazione affidabili, warmup della cache fredda e trasmissione multi-cluster.
- Esplora i file di origine del grafico Memcached e del grafico McMcrouter per ulteriori dettagli sulle rispettive configurazioni Kubernetes.
- Scopri di più sulle tecniche efficaci per utilizzare Memcached su App Engine. Alcuni si applicano ad altre piattaforme, come GKE.