Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este guia demonstra como validar a resiliência de um cluster Valkey implantado no AKS (Serviço de Kubernetes do Azure) usando a estrutura de teste de carga do Locust. Ele percorre a criação de um cliente de teste, implantando-o no AKS, simulando falhas e analisando o comportamento do cluster.
Observação
Este artigo contém referências ao termo mestre (primário), que é um termo que a Microsoft não usa mais. Quando o termo for removido do software Valkey, o removeremos deste artigo.
Criar um aplicativo cliente de exemplo para Valkey
As etapas a seguir mostram como criar um aplicativo cliente de exemplo para o Valkey.
O aplicativo cliente de exemplo usa a estrutura de teste de carga locust para simular uma carga de trabalho no cluster Valkey que você configurou e implantou. O código Python implementa uma classe Locust User que se conecta ao cluster Valkey e executa uma operação de definição e obtenção . Você pode expandir essa classe para implementar operações mais complexas.
Observação
Recomendamos que você use o fluxo de autenticação mais seguro disponível. O fluxo de autenticação descrito neste procedimento requer um alto grau de confiança no aplicativo e traz riscos que não estão presentes em outros fluxos. Você só deve usar esse fluxo quando outros fluxos mais seguros, como identidades gerenciadas, não forem viáveis.
Crie o Dockerfile e
requirements.txtcoloque-os em um novo diretório usando os seguintes comandos:mkdir valkey-client cd valkey-client cat > Dockerfile <<EOF FROM python:3.10-slim-bullseye COPY requirements.txt . COPY locustfile.py . RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt EOF cat > requirements.txt <<EOF valkey locust EOFCrie o
locustfile.pyarquivo que contém o código do aplicativo cliente Valkey:cat > locustfile.py <<EOF import time from locust import between, task, User, events,tag, constant_throughput from valkey import ValkeyCluster from random import randint class ValkeyLocust(User): wait_time = constant_throughput(50) host = "valkey-cluster.valkey.svc.cluster.local" def __init__(self, *args, **kwargs): super(ValkeyLocust, self).__init__(*args, **kwargs) self.client = ValkeyClient(host=self.host) def on_stop(self): self.client.close() @task @tag("set") def set_value(self): self.client.set_value("set_value") @task @tag("get") def get_value(self): self.client.get_value("get_value") class ValkeyClient(object): def __init__(self, host, *args, **kwargs): super().__init__(*args, **kwargs) with open("/etc/valkey-password/valkey-password-file.conf", "r") as f: self.password = f.readlines()[0].split(" ")[1].strip() self.host = host self.vc = ValkeyCluster(host=self.host, port=6379, password=self.password, username="default", cluster_error_retry_attempts=0, socket_timeout=2, keepalive=1 ) def set_value(self, key, command='SET'): start_time = time.perf_counter() try: result = self.vc.set(randint(0, 1000), randint(0, 1000)) if not result: result = '' length = len(str(result)) total_time = (time.perf_counter()- start_time) * 1000 events.request.fire( request_type=command, name=key, response_time=total_time, response_length=length, ) except Exception as e: total_time = (time.perf_counter()- start_time) * 1000 events.request.fire( request_type=command, name=key, response_time=total_time, response_length=0, exception=e ) result = '' return result def get_value(self, key, command='GET'): start_time = time.perf_counter() try: result = self.vc.get(randint(0, 1000)) if not result: result = '' length = len(str(result)) total_time = (time.perf_counter()- start_time) * 1000 events.request.fire( request_type=command, name=key, response_time=total_time, response_length=length, ) except Exception as e: total_time = (time.perf_counter()- start_time) * 1000 events.request.fire( request_type=command, name=key, response_time=total_time, response_length=0, exception=e ) result = '' return result EOF
Criar e enviar por push a imagem do Docker para o ACR
Crie a imagem do Docker e carregue-a no ACR (Registro de Contêiner do Azure) usando o
az acr buildcomando.az acr build --image valkey-client --registry ${MY_ACR_REGISTRY} .Verifique se a imagem foi enviada por push com êxito usando o
az acr repository listcomando.az acr repository list --name ${MY_ACR_REGISTRY} --output tableA saída deve mostrar a
valkey-clientimagem, como no exemplo a seguir:Result ---------------- valkey-client
Implantar o pod de cliente de exemplo no AKS
Crie um
Podque use a imagem do cliente Valkey criada na etapa anterior usando o comandokubectl apply. A especificação do pod contém o volume CSI do Repositório Secreto com a senha Valkey que o cliente usa para se conectar ao cluster Valkey.kubectl apply -f - <<EOF --- kind: Pod apiVersion: v1 metadata: name: valkey-client namespace: valkey spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: agentpool operator: In values: - nodepool1 containers: - name: valkey-client image: ${MY_ACR_REGISTRY}.azurecr.io/valkey-client command: ["locust", "--processes", "4"] volumeMounts: - name: valkey-password mountPath: "/etc/valkey-password" volumes: - name: valkey-password csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "valkey-password" EOFEncaminhe a porta 8089 para acessar a interface da Web do Locust em seu computador local usando o comando
kubectl port-forward.kubectl port-forward -n valkey valkey-client 8089:8089Acesse a interface
http://localhost:8089da Web do Locust e inicie o teste. Você pode ajustar o número de usuários e a taxa de geração para simular uma carga de trabalho no cluster Valkey. O grafo a seguir usa 100 usuários e uma taxa de geração de 10:
Simular falha e observar o comportamento do cluster Valkey
Simule uma interrupção excluindo o
StatefulSete usando o comandokubectl deletecom o sinalizador--cascade=orphan. A meta é poder excluir um único pod sem que oStatefulSetrecrie imediatamente o pod excluído.kubectl delete statefulset valkey-masters --cascade=orphanExclua o
valkey-masters-0pod usando okubectl delete podcomando.kubectl delete pod valkey-masters-0Verifique a lista de pods usando o
kubectl get podscomando.kubectl get podsA saída deve indicar que o pod
valkey-masters-0foi excluído. Os outros pods devem estar no estadoRunning, conforme mostrado no exemplo a seguir:NAME READY STATUS RESTARTS AGE valkey-client 1/1 Running 0 6m34s valkey-masters-1 1/1 Running 0 16m valkey-masters-2 1/1 Running 0 16m valkey-replicas-0 1/1 Running 0 16m valkey-replicas-1 1/1 Running 0 16m valkey-replicas-2 1/1 Running 0 16mObtenha os logs do
valkey-replicas-0pod usando okubectl logs valkey-replicas-0comando.kubectl logs valkey-replicas-0Na saída, observamos que o evento completo dura cerca de 18 segundos:
1:S 05 Nov 2024 12:18:53.961 * Connection with primary lost. 1:S 05 Nov 2024 12:18:53.961 * Caching the disconnected primary state. 1:S 05 Nov 2024 12:18:53.961 * Reconnecting to PRIMARY 10.224.0.250:6379 1:S 05 Nov 2024 12:18:53.961 * PRIMARY <-> REPLICA sync started 1:S 05 Nov 2024 12:18:53.964 # Error condition on socket for SYNC: Connection refused 1:S 05 Nov 2024 12:18:54.910 * Connecting to PRIMARY 10.224.0.250:6379 1:S 05 Nov 2024 12:18:54.910 * PRIMARY <-> REPLICA sync started 1:S 05 Nov 2024 12:18:54.912 # Error condition on socket for SYNC: Connection refused 1:S 05 Nov 2024 12:18:55.920 * Connecting to PRIMARY 10.224.0.250:6379 [..CUT..] 1:S 05 Nov 2024 12:19:10.056 * Connecting to PRIMARY 10.224.0.250:6379 1:S 05 Nov 2024 12:19:10.057 * PRIMARY <-> REPLICA sync started 1:S 05 Nov 2024 12:19:10.058 # Error condition on socket for SYNC: Connection refused 1:S 05 Nov 2024 12:19:10.709 * Node c44d4b682b6fb9b37033d3e30574873545266d67 () reported node 9e7c43890613cc3ad4006a9cdc0b5e5fc5b6d44e () as not reachable. 1:S 05 Nov 2024 12:19:10.864 * NODE 9e7c43890613cc3ad4006a9cdc0b5e5fc5b6d44e () possibly failing. 1:S 05 Nov 2024 12:19:11.066 * 10000 changes in 60 seconds. Saving... 1:S 05 Nov 2024 12:19:11.068 * Background saving started by pid 29 1:S 05 Nov 2024 12:19:11.068 * Connecting to PRIMARY 10.224.0.250:6379 1:S 05 Nov 2024 12:19:11.068 * PRIMARY <-> REPLICA sync started 1:S 05 Nov 2024 12:19:11.069 # Error condition on socket for SYNC: Connection refused 29:C 05 Nov 2024 12:19:11.090 * DB saved on disk 29:C 05 Nov 2024 12:19:11.090 * Fork CoW for RDB: current 0 MB, peak 0 MB, average 0 MB 1:S 05 Nov 2024 12:19:11.169 * Background saving terminated with success 1:S 05 Nov 2024 12:19:11.884 * FAIL message received from ba36d5167ee6016c01296a4a0127716f8edf8290 () about 9e7c43890613cc3ad4006a9cdc0b5e5fc5b6d44e () 1:S 05 Nov 2024 12:19:11.884 # Cluster state changed: fail 1:S 05 Nov 2024 12:19:11.974 * Start of election delayed for 510 milliseconds (rank #0, offset 7225807). 1:S 05 Nov 2024 12:19:11.976 * Node d43f370a417d299b78bd1983792469fe5c39dcdf () reported node 9e7c43890613cc3ad4006a9cdc0b5e5fc5b6d44e () as not reachable. 1:S 05 Nov 2024 12:19:12.076 * Connecting to PRIMARY 10.224.0.250:6379 1:S 05 Nov 2024 12:19:12.076 * PRIMARY <-> REPLICA sync started 1:S 05 Nov 2024 12:19:12.076 * Currently unable to failover: Waiting the delay before I can start a new failover. 1:S 05 Nov 2024 12:19:12.078 # Error condition on socket for SYNC: Connection refused 1:S 05 Nov 2024 12:19:12.581 * Starting a failover election for epoch 15. 1:S 05 Nov 2024 12:19:12.616 * Currently unable to failover: Waiting for votes, but majority still not reached. 1:S 05 Nov 2024 12:19:12.616 * Needed quorum: 2. Number of votes received so far: 1 1:S 05 Nov 2024 12:19:12.616 * Failover election won: I'm the new primary. 1:S 05 Nov 2024 12:19:12.616 * configEpoch set to 15 after successful failover 1:M 05 Nov 2024 12:19:12.616 * Discarding previously cached primary state. 1:M 05 Nov 2024 12:19:12.616 * Setting secondary replication ID to c0b5b2df8a43b19a4d43d8f8b272a07139e0ca34, valid up to offset: 7225808. New replication ID is 029fcfbae0e3e4a1dccd73066043deba6140c699 1:M 05 Nov 2024 12:19:12.616 * Cluster state changed: okDurante essa janela de tempo de 18 segundos, observamos que as gravações no fragmento que pertence ao pod excluído estão falhando, e o cluster do Valkey está selecionando um novo primário. A latência da solicitação aumenta para 60 ms durante essa janela de tempo.
Depois que a nova primária é eleita, o cluster Valkey continua a atender solicitações com uma latência de cerca de 2 ms.
Próxima etapa
Colaboradores
A Microsoft atualiza este artigo. Os seguintes colaboradores o escreveram originalmente:
- Nelly Kiboi | Engenheiro de Serviços
- Saverio Proto | Engenheiro de Experiência do Cliente Principal