🔎 MSA(MicroService Architecture)란?
여러 개의 작은 서비스로 구성되어 각 서비스가 독립적으로 개발되고 배포되는 구조
→ 전체 시스템이 분산되어 있어 개발, 배포가 독립적으로 가능하며 확장성과 유지 관리가 용이하다
우리 프로젝트에서는 회원, 감정 분석 - 주류 추천, 주류 리뷰 관리 이렇게 총 3가지로 구분하였다
+ 각 서비스마다 독립적인 DB!
🔎 Netflix OSS Eureka Server
✅ Spring Cloud Netflix
스프링 부트 애플리케이션에 대한 통합 환경 구성을 지원하는 Netflix의 OSS 서비스
✅ Eureka
Netflix OSS 서비스 중 하나로 각각의 서비스 인스턴스들이 동적으로 확장, 축소 되더라도 인스턴스의 상태를 하나의 서비스로 관리할 수 있는 서비스
최초에는 모든 서비스가 Spring Cloud에 의해서 관리되었지만 현재는 몇몇 기술들을 재구성 혹은 발전시키거나 독립적인 서비스로 진화시켜 기존의 서비스들은 Maintenance 모드로 들어간 것들이 존재한다
* Maintenance : 모듈을 유지 보수 모드로 전환하면 Spring-Cloud 팀이 더 이상 모듈에 새 기능을 추가하지 않게 된다
<구성>
Eureka는 Eureka Server와 Eureka Client로 구성된다
- Eureka Server : Eureka Client에 해당하는 마이크로서비스들의 상태 정보가 등록되어 있는 레지스트리를 갖는다
- Eureka Client : 서비스가 시작될 때 Eureka Server에 자신의 정보를 등록한다. 등록된 후에는 30초마다 레지스트리에 ping을 전송하여 자신이 가용 상태임을 알리는데 일정 횟수 이상 ping이 확인되지 않으면 Eureka Server에서 해당 서비스를 레지스트리에서 제외시킨다
<프로젝트에 적용하기>
1. Service Discovery Sever 프로젝트 생성
이때, 아래와 같이 dependency 창에서 Eureka Server를 추가한다
2. eureka 서버의 application.yml 파일 추가
spring:
application:
name: eureka
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- register-with-eureka : 유레카 서비스 등록 여부
- fetch-registry : 레지스트리 정보 캐싱 여부
3. @EnableEurekaServer 어노테이션 추가
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
4. 게이트웨이 서비스 생성
이때, 아래와 같이 dependency 창에서 Gateway를 추가한다 + Eureka Discovery Client도 추가
5. 게이트웨이 서비스 프로젝트의 application.yml 작성
eureka:
instance:
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka/
- prefer-ip-address : 유레카 서비스 등록 여부
- register-with-eureka : 레지스트리에 자신을 등록할 것인지에 대한 여부
- fetch-registry : 레지스트리에 있는 정보를 가져올 것인지에 대한 여부
6. 게이트웨이 서비스 프로젝트에도 동일하게 @EnableEurekaServer 어노테이션 추가해야 한다
7. Eureka Server에 Service 등록
Service 프로젝트 생성 후 Eureka Discovery Client 추가
(Spring Web도 추가해야 한다)
8. 서비스 프로젝트의 application.yml 파일 작성
eureka:
instance:
prefer-ip-address: true
lease-renewal-interval-in-seconds: 30
client:
registry-fetch-interval-seconds: 30
disable-delta: true
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka/
- registry-fetch-interval-seconds : 레지스트리 정보 캐싱 여부
- disable-delta : 유레카 서버에게 서비스 정보를 가져올 때 변경된 내용만 가지고 오는 것에 대한 여부
9. 서비스 프로젝트에도 동일하게 @EnableEurekaServer 어노테이션 추가해야 한다
📢 요청 보내기
http://localhost:9000/auth/login으로 요청하면 게이트웨이 서비스가 이를 auth 서비스의 /login 경로로 라우팅한다
auth 서비스의 경우 게이트웨이에서 필터를 추가하지 않았기 때문에 따로 인증처리는 진행되지 않는다
🔎 필터 추가하기
API Gateway는 API 서버 앞단에서 모든 API 서버들의 엔드포인트를 단일화 해주는 또 다른 서버이다
API에 대한 인증과 인가 기능을 가지고 있으며 메시지의 내용에 따라 애플리케이션 내부에 있는 마이크로 서비스로 라우팅하는 역할을 한다
→ 이때 Filter 기능을 통해 조건을 분기한다
gateway:
routes:
- id: auth
uri: http://localhost:8090/
predicates:
- Path=/auth/**
- id: analyze
uri: http://localhost:8091/
predicates:
- Path=/analyze/**
filters:
- name: AuthorizationHeaderFilter
라우팅 설정 아래에 filters를 추가하여 일반 커스텀 필터(AuthorizationHeaderFilter)를 적용하였다
auth 서비스의 경우에는 인증 요청을 진행하지 않으며 analyze 서비스에 대해 인증을 진행하게 된다
@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {
public AuthorizationHeaderFilter() {
super(Config.class);
}
public static class Config {
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
};
}
}
AuthorizationHeaderFilter에는 jwt 토큰을 검증하는 코드를 구현하였다
🔎 서비스 간 통신은 어떻게?
우리 프로젝트에서는 회원이 주류 리뷰를 남길 때 해당 회원의 정보가 필요한데 주류 리뷰 서비스와 회원 서비스가 분리되어 있기 때문에 MSA간의 통신을 기반으로 데이터를 가져와야 했다
1️⃣ RestTemplate
HTTP 통신을 기반으로 다른 MSA에 요청을 날리고 얻어온 응답을 활용하는 방식이다
2️⃣ FeignClient
Feign은 서비스 간 통신을 구현할 수 있도록 도와주는 라이브러리이다
내부적으로 HTTP 통신 코드를 자동으로 생성해준다
인터페이스를 정의하고 메서드를 추가하여 RESTful 서비스 간의 통신을 직접 정의하지 않고 인터페이스 형태로 사용이 가능하다
(우리 프로젝트에서는 FeginClient를 사용하였다)
@FeignClient(name = "auth-service", url = "http://sunjoo-server-auth-spring-1:8090")
public interface UserClient {
@GetMapping("/auth/userinfo")
UserInfoResponse getUserInfo(@RequestHeader("Authorization") String token);
}
따로 UserClinet 클래스 생성 후 위와 같은 코드를 작성한다
name에는 다른 MSA의 이름을 적어주고 컨트롤러를 작성하는 것과 유사하게 GET으로 auth-service의 /auth/userinfo로 요청을 정의하고 요청 헤더에 토큰을 추가해주었다
'프로젝트 내용 정리 > Sunjoo' 카테고리의 다른 글
[CORS] CORS란? CORS 에러 해결! (0) | 2024.06.30 |
---|