10. 분리에 따른 몇 가지 이점
• 명시적인 (강제) 언어 경계 à bounded
• 컨텍스트별 독립적인 발전
• 인터페이스에 기반한 컨텍스트 간 통신
10
11. Microservice의 특성
• James Lewis, Martin Fowler에 따르면
– 서비스로서 컴포넌트화
– 비지니스 수행에 따른 구성
– 프로젝트가 아닌 제품
– 똑똑한 엔드포인트와 더미(Dumb) 파이프
– 분산화 거버넌스
– 분산화된 데이터 관리
– 인프라 자동화
– 장애 방지 설계
– 진화하는 설계
11
* http://martinfowler.com/articles/microservices.html
12. 서비스로서 컴포넌트화
• 독립 배포 à 서비스의 응집도(경계) 높아짐
• 명시적 인터페이스 à 공개 인터페이스
12
13. 비지니스 수행에 따른 구성
13
발췌: http://martinfowler.com/articles/microservices.html
23. 이벤트 소싱Event Sourcing
23
* http://martinfowler.com/eaaDev/EventSourcing.html
어플리케이션의 모든 상태 변화를
순서에 따라 이벤트로 보관한다.
Capture all changes to an
application state as a sequence of
events.
24. 도메인 객체와 이벤트 소싱
• 도메인 객체 조회
– 저장한 이벤트로부터 도메인 객체 생성
• 도메인 객체 변경
– 모든 상태 변화에 대한 이벤트를 저장
• 일관성의 기준인 애그리거트Aggregate 단위
24
25. 이벤트 구성
• 구성
– 애그리거트 타입
– 애그리거트 식별자
– 버전
– 이벤트 타입
– 이벤트 시간
– 증분(변경) 내역(payload)
• 이벤트 구분(unique idx)
– 애그리거트 타입, 애그리거트 식별자, 버전
25
27. 애그리거트 조회
• 애그리거트는 이벤트 반영
27
public class Order extends Aggregate {
public void on(OrderPlacedEvent evt) {
this.lines = evt.getOrderLines();
this.shippingInfo = evt.getShippingInfo();
}
public void on(ShippingInfoChangedEventevt) {
this.shippingInfo = evt.getShippingInfo();
}
public void on(ShippedEvent evt) {
this.state = SHIPPED;
}
public abstract class Aggregate {
private Integer version;
public void handle(Event evt) {
this.version = evt.getVersion();
Events.handle(this, evt);
}
}
28. 애그리거트 변경
• 애그리거트에서 이벤트 발생
28
public class Order extends Aggregate {
public void cancel() {
….
OrderCanceledEvent evt =
new OrderCanceledEvent(getId(),
version + 1);
super.apply(evt);
}
public abstract class Aggregate {
List<Event> uncommittedEvents;
public void apply(Event evt) {
addUncommittedEvent(evt);
handle(evt);
}
public List<Event> getUncommittedEvents() {
return uncommittedEvents;
}
29. 애그리거트 변경
• 트랜잭션에서 이벤트 저장
29
public class CancelOrderService {
@Transactional
public void cancel(String orderId) {
Order order =
orderRepository.findById(orderId);
checkNull(order);
order.cancel();
}
}
class TransactionHandler {
public void commit() {
List<Aggregate> aggs = getAllUOW();
for (Aggregate agg : aggs) {
eventStore.append(
agg.getClass(),
agg.getUncomittedEvents()
);
}
}
30. 애그리거트 생성
• 애그리거트 생성자 : 생성 이벤트 발생
30
public class PlaceOrderService {
@Transactional
public void cancel(String orderId) {
Order order = new Order(…);
repository.save(order);
}
}
public class Order extends Aggregate {
public Order(…) {
….
OrderCreatedEvent evt =
new OrderCreatedEvent(
getId(), lines, shippingInfo,
1);
super.apply(evt);
}
31. 이벤트 소싱과 유지보수
• 새로운 데이터 추가
31
public class Order extends Aggregate {
private String note;
public Order(…) {
….
OrderCreatedV2Event evt = new OrderCreatedV2Event(...);
super.apply(evt);
}
public void on(OrderCreatedEvent evt) {
…
this.note = "";
}
public void on(OrderCreatedV2Event evt) {
…
this.note = evt.getNote();
}
없어지는 것
- DB 작업 일정
- 매핑 설정 변경
32. 이벤트 소싱 적용한 애그리거트
• 임피던스 미스매치(impedance mismatch) 없음
• 애그리거트 간 참조는 ID
• 비선점 잠금
32
34. SQL(ORM) vs 이벤트 소싱
• 변화되는 것
34
영역 적용 전 (RDBMS/ORM) 적용 후
도메인 객체 로딩 SQL : SELECT 쿼리
ORM : 프레임워크가 매핑
설정을 이용해서 SELECT 쿼리
실행
- 이벤트로부터 도메인 객체 생성
- 도메인 객체의 이벤트 핸들러를
이용해 상태 변경 반영
도메인 기능 SQL : 서비스 클래스
ORM : (일부) 엔티티 클래스
- 도메인 객체가 수행
- 상태 변경을 위한 이벤트 생성
상태 변경 반영
(데이터 변경)
SQL : Insert/Update/Delete 쿼리
ORM : 엔티티 프로퍼티를
변경하면 ORM 프레임워크가
알맞은 쿼리 실행
- 도메인 객체가 발생한 이벤트를
저장소에 보관
35. 장점
• DB에 의존적이지 않은 도메인 코드 구현
– 테이블이나 ORM 기술의 제한/제약에서 벗어남
• 기능 변경
– 하위 호환 처리가 상대적으로 쉬움
– 이벤트로부터 완전히 새로운 도메인 객체의 생성도 가능
• 버그 추적 용이
– 이벤트를 차례대로 검사하면서 버그 원인 추적 가능
• 객체 지향/DDD와 좋은 궁합
– 복잡한 도메인을 객체 지향적으로 구현하기에 좋음
• CQRS와 좋은 궁합
– 조회 관련 코드를 도메인에서 분리
– 조회 모델 분리로 조회 성능 향상 가능
35
36. 단점
• 익숙하지 않음
– SQL 위주(데이터 중심) 개발 성향인 경우 적응 힘듬
• 단순 모델에는 적합하지 않음
– 단순 모델에 적용하기엔 구현이 복잡해짐
• 도구 부족
– 이벤트 소싱과 CQRS 지원 프레임워크 부족
• 운영시 어려움
– 이벤트 데이터만으로는 최신 상태의 빠른 확인 불가
• CQRS 필수!
36
39. 길게 실행되는 프로세스
Long Running Business Process
39
주문하기 상품보내기 배송시작알리기
구매확정
요청하기
40. 길게 실행되는 프로세스
40
주문하기 상품보내기
배송시작
알리기
구매확정
요청하기
배송시작함주문함
배송시작집하하기 전달
배송완료함
입금하기
결제함
41. 길게 실행되는 프로세스/트랜잭션의 특징
• 여러 개의 작은 프로세스(트랜잭션)로 구성
• 하위 프로세스가 순서대로 실행되는 건 아님
• 여러 모듈/서비스가 (비동기로) 엮임
• 한 트랜잭션이 아님
• 실패는 롤백 대신 보상으로 처리
41
42. SAGA
• 여러 하위 트랜잭션 집합으로 구성된 LLT
– LLT: Long Lived Transaction
– 단일 실행 단위
• 각 하위 트랜잭션은 단독 트랜잭션
– 하위 트랜잭션 단위로 일관성 보장
• 각 하위 트랜잭션은 서로 연관
• 하위 트랜잭션 실패시, 보상 트랜잭션
– 일부만 성공해도 끝나지 않음
42
* SAGAS (Hector Garcia-Molina, 1987)