- 먼저 서비스를 키려면
- config-server를 켜야 yml파일을 읽어올수 있음
- docker의 rabbit mq 도 켜야함
- user-service에서 orders를 order_service에 요청해서 받아오기

@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findByUserId(userId);
if(userEntity==null){
throw new UsernameNotFoundException("User not found");
}
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
// ArrayList<ResponseOrder> orders = new ArrayList<>();
/* Using RestTemplate */
String orderUrl = String.format(env.getProperty("order_service.url"), userId);
ResponseEntity<List<ResponseOrder>> orderResponse =
restTemplate.exchange(orderUrl, GET, null, new ParameterizedTypeReference<List<ResponseOrder>>() {
});
List<ResponseOrder> orderList = orderResponse.getBody();
userDto.setOrders(orderList);
return userDto;
}
- rest template bean을 등록해야함


* 단점
- 해결 : 유레카 서비스에 동록되어있는 서비스이름으로 바꾸면 됨
- port변경, ip 변경에도 대비 가능함


RestTemplate과 Eureka Server의 작동 원리를 설명해드리겠습니다:
1. Eureka 서비스 디스커버리 작동 원리
[User Service] <----> [Eureka Server] <----> [Order Service]
↑ ↑
| |
등록/조회 등록/조회
- 서비스 등록 과정:
// 각 서비스는 시작 시 Eureka Server에 자신의 정보를 등록 OrderService -> Eureka Server: "나는 order-service이고 localhost:8000에서 실행 중" UserService -> Eureka Server: "나는 user-service이고 localhost:8001에서 실행 중"
- 서비스 조회 과정:
// 서비스가 다른 서비스를 호출할 때 UserService -> Eureka Server: "order-service의 위치를 알려주세요" Eureka Server -> UserService: "order-service는 localhost:8000입니다"
2. @LoadBalanced RestTemplate 작동 원리
@LoadBalanced
RestTemplate restTemplate;
// http://ORDER-SERVICE/order-service/%s/orders 호출 시
1. "ORDER-SERVICE" 를 실제 호스트로 변환 필요
2. Eureka Server에서 서비스 위치 조회
3. 실제 호출: http://localhost:8000/order-service/%s/orders
3. 전체 통신 흐름
1. User Service 시작
- Eureka Server에 등록
- 서비스 이름: user-service
- 위치: localhost:8001
2. Order Service 시작
- Eureka Server에 등록
- 서비스 이름: order-service
- 위치: localhost:8000
3. RestTemplate 호출 시
UserService -> EurekaServer: "ORDER-SERVICE 위치 요청"
EurekaServer -> UserService: "localhost:8000 응답"
UserService -> OrderService: "localhost:8000으로 실제 API 호출"
4. 로드밸런싱
// 여러 인스턴스가 있을 경우
OrderService1: localhost:8000
OrderService2: localhost:8001
OrderService3: localhost:8002
@LoadBalanced RestTemplate은 자동으로 부하 분산:
- Round Robin (기본)
- 가중치 기반
- 최소 연결 수
5. 실제 코드에서의 동작
// 1. 서비스 등록 (application.yml)
spring:
application:
name: order-service // Eureka에 등록될 이름
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
// 2. 서비스 호출 (UserServiceImpl.java)
String orderUrl = String.format(env.getProperty("order_service.url"), userId);
// ORDER-SERVICE는 Eureka를 통해 실제 호스트:포트로 변환됨
// http://ORDER-SERVICE/order-service/123/orders
// -> http://localhost:8000/order-service/123/orders
RestTemplate restTemplate;
ResponseEntity<List<ResponseOrder>> response =
restTemplate.exchange(orderUrl, HttpMethod.GET, null,
new ParameterizedTypeReference<List<ResponseOrder>>() {});
6. 고가용성 지원
// 여러 서비스 인스턴스 실행 시
OrderService (instance 1) - port 8000
OrderService (instance 2) - port 8001
// @LoadBalanced RestTemplate이 자동으로:
1. 서비스 디스커버리
2. 로드 밸런싱
3. 장애 극복
이해하기 쉽게 정리하면:
- 모든 서비스는 Eureka Server에 자신을 등록
- 서비스 간 통신 시 서비스 이름 사용
- @LoadBalanced RestTemplate이 서비스 이름을 실제 주소로 변환
- 자동 로드밸런싱으로 여러 인스턴스에 요청 분산
* 오류
- restTemplate에서 404 에러가뜸
- 의심 : ORDER-SERVICE를 localhost로 못바꾸는거 아닌가? -> 아님
- url 패턴을 아래와같이 수정시 잘 작동함
String testUrl = "http://ORDER-SERVICE/health_check"; // URL 패턴 수정
- 원인분석
API Gateway의 라우팅 설정에는 보통 다음과 같이 /order-service/**
패턴이 포함되어 있을 것입니다:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://ORDER-SERVICE
predicates:
- Path=/order-service/**
서비스 간 직접 통신(RestTemplate)과 API Gateway를 통한 통신의 차이:
- API Gateway 통해서 호출할 때:
Client -> http://gateway:8000/order-service/{userId}/orders
- Gateway가
/order-service
를 보고 ORDER-SERVICE로 라우팅
- 서비스 간 직접 통신할 때:
UserService -> http://ORDER-SERVICE/{userId}/orders
- OrderController의 매핑 구조를 직접 따라야 함
- Gateway의 라우팅 규칙이 적용되지 않음
그래서 직접 통신할 때는 Gateway의 라우팅 규칙이 아닌, 실제 OrderController의 매핑 구조를 따라야 합니다.
네, 맞습니다. 마이크로서비스 간 내부 통신에서 RestTemplate을 사용할 때는 API Gateway를 거치지 않고 서비스를 직접 호출합니다.
작동 흐름을 보면:
- 외부 요청 (API Gateway 경유)
Client -> API Gateway (8000) -> 각 서비스 http://gateway:8000/order-service/** -> Order Service
- 내부 서비스 간 통신 (API Gateway 미경유)
User Service -> Order Service (직접 통신) http://ORDER-SERVICE/** -> Order Service
이렇게 설계된 이유:
- 성능 최적화 - 불필요한 게이트웨이 홉(hop) 제거
- 내부 통신의 단순화
- 불필요한 오버헤드 방지
그래서 RestTemplate로 내부 호출 시에는 OrderController의 실제 엔드포인트 매핑을 따라야 하고, API Gateway의 라우팅 규칙은 고려하지 않아도 됩니다.
* 결론

- 이게 http:localhost:order-service포트번호 로 변환된다.
'Java > Spring-Cloud' 카테고리의 다른 글
[스프링 msa] 대칭키를 이용한 암호화 (0) | 2025.02.11 |
---|---|
[Spring] spring cloud bus 써보기 (0) | 2025.02.04 |