문제 상황
기존 방식대로 Spring WebFlux 에서 HTTP Client로 사용되는 비동기적으로 작동하는 모듈인 WebClient를 활용하여 SageMaker 엔드포인트에 POST 요청을 시도했다.
그런데 CloudWatch에서 요청 시도에 대한 로깅은 찍히는데, 웹서버로 리턴이 들어오지 않는 상황이었다.
알고 보니, AWS SageMaker는 사용하는 IAM에 대한 정보를 바탕으로 AWS Signature를 Header에 담아 전송해야하는 것이었다.
이를 해결하기 위해 Spring에서는 aws sagemaker-runner 라이브러리를 사용해야 한다.
해결
1. build.gradle에 다음과 같은 라이브러리를 추가한다.
implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.4'
implementation 'com.amazonaws:aws-java-sdk-sagemakerruntime:1.12.762'
2. SageMaker Runtime을 위한 Configuration을 등록한다.
package conference.clerker.global.aws;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntime;
import com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntimeClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AmazonSageMakerRuntimeConfig {
// AWS 자격 증명 및 리전 설정
@Value("${other.aws.access-key}")
private String accessKey;
@Value("${other.aws.secret-key}")
private String secretKey;
@Value("${other.aws.region}")
private String awsRegion;
@Bean
public AmazonSageMakerRuntime amazonSageMakerRuntime() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
// 클라이언트 구성 설정
ClientConfiguration clientConfig = new ClientConfiguration()
.withConnectionTimeout(10_000) // 연결 타임아웃 설정 (예: 10초)
.withSocketTimeout(300_000) // 소켓 타임아웃 설정 (예: 5분)
.withMaxErrorRetry(0); // 자동 재시도 비활성화
return AmazonSageMakerRuntimeClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withClientConfiguration(clientConfig)
.withRegion(awsRegion)
.build();
}
}
3. SageMaker에 invoke 메서드를 활용하여 요청을 보내고 응답을 리턴한다.
@RestController
@RequiredArgsConstructor
public class ConnectToSageMakerEndpoint {
private final AmazonSageMakerRuntime amazonSageMakerRuntime;
@PostMapping("/invoke-sagemaker")
public String invokeModelServerAsync(ModelRequestDTO modelRequestDTO) {
try {
ObjectMapper objectMapper = new ObjectMapper();
String payload = objectMapper.writeValueAsString(modelRequestDTO);
InvokeEndpointRequest invokeEndpointRequest = new InvokeEndpointRequest()
.withEndpointName(endpointName) // endpointName 직접 주입
.withContentType("application/json")
.withBody(ByteBuffer.wrap(payload.getBytes(StandardCharsets.UTF_8)));
InvokeEndpointResult invokeEndpointResult = sagemakerRuntimeClient.invokeEndpoint(invokeEndpointRequest);
return new String(invokeEndpointResult.getBody().array());
} catch (Exception e) {
log.error("모델 서버 호출 중 오류 발생: {}", e.getMessage(), e);
}
}
}
참고
https://docs.aws.amazon.com/ko_kr/sagemaker/latest/dg/serverless-endpoints-invoke.html
서버리스 엔드포인트 호출 - Amazon SageMaker
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
Calling SageMaker Runtime Endpoint using SpringBoot and Java
Hey NetHeads!! off-late, I have been working on AWS Sagemaker to deploy and serve Machine Learning models. While scratching my head to…
dummybot.medium.com
'Back-end > Spring' 카테고리의 다른 글
[Spring] Private 메서드에 @Transactional 선언 시 트랜잭션이 동작하는가? (0) | 2025.01.16 |
---|---|
[Spring] Spring Data JPA에서 새로운 Entity인지 판단하는 방법? (1) | 2024.12.08 |
[Spring] self-hosted Runner를 통한 CI/CD 배포 (0) | 2024.11.21 |
[Spring] @RequestPart vs @RequestParam vs @RequestBody (1) | 2024.10.11 |
[Spring] Spring Boot에서 Google Meet API 적용해보기 (10) | 2024.10.06 |