

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Acciones por lotes de Amazon SQS
<a name="sqs-batch-api-actions"></a>

Amazon SQS permite realizar acciones por lotes para ayudarle a reducir los costos y manipular hasta 10 mensajes con una sola acción. Estas acciones por lotes incluyen:
+ `[SendMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html)`
+ `[DeleteMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessageBatch.html)`
+ `[ChangeMessageVisibilityBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibilityBatch.html)`

Al utilizar acciones por lotes, puede realizar varias operaciones en una sola llamada a la API, lo que ayuda a optimizar el rendimiento y reducir los costos. Puede aprovechar la funcionalidad por lotes mediante la API de consultas o cualquier AWS SDK que admita las acciones por lotes de Amazon SQS.

**Detalles importantes**
+ **Límite de tamaño de los mensajes:** el tamaño total de todos los mensajes enviados en una única llamada `SendMessageBatch` no puede superar los 1 048 576 bytes (1 MiB).
+ **Permisos:** no se pueden establecer permisos para `SendMessageBatch`, `DeleteMessageBatch` ni `ChangeMessageVisibilityBatch` de forma explícita. Sin embargo, al establecer permisos para `SendMessage`, `DeleteMessage` o `ChangeMessageVisibility`, se establecen también permisos para las versiones por lotes correspondientes de esas acciones.
+ **Soporte de consola:** la consola de Amazon SQS no es compatible con las acciones de procesamiento por lotes. Debe usar la API de consultas o un AWS SDK para realizar operaciones por lotes.

## Procesamiento por lotes de las acciones de los mensajes
<a name="batching-message-actions"></a>

Para optimizar aún más los costos y la eficiencia, tenga en cuenta las siguientes prácticas recomendadas para acciones de mensajes de procesamiento por lotes:
+ **Acciones de la API de procesamiento por lotes:** use las [acciones de la API de procesamiento por lotes de Amazon SQS](#sqs-batch-api-actions) para enviar, recibir y eliminar mensajes, y para cambiar el tiempo de espera de visibilidad de varios mensajes con una sola acción. Esto reduce el número de llamadas a la API y los costos asociados.
+ **Almacenamiento en búfer del cliente y sondeos largos:** combine el almacenamiento en búfer del cliente con el procesamiento de solicitudes por lotes mediante un sondeo largo junto con el [cliente asíncrono con almacenamiento en búfer](sqs-client-side-buffering-request-batching.md) incluido en el AWS SDK para Java. Este enfoque ayuda a minimizar el número de solicitudes y optimiza la gestión de grandes volúmenes de mensajes.

**nota**  
El cliente asíncrono con búfer de Amazon SQS no admite actualmente las colas FIFO.

# Habilitación del almacenamiento en búfer del cliente y del agrupamiento en lotes de solicitudes con Amazon SQS
<a name="sqs-client-side-buffering-request-batching"></a>

[AWS SDK para Java](https://aws.amazon.com/sdkforjava/) incluye `AmazonSQSBufferedAsyncClient` que tiene acceso a Amazon SQS. Este cliente permite agrupar fácilmente en lotes las solicitudes mediante el almacenamiento en búfer del cliente. Las llamadas realizadas desde el cliente se almacenan primero en búfer y, después, se envían como una solicitud por lotes a Amazon SQS.

El almacenamiento en búfer en el cliente permite almacenar en búfer hasta diez solicitudes y enviarlas como una solicitud por lotes, lo que disminuye el costo de uso de Amazon SQS y el número de solicitudes enviadas. `AmazonSQSBufferedAsyncClient` almacena en búfer tanto las llamadas sincrónicas como las asincrónicas. Las solicitudes por lotes y la compatibilidad con los [sondeos largos](sqs-short-and-long-polling.md) también pueden contribuir a mejorar el rendimiento. Para obtener más información, consulte [Aumento del rendimiento mediante el escalado horizontal y agrupación en lotes de acciones con Amazon SQS](sqs-throughput-horizontal-scaling-and-batching.md).

Dado que `AmazonSQSBufferedAsyncClient` implementa la misma interfaz que `AmazonSQSAsyncClient`, la migración de `AmazonSQSAsyncClient` a `AmazonSQSBufferedAsyncClient` solo suele requerir cambios mínimos en el código.

**nota**  
El cliente asíncrono con búfer de Amazon SQS no admite actualmente las colas FIFO.

## Uso de Amazon SQSBuffered AsyncClient
<a name="using-buffered-async-client"></a>

Antes de comenzar, complete los pasos de [Configuración de Amazon SQS](sqs-setting-up.md). 

### AWS SDK para Java 1.x
<a name="using-buffered-async-client-java1"></a>

Para el AWS SDK para Java 1.x, puedes crear uno nuevo `AmazonSQSBufferedAsyncClient` basado en el siguiente ejemplo:

```
// Create the basic Amazon SQS async client
final AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();
 
// Create the buffered client
final AmazonSQSAsync bufferedSqs = new AmazonSQSBufferedAsyncClient(sqsAsync);
```

Después de crear el nuevo `AmazonSQSBufferedAsyncClient`, puede utilizarlo para enviar varias solicitudes a Amazon SQS (del mismo modo que con `AmazonSQSAsyncClient`), por ejemplo:

```
final CreateQueueRequest createRequest = new CreateQueueRequest().withQueueName("MyQueue");
 
final CreateQueueResult res = bufferedSqs.createQueue(createRequest);
 
final SendMessageRequest request = new SendMessageRequest();
final String body = "Your message text" + System.currentTimeMillis();
request.setMessageBody( body );
request.setQueueUrl(res.getQueueUrl());
 
final Future<SendMessageResult> sendResult = bufferedSqs.sendMessageAsync(request);
 
final ReceiveMessageRequest receiveRq = new ReceiveMessageRequest()
    .withMaxNumberOfMessages(1)
    .withQueueUrl(queueUrl);
final ReceiveMessageResult rx = bufferedSqs.receiveMessage(receiveRq);
```

### Configuración de Amazon SQSBuffered AsyncClient
<a name="configuring-buffered-async-client"></a>

`AmazonSQSBufferedAsyncClient` está preconfigurado con ajustes válidos para la mayoría de los casos de uso. Se pueden configurar ajustes adicionales de `AmazonSQSBufferedAsyncClient`; por ejemplo:

1. Crear una instancia de la clase `QueueBufferConfig` con los parámetros de configuración necesarios.

1. Proporcionar la instancia al constructor `AmazonSQSBufferedAsyncClient`.

```
// Create the basic Amazon SQS async client
final AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();
 
final QueueBufferConfig config = new QueueBufferConfig()
    .withMaxInflightReceiveBatches(5)
    .withMaxDoneReceiveBatches(15);
 
// Create the buffered client
final AmazonSQSAsync bufferedSqs = new AmazonSQSBufferedAsyncClient(sqsAsync, config);
```


**QueueBufferConfig parámetros de configuración**  

| Parámetro | Predeterminado | Description (Descripción) | 
| --- | --- | --- | 
| longPoll | true |  Cuando `longPoll` se establece en `true`, `AmazonSQSBufferedAsyncClient` intenta utilizar el sondeo largo a la hora de consumir mensajes.  | 
| longPollWaitTimeoutSeconds | 20 s |  El tiempo máximo, en segundos, que una llamada a `ReceiveMessage` se bloquea en el servidor a la espera de que aparezcan mensajes en la cola antes de devolver un resultado de recepción vacío.  Este parámetro no tiene ningún efecto cuando el sondeo largo está deshabilitado.   | 
| maxBatchOpenMs | 200ms |  El tiempo máximo, en milisegundos, que una llamada saliente espera otras llamadas para procesar por lotes mensajes del mismo tipo. Cuanto mayor sea el valor, menos lotes son necesarios para realizar la misma cantidad de trabajo (no obstante, la primera llamada de un lote tiene que esperar más tiempo). Cuando se establece este parámetro en `0`, las solicitudes enviadas no esperan a otras solicitudes, lo que en la práctica deshabilita el procesamiento por lotes.  | 
| maxBatchSize | 10 solicitudes por lote |  El número máximo de mensajes que se procesan juntos por lotes en una sola solicitud. Cuanto mayor sea la configuración, menos lotes serán necesarios para llevar a cabo el mismo número de solicitudes.  El valor máximo permitido para Amazon SQS es de diez solicitudes por lote.   | 
| maxBatchSizeBytes | 1 MiB |  El tamaño máximo de un lote de mensajes, en bytes, que el cliente intenta enviar a Amazon SQS.  El valor máximo permitido para Amazon SQS es de 1 MiB.   | 
| maxDoneReceiveBatches | 10 lotes |  El número máximo de lotes de recepción que `AmazonSQSBufferedAsyncClient` captura previamente y almacena en el lado del cliente. Cuanto mayor sea el valor, más solicitudes de recepción podrán satisfacerse sin tener que realizar una llamada a Amazon SQS (sin embargo, cuantos más mensajes se capturen previamente, más tiempo permanecerán en el búfer, lo que hará que caduque su propio tiempo de espera de visibilidad).  `0` indica que se ha deshabilitado la captura previa de mensajes y que estos solo se consumen bajo demanda.   | 
| maxInflightOutboundBatches | 5 lotes |  El número máximo de lotes salientes activos que se pueden procesar al mismo tiempo. Cuanto mayor sea el valor, más rápido se podrán enviar los lotes salientes (sujeto a cuotas como la CPU o el ancho de banda) y más subprocesos podrá consumir `AmazonSQSBufferedAsyncClient`.  | 
| maxInflightReceiveBatches | 10 lotes |  El número máximo de lotes de recepción activos que se pueden procesar al mismo tiempo. Cuanto mayor sea el valor, más mensajes de podrán recibir (sujeto a cuotas como la CPU o el ancho de banda) y más subprocesos podrá consumir `AmazonSQSBufferedAsyncClient`.  `0` indica que se ha deshabilitado la captura previa de mensajes y que estos solo se consumen bajo demanda.   | 
| visibilityTimeoutSeconds | -1 |  Cuando este parámetro se establece en un valor positivo distinto de cero, el tiempo de espera de visibilidad que se establece aquí anula el tiempo de espera de visibilidad definido en la cola desde la que se consumen los mensajes.  `-1` indica que está seleccionada la configuración predeterminada de la cola. No se puede establecer el tiempo de espera de visibilidad en `0`.   | 

### AWS SDK para Java 2.x
<a name="using-buffered-async-client-java2"></a>

Para el AWS SDK para Java 2.x, puede crear un nuevo `SqsAsyncBatchManager` basado en el siguiente ejemplo:

```
// Create the basic Sqs Async Client
SqsAsyncClient sqs = SqsAsyncClient.builder() 
    .region(Region.US_EAST_1) 
    .build();

// Create the batch manager
SqsAsyncBatchManager sqsAsyncBatchManager = sqs.batchManager();
```

Después de crear el nuevo `SqsAsyncBatchManager`, puede utilizarlo para enviar varias solicitudes a Amazon SQS (del mismo modo que con `SqsAsyncClient`), por ejemplo:

```
final String queueName = "MyAsyncBufferedQueue" + UUID.randomUUID();
final CreateQueueRequest request = CreateQueueRequest.builder().queueName(queueName).build();
final String queueUrl = sqs.createQueue(request).join().queueUrl();
System.out.println("Queue created: " + queueUrl);


// Send messages
CompletableFuture<SendMessageResponse> sendMessageFuture;
for (int i = 0; i < 10; i++) {
    final int index = i;
    sendMessageFuture = sqsAsyncBatchManager.sendMessage(
            r -> r.messageBody("Message " + index).queueUrl(queueUrl));
    SendMessageResponse response= sendMessageFuture.join();
    System.out.println("Message " + response.messageId() + " sent!");
}

// Receive messages with customized configurations
CompletableFuture<ReceiveMessageResponse> receiveResponseFuture = customizedBatchManager.receiveMessage(
        r -> r.queueUrl(queueUrl)
                .waitTimeSeconds(10)
                .visibilityTimeout(20)
                .maxNumberOfMessages(10)
);
System.out.println("You have received " + receiveResponseFuture.join().messages().size() + " messages in total.");

// Delete messages
DeleteQueueRequest deleteQueueRequest =  DeleteQueueRequest.builder().queueUrl(queueUrl).build();
int code = sqs.deleteQueue(deleteQueueRequest).join().sdkHttpResponse().statusCode();
System.out.println("Queue is deleted, with statusCode " + code);
```

### Configurando SqsAsyncBatchManager
<a name="configuring-SqsAsyncBatchManager"></a>

`SqsAsyncBatchManager` está preconfigurado con ajustes válidos para la mayoría de los casos de uso. Se pueden configurar ajustes adicionales de `SqsAsyncBatchManager`; por ejemplo:

Creación de una configuración personalizada a través de `SqsAsyncBatchManager.Builder`:

```
SqsAsyncBatchManager customizedBatchManager = SqsAsyncBatchManager.builder() 
    .client(sqs)
    .scheduledExecutor(Executors.newScheduledThreadPool(5))
    .overrideConfiguration(b -> b 
        .maxBatchSize(10)
        .sendRequestFrequency(Duration.ofMillis(200))
        .receiveMessageMinWaitDuration(Duration.ofSeconds(10))
        .receiveMessageVisibilityTimeout(Duration.ofSeconds(20)) 
        .receiveMessageAttributeNames(Collections.singletonList("*"))
        .receiveMessageSystemAttributeNames(Collections.singletonList(MessageSystemAttributeName.ALL)))
    .build();
```


**Parámetros `BatchOverrideConfiguration`**  

| Parámetro | Predeterminado | Description (Descripción) | 
| --- | --- | --- | 
| maxBatchSize |  10 solicitudes por lote  | El número máximo de mensajes que se procesan juntos por lotes en una sola solicitud. Cuanto mayor sea la configuración, menos lotes serán necesarios para llevar a cabo el mismo número de solicitudes.  El valor máximo permitido para Amazon SQS es de 10 solicitudes por lote.  | 
| sendRequestFrequency |  200ms  | El tiempo máximo, en milisegundos, que una llamada saliente espera otras llamadas para procesar por lotes mensajes del mismo tipo. Cuanto mayor sea el valor, menos lotes son necesarios para realizar la misma cantidad de trabajo (no obstante, la primera llamada de un lote tiene que esperar más tiempo). Cuando se establece este parámetro en `0`, las solicitudes enviadas no esperan a otras solicitudes, lo que en la práctica deshabilita el procesamiento por lotes. | 
| receiveMessageVisibilityTimeout |  -1  | Cuando este parámetro se establece en un valor positivo distinto de cero, el tiempo de espera de visibilidad que se establece aquí anula el tiempo de espera de visibilidad definido en la cola desde la que se consumen los mensajes.   `1` indica que está seleccionada la configuración predeterminada de la cola. No se puede establecer el tiempo de espera de visibilidad en `0`.   | 
| receiveMessageMinWaitDuration |  50 ms  | La cantidad mínima de tiempo (en milisegundos) que una llamada `receiveMessage` espera a que se recuperen los mensajes disponibles. Cuanto mayor sea la configuración, menos lotes serán necesarios para llevar a cabo el mismo número de solicitudes.  | 

# Aumento del rendimiento mediante el escalado horizontal y agrupación en lotes de acciones con Amazon SQS
<a name="sqs-throughput-horizontal-scaling-and-batching"></a>

Amazon SQS admite mensajería de alto rendimiento. Para obtener más información sobre los límites de rendimiento, consulte [Cuotas de mensajes de Amazon SQS](quotas-messages.md).

Para maximizar el rendimiento:
+ [Escale](#horizontal-scaling) los productores y consumidores horizontalmente agregando más instancias de cada uno de ellos.
+ Utilice el procesamiento por [lotes de acciones](#request-batching) para enviar o recibir varios mensajes en una sola solicitud, lo que reduce la sobrecarga de llamadas a la API.

## Escalado horizontal
<a name="horizontal-scaling"></a>

Dado que se accede a Amazon SQS a través de un protocolo HTTP de solicitud-respuesta, la *latencia de solicitudes* (el intervalo de tiempo que transcurre entre que se inicia una solicitud y se recibe una respuesta) limita el rendimiento que se puede alcanzar con un solo subproceso a través de una única conexión. Por ejemplo, si la latencia desde un cliente basado en Amazon EC2 hasta Amazon SQS en la misma región es de una media de 20 ms, el rendimiento máximo desde un único subproceso a través de una única conexión será de una media de 50 transacciones por segundo. 

El *escalado horizontal* supone aumentar el número de productores de mensajes (que realizan solicitudes `[SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)`) y consumidores de mensajes (que realizan solicitudes `[ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)` y `[DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html)`) para aumentar el desempeño general de la cola. Existen tres métodos para realizar el escalado horizontal:
+ Aumentar el número de subprocesos por cliente
+ Añadir más clientes
+ Aumentar el número de subprocesos por cliente y añadir más clientes

Cuando se añaden más clientes, se consiguen ganancias prácticamente lineales en el desempeño de la cola. Por ejemplo, si se duplica el número de clientes, también se obtiene el doble de desempeño. 

## Agrupación en lotes de acciones
<a name="request-batching"></a>

La *agrupación por lotes* realiza más trabajo durante cada ciclo de ida y vuelta al servicio (por ejemplo, al enviar varios mensajes en una única solicitud `SendMessageBatch`). Las acciones de procesamiento por lotes de Amazon SQS son `[SendMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html)`, `[DeleteMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessageBatch.html)` y `[ChangeMessageVisibilityBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibilityBatch.html)`. Para aprovechar el procesamiento por lotes sin modificar los productores ni los consumidores, puede utilizar el [Cliente asincrónico en búfer de Amazon SQS](sqs-client-side-buffering-request-batching.md).

**nota**  
Debido a que `[ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)` puede procesar 10 mensajes a la vez, no hay ninguna acción `ReceiveMessageBatch`.

La agrupación en lotes distribuye la latencia de la acción por lotes entre varios mensajes en una solicitud por lotes, en lugar de aceptar toda la latencia para un único mensaje (por ejemplo, una solicitud `[SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)`). Como en cada ciclo de ida y vuelta se realiza más trabajo, las solicitudes por lotes hacen un uso más eficaz de los subprocesos y las conexiones, por lo que se mejora el desempeño.

Puede combinar la agrupación en lotes con el escalado horizontal para proporcionar un desempeño con menos subprocesos, conexiones y solicitudes de los que serían necesarios en el caso de utilizar solicitudes de mensajes individuales. Puede utilizar acciones de Amazon SQS por lotes para enviar, recibir o eliminar hasta diez mensajes a la vez. Dado que el uso de Amazon SQS se factura por solicitudes, el procesamiento por lotes puede reducir significativamente los costos. 

La agrupación en lotes puede introducir cierta complejidad en una aplicación (por ejemplo, la aplicación debe acumular los mensajes antes de enviarlos, o a veces debe esperar más para recibir una respuesta). Sin embargo, la agrupación en lotes puede resultar eficaz en los casos siguientes: 
+ Cuando la aplicación genera muchos mensajes en poco tiempo, por lo que el retraso nunca es muy largo. 
+ Cuando un consumidor de mensajes busca mensajes en una cola a discreción, a diferencia de los productores de mensajes típicos que tienen que enviar mensajes como respuesta a eventos que no controlan. 

**importante**  
Una solicitud por lotes puede realizarse correctamente aunque se hayan producido errores en mensajes individuales del lote. Después de una solicitud por lotes, compruebe siempre si hay errores en mensajes individuales y vuelva a intentar la acción si es necesario.

## Ejemplo funcional en Java de solicitudes de una sola operación y por lotes
<a name="working-java-example-batch-requests"></a>

### Requisitos previos
<a name="batch-request-java-example-prerequisites"></a>

Añada los paquetes `aws-java-sdk-sqs.jar`, `aws-java-sdk-ec2.jar` y `commons-logging.jar` a la ruta de clases de compilación Java. Los siguientes ejemplos muestran estas dependencias en el archivo `pom.xml` de un proyecto Maven.

```
<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-sqs</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-ec2</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>LATEST</version>
    </dependency>
</dependencies>
```

### SimpleProducerConsumer.java
<a name="batch-request-java-example-code"></a>

En el siguiente ejemplo de código Java se implementa un patrón productor-consumidor sencillo. El subproceso principal genera una serie de subprocesos productores y consumidores que procesan mensajes de 1 KB durante el tiempo especificado. Este ejemplo incluye productores y consumidores que realizan solicitudes de una única operación y otros que realizan solicitudes por lotes.

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */

import com.amazonaws.AmazonClientException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Start a specified number of producer and consumer threads, and produce-consume
 * for the least of the specified duration and 1 hour. Some messages can be left
 * in the queue because producers and consumers might not be in exact balance.
 */
public class SimpleProducerConsumer {

    // The maximum runtime of the program.
    private final static int MAX_RUNTIME_MINUTES = 60;
    private final static Log log = LogFactory.getLog(SimpleProducerConsumer.class);

    public static void main(String[] args) throws InterruptedException {

        final Scanner input = new Scanner(System.in);

        System.out.print("Enter the queue name: ");
        final String queueName = input.nextLine();

        System.out.print("Enter the number of producers: ");
        final int producerCount = input.nextInt();

        System.out.print("Enter the number of consumers: ");
        final int consumerCount = input.nextInt();

        System.out.print("Enter the number of messages per batch: ");
        final int batchSize = input.nextInt();

        System.out.print("Enter the message size in bytes: ");
        final int messageSizeByte = input.nextInt();

        System.out.print("Enter the run time in minutes: ");
        final int runTimeMinutes = input.nextInt();

        /*
         * Create a new instance of the builder with all defaults (credentials
         * and region) set automatically. For more information, see Creating
         * Service Clients in the AWS SDK for Java Developer Guide.
         */
        final ClientConfiguration clientConfiguration = new ClientConfiguration()
                .withMaxConnections(producerCount + consumerCount);

        final AmazonSQS sqsClient = AmazonSQSClientBuilder.standard()
                .withClientConfiguration(clientConfiguration)
                .build();

        final String queueUrl = sqsClient
                .getQueueUrl(new GetQueueUrlRequest(queueName)).getQueueUrl();

        // The flag used to stop producer, consumer, and monitor threads.
        final AtomicBoolean stop = new AtomicBoolean(false);

        // Start the producers.
        final AtomicInteger producedCount = new AtomicInteger();
        final Thread[] producers = new Thread[producerCount];
        for (int i = 0; i < producerCount; i++) {
            if (batchSize == 1) {
                producers[i] = new Producer(sqsClient, queueUrl, messageSizeByte,
                        producedCount, stop);
            } else {
                producers[i] = new BatchProducer(sqsClient, queueUrl, batchSize,
                        messageSizeByte, producedCount,
                        stop);
            }
            producers[i].start();
        }

        // Start the consumers.
        final AtomicInteger consumedCount = new AtomicInteger();
        final Thread[] consumers = new Thread[consumerCount];
        for (int i = 0; i < consumerCount; i++) {
            if (batchSize == 1) {
                consumers[i] = new Consumer(sqsClient, queueUrl, consumedCount,
                        stop);
            } else {
                consumers[i] = new BatchConsumer(sqsClient, queueUrl, batchSize,
                        consumedCount, stop);
            }
            consumers[i].start();
        }

        // Start the monitor thread.
        final Thread monitor = new Monitor(producedCount, consumedCount, stop);
        monitor.start();

        // Wait for the specified amount of time then stop.
        Thread.sleep(TimeUnit.MINUTES.toMillis(Math.min(runTimeMinutes,
                MAX_RUNTIME_MINUTES)));
        stop.set(true);

        // Join all threads.
        for (int i = 0; i < producerCount; i++) {
            producers[i].join();
        }

        for (int i = 0; i < consumerCount; i++) {
            consumers[i].join();
        }

        monitor.interrupt();
        monitor.join();
    }

    private static String makeRandomString(int sizeByte) {
        final byte[] bs = new byte[(int) Math.ceil(sizeByte * 5 / 8)];
        new Random().nextBytes(bs);
        bs[0] = (byte) ((bs[0] | 64) & 127);
        return new BigInteger(bs).toString(32);
    }

    /**
     * The producer thread uses {@code SendMessage}
     * to send messages until it is stopped.
     */
    private static class Producer extends Thread {
        final AmazonSQS sqsClient;
        final String queueUrl;
        final AtomicInteger producedCount;
        final AtomicBoolean stop;
        final String theMessage;

        Producer(AmazonSQS sqsQueueBuffer, String queueUrl, int messageSizeByte,
                 AtomicInteger producedCount, AtomicBoolean stop) {
            this.sqsClient = sqsQueueBuffer;
            this.queueUrl = queueUrl;
            this.producedCount = producedCount;
            this.stop = stop;
            this.theMessage = makeRandomString(messageSizeByte);
        }

        /*
         * The producedCount object tracks the number of messages produced by
         * all producer threads. If there is an error, the program exits the
         * run() method.
         */
        public void run() {
            try {
                while (!stop.get()) {
                    sqsClient.sendMessage(new SendMessageRequest(queueUrl,
                            theMessage));
                    producedCount.incrementAndGet();
                }
            } catch (AmazonClientException e) {
                /*
                 * By default, AmazonSQSClient retries calls 3 times before
                 * failing. If this unlikely condition occurs, stop.
                 */
                log.error("Producer: " + e.getMessage());
                System.exit(1);
            }
        }
    }

    /**
     * The producer thread uses {@code SendMessageBatch}
     * to send messages until it is stopped.
     */
    private static class BatchProducer extends Thread {
        final AmazonSQS sqsClient;
        final String queueUrl;
        final int batchSize;
        final AtomicInteger producedCount;
        final AtomicBoolean stop;
        final String theMessage;

        BatchProducer(AmazonSQS sqsQueueBuffer, String queueUrl, int batchSize,
                      int messageSizeByte, AtomicInteger producedCount,
                      AtomicBoolean stop) {
            this.sqsClient = sqsQueueBuffer;
            this.queueUrl = queueUrl;
            this.batchSize = batchSize;
            this.producedCount = producedCount;
            this.stop = stop;
            this.theMessage = makeRandomString(messageSizeByte);
        }

        public void run() {
            try {
                while (!stop.get()) {
                    final SendMessageBatchRequest batchRequest =
                            new SendMessageBatchRequest().withQueueUrl(queueUrl);

                    final List<SendMessageBatchRequestEntry> entries =
                            new ArrayList<SendMessageBatchRequestEntry>();
                    for (int i = 0; i < batchSize; i++)
                        entries.add(new SendMessageBatchRequestEntry()
                                .withId(Integer.toString(i))
                                .withMessageBody(theMessage));
                    batchRequest.setEntries(entries);

                    final SendMessageBatchResult batchResult =
                            sqsClient.sendMessageBatch(batchRequest);
                    producedCount.addAndGet(batchResult.getSuccessful().size());

                    /*
                     * Because SendMessageBatch can return successfully, but
                     * individual batch items fail, retry the failed batch items.
                     */
                    if (!batchResult.getFailed().isEmpty()) {
                        log.warn("Producer: retrying sending "
                                + batchResult.getFailed().size() + " messages");
                        for (int i = 0, n = batchResult.getFailed().size();
                             i < n; i++) {
                            sqsClient.sendMessage(new
                                    SendMessageRequest(queueUrl, theMessage));
                            producedCount.incrementAndGet();
                        }
                    }
                }
            } catch (AmazonClientException e) {
                /*
                 * By default, AmazonSQSClient retries calls 3 times before
                 * failing. If this unlikely condition occurs, stop.
                 */
                log.error("BatchProducer: " + e.getMessage());
                System.exit(1);
            }
        }
    }

    /**
     * The consumer thread uses {@code ReceiveMessage} and {@code DeleteMessage}
     * to consume messages until it is stopped.
     */
    private static class Consumer extends Thread {
        final AmazonSQS sqsClient;
        final String queueUrl;
        final AtomicInteger consumedCount;
        final AtomicBoolean stop;

        Consumer(AmazonSQS sqsClient, String queueUrl, AtomicInteger consumedCount,
                 AtomicBoolean stop) {
            this.sqsClient = sqsClient;
            this.queueUrl = queueUrl;
            this.consumedCount = consumedCount;
            this.stop = stop;
        }

        /*
         * Each consumer thread receives and deletes messages until the main
         * thread stops the consumer thread. The consumedCount object tracks the
         * number of messages that are consumed by all consumer threads, and the
         * count is logged periodically.
         */
        public void run() {
            try {
                while (!stop.get()) {
                    try {
                        final ReceiveMessageResult result = sqsClient
                                .receiveMessage(new
                                        ReceiveMessageRequest(queueUrl));

                        if (!result.getMessages().isEmpty()) {
                            final Message m = result.getMessages().get(0);
                            sqsClient.deleteMessage(new
                                    DeleteMessageRequest(queueUrl,
                                    m.getReceiptHandle()));
                            consumedCount.incrementAndGet();
                        }
                    } catch (AmazonClientException e) {
                        log.error(e.getMessage());
                    }
                }
            } catch (AmazonClientException e) {
                /*
                 * By default, AmazonSQSClient retries calls 3 times before
                 * failing. If this unlikely condition occurs, stop.
                 */
                log.error("Consumer: " + e.getMessage());
                System.exit(1);
            }
        }
    }

    /**
     * The consumer thread uses {@code ReceiveMessage} and {@code
     * DeleteMessageBatch} to consume messages until it is stopped.
     */
    private static class BatchConsumer extends Thread {
        final AmazonSQS sqsClient;
        final String queueUrl;
        final int batchSize;
        final AtomicInteger consumedCount;
        final AtomicBoolean stop;

        BatchConsumer(AmazonSQS sqsClient, String queueUrl, int batchSize,
                      AtomicInteger consumedCount, AtomicBoolean stop) {
            this.sqsClient = sqsClient;
            this.queueUrl = queueUrl;
            this.batchSize = batchSize;
            this.consumedCount = consumedCount;
            this.stop = stop;
        }

        public void run() {
            try {
                while (!stop.get()) {
                    final ReceiveMessageResult result = sqsClient
                            .receiveMessage(new ReceiveMessageRequest(queueUrl)
                                    .withMaxNumberOfMessages(batchSize));

                    if (!result.getMessages().isEmpty()) {
                        final List<Message> messages = result.getMessages();
                        final DeleteMessageBatchRequest batchRequest =
                                new DeleteMessageBatchRequest()
                                        .withQueueUrl(queueUrl);

                        final List<DeleteMessageBatchRequestEntry> entries =
                                new ArrayList<DeleteMessageBatchRequestEntry>();
                        for (int i = 0, n = messages.size(); i < n; i++)
                            entries.add(new DeleteMessageBatchRequestEntry()
                                    .withId(Integer.toString(i))
                                    .withReceiptHandle(messages.get(i)
                                            .getReceiptHandle()));
                        batchRequest.setEntries(entries);

                        final DeleteMessageBatchResult batchResult = sqsClient
                                .deleteMessageBatch(batchRequest);
                        consumedCount.addAndGet(batchResult.getSuccessful().size());

                        /*
                         * Because DeleteMessageBatch can return successfully,
                         * but individual batch items fail, retry the failed
                         * batch items.
                         */
                        if (!batchResult.getFailed().isEmpty()) {
                            final int n = batchResult.getFailed().size();
                            log.warn("Producer: retrying deleting " + n
                                    + " messages");
                            for (BatchResultErrorEntry e : batchResult
                                    .getFailed()) {

                                sqsClient.deleteMessage(
                                        new DeleteMessageRequest(queueUrl,
                                                messages.get(Integer
                                                        .parseInt(e.getId()))
                                                        .getReceiptHandle()));

                                consumedCount.incrementAndGet();
                            }
                        }
                    }
                }
            } catch (AmazonClientException e) {
                /*
                 * By default, AmazonSQSClient retries calls 3 times before
                 * failing. If this unlikely condition occurs, stop.
                 */
                log.error("BatchConsumer: " + e.getMessage());
                System.exit(1);
            }
        }
    }

    /**
     * This thread prints every second the number of messages produced and
     * consumed so far.
     */
    private static class Monitor extends Thread {
        private final AtomicInteger producedCount;
        private final AtomicInteger consumedCount;
        private final AtomicBoolean stop;

        Monitor(AtomicInteger producedCount, AtomicInteger consumedCount,
                AtomicBoolean stop) {
            this.producedCount = producedCount;
            this.consumedCount = consumedCount;
            this.stop = stop;
        }

        public void run() {
            try {
                while (!stop.get()) {
                    Thread.sleep(1000);
                    log.info("produced messages = " + producedCount.get()
                            + ", consumed messages = " + consumedCount.get());
                }
            } catch (InterruptedException e) {
                // Allow the thread to exit.
            }
        }
    }
}
```

### Monitoreo de las métricas de volumen de la ejecución del ejemplo
<a name="batch-request-java-example-monitoring-metrics"></a>

Amazon SQS genera automáticamente métricas de volumen para los mensajes enviados, recibidos y eliminados. Puede tener acceso a estas y otras métricas a través de la pestaña **Monitoring (Monitoreo)** de la cola o en la [CloudWatch consola](https://console.aws.amazon.com/cloudwatch/home).

**nota**  
Las métricas pueden tardar en estar disponibles hasta 15 minutos después del inicio de la cola.