MicroService Architecture (MSA)
마이크로서비스 아키텍처를 알아보자면 마이크로서비스란 작고, 독립적으로 배포 가능한 각각의 기능을 수행하는 서비스로 구성된 프레임워크라고 할 수 있습니다. 마이크로서비스는 완전히 독립적으로 배포가 가능하고, 다른 기술 스택(개발 언어, 데이터베이스 등)이 사용 가능합니다!!
특히나 최근들어 도메인 중심으로 돌아가고 있기때문에
MSA가 주목받고 있는 이유중 하나인것 같습니다.
프로젝트 규모가 작으면 필요성을 그닥 못느끼겠지만
규모가 커지면 커질수록 MSA의 중요성이 커지는 것 같습니다.
특히나 모든 기능을 하나의 서비스가 다 맡아버리면 서버와 성능이 부하가 심하기때문에
서비스 분리는 선택이 아닌 필수가 아닐까 라고 생각이 듭니다.
배포
서비스 별 개별 배포 가능 ( 무중단 배포의 장점 )
확장
특정 서비스에 대한 확장성이 용이함.
클라우드 사용에 적합한 아키텍쳐.
장애
장애가 전체 서비스로 확장될 가능성이 적음
부분적 장애에 대한 격리가 수월함
스프링에서는 MSA를 구축할 수 있도록 환경을 제공해주는 프로젝트가 있는데
바로 Spring Cloud 입니다.
Spring Cloud Netflix Zuul (API Gateway)
Spring Cloud Netflix Eureka는 Microservices 앞 단에 위치하는 API Gateway로, 클라이언트의 호출을 받아 뒷 단의 Microservices에게 전달합니다. 모든 Service들이 처리해야하는 공통 코드를 처리합니다. ( 라우팅, 필터 등등 )
Spring Cloud Config
Spring Cloud Config는 설정 외부화를 위한 프로젝트로, 설정 정보를 저장하고 제공하는 서버를 구축합니다. 각 클라이언트는 설정 서버로부터 설정 정보를 조회합니다.
Miscroservices
실제 서비스(도메인)를 제공하는 서버 ( 스프링 부트 )
Spring Cloud Netflix Eureka
Spring Cloud Netflix Eureka는 Service Discovery Pattern을 위한 프로젝트로, Eureka Server와 Eureka Client로 구성되어 있다. (로드 밸런싱, 장애 조치 등등)
Spring Cloud Netflix Hystrix
MSA 환경에서는 장애가 큰 이슈가 되기도 한다.
Spring Cloud Netflix Hystrix는 장애가 일어났을 때, 한 서비스의 장애가 다른 서비스로 전파되지 않도록 사전에 차단해주는 것이다.
Spring Cloud Stream 또는 kafka 또는 RabbitMQ
MSA에서는 Event driven 아키텍처를 많이 권장하는데 서비스간의 결합도를 많이 줄일 수 있기 때문입니다.
Spring Cloud Stream는 Event driven MSA를 구축하기 위한 프로젝트로,
코드 즉 비즈니스 로직을 거의 변경하지 않고 의존성과 설정의 변경만으로 쉽게 연동할 수 있는 프로젝트를 제공해줍니다.
또한 마이크로 서비스들 사이의 통신을 비동기적으로 도와주는 메세지 큐인 kafka 와 RabbitMQ가 Spring Cloud Stream과 같이 자주 쓰입니다.
일단 MSA 전체 구성요소를 전부 구축하려면 시간이 소요되니 간단한 Config 서버만 구축을 해보았습니다.
먼저 서버를 구축하기 전에 Config 파일을 Github 저장소에 올려둘게요.
프로파일 별로 올려봤습니다.
스프링 사이트에서 Config Server 의존성을 추가하고 다운을 받아봅시다.
@SpringBootApplication
@EnableConfigServer // 이부분만 추가 하면 끝!
public class SpringConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringConfigServerApplication.class, args);
}
}
// application.properties
server.port=8088
spring.cloud.config.server.git.uri=https://github.com/boo105/SpringCloudConfig
다운한 프로젝트의 Application Class에서 @EnableConfigServer
추가해주고
application.properties에서 포트를 8088, Config 설정 파일 올린 uri 를 설정해주면 끝입니다!!!!!!
이렇게 구축하기 쉬운줄 몰랐어요 ㅋㅋㅋㅋㅋㅋㅋ
위에 내용만 설정해줬는데 바로 설정값이 날라오네요 ㅋㅋㅋㅋㅋㅋㅋㅋ
이제 실제 Client 프로젝트를 만들고 거기에 적용을 시켜보겠습니다.
이번에도 spring 사이트에서 Config Client 의존성넣고 만들어봅시다.
(그냥 build.gradle
에다가 의존성 추가해도 되요)
@RestController
public class ConfigController {
private final StaticConfigService configStaticService;
private final DynamicConfigService configDynamicService;
@Autowired
public ConfigController(StaticConfigService configStaticService,
DynamicConfigService configDynamicService) {
this.configStaticService = configStaticService;
this.configDynamicService = configDynamicService;
}
@GetMapping(value = "/static")
public Object getConfigFromStatic() {
return configStaticService.getConfig();
}
@GetMapping(value = "/dynamic")
public Object getConfigFromDynamic() {
return configDynamicService.getConfig();
}
}
@Service
public class StaticConfigService {
@Value("${my.name}")
private String name;
@Value("${my.age}")
private String age;
public Map<String, String> getConfig() {
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
return map;
}
}
@Service
@RefreshScope // 차이점이라고는 이 어노테이션 단 하나!!!
public class DynamicConfigService {
@Value("${my.name}")
private String name;
@Value("${my.age}")
private String age;
public Map<String, String> getConfig() {
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
return map;
}
}
// application.properties
spring.profiles.active=dev
spring.config.import=optional:configserver:http://localhost:8088
// 나중에 Config 변경 된거 갱신 요청하기 위해 씀
management.endpoints.web.exposure.include=refresh
Dynamic 과 Static의 차이점은 Config가 변경이 되었을때
프로젝트를 다시 빌드, 배포를 하지 않더라도 변경된 Config 설정을 읽어올수 있다는 차이점이 있습니다.
위에 처럼 Client 프로젝트를 구축하고 실행하여 확인해보겠습니다.
Config 변경 전
GET /static
, GET /dynamic
Config 변경 전이므로 둘다 똑같은 설정 값을 불러옵니다.
Config 변경 후
Github에 저장된 Config를 변경을 하고 Request를 해봤지만
엥? 전혀 변경되지 않았습니다.
알고 봤더니 POST "http://localhost:8080/actuator/refresh"
로
변경된 Config를 갱신해주세요~~ 라고 요청을 해야지 변경된 값이 읽어와진다고 하였습니다.
하지만 이 요청을 하려면 먼저 의존성에
implementation 'org.springframework.boot:spring-boot-starter-actuator'
이것을 추가해주시고
요청을 해주시면 이러한 Response가 날아옵니다.
그 이후 다시 Config를 Request를 해주면
두두두둥!!! 빌드, 배포를 다시 안하고!!! 프로그램을 다시 실행안해도
변경된 Config 설정 값이 읽어졌습니다!!!!!!!!!!
아 참고로 GET /static
은 변경 전 Config를 불러옵니다.
GET /dynamic
만 변경 된 Config를 불러오니 유의하시길 바랍니다.
이상으로 Config Server 구축을 하고 Client 까지 만들어서 테스트를 해봤는데
매우 매우 간단하게 구축했는데 불러와지는걸 보고 너무 기쁘고 재미있네요 ㅋㅋㅋ
예제 코드
MSA의 구조가 복잡해 보였는데 제대로 이해하고 나니까 생각외로 쉬운 구조였다고 생각합니다.
다만 실제로 구축하기에는 어느정도 물리적인 자원과 시간이 필요할것같아서
구축 자체는 쉽지 않을것같습니다.
Config Server는 매우 매우 간단하게 구축에 성공했는데
나머지 구성요소들도 구축이 간단할지 모르겠네요 ㅎㅎㅎ
하지만 나중에 시간이 된다면 차츰 MSA 전체를 구축할것 같습니다.