Domain Driven Design và Event Driven
Architecture
trong xây dựng Enterprise Software
Lê Minh Nghĩa
Solution Architect from Tiki
22/10/2016
Giới thiệu về bản thân
• Lê Minh Nghĩa
• Solution Architect – tiki.vn
• Email: [email protected]
• Facebook: /nghialeminh
Các nội dung chính
1. Các yêu cầu đặt ra
2. Ứng dụng Domain Driven Design
3. Event - driven Architecture
4. Một số Case Studies
5. Kết luận
3
1. Các yêu cầu đặt ra
• Khả năng mở rộng về mặt nghiệp vụ.
• Khả năng mở rộng về mặt hiệu năng
4
1.1. Khả năng mở rộng về nghiệp vụ
• Nghiệp vụ luôn luôn thay đổi. Thiết kế là để đáp ứng nhu cầu thay đổi.
• Có model dữ liệu phải nhất quán và rõ ràng
• Logic nghiệp vụ phải tập trung
• Cấu trúc thống nhất
• Mọi thành phần đều có thể thay thế.
• Tiếp cận: Domain Driven Design
5
1.2. Mở rộng về mặt hiệu năng
• Không dùng chung một mô hình xử lý
• Đảm bảo khả năng tích hợp và mở rộng
• Đảm bảo tính ổn định trong môi trường phân tán.
• Tiếp cận: Event driven Architecture
6
1.3. Mô hình kiến trúc
7
DatabaseMessage Queue Caching
2. Ứng dụng Domain Driven Design
• Khó khăn khi phát triển
• Thiết kế Aggregate
• Infrastructure Layer
• Mức độ tái sử dụng
8
2.1. Khó khăn khi phát triển
• Không có model dữ liệu nhất quán.
• Trùng lặp mã nguồn lớn
• Khó kiểm soát khi nghiêp vụ bùng nổ
• Không có cấu trúc API thống nhất
• Khó đảm bảo tính nhất quán
9
2.2. Aggregrate
Là một nhóm các đối tượng dữ liệu được đối xử như một thể thống nhất
trong hệ thống
VD: order và order line phải coi như là hai thành phần nhất quán của
đối tượng aggregate order, định danh trong hệ thống là order id.
10
2.2. Aggregrate
11
2.2. Aggregrate
- Đảm bảo cách nhìn thống nhất trong toàn bộ hệ thống
- Khi nói đến một aggregate phải nói tới một đối tượng dữ liệu toàn vẹn,
đầy đủ.
- Không tồn tại các nghiệp vụ riêng biệt với từng thành phần của một
aggregate
- Tất cả logic từ data access tới service đều phải xoay quanh các
aggregate
12
2.2. Aggregate
• Chọn lựa phạm vi aggregate vừa đủ.
• Phạm vi aggregate quá lớn sẽ dẫn tới performance không tốt.
• Phạm vị aggregate quá bé sẽ dẫn tới logic bị phân mảnh và khó quản
lý.
• Đảm bảo các thành phần của một aggregate luôn nhất quán
13
2.2. Aggregate
Sử dụng pattern về data access thống nhất:– Repository Pattern
– ORM
Cấu trúc resources API tương ứng với các Aggregate
14
2.2. Aggregate
Don’t Repeat Yourself:
• Không nhầm lẫn Aggregate và các DTO
• Không design API dựa theo nhu cầu hiển thị
• Không xây dựng data access theo từng chức năng.
15
2.3. Infrastructure Layer
DatabaseMessage Queue Caching
16
2.3. Infrastructure Layer
• Đảm nhiệm vai trò làm việc với các thành phân bên dưới như DB,
Message Queue, File…
• Phần lớn logic của hệ thống là logic nghiệp vụ
• Không để logic của phần infrastructure làm giảm tốc độ phát triển
của nghiệp vụ
17
2.3. Infrastructure Layer
• Phải có khả năng tái sử dụng cao
• Phai nhất quán trong toàn bộ cấu trúc hệ thống
• Pattern:
- Repository Pattern
- Observer Pattern
- ORM Pattern
18
2.4. Mức độ tái sử dụng
Applications – Web App, API, Server Application…
Application Service
Domain Service
Domain Model
Infrastructures
19
Mức độ sử dụng
2.4. Mức độ tái sử dụng
• Các layer càng cao thì càng được sử dụng nhiều.
• Các layer càng bên dưới thì càng phải tái sử dụng cao
• Tránh thiết kế để độ phức tạp là ngang nhau giữa tất cả các layer.
• Tốc độ phát triển ngày một nhanh, vì tích lũy được các logic trước đó.
• Phải luôn kiểm soát, refactor mã nguồn.
• Phải ám ảnh triết lý: Don’t Repeat Yourself!
20
3. Event – Driven Architecture.
• Yêu cầu mở rộng về mặt hệ thống
• Event Drivent Archtecture trong Distributed System
• Message Bus/Event Bus
• Event Sourcing
• Tích hợp hệ thống
• Đảm bảo thứ tự message
21
3.1. Yêu cầu mở rộng hệ thống
• Không chia được thì không scale được
• Scale độc lập nhiều thành phần
• Giải quyết tính ổn định trong tích hợp hệ thống
22
3.2. EDA trong Distributed System
Request Driven Architecture
23
3.2. EDA trong Distributed System
Request Driven Architecture:
• Phức tạp khi tích hợp hệ thống
• Rất khó để quản lý tính nhất quán của dữ liệu
• Khó để mở rộng độc lập các thành phần của hệ thống
24
3.2. EDA trong Distributed System
25
Event Driven Architecture
3.2. EDA trong Distributed System
Event Driven Architecture
- Lose couping toàn bộ hệ thống
- Dễ dàng tích hợp
- Quản lý luồng message
26
3.3. Message Bus
• Đóng vai trò truyền gửi message trong hệ thống
• Đảm bảo quá trình truyền gửi ổn định
• Có khả năng điều hướng message
• Dễ dàng tích hợp với các thành phần trong hệ thống.
• Là đối tượng về mặt logic của các hạ tầng message queue
27
3.3. Message Bus
Logistic
SystemOperation
Data
WarehouseTracking Optimize
Message Bus
3.3. Message Bus
Có thể trừu tượng hóa thành hai loại:
- Event Bus : truyền gửi các event đã xảy ra
- Command Bus: truyền gửi bất đồng bộ các lệnh thay đổi dữ liệu trong
hệ thống.
29
3.4 Event Sourcing
30
3.4 Event Sourcing
• Lưu trữ thay đổi của đối tượng
• Tách các phần ghi và đọc trong hê thống
31
3.4 Event Sourcing và thực tế áp dụng
• Việc xây dựng cấu trúc lưu trữ Event Store cho tất cả là phức tạp
• Kiểm soát tính đồng thời trong các thao tác cập nhật khó khăn
• Phân tích read side thành nhiều thành phần tùy theo yêu cầu về tính
nhất quán và đồng thời với write side.
• Nên dùng Event Store để lưu log hơn là main database.
32
3.4 Event Sourcing và thực tế áp dụng
Ví dụ: Cập nhật trạng thái đơn hàng:
- Nếu cần lấy ngay trạng thái thành công hay thất bại để hiển thị sử
dụng chung một mô hình lưu trữ cho hai việc
- Nếu sau khi cập nhật tác động tới dữ liệu ở khâu vận hành khác
read side là cấu trúc lưu trữ phục vụ khâu vận hành
33
3.5. Đảm bảo thứ tự của message
• Đảm bảo thứ tự message có vai trò quyết định với tính ổn định của
toàn hệ thống
VD: để tracking trạng thái hàng hóa, khi vận hành có hai event:
- e1: nhập kho
- e2: xuất kho
Các event gửi trong môi trường phân tán, thứ tự e1, và e2 có thể bị đảo
lộn.
Khi số lượng event càng lớn, thì tỉ lệ lỗi càng cao, ảnh hưởng độ ổn định
hệ thống.
34
3.5. Đảm bảo thứ tự message
• Đảm bảo thứ tự ghi dữ liệu
• Đảm bảo thứ tự gửi event
• Đảm bảo thứ tứ nhận event
35
3.5.1. Đảm bảo thứ tự ghi
• Các event được append vào một log. Ví dụ: insert vào một table.
• Các lệnh insert thường không lock nhau, do đó các lệnh insert có thể thực thi đồng thời.
VD:
- Thời điểm T1: lấy order và xử lý
Process 1: Get Order – version = 1
DoSomething()
version = version + 1 2 event E2
Process 2: Get Order – version = 1
DoSomething()
version = version + 1 2 event E2
- Thời điểm T2: lưu kết quả xử lý: lưu các event lại.
Do các lệnh insert không lock nhau, nên lưu trữ sẽ là: E1 – E2 – E2
Wrong!
36
3.5.1. Đảm bảo thứ tự ghi
Solution 1: lock theo key range, sử dụng transaction mode lock serializable
Ví dụ: lock theo key là id order
Solution 2: sử dụng hai resources:
R1: snapshot của object
R2: event log
Lock lệnh update trên R1 và append vào R2
Solution 3: nếu lưu event trên table, thì sử dụng bộ cặp primary key của event:
Aggregate Id – Version
Các event cùng version sẽ bị đụng độ khi insert.
37
3.5.2. Đảm bảo thứ tự gửi
Các message có thể bị gửi sai thứ tự, dù thời điểm xử lý diễn ra đúng thứ
tự.
VD:
- Thời điểm T1:
DoSomething();
Send Event 1;
- Thời điểm T2:
DoSomething();
Send Event 2;
Event 1 send đi lỗi, Event 2 lại send thành công Wrong!
38
3.5.2. Đảm bảo thứ tự gửi
Solution:
- Không áp dụng đồng thời ghi DB và gửi event vì không có transaction.
- Phải gửi log các event trước khi gửi đi
- Gộp nhóm các event theo id của aggregate phát event. Lưu trữ event với
cặp key: aggregateId – version
- Load các event cần gửi theo aggregate id, và gửi tuần tự theo version
- Dừng gửi ngay khi gặp event lỗi
- Xử lý sự cố Load lại theo aggregateId và gửi tiếp theo thứ tự version
- Sử dụng hai bảng:
• Bảng Event để store event
• Bảng Undispatched Event để lưu tạm các event chờ gửi, sẽ xóa sau khi gửi xong.
39
3.5.2. Đảm bảo thứ tự gửi
ID Version
ABC 3
XYZ 2
40
ID Version Payload
ABC 1 ….
ABC 2 ….
ABC 3 ….
XYZ 1 ….
XYZ 2 ….
Order
Event
ID Version Payload
ABC 1 ….
ABC 2 ….
ABC 3 ….
XYZ 1 ….
XYZ 2 ….
Undispatched Event
3.5.3. Đảm bảo thứ tự nhận message
Các message khi được dequeue song song có thể sẽ bị mất thứ tự khi
xử lý:
• T1: message 1 dequeue và P1 process
• T2: message 2 dequeue và P2 process
Vì P1 xử lý lâu hơn P2 nên P2 commit trước Wrong!
41
3.5.3. Đảm bảo thứ tự nhận message
• Gom nhóm các message theo một định danh: ví dụ aggregate id
• Các message của một nhóm chỉ được nhận bởi một thread tại một
thời điểm
• Tận dụng các tính năng Partition của Kafka hoặc Session của Windows
Service Bus để đảm bảo thứ tự message khi routing
42
3.6. Tích hợp hệ thống.
• Message Bus giúp đơn giản quá trình tích hợp message
• Các thành phần tích hợp dựa trên nền tảng message bus
43
Context A Context B
Message Bus
3.6. Tích hợp hệ thống.
• Giữa các context không nên biết tới thành phần sẽ consumer
message của nó
• Logic luồng message khác với logic thực thi tại từng thành phần
• Các context khác nhau yêu cầu các định dạng message khác nhau
44
3.6.1. Process Manager
• Dùng để giải quyết vấn đề điều phối giữa các luồng message
• Đóng vai trò là thành phần trung tâm trong việc tổ chức logic của
luồng message
• Không xử lý logic nghiệp vụ, chỉ làm logic điều phối luồng.
• Phát huy vai trò lớn khi các logic luồng phức tạp.
45
3.6.2. Process Manager
46
Context A Context B
Message Bus
Process
Manager
3.6.3. Translator Pattern
• Đóng vai trò chuyển đổi message thành các định dạng phù hợp với
consumer
• Tách logic phát message khỏi logic transform message
47
Context A Context B
Message Bus
Translator B
4. Case Studies
• Một số yêu cầu cơ bản của bàn tài toán giao vận.
• Xác định các đối tượng dữ liệu cơ bản
• Xây dựng cấu trúc đầu tiên
• Apply Event Sourcing
• Event Handler/Command Handler
• Mô hình hệ thống
48
4.1. Các yêu cầu cơ bản.
• Quản lý các đối tượng hàng hóa: đơn hàng, gói hàng, carton…
• Quản lý luồng nghiệp vụ đơn hàng: gom hàng, nhặt hàng, xuất
nhập…
• Theo dõi trạng thái đơn hàng
• Báo cáo và phân tích
49
4.2. Các đối tượng cơ bản
50
SO
Items
Package
Items
Carton
Items
4.3. Xây dựng cấu trúc đầu tiên
51
ApplicationIn
fras
tru
ctu
res Application Service
Domain Service
Domain Model
4.3.1. Domain Models
52
public partial class SO : EventSourced, IStateContext
public partial class Package : EventSourced, IStateContext
public partial class Carton : EventSourced, IStateContext
4.2.2. Infrastructure
53
public interface IRepository<Context> where Context : DbContext
{
void Save<T>( T aggregate ) where T : class;
T Find<T>( object id ) where T : class;
IQueryable<T> Get<T>( Expression<Func<T, bool>> predicate ) where T :
class;
}
4.2.3. Domain Services
54
public class PackageService : IPackageService
{
private readonly Func<IRepository<DbContext>>
repositoryFactory;
public Package CreatePackage(CreatePack param)
{
Package package =
createActivity.MakePackage(param);
repository.Save<Package>(package);
repository.SaveChanges();
return package;
}
}
4.3. Apply Event Sourcing
• Quản lý các đối tượng trạng thái các đối tượng hàng hóa để theo dõi
• Xây dựng model cho việc lưu trữ event
• Thay đổi tầng lưu trữ để đảm bảo không thay đổi tầng logic
55
4.3.1. Xây dựng model cho event
56
Event Sourced
- ListPendingEvent (VersionEvent)
- Version: integer
- RaiseEvent(Event)
SO CartonPackage
VersionEvent
- SourceId: Guid
- Version: integer
StateChan
ed Event
4.3.1. Xây dựng model cho event
57
4.3.1. Xây dựng model cho event
58
4.3.3. Thay đổi Infrastructure
• Lưu trữ thay đổi thì gửi event đi
• Chỉ thay đổi tầng Repository
59
4.3.3. Thay đổi Infrastructure
60
4.3.3. Domain Service giữ nguyên
• Chi cấu hình Dependency Injection lại Repository, giữ nguyên logic
61
4.3.4. Event Handler/Command Handler
62
Event Bus
Message Receiver
Message Dispatcher Command Dispatcher
Infrastructures
Domain Service
Comand Handler Event Handler
4.3.4. Event Handler/Command Handler
63
4.5. Mô hình hệ thống
64
Command/Event Bus
Carton
Processing
Tracking
System
SO
Processing
Data
Warehoouse
Package
Processing
Routing
Optimize
5. Kết luận
1. DDD giúp có một cấu trúc tách bạch, rõ ràng
2. Phải thiết kế để mọi thành phần đều có thể thay
thế và mở rộng
3. Event Drivent Architecture phù hợp để scaling mở
rộng hệ thống.
4. Sử dụng một model thống nhất
5. Xây dựng tách bách infrastructure với business layer
65
Xin chân thành cám ơn!
Top Related