[Spring Cloud] Eureka Server 설정 및 MSA 통신 방법

rockstar·2023년 6월 23일

Spring

목록 보기
9/10

Eureka Client Configuration 속성

Discovery Service
등록되어 있으면서, 찾을 수 있는 서비스

register-with-eureka
클라이언트가 자신을 Eureka 서버에 등록할지 여부를 결정

fetch-registry
Eureka서버로부터 인스턴스들의 정보를 주기적으로 가져올 것인지를 설정

Eureka Server 설정

Eureka 서버에서 아래와 같이 설정을 하는 이유는 설정의 기본 값이 true인 반면에, Eureka서버는 Client로 등록하지 않기 때문이다.

eureka:
	client:
		register-with-eureka: false
		fetch-registry: false

Client Server 설정

eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
  client:
    fetch-registry: true
    register-with-eureka: true

Spring Cloud MSA 간 통신

1. RestTemplate

다른 서비스의 RESTful API에 HTTP 요청을 보내고, 응답을 받아올 수 있는 방식의 RestTemplate은 아래와 같이 작성한다.

ResponseEntity<String> response = restTemplate.getForEntity("http://api.example.com/users", String.class);
if (response.getStatusCode().isSuccessful()) {
  String responseBody = response.getBody();
} else {
  throw new Exception(...);
}

2. Feign Client

Interface를 만들고, 호출하고 싶은 MicroService의 이름을 등록해서 호출 가능한 Feign Client는 아래와 같이 작성한다.

유저 서비스 예시 -> 유저가 Order서비스를 가지고 있는 것처럼 사용할 수 있다.
편하게 사용 가능

@FeignClient("order")
public interface OrderClient{
	
    @RequestMapping(method=RequestMethod.GET, value="/order")
    List<Order> getOrder();
 }

기존의 로드밸런싱

Neflix의 Ribbon이라는 서비스를 사용했었지만, 최근 Functional Programming과 잘 맞지 않기 때문에 (비동기처리가 잘 X)그래서 사용을 잘X

Neflix Zuul

Maintaning이 돼서 Spring Cloud 사용

Spring Cloud Custom Filter

  • exchange를 통해서 Request, Response 가져오기
  • 처리가 끝난 후 Post Filter를 추가하여 return
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
		@Override
		public GatewayFilter apply(Config config) {
			return (exchange, chain) -> {
				ServerHttpRequest request = exchange.getRequest();
				ServerHttpResponse response = exchange.getResponse();
				log.info("Custom Pre Filter: Request URI -> {}", request.getId());

				return chain.filter(exchange).then(Mono.fromRunnable(() -> {
					log.info("Custom Post Filter: Response code -> {}", response.getStatusCode());
				}));
			};
		}

기본 Filter Yaml 파일 적용

아래의 방식은 따로 Custom Filter를 만들지 않고 적용하는 방식이다.

spring:
	cloud:
 		gateway:
        	routes:
              - id: user
                uri: http://localhost:8080/
                predicates:
                  - Path=/users/**
                filters:
                  //request와 request-header는 Key, Value의 형태다.
                  -AddRequestHeader=user-request, user-request-header
                  -AddResponseHeader=user-response, user-response-header
              - id: order
                uri: http://localhost:8082/
                predicates:
                  - Path=/orders/**
                filters:
                  //request와 request-header는 Key, Value의 형태다.
                  -AddRequestHeader=order-request, order-request-header
                  -AddResponseHeader=order-response, order-response-header

Custom Filter Yaml 파일 적용

아래의 방식은 Custom Filter을 만든 후 적용하는 방식이다. 인자 값이 없는 Filter

spring:
	cloud:
 		gateway:
        	routes:
              - id: user
                uri: http://localhost:8080/
                predicates:
                  - Path=/users/**
                filters:
                  - CustomFilter
              - id: order
                uri: http://localhost:8082/
                predicates:
                  - Path=/orders/**
                filters:
                  - CustomFilter

Global Filter 적용

아래처럼 default-filters 속성을 사용해서 커스터마이징한 Filter와 Config의 속성들에 값을 넣어주면 되고, 추가적으로 인자 값이 필요하기 때문에 주입해줘야 한다.

Ordered.HIGHEST_PRECEDENCE 또는 Ordered.LOWEST_PRECEDENCE 키워드는 Filter의 순서를 설정해준다. Ordered.HIGHEST_PRECEDENCE은 먼저, Ordered.LOWEST_PRECEDENCE는 가장 나중에 실행이 된다고 생각하면 됨

@Component
@Slf4j
public class LoggingFilter extends AbstractGatewayFilterFactory<LoggingFilter.Config> {

	public LoggingFilter() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		GatewayFilter filter = new OrderedGatewayFilter((exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest();
			ServerHttpResponse response = exchange.getResponse();

			log.info("Logging Filter baseMessage = {}", config.getBaseMessage());

			//Pre Filter
			if (config.preLogger) {
				log.info("Pre Filter Request ID = {}", request.getId());
			}

			//Post Filter
			return chain.filter(exchange).then(Mono.fromRunnable(() -> {
				if (config.postLogger) {
					log.info("Post Filter Response Code = {}", response.getStatusCode());
				}
			}));
		},Ordered.HIGHEST_PRECEDENCE);

		return filter;
	}


	//Config 클래스 static인 것에 주의
	@Data
	public static class Config {
    
    	//아래의 속성들은 application.yml에서 주입
		private String baseMessage;
		private boolean preLogger;
		private boolean postLogger;
	}
}
spring:
  application:
    name: api-gateway
    
  cloud:
    gateway:
      default-filters:
        - name: LoggingFilter
          args:
            baseMessage: Logging Filter
            preLogger: true
            postLogger: true
      routes:
        - id: user
          uri: http://localhost:8080/
          predicates:
            - Path=/users/**


eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}

  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:8761/eureka

0개의 댓글