Práticas recomendadas para otimização e eficiência de desempenho no Amazon MQ para RabbitMQ - Amazon MQ

Práticas recomendadas para otimização e eficiência de desempenho no Amazon MQ para RabbitMQ

Você pode otimizar o desempenho do agente do Amazon MQ para RabbitMQ maximizando o throughput, minimizando a latência e garantindo a utilização eficiente dos recursos. Complete as práticas recomendadas a seguir para otimizar o desempenho da aplicação.

Etapa 1: Manter o tamanho das mensagens abaixo de 1 MB

Recomendamos manter as mensagens com menos de 1 megabyte (MB) para desempenho e confiabilidade ideais.

O RabbitMQ 3.13 oferece suporte a tamanhos de mensagem de até 128 MB por padrão, mas mensagens grandes podem acionar alarmes de memória imprevisíveis que bloqueiam a publicação e potencialmente criam pressão de alta memória quando se replica mensagens entre os nós. Mensagens superdimensionadas também podem afetar os processos de reinicialização e recuperação do agente, o que aumenta os riscos à continuidade do serviço e pode causar degradação do desempenho.

Armazenar e recuperar cargas úteis grandes usando o padrão de verificação de reivindicações

Para gerenciar mensagens grandes, você pode implementar o padrão de verificação de reinvindicação armazenando a carga útil da mensagem no armazenamento externo e enviando somente o identificador de referência da carga útil por meio do RabbitMQ. O consumidor usa o identificador de referência da carga útil para recuperar e processar a mensagem grande.

O diagrama a seguir demonstra como usar o Amazon MQ para RabbitMQ e o Amazon S3 para implementar o padrão de verificação de reivindicações.

Diagram showing data flow between Producer, Consumer, Amazon MQ broker, and AWS S3.

O exemplo a seguir demonstra esse padrão usando-se o Amazon MQ, o AWSSDK para Java 2.x e o Amazon S3:

  1. Primeiro, defina uma classe de mensagem que conterá o identificador de referência do Amazon S3.

    class Message { // Other data fields of the message... public String s3Key; public String s3Bucket; }
  2. Crie um método de publicador que armazene a carga útil no Amazon S3 e envie uma mensagem de referência por meio do RabbitMQ.

    public void publishPayload() { // Store the payload in S3. String payload = PAYLOAD; String prefix = S3_KEY_PREFIX; String s3Key = prefix + "/" + UUID.randomUUID(); s3Client.putObject(PutObjectRequest.builder() .bucket(S3_BUCKET).key(s3Key).build(), RequestBody.fromString(payload)); // Send the reference through RabbitMQ. Message message = new Message(); message.s3Key = s3Key; message.s3Bucket = S3_BUCKET; // Assign values to other fields in your message instance. publishMessage(message); }
  3. Implemente um método de consumidor que recupere a carga útil do Amazon S3, processe a carga útil e exclua o objeto do Amazon S3.

    public void consumeMessage(Message message) { // Retrieve the payload from S3. String payload = s3Client.getObjectAsBytes(GetObjectRequest.builder() .bucket(message.s3Bucket).key(message.s3Key).build()) .asUtf8String(); // Process the complete message. processPayload(message, payload); // Delete the S3 object. s3Client.deleteObject(DeleteObjectRequest.builder() .bucket(message.s3Bucket).key(message.s3Key).build()); }

Etapa 2: Usar basic.consume e consumidores duradouros

Usar basic.consume com um consumidor de longa data é mais eficiente do que pesquisar o uso de mensagens individuais do basic.get. Para obter mais informações, consulte Pesquisa de mensagens individuais.

Etapa 3: Configurar pré-busca

Você pode usar o valor de pré-busca RabbitMQ para otimizar como seus consumidores consomem mensagens. O RabbitMQ implementa o mecanismo de pré-busca do canal fornecido pelo AMQP 0-9-1 aplicando a contagem de pré-busca aos consumidores em oposição aos canais. O valor de pré-busca é usado para especificar quantas mensagens estão sendo enviadas ao consumidor em um determinado momento. Por padrão, o RabbitMQ define um tamanho ilimitado de buffer para aplicações do cliente.

Há muitos fatores a serem considerados ao definir uma contagem de pré-busca para seus consumidores RabbitMQ. Primeiro, considere o ambiente e a configuração dos seus consumidores. Como os consumidores precisam manter todas as mensagens na memória enquanto estão sendo processadas, um alto valor de pré-busca pode ter um impacto negativo na performance de seus consumidores e, em alguns casos, pode resultar em um consumidor potencialmente travando tudo. Da mesma forma, o próprio agente RabbitMQ mantém todas as mensagens que envia armazenadas em cache na memória até receber reconhecimento do consumidor. Um valor de pré-busca alto pode fazer com que o servidor RabbitMQ fique sem memória rapidamente se a confirmação automática não estiver configurada para os consumidores e se os consumidores demorarem um tempo relativamente longo para processar mensagens.

Com as considerações acima em mente, recomendamos sempre definir um valor de pré-busca para evitar situações em que um agente RabbitMQ ou seus consumidores ficam sem memória devido a um grande número de mensagens não processadas ou não confirmadas. Se você precisar otimizar seus agentes para processar grandes volumes de mensagens, você pode testar seus agentes e consumidores usando uma gama de contagens de pré-busca para determinar o valor em que ponto a sobrecarga de rede se torna em grande parte insignificante em comparação com o tempo que um consumidor leva para processar mensagens.

nota
  • Se as aplicações do seu cliente tiverem configurado para confirmar automaticamente a entrega de mensagens aos consumidores, a definição de um valor de pré-busca não terá efeito.

  • Todas as mensagens pré-buscadas são removidas da fila.

O exemplo a seguir demonstra a configuração de um valor de pré-busca de 10 para um único consumidor usando a biblioteca do cliente Java RabbitMQ.

ConnectionFactory factory = new ConnectionFactory(); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.basicQos(10, false); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume("my_queue", false, consumer);
nota

Na biblioteca do cliente Java RabbitMQ, o valor padrão para global está definido como false, de modo que o exemplo acima pode ser escrito simplesmente como channel.basicQos(10).

Etapa 4: Usar o Celery 5.5 ou posterior com filas de quórum

O Python Celery, um sistema distribuído de filas de tarefas, pode gerar muitas mensagens não críticas quando enfrenta uma alta carga de tarefas. Essa atividade adicional do agente pode desencadear Amazon MQ for RabbitMQ: Alarme de alta memória e levar à indisponibilidade do agente. Para reduzir a chance de acionar o alarme de memória, faça o seguinte:

Para todas as versões do Celery

  1. Desative task_create_missing_queues para mitigar a rotatividade da fila.

  2. Em seguida, desative worker_enable_remote_control para interromper a criação dinâmica de filas do celery@...pidbox. Isso reduzirá a rotatividade de filas no agente.

    worker_enable_remote_control = false
  3. Para reduzir ainda mais a atividade de mensagens não críticas, desative o worker-send-task-events do Celery sem incluir -E ou o sinalizador --task-events quando iniciar a aplicação Celery.

  4. Inicie a aplicação Celery usando os seguintes parâmetros:

    celery -A app_name worker --without-heartbeat --without-gossip --without-mingle

Para as versões 5.5 e posteriores do Celery

  1. Atualize para a versão 5.5 do Celery, a versão mínima que oferece suporte a filas de quórum, ou uma versão posterior. Para verificar qual versão do Celery você está usando, use celery --version. Para obter mais informações sobre quóruns, consulte Filas de quórum do RabbitMQ no Amazon MQ.

  2. Depois de atualizar para o Celery 5.5 ou posterior, configure task_default_queue_type como “quórum”.

  3. Em seguida, você também deve ativar a opção Publish Confirms (Publicar confirmações) nas Broker Transport Options (Opções de transporte da corretora):

    broker_transport_options = {"confirm_publish": True}