비동기 프로그래밍 사용 - AWS SDK for Java 2.x

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

비동기 프로그래밍 사용

몇 개의 스레드에서 높은 동시성을 구현하는 비차단 I/O를 지원하는 비동기 클라이언트가 AWS SDK for Java 2.x 특징입니다. 하지만 전체 논블로킹 I/O는 보장되지 않습니다. 비동기 클라이언트는 자격 증명 검색, 서명 버전 4 (SigV4) 를 사용한AWS 요청 서명 또는 엔드포인트 검색과 같은 일부 경우에 호출을 차단할 수 있습니다.

비동기 메서드는 클라이언트가 서비스로부터 응답을 받을 때까지 스레드의 실행을 차단합니다. 비동기 메서드는 (값을) 즉시 반환하며, 응답을 기다리지 않고 제어 권한을 호출 스레드에 넘겨줍니다.

비동기 메서드는 응답이 제공되기 전에 (값을) 반환하므로 준비되었을 때 응답을 가져올 방법이 필요합니다. 2.x의 비동기 클라이언트에 대한 메서드는 준비가 되면 응답에 액세스할 수 있도록 하는 CompletableFuture 객체를 AWS SDK for Java 반환합니다.

비 스트리밍 작업

비 스트리밍 작업에서 비동기 메서드 호출은 동기 메서드와 유사합니다. 하지만 이 비동기 메서드는 향후의 비동기 작업 결과를 포함하는 CompletableFuture객체를 AWS SDK for Java 반환합니다.

결과를 사용할 수 있을 때 완료하는 작업을 사용하여 CompletableFuture whenComplete() 메서드를 호출합니다. CompletableFutureget() 메서드를 호출하여 응답 객체를 가져올 수 있도록 Future 인터페이스를 구현합니다.

다음은 객체를 저장할 수 있는 Amazon DynamoDB 함수를 수신하여 테이블 목록을 가져오는 비동기 작업의 예입니다. CompletableFuture ListTablesResponse 비동기식 호출이 완료된 경우에만 whenComplete()에 대한 호출에서 정의한 작업을 수행할 수 있습니다.

가져오기

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; import java.util.List; import java.util.concurrent.CompletableFuture;

코드

public class DynamoDBAsyncListTables { public static void main(String[] args) throws InterruptedException { // Create the DynamoDbAsyncClient object Region region = Region.US_EAST_1; DynamoDbAsyncClient client = DynamoDbAsyncClient.builder() .region(region) .build(); listTables(client); } public static void listTables(DynamoDbAsyncClient client) { CompletableFuture<ListTablesResponse> response = client.listTables(ListTablesRequest.builder() .build()); // Map the response to another CompletableFuture containing just the table names CompletableFuture<List<String>> tableNames = response.thenApply(ListTablesResponse::tableNames); // When future is complete (either successfully or in error) handle the response tableNames.whenComplete((tables, err) -> { try { if (tables != null) { tables.forEach(System.out::println); } else { // Handle error err.printStackTrace(); } } finally { // Lets the application shut down. Only close the client when you are completely done with it. client.close(); } }); tableNames.join(); } }

다음 코드 예제에서는 비동기식 클라이언트를 사용하여 테이블에서 항목을 검색하는 방법을 보여 줍니다. 의 getItem 메서드를 DynamoDbAsyncClient 호출하여 원하는 항목의 테이블 이름과 기본 키 값을 가진 GetItemRequest객체를 전달합니다. 일반적으로 이 방식으로 작업에 필요한 데이터를 전달합니다. 이 예에서는 문자열 값이 전달되는 것을 알 수 있습니다.

가져오기

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; import software.amazon.awssdk.services.dynamodb.model.AttributeValue; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;

코드

public static void getItem(DynamoDbAsyncClient client, String tableName, String key, String keyVal) { HashMap<String, AttributeValue> keyToGet = new HashMap<String, AttributeValue>(); keyToGet.put(key, AttributeValue.builder() .s(keyVal).build()); try { // Create a GetItemRequest instance GetItemRequest request = GetItemRequest.builder() .key(keyToGet) .tableName(tableName) .build(); // Invoke the DynamoDbAsyncClient object's getItem java.util.Collection<AttributeValue> returnedItem = client.getItem(request).join().item().values(); // Convert Set to Map Map<String, AttributeValue> map = returnedItem.stream().collect(Collectors.toMap(AttributeValue::s, s->s)); Set<String> keys = map.keySet(); for (String sinKey : keys) { System.out.format("%s: %s\n", sinKey, map.get(sinKey).toString()); } } catch (DynamoDbException e) { System.err.println(e.getMessage()); System.exit(1); }

전체 예제를 참조하십시오. GitHub

스트리밍 작업

스트리밍 작업의 경우 콘텐츠를 점진적으로 제공하려면 AsyncRequestBody를 제공하고 응답을 수신하고 AsyncResponseTransformer처리하려면 a를 제공해야 합니다.

다음 예제에서는 작업을 사용하여 파일을 Amazon S3 비동기적으로 업로드합니다. PutObject

가져오기

import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

코드

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncOps <bucketName> <key> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " key - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String key = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(key) .build(); // Put the object into the bucket CompletableFuture<PutObjectResponse> future = client.putObject(objectRequest, AsyncRequestBody.fromFile(Paths.get(path)) ); future.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object uploaded. Details: " + resp); } else { // Handle error err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); future.join(); } }

다음 예제에서는 작업을 사용하여 Amazon S3 비동기적으로 파일을 가져옵니다. GetObject

가져오기

import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

코드

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncStreamOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncStreamOps <bucketName> <objectKey> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " objectKey - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String objectKey = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); GetObjectRequest objectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(objectKey) .build(); CompletableFuture<GetObjectResponse> futureGet = client.getObject(objectRequest, AsyncResponseTransformer.toFile(Paths.get(path))); futureGet.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object downloaded. Details: "+resp); } else { err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); futureGet.join(); } }

고급 작업

AWS SDK for Java 2.x는 비동기 이벤트 기반 네트워크 응용 프로그램 프레임워크인 Netty를 사용하여 I/O 스레드를 처리합니다. AWS SDK for Java 2.x는 클라이언트 요청에서 Netty 클라이언트로 반환된 퓨처를 완료하기 위해 Netty를 ExecutorService 뒷받침합니다. HTTP 이러한 추상화는 개발자가 스레드 중지 또는 대기를 선택하는 경우 애플리케이션이 비동기 프로세스를 차단하는 위험을 줄여줍니다. 기본적으로 각 비동기 클라이언트는 프로세서 수에 따라 스레드 풀을 만들고 ExecutorService 내에서 대기열의 작업을 관리합니다.

고급 사용자는 빌드 시 다음 옵션을 사용하여 비동기 클라이언트를 만들 때 스레드 풀 크기를 지정할 수 있습니다.

코드

S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, Executors.newFixedThreadPool(10) ) ) .build();

성능을 최적화하려면 자체의 스레드 풀 실행기를 관리하고 클라이언트를 구성할 때 이를 포함시킬 수 있습니다.

ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(<custom_value>), new ThreadFactoryBuilder() .threadNamePrefix("sdk-async-response").build()); // Allow idle core threads to time out executor.allowCoreThreadTimeOut(true); S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, executor ) ) .build();