By event storming, we can derive so many meaningful objects such as Entity, Domain Events, and Services that can be mapped with implementation objects in Spring cloud.
2. 커머스 영역 예제
• 쇼핑몰 카탈로그 관리에서 주문, 재고
확인, 배송조회, 프로모션에 이르는 예
제
• MSA 적용 관심도가 가장 높은 영역중
하나
• 행사 제품과 특정 세일즈 기간에 특정
서비스가 핫-스폿으로 요청이 폭주하는
경향은 마이크로 서비스의 Self-
Healing, 결함내성, 동적 확장 등의
MSA 설계 강점을 잘 설명할 수 있음
• 챗봇을 통한 기존 고객에 대한 재방문
을 높히고 고객 성향 분석을 통한 추천
상품 제공
• MSA 플랫폼 상에 머신러닝 워크로드를
수행하는 Tensorflow, Keras 등의
Polyglot 한 다양한 플랫폼을 운영
3. Event Storming – Event 들을 먼저 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
우리 서비스에는 어떤 비즈니스 이벤트들이 발생하는가?
현업이 사용하는 용어를 그대로 사용 (Ubiquitous Language)
용어의 namespace 를 구지 나누려는 노력을 하지 않음
4. Event Storming – Command 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
Event를 발생시키는 명령은 무엇인가? UI를 통해? or 시간도래? or 다른 이벤트에 의해?
5. Event Storming – Entity 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
제고
• 제품정보
• 수량
6. Event Storming – Sub-domain 과
Bounded Context
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
재고
• 제품정보
• 수량
Order
InventoryCustomer
7. Event Storming – Core / Supportive /
General Sub-domain
가입
탈퇴
주문 결재완료
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
입고입력
결재완료
사용자등록
비밀번호분
실처리
IAM (General)
Billing (Supportive)
구독일
도래
인보이
스발행
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
재고
• 제품정보
• 수량
수취확인
Order (Core)
Inventory
(Core)
Customer (Core)
로그발
생 수집
8. 검증: 트랜잭션 검증 매트릭스*
Customer Order Inventory
고객 주문이력 입출고
이력
재고량
Customer 가입 CU
Order
주문 R C C U
취소 D C U
Inventory
입고 C U
출고 C U
8ACID Transaction Don’t care Eventual Transaction
Entities
Events
9. 검증: 트랜잭션 유형 결정
9ACID Transaction Don’t care Eventual Transaction
• 이벤트의 발생 MS 와 Entity 접근의 CUD 가 완전히 동일한 MS
내에서만 벌어지면 ACID Transaction 가능
• 이벤트의 발생 MS 와 Entity 접근의 MS 가 R (read) 수준에서만
분산되어 벌어지면 값 참조 호출만으로 문제없음(don’t care)
• 이벤트의 발생 MS 와 Entity 접근의 MS 가 CUD 차원에서 걸쳐
지면 Eventual Transaction 비용 발생
10. Event Storming to DDD and
Implementations
가입 탈퇴
주문
결재완료
입고
출고
가입화면
입력
탈퇴화면비밀번호
분실화면
주문서
작성
PG결재 수취확인
버튼
입고입력
결재완료
사용자등록
비밀번호분
실처리
구독일
도래
인보이스
발행
고객 주문 재고
수취확인
Entities or Document DB
Business Events / Kafka Topics
UI or Service (REST API by Repository Pattern) or Batch Jobs
11. Decomposition to Micro Services
(Spring Boot Applications)
Customer
IAM
Order Inventory
Billing
12. Entity Class 와 Repository 작성
고객 주문 재고
public interface OrderRepository extends
MultitenantRepository<Order, java.lang.Long> {
}
@Entity
@Table(name="Ordertable")
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private java.lang.Long id;
private java.util.Date date;
private java.lang.String status;
@OneToMany(mappedBy="order")
private List<Item> itemList;
}
@Entity
@Multitenant
@TenantDiscriminatorColumn(
name = "TENANTID",
contextProperty = "tenant-id"
)
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
}
public interface CustomerRepository extends
MultitenantRepository<Customer, Long> {
List<Customer> findByLastName(String
lastName);
}
@Entity
@Table(name="Itemtable")
public class Item {
@Id @GeneratedValue(strategy=GenerationType.AUT
private java.lang.Long id;
private java.lang.String name;
private java.lang.Long stock;
@ManyToOne
private Order order;
}
public interface ItemRepository extends
MultitenantRepository<Item, java.lang.Long> {
}
13. Service 의 생성
주문서
작성
수취확인
버튼
Repository Pattern 으로 생성된 것
사용할 수 있는 경우
주문서 작성을 위한 백엔드 API 는
Order Repository 에서 생성된
CRUD actions 들 중 POST Service
를 그대로 사용할 수 있으므로 별
도 구현할 필요 없다. 마찬가지 주
문서 수정, 삭제도 각각 PATCH,
DELETE 로 생성된 API를 사용하면
된다.
Repository 에서 생성된 API 를 사용 못하
는 경우, 별도 Spring MVC Service 로 생성
수취 확인을 위한 백엔드 API 는 Order
Repository 에 생성된 PUT-POST-PATCH-
DELETE 중 적합한 것이 없으므로 별도 추
가 action URI를 만드는 것이 적합
@RequestMapping(method= RequestMethod.POST,
path="/orders/confirm-delivered")
public int confirmDelivered(Order order);
14. Domain Event 생성과 pub 처리
public class OrderPlacedEvent{
Order order;
}
#OrderPlacedEvent.java
주문
결재완료
결재완료
로그발생수취확인
@PostPersist
public void orderPlaced(){
messageChannel.send(MessageBuilder
.withPayload(new OrderPlacedEvent(this))
.build());
}
#Order.java
* 이벤트의 Publish trigger 는
주로 Entity 의 발생과 함께 하는 경우가 많음
15. Domain Event 의 sub 처리
Inventory 서비스 내부
주문
출고
Order (Core)
Inventory
(Core)
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent orderPlacedEv
{
Item item = itemRepository.findOne(orderPlacedEvent.getItemId()
item.setStock(item.getStock()-1);
itemRepository.save(item);
}
16. Domain Event 의 sub 처리 II –
Marketing Service 의 등장
주문
출고
Order (Core) Inventory
(Core)
Marketing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent
orderPlacedEvent) {
…. 고객 선호도 정보 저장 …
……. 유사 상품 추천 ……..
}
Marketing (Supportive)
주문
마케팅
정보
수집
• Least Coupling
• No Code Change in event
originator
• Don’t need to share database
(Store event data by each
microservices in preferred
format for their need)
17. Domain Event 의 sub 처리 III – Anti-
corruption Layer
주문
Order (Core)
Billing (Supportive)
Billing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload MeteringLogEvent meteringEve
…. 빌링 처리 …
}
OrderPlacedEvent
Not compatible!
인보이스
발행
로그발생
18. Domain Event 의 sub 처리 III – Anti-
corruption Layer
주문
Anti-
Corruption
처리
Order (Core)
Order-Billing
(Anti-corruption)
Billing (Supportive)
인보이스
발행
Order-Billing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent orderEvent
messageChannel.send(MessageBuilder
.withPayload(new MeteringLogEvent(orderEvent))
.build());
}
로그발생
• Anti-corruption Layer 를 위해 새로운
MS 를 또 관리하는 것이 부담이 되는
경우
• BPM 을 통해서 Anti-corruption Layer
를 위한 Micro service 를 그때 그때 생
성하고 폐기할 수 있음
• 마이크로 서비스간에 Glue 역할
21. Generate Micro services with Repository
Pattern
코드생성
Git 커밋
빌드 & 배포
서비스 접속 URL
고객
주문
재고
주문서
CRUD
고객
CRUD
재고
CRUD
22. Test the generated micro service –
Order Service
http http://backend-commerce-order-dev.pas-mini.io/items name="OO 건조기" stock=5
{
"_links": {
"item": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1"
},
"order": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1/order"
},
"self": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1"
}
},
"name": "OO 건조기",
"stock": 5
}
23. Generated Code details –Spring Boot
on Spring Cloud MSA Chassis
Main Application
Domain Classes
Services and Repositories
Settings
방법1의 Entity-Repository 패
턴에 대한 작업을 대신해줌
28. CQRS 를 통한 분산 트랜잭션 처리
총구매액: 500 총마일리지: 5
총구매액: 600 총마일리지: 5
총구매액: 600 총마일리지: 6
총구매액: 700 총마일리지: 6
총구매액: 700 총마일리지: 7
Consistent
In-consistent
조회화면서비스구성 (CQRS)
Mileage
(MongoDB)
Order
(MySQL)
Kafka (메시지보장)
OrderPlaced
(pub)
OrderPlaced
(sub)
Client (Web/Mobile)
POST
Update
29. 여기서 선택의 길을 만남
• ‘잠깐의’ 데이터 불일치가 얼마나 크리티컬 한가?
• 크리티컬 하다고 응답한다면, 내 서비스의 성능과 확장
성에 비하여 크리티컬 한가?
• 성능과 확장성 보다 크리티컬 하다면, 성능과 확장성을
포기할 수 있는가?
• 성공한 내 서비스의 경쟁자들은 무엇을 포기했는가?
• 강력한 의사결정 필요
30. CQRS 를 통한 분산 트랜잭션 처리 – 불
일치가 Mission Critical 한 경우
총구매액: 500 총마일리지: 5
총구매액: 600 총마일리지: 5 (PENDING)
총구매액: 600 총마일리지: 6
총구매액: 700 총마일리지: 6 (PENDING)
총구매액: 700 총마일리지: 7
Consistent
In-consistent
조회화면서비스구성 (CQRS)
Mileage
(MongoDB)
Order
(MySQL)
Kafka
OrderPlaced
(pub, PENDING)
OrderPlaced
(sub)
Client (Web/Mobile)
POST
All-done
(pub)
All-done
(sub, CLEAR PENDING)
31. CQRS 를 통한 분산 트랜잭션 처리 –
Rollback (Saga Pattern)
총구매액: 500 총마일리지: 5
총구매액: 600 총마일리지: 5 (PENDING)
총구매액: 600 총마일리지: 6
총구매액: 700 총마일리지: 6 (PENDING)
총구매액: 700 총마일리지: 7 실패
Consistent
In-consistent
조회화면서비스구성 (CQRS)
Mileage
(MongoDB)
Order
(MySQL)
Kafka
OrderPlaced
(pub, PENDING)
OrderPlaced
(sub)
Client (Web/Mobile)
POST
All-done
(pub)
FAILED
(sub, DELETE or CANCEL)
FAILED
(pub)
If~else
총구매액: 600 총마일리지: 6
32. BPMN 을 이용한 CQRS와 Sagas
https://www.infoq.com/articles/events-workflow-automation