Capstone-F5

MSA 구조에서 서버간 통신 방법

신입 개발자 박상우의 개발자 도전기 2024. 12. 2. 12:24
마이크로서비스 구조에서 서버 간 통신 방법

마이크로서비스 구조에서 서버 간 통신 방법

1. 개요

마이크로서비스 아키텍처(MSA)에서는 각 서비스가 독립적으로 분리되어 운영된다. 반면, 모든 서비스가 하나의 프로젝트에 담겨 있는 모놀리틱 아키텍처에서는 값 조회가 비교적 간단하다.

MSA에서는 특정 값이 내 서버에 존재하지 않을 경우, 다른 서버에서 값을 가져와 사용하는 일이 빈번히 발생한다. 이번 프로젝트에서는 서버 간 데이터를 POST, GET 방식으로 주고받는 방법을 설명한다.

2. 서버 간 값 조회 예제

public Long getDesigner(Long id) {
    // ACCOUNT-SERVER에서 서비스 인스턴스를 가져온다.
    List instances = discoveryClient.getInstances("ACCOUNT-SERVER");
    if (instances == null || instances.isEmpty()) {
        throw new IllegalStateException("No Account-Server instances available");
    }

    // 무작위 인스턴스 선택
    ServiceInstance accountService = instances.get(new Random().nextInt(instances.size()));

    // URI 빌드
    URI uri = UriComponentsBuilder.fromUri(accountService.getUri())
            .path("/api/account/designer/get-designer/{id}")
            .buildAndExpand(id)
            .toUri();

    // HTTP 요청 헤더 설정
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity httpEntity = new HttpEntity<>(headers);

    try {
        // GET 요청 실행
        ResponseEntity response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, Map.class);

        if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
            Map responseBody = response.getBody();

            // 디자이너 인덱스 추출 (JSON의 'id' 필드 또는 'index' 필드로 가정)
            Object index = responseBody.get("id"); // 또는 responseBody.get("index");

            if (index != null) {
                return Long.valueOf(index.toString()); // 인덱스를 Long으로 변환하여 반환
            } else {
                throw new IllegalStateException("Designer index not found in response.");
            }
        } else {
            throw new IllegalStateException("Failed to get designer information.");
        }
    } catch (Exception e) {
        throw new IllegalStateException("Failed to send request to Account-Server", e);
    }
}

3. 코드 분석

3.1 서비스 인스턴스 가져오기

List instances = discoveryClient.getInstances("ACCOUNT-SERVER");

유레카(Eureka) 서버를 통해 ACCOUNT-SERVER라는 이름을 가진 서비스의 모든 인스턴스를 가져온다. MSA 환경에서는 같은 서비스가 여러 인스턴스로 실행될 수 있으므로, 유레카에서 인스턴스 목록을 조회한다.

3.2 인스턴스 존재 여부 확인

if (instances == null || instances.isEmpty()) {
    throw new IllegalStateException("No Account-Server instances available");
}

만약 ACCOUNT-SERVER 인스턴스가 없다면 예외를 발생시킨다. 이는 네트워크 연결 문제 또는 서버 실행 여부를 확인할 때 유용하다.

3.3 무작위 인스턴스 선택

ServiceInstance accountService = instances.get(new Random().nextInt(instances.size()));

여러 인스턴스 중 하나를 무작위로 선택합니다. 이는 간단한 로드 밸런싱 방식으로, 부하를 분산시키는 데 유용하다.

3.4 URI 빌드

URI uri = UriComponentsBuilder.fromUri(accountService.getUri())
    .path("/api/account/designer/get-designer/{id}")
    .buildAndExpand(id)
    .toUri();

선택된 서비스 인스턴스의 URI를 기반으로 GET 요청을 보낼 API 엔드포인트를 생성한다. id 값을 경로 변수로 추가한다.

3.5 HTTP 요청 헤더 설정

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity<>(headers);

요청의 헤더를 설정합니다. JSON 형식으로 데이터를 주고받기 위해 Content-Typeapplication/json으로 설정한다.

3.6 GET 요청 실행

ResponseEntity response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, Map.class);

RestTemplate를 사용하여 다른 서버에 GET 요청을 보낸다. 응답은 ResponseEntity 객체로 받는다.

3.7 응답 데이터 처리

Map responseBody = response.getBody();
Object index = responseBody.get("id");
return Long.valueOf(index.toString());

응답 데이터에서 id 값을 추출하여 Long 형식으로 반환한다. 이는 다른 서버에서 디자이너 정보를 성공적으로 가져왔음을 의미한다.

4. 결론

MSA 환경에서는 각 서버가 독립적으로 동작하기 때문에 필요한 데이터를 가져오기 위해 서버 간 통신이 중요하다. 위 코드는 유레카 서버를 통해 서비스 인스턴스를 조회하고, RestTemplate를 사용해 데이터를 요청하는 과정을 보여준다.

이 방법은 서버 간 데이터를 안전하고 효율적으로 주고받는 데 유용하며, 네트워크 장애나 데이터 누락 같은 문제를 해결할 수 있다.