- 스프링5의 WebFlux 사용
- RabbitMQ와 같은 메시징 서버 사용 (비동기 상호작용에 사용)
- Mono를 reponse body로 반환 -> 비동기 논블록킹 모드에서 mono가 일을 마친후에 Greet객체가 직렬화되는 것
- 리액티브 스트림의 이행
- 발행자, 구독자, 구독, 프로세서
- 리액터에는 발행자 프로세서로 사용되는 두 개의 구현체가 있음 -> Flux와 Mono
Mono는 0-1개의 결과만을 처리하기 위한 Reactor의 객체이고, Flux는 0-N개인 여러 개의 결과를 처리하는 객체입니다. Reactor를 사용해 일련의 스트림을 코드로 작성하다 보면 보통 여러 스트림을 하나의 결과를 모아줄 때 Mono를 쓰고, 각각의 Mono를 합쳐서 여러 개의 값을 여러 개의 값을 처리하는 Flux로 표현할 수도 있습니다. 자세한 설명은 Reactor의 Mono reference와 Flux reference를 읽어 보시면 됩니다. Mono와 Flux모두 Reactive Stream의 Publisher 인터페이스를 구현하고 있으며, Reactor에서 제공하는 풍부한 연산자들(operators)의 조합을 통해 스트림을 표현할 수 있습니다. 예를 들어 Flux에서 하나의 결과로 값을 모아주는 reduce연산자는 Mono를 리턴하고, Mono에서 flatMapMany라는 연산자를 사용하면 하나의 값으로부터 여러 개의 값을 취급하는 Flux를 리턴할 수 있습니다. 그리고 Publisher인터페이스에 정의된 subscribe메서드를 호출함으로써 Mono나 Flux가 동작하도록 할 수 있습니다. 자세한 내용은 예제 코드를 통해 다루도록 하겠습니다.
- 하나의 스트림에서 여러 스트림으로 -> https://tech.kakao.com/2018/05/29/reactor-programming/
클라이언트: 권한부여서버에 요청을 보냄 (authorization) 권한부여서버: 요청검즘, 클라이언트에게 access 토큰을 줌 access 토큰을 사용하여 모든 요청시 검즘 @EnableResourceServer : OAuth2 토큰을 검증하는 보안 필터를 활성화하여 access 토큰을 검증할수 있게 함 @EnableAuthorizationServer : 토큰을 저장하는 인메모리 저장소를 가진 권한 서버 생성 OAuth2RestTemplate 객체 사용 ResourceServerConfigurer, AuthorizationServerConfigurer 수정 필요
@CrossOrigiin method뿐만 아니라 class에도 붙일 수 있음 WebMvcConfigurer 빈을 사용하고 addCorsMappings method를 재정의하면 애플리케이션 전체에 걸쳐 효력을 미치는 CORS를 적용할 수 있음
dump mapping health autoconfig metris
Swagger Springfox : REST API 문서 자동 생성 예제 (p176)
- 자율적 기능
- 배포단위 크기
- 분리하기에 적합한 기능 or 서브도메인
- 폴리글랏 아키텍처
- 선택적 확장
- 애자일 팀과 협력 개발
- 단일 책임
- 복제가능성과 변경 가능성
- 결합과 응집
- 오케스트레이션 방식 - 오케스트레이터가 중앙의 두뇌 역할을 담당하여 서비스들을 모아 조율
- 연출방식 - 중앙두뇌 없음, 이벤트 별로 독립적으로 서로 다른 로직 적용, 지나치게 복잡해지지 않게 조심해야함
기본 원칙은 자율성과 자기 완비성. 이원칙을 준수하기 위해 코드나 라이브러리를 복제해야 할 수도 있다. 공통되는 부분을 별도의 마이크로서비스로 떼어내는것도 가능하지만 효용보다 복잡성 증가 비용이 더 클수도 있다. 여러 서비스에 공통 라이브러리를 복제하는 것은 트레이드오프 관계
많은경우 백엔드의 프록시 역할 API 게이트웨이가 마이크로서비스 마다 있거나 / 공통 API 게이트웨이 사용
기존 서비스 사용자에게 영향을 미치지 않으면서 새로운 서비스 출시 가능 URI 버저닝 미디어 타입 버저닝 커스텀 헤더
정적, 변경될 가능성 없음 -> 하드코딩 공통 마이크로서비스로 구현 -> 모든 서비스가 마스터데이터를 여러번 호출하는 단점 모든 마이크로서비스에 복제 -> 유지복잡. 성능친화. 코드와 데이터가 단순하고 정적인경우 적합 필요한 데이터를 로컬 캐시 -> 데이터 규모에 따라 Ehcache, Hazelcast, Infinispan 등 사용 가능
ex) 과금, 송장, 주문... -> 송장정보와 주문정보가 과금 서비스에 복제되는 방식
- 사전집계: 데이터가 생성될때 사전집계(주문생성-> 과금 마이크로서비스에 이벤트 발송 -> 월별 정산을 위해 내부적으로 계속 데이터 집계 이렇게하면 과금 마이크로서비스가 과금 처리를 위해 외부로 요청을 보낼 필요가 없어지지만, 데이터 중복이 발생함
- 배치: 사전집계가 불가능할때 사용할 수 있음
넷플릭스 OSS에서 유래 self-registration, 동적탐색 및 부하분산(리본사용)
MSA와 같은 분산 환경은 서비스 간의 원격 호출로 구성이 된다. 원격 서비스 호출은 IP 주소와 포트를 이용하는 방식이 되는다. 클라우드 환경이 되면서 서비스가 오토 스케일링등에 의해서 동적으로 생성되거나 컨테이너 기반의 배포로 인해서, 서비스의 IP가 동적으로 변경되는 일이 잦아졌다. 그래서 서비스 클라이언트가 서비스를 호출할때 서비스의 위치 (즉 IP주소와 포트)를 알아낼 수 있는 기능이 필요한데, 이것을 바로 서비스 디스커버리 (Service discovery)라고 한다. Service A의 인스턴스들이 생성이 될때, Service A에 대한 주소를 Service registry (서비스 등록 서버) 에 등록해놓는다. Service A를 호출하고자 하는 클라이언트는 Service registry에 Service A의 주소를 물어보고 등록된 주소를 받아서 그 주소로 서비스를 호출한다.
가장 쉬운 방법으로는 DNS 레코드에 하나의 호스트명에 여러개의 IP를 등록하는 방식으로 구현이 가능하다. 그러나 DNS는 레코드 삭제시 업데이트 되는 시간등이 소요되기 때문에, 그다지 적절한 방법은 아니기 때문에, ZooKeeper나 etcd 와 같은 서비스를 이용할 수 있고 또는 Service discovery에 전문화된 솔루션으로는 Netflix의 Eureka나 Hashcorp의 Consul과 같은 서비스가 있다.
Eureka 서비스에 고가용성을 적용하는 좋은 방법은 여러 대의 eureka 서버를 클러스터링해서 로드밸런서 뒤에 두는 것이다. Eureka 서버는 P2P 방식의 데이터 동기화 메커니즘을 가졌다. 런타임의 상태 정보는 DB에 저장디지 않고 인메모리 캐시에서 관리된다.
게이트웨이 서비스 내부적으로 서비스 탐색을 위해 eureka 서버를 사용하고 서비스 인스턴스 사이의 부하분산을 위해 ribbon을 사용함 클라이언트가 eureka 클라이언트이기도 하면 Zuul은 다른 마이크로서비스와 같이 자신의 서비스ID로 eureka에 자기자신을 등록하고, 클라이언트는 eureka에 등록된 서비스ID를 통해 Zuul 인스턴스에 접근할 수 있다. 클라이언트가 eureka 클라이언트가 아니라면, eureka 서버에 의한 부하분산 처리를 사용할 수 없기 때문에 HAProxy와 같은 로드밸런서 뒤에 위치해 실행한다. 양쪽 경우 모두 마이크로서비스는 eureka 서버를 이용하는 Zuul에 의해 부하문산 처리가 이뤄진다.
클라우드 스트림(리액티브 마이크로서비스를 위함) (p380) 메시지브로커 사용. 스프링 클라우드 스트림은 메시징 추상화 기능을 제공. 실제 메시징 구현체는 RabbitMQ, Kafka일수 있음 클라우드 스트림은 입구(source)와 출구(sink)에서 동작함
마이크로서비스는 독립적인 물리적 장비나 가상머신에서 운영되므로 로그파일은 결국 각 마이크로서비스별로 파편화된다. 따라서 로그파일을 애플리케이션 내부에 저장하지 말고 외부화해야 한다.
로그 스트림(log stream) : 로그 생산자가 만들어내는 로그 메시지의 stream 로그 적재기(log shipper) : ㄹ그 적재기는 로그 메시지의 수집을 담당하여 로그 저장소(log store) : 로그 저장소는 로그 메시지를 저장. ex) hdfs 로그 스트림 처리기 로그 대시보드
logback appenders 사용하여 로그 메시지를 로글리 서비스로 직접 스트리밍
papertrial, logsene, sumo logic, google cloud logging, logentries
Graylog : 로그 저장을 위해 ElasticSearch를 사용하고 저장소로 MongoDB를 사용되는 Splunk : 로그 파일 적재 방식을 사용
로그적재기 로그 스트림 처리기 -> 전통적인 반응 분석에서는 할 수 없었던 어떤 특정한 이벤트 스트림에 반응할 수 있기 때문에 404 오류처리처럼 시급히 처리해야하는 상황에서 유용 Flume과 Kafka를 Storm이나 Spark Streaming과 함께 사용 로그 메시지를 수집하는데 유용한 플룸 어펜더를 통해, 분산된 카프카 메시지 큐에 푸시한다. 스트림 프로세서는 수집된 데이터를 일래스틱서치 및 기타 로그 저장소로 보내기전에 즉시 처리 로그 저장소 실시간 로그 메시지는 일래스틱서치에 저장 -> 클라이언트가 텍스트 기반 인덱스를 바탕으로 쿼리할 수 있음 HDFS는 일반적으로 아카이브된 로그 메시지를 저장하는데 사용 MongoDB나 카산드라는 매월 집계되는 트랜잭션 수와 같은 요약 데이터를 저장하는데 사용
대시보드
사용자 정의 로깅 구현 (p400) 로그스태시, 일래스틱서치, 키바나 조합 ( ELK 스택)
스프링 클라우드 슬루스 -> 분산 로그 추적
히스트리스는 빨리 실패하고 빨리 복구하는 것을 원칙으로 함 서비스에 문제가 있는 경우 히스트릭스가 서비스 격리에 도움을 줌 넷플릭스에서 테스트 된 라이브러리이며 서킷 브레이커 패턴을 바탕으로 함 API 게이트웨이 서비스를 변경해 히스트릭스에 통합 (p416)
파편화된 데이터는 데이터분석을 어렵게 만드는데 이벤트소싱 패턴을 이용하면 잘 처리할 수 있다 ex) 상태가 변경되면 마이크로서비스는 상태변화를 이벤트로 발행, 관련 마이크로서비스들은 이러한 이벤트를 구독하고 요구사항에 맞게 처리할 수 있다. 중앙 이벤트 저장소는 이러한 이벤트를 구독하고 나중에 분석할 수 있게 빅데이터 저장소에 저장할 수 있다. -> 마이크로서비스 -> 이벤트 -> kafka -> flume -> 하둡클러스터
비동기적 알람 ( 이벤트 publish 및 subscribe하여 workflow 유연하게 처리, 각 업무 모듈간 독립적. (이벤트 발행 및 구독)
ex) 현재 시스템에서 잔여석이 1석인데, 여러명의 고객이 동시에 예약하는 시나리오를 처리할때 예약과 목록의 업데이트를 같은 트랙잭션에서 처리하지 않고 이벤트 주도 패턴 (event driven pattern)을 적용한다면 시스템 상태가 불일치하는 결과가 생길 수 있음