Java에서 Queue Storage를 사용하는 방법

개요

이 가이드에서는 Azure Queue Storage 서비스를 사용하여 일반 시나리오를 수행하는 방법을 보여 줍니다. 샘플은 Java로 작성되었으며 Java용 Azure Storage SDK(영문)를 사용합니다. 시나리오에는 큐 메시지 삽입하기, 미리보기, 가져오기, 그리고 삭제하기 가 포함됩니다. 큐 생성삭제 코드도 다룹니다. 큐에 대한 자세한 내용은 다음 단계 섹션을 참조하세요.

Queue Storage란?

Azure Queue Storage는 HTTP 또는 HTTPS를 사용하여 인증된 호출을 통해 전 세계 어디에서나 액세스할 수 있는 다수의 메시지를 저장하기 위한 서비스입니다. 단일 큐 메시지의 크기는 최대 64KB일 수 있으며, 하나의 큐에 스토리지 계정의 총 용량 제한까지 수백만 개의 메시지가 포함될 수 있습니다. Queue Storage는 비동기적으로 처리할 작업의 백로그를 만드는 데 자주 사용됩니다.

큐 서비스 개념

Azure 큐 서비스에는 다음 구성 요소가 포함됩니다.

Azure 큐 서비스 구성 요소

  • Storage 계정: Azure Storage에 대한 모든 액세스는 Storage 계정을 통해 수행됩니다. 스토리지 계정에 대한 자세한 내용은 스토리지 계정 개요를 참조하세요.

  • 큐: 큐에는 메시지 집합이 포함됩니다. 모든 메시지는 큐에 있어야 합니다. 큐 이름은 모두 소문자여야 합니다. 큐의 명명에 대한 자세한 내용은 큐 및 메타데이터 명명을 참조하세요.

  • 메시지: 최대 64KB인 임의 형식의 메시지입니다. 메시지가 큐에 남아 있을 수 있는 최대 시간은 7일입니다. 2017-07-29 이상 버전에서 허용되는 최대 TTL(Time to Live)은 모든 양수 또는 메시지가 만료되지 않는 -1입니다. 이 매개 변수를 생략하면 기본 TTL(Time to Live)은 7일입니다.

  • URL 형식: 큐는 http://<storage account>.queue.core.windows.net/<queue> URL 형식을 사용하여 주소를 지정할 수 있습니다.

    다음 URL은 다이어그램에 있는 큐의 주소를 지정합니다.

    http://myaccount.queue.core.windows.net/incoming-orders

Azure Storage 계정 만들기

첫 번째 Azure Storage 계정을 가장 쉽게 만드는 방법은 Azure Portal을 사용하는 것입니다. 자세한 내용은 스토리지 계정 만들기를 참조하십시오.

또한 Azure PowerShell, Azure CLI 또는 .NET용 Azure Storage 리소스 공급자를 사용하여 Azure 스토리지 계정을 만들 수도 있습니다.

이 시점에서 스토리지 계정을 Azure에 만들지 않으려는 경우 Azurite 스토리지 에뮬레이터를 사용하여 로컬 환경에서 코드를 실행하고 테스트할 수도 있습니다. 자세한 내용은 로컬 Azure Storage 개발에 Azurite 에뮬레이터 사용을 참조하세요.

Java 애플리케이션 만들기

먼저 개발 시스템이 Java용 Azure Queue Storage 클라이언트 라이브러리 v12에 나열된 필수 구성 요소를 충족하는지 확인합니다.

queues-how-to-v12이라는 Java 애플리케이션을 만들려면 다음을 수행합니다.

  1. 콘솔 창(예: cmd, PowerShell 또는 Bash)에서 Maven을 사용하여 queues-how-to-v12라는 새 콘솔 앱을 만듭니다. 다음 mvn 명령을 입력하여 "hello world" Java 프로젝트를 만듭니다.

     mvn archetype:generate \
         --define interactiveMode=n \
         --define groupId=com.queues.howto \
         --define artifactId=queues-howto-v12 \
         --define archetypeArtifactId=maven-archetype-quickstart \
         --define archetypeVersion=1.4
    
    mvn archetype:generate `
        --define interactiveMode=n `
        --define groupId=com.queues.howto `
        --define artifactId=queues-howto-v12 `
        --define archetypeArtifactId=maven-archetype-quickstart `
        --define archetypeVersion=1.4
    
  2. 프로젝트를 생성하는 출력은 다음과 같습니다.

    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------< org.apache.maven:standalone-pom >-------------------
    [INFO] Building Maven Stub Project (No POM) 1
    [INFO] --------------------------------[ pom ]---------------------------------
    [INFO]
    [INFO] >>> maven-archetype-plugin:3.1.2:generate (default-cli) > generate-sources @ standalone-pom >>>
    [INFO]
    [INFO] <<< maven-archetype-plugin:3.1.2:generate (default-cli) < generate-sources @ standalone-pom <<<
    [INFO]
    [INFO]
    [INFO] --- maven-archetype-plugin:3.1.2:generate (default-cli) @ standalone-pom ---
    [INFO] Generating project in Batch mode
    [INFO] ----------------------------------------------------------------------------
    [INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
    [INFO] ----------------------------------------------------------------------------
    [INFO] Parameter: groupId, Value: com.queues.howto
    [INFO] Parameter: artifactId, Value: queues-howto-v12
    [INFO] Parameter: version, Value: 1.0-SNAPSHOT
    [INFO] Parameter: package, Value: com.queues.howto
    [INFO] Parameter: packageInPathFormat, Value: com/queues/howto
    [INFO] Parameter: version, Value: 1.0-SNAPSHOT
    [INFO] Parameter: package, Value: com.queues.howto
    [INFO] Parameter: groupId, Value: com.queues.howto
    [INFO] Parameter: artifactId, Value: queues-howto-v12
    [INFO] Project created from Archetype in dir: C:\queues\queues-howto-v12
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  6.775 s
    [INFO] Finished at: 2020-08-17T15:27:31-07:00
    [INFO] ------------------------------------------------------------------------
    
  3. 새로 만든 queues-howto-v12 디렉터리로 전환합니다.

    cd queues-howto-v12
    

패키지 설치

텍스트 편집기에서 pom.xml 파일을 엽니다. 종속성 그룹에 다음 종속성 요소를 추가합니다.

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-storage-queue</artifactId>
  <version>12.6.0</version>
</dependency>

Queue Storage에 액세스하도록 애플리케이션 구성

Azure Storage API를 사용하여 큐에 액세스하려는 Java 파일의 맨 위에 다음 가져오기 명령문을 추가합니다.

// Include the following imports to use queue APIs
import com.azure.core.util.*;
import com.azure.storage.queue.*;
import com.azure.storage.queue.models.*;

Azure Storage 연결 문자열 설정

Azure Storage 클라이언트는 스토리지 연결 문자열을 사용하여 데이터 관리 서비스에 액세스합니다. Azure Portal에 나열된 스토리지 계정의 이름 및 기본 액세스 키를 가져옵니다. 이를 연결 문자열에서 AccountNameAccountKey 값으로 사용합니다. 이 예제는 정적 필드가 연결 문자열을 포함할 수 있도록 선언하는 방법을 보여 줍니다.

// Define the connection-string with your values
final String connectStr = 
    "DefaultEndpointsProtocol=https;" +
    "AccountName=your_storage_account;" +
    "AccountKey=your_storage_account_key";

다음 샘플에서는 스토리지 연결 문자열을 포함하는 String 개체가 있다고 가정합니다.

방법: 큐 만들기

QueueClient 개체는 큐와 상호 작용하기 위한 작업을 포함합니다. 다음 코드는 QueueClient 개체를 만듭니다. 이 QueueClient 개체를 사용하여 사용하려는 큐를 만들 수 있습니다.

public static String createQueue(String connectStr)
{
    try
    {
        // Create a unique name for the queue
        String queueName = "queue-" + java.util.UUID.randomUUID();

        System.out.println("Creating queue: " + queueName);

        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queue = new QueueClientBuilder()
                                .connectionString(connectStr)
                                .queueName(queueName)
                                .buildClient();

        // Create the queue
        queue.create();
        return queue.getQueueName();
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println("Error code: " + e.getErrorCode() + "Message: " + e.getMessage());
        return null;
    }
}

큐에 메시지 추가 방법

기존 큐에 메시지를 삽입하려면 sendMessage 메서드를 호출합니다. 메시지는 문자열(UTF-8 형식) 또는 바이트 배열에서 만들 수 있습니다. 다음은 문자열 메시지를 큐로 보내는 코드입니다.

public static void addQueueMessage
    (String connectStr, String queueName, String messageText)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        System.out.println("Adding message to the queue: " + messageText);

        // Add a message to the queue
        queueClient.sendMessage(messageText);
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

방법: 다음 메시지 보기

큐에서 메시지를 제거하지 않고도 peekMessage를 호출하여 큐의 앞에서 원하는 메시지를 미리 볼 수 있습니다.

public static void peekQueueMessage
    (String connectStr, String queueName)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        // Peek at the first message
        PeekedMessageItem peekedMessageItem = queueClient.peekMessage();
        System.out.println("Peeked message: " + peekedMessageItem.getMessageText());
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

방법: 대기 중인 메시지의 콘텐츠 변경

큐에 있는 메시지의 콘텐츠를 변경할 수 있습니다. 메시지가 작업 태스크를 나타내는 경우 이 기능을 사용하여 상태를 업데이트할 수 있습니다. 다음 코드는 새로운 콘텐츠로 큐 메시지를 업데이트하고 표시 시간 제한이 30초 더 늘어나도록 설정합니다. 표시 시간 제한을 확장하면 클라이언트는 메시지 작업을 계속하는 데 추가로 30초 정도 걸립니다. 재시도 횟수도 유지할 수 있습니다. 메시지가 n 번 이상 다시 시도된 경우, 메시지를 지울 수도 있습니다. 이 시나리오는 처리될 때마다 애플리케이션 오류를 트리거하는 메시지를 차단하여 보호해 줍니다.

다음 코드 샘플에서는 메시지 큐를 검색하여 내용에서 검색 문자열과 일치하는 최초의 메시지를 찾고 메시지 내용을 수정한 후 종료합니다.

public static void updateQueueMessage
    (String connectStr, String queueName,
    String searchString, String updatedContents)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        // The maximum number of messages to retrieve is 32
        final int MAX_MESSAGES = 32;

        // Iterate through the queue messages
        for (QueueMessageItem message : queueClient.receiveMessages(MAX_MESSAGES))
        {
            // Check for a specific string
            if (message.getMessageText().equals(searchString))
            {
                // Update the message to be visible in 30 seconds
                queueClient.updateMessage(message.getMessageId(),
                                          message.getPopReceipt(),
                                          updatedContents,
                                          Duration.ofSeconds(30));
                System.out.println(
                    String.format("Found message: \'%s\' and updated it to \'%s\'",
                                    searchString,
                                    updatedContents)
                                  );
                break;
            }
        }
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

다음 코드 샘플에서는 큐에 표시되는 첫 번째 메시지만 업데이트합니다.

public static void updateFirstQueueMessage
    (String connectStr, String queueName, String updatedContents)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        // Get the first queue message
        QueueMessageItem message = queueClient.receiveMessage();

        // Check for a specific string
        if (null != message)
        {
            // Update the message to be visible in 30 seconds
            UpdateMessageResult result = queueClient.updateMessage(message.getMessageId(),
                                                                   message.getPopReceipt(),
                                                                   updatedContents,
                                                                   Duration.ofSeconds(30));
            System.out.println("Updated the first message with the receipt: " +
                    result.getPopReceipt());
        }
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

방법: 큐 길이 가져오기

큐에 있는 메시지의 추정된 개수를 가져올 수 있습니다.

getProperties 메서드는 현재 큐에 있는 메시지 수를 포함하여 여러 값을 반환합니다. 요청 후에 메시지를 추가하거나 제거할 수 있으므로 개수는 근사치입니다. getApproximateMessageCount 메서드는 Queue Storage를 호출하지 않고, 호출에 의해 검색된 마지막 값을 getProperties로 반환합니다.

public static void getQueueLength(String connectStr, String queueName)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        QueueProperties properties = queueClient.getProperties();
        long messageCount = properties.getApproximateMessagesCount();

        System.out.println(String.format("Queue length: %d", messageCount));
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

큐에서 다음 메시지를 제거하는 방법

다음 코드는 2단계를 거쳐 큐에서 메시지를 제거합니다. receiveMessage를 호출하면 큐에서 다음 메시지를 가져옵니다. receiveMessage에서 반환된 메시지는 이 큐의 메시지를 읽는 다른 코드에는 표시되지 않습니다. 기본적으로, 이 메시지는 30초간 표시되지 않습니다. 큐에서 메시지 제거를 완료하려면 deleteMessage도 호출해야 합니다. 코드에서 메시지를 처리하지 못하는 경우 이 두 단계 프로세스를 통해 동일한 메시지를 받고 다시 시도할 수 있습니다. 코드는 메시지가 처리된 직후에 deleteMessage를 호출합니다.

public static void dequeueMessage(String connectStr, String queueName)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        // Get the first queue message
        QueueMessageItem message = queueClient.receiveMessage();

        // Check for a specific string
        if (null != message)
        {
            System.out.println("Dequeing message: " + message.getMessageText());

            // Delete the message
            queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
        }
        else
        {
            System.out.println("No visible messages in queue");
        }
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

큐에서 메시지를 제거하는 추가 옵션

큐에서 메시지 검색을 사용자 지정할 수 있는 방법으로는 두 가지가 있습니다. 먼저, 메시지의 배치(최대 32개)를 가져옵니다. 다음으로, 표시하지 않는 시간 제한을 더 길거나 더 짧게 설정하여 코드에서 각 메시지를 완전히 처리하는 시간을 늘리거나 줄일 수 있습니다.

다음 코드 예제는 receiveMessages 메서드를 사용하여 한 번 호출에 20개의 메시지를 가져옵니다. 그런 다음에 for 루프를 사용하여 각 메시지를 처리합니다. 또한 각 메시지에 대해 표시하지 않는 제한 시간을 5분(300초)으로 설정합니다. 시간 제한은 모든 메시지에 동시에 시작됩니다. receiveMessages에 대한 호출 이후로 5분이 지나고 나면 삭제되지 않은 모든 메시지가 다시 표시됩니다.

public static void dequeueMessages(String connectStr, String queueName)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        // The maximum number of messages to retrieve is 20
        final int MAX_MESSAGES = 20;

        // Retrieve 20 messages from the queue with a
        // visibility timeout of 300 seconds (5 minutes)
        for (QueueMessageItem message : queueClient.receiveMessages(MAX_MESSAGES,
                Duration.ofSeconds(300), Duration.ofSeconds(1), new Context("key1", "value1")))
        {
            // Do processing for all messages in less than 5 minutes,
            // deleting each message after processing.
            System.out.println("Dequeing message: " + message.getMessageText());
            queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
        }
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

큐 나열하는 방법

현재 큐의 목록을 가져오려면 QueueServiceClient.listQueues() 메서드를 호출해 QueueItem 개체 컬렉션을 반환합니다.

public static void listQueues(String connectStr)
{
    try
    {
        // Instantiate a QueueServiceClient which will be
        // used to list the queues
        QueueServiceClient queueServiceClient = new QueueServiceClientBuilder()
                                    .connectionString(connectStr)
                                    .buildClient();

        // Loop through the collection of queues.
        for (QueueItem queue : queueServiceClient.listQueues())
        {
            // Output each queue name.
            System.out.println(queue.getName());
        }
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

방법: 큐 삭제

큐와 큐에 포함된 모든 메시지를 삭제하려면 QueueClient 개체의 delete 메서드를 호출합니다.

public static void deleteMessageQueue(String connectStr, String queueName)
{
    try
    {
        // Instantiate a QueueClient which will be
        // used to create and manipulate the queue
        QueueClient queueClient = new QueueClientBuilder()
                                    .connectionString(connectStr)
                                    .queueName(queueName)
                                    .buildClient();

        System.out.println("Deleting queue: " + queueClient.getQueueName());

        // Delete the queue
        queueClient.delete();
    }
    catch (QueueStorageException e)
    {
        // Output the exception message and stack trace
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
}

Azure Storage 코드 샘플 리포지토리 확인

다운로드하고 실행할 수 있는 엔드투엔드 Azure Storage 코드 샘플을 쉽게 사용하려면 Azure Storage 샘플 목록을 확인하세요.

다음 단계

이제 Queue Storage의 기본 사항을 배웠으므로 다음 링크를 따라 좀 더 복잡한 스토리지 작업에 대해 알아보세요.