cqrs eventstore
TRANSCRIPT
CQRS with
JOliver Event Store
v3
Дорога к CQRS
GUIDatabase
accessBusiness
logicGUI
Database accessBusiness
logic
GUI
GUI
Database access
GUIDatabase accessBusiness
logic
GUI
GUI Database access
Business logic
GUI
Business logic
Business logicGUIDatabase access
GUI
Business logic
Data access
M$$SQL
GUI
Domain Model
ORM
Database
M$$SQL
GUI
Domain Model
ORM
Database
Lazy Loading !!! OUCH!
M$$SQL
GUI
Domain Model
ORM
Database
DTO
M$$SQL
GUI
Domain Model
ORM
Database
DTO
Object-To-Object Mapping !!!
OUCH!
RDB
ORM
Отчеты
Domain
8-ми этажный SQL
А ручки то, на что?
RDB
Ручками
Отчеты
N этажный SQL(правда, почище и побыстрее, чем с ORM)
SQL красиво упрятан за фасадом
хранимых процедур
RDB
DTO
Handcrafted SQL
ORM
Application Services
Domain Object
Domain Object
Reporting Services
3NF with optimizations like 1NF
in some places
DTO DTO DTO
Form UI Reports UI
send
request
RDB
DTO
Handcrafted SQLORM
Application Services
Domain Object
Reporting Services
DTO DTO DTO
Form UI Reports UI
Здесьжирненько
И что дальше?
Data Storage
Command
Application Services
Domain Object
Query Services
Client
Domain Object
Query
Data Storage
DTO DTO
CQRS (did you mean “Cars”?)
Domain Model View Model
Как синхронизировать ?
ORMDomain Changeset Denormalizer
View Model
Потеря «сути» изменений
Непрозрачный сгусток данных
CQRS+
Event Sourcing =
LOVE!
ORMDomain
Storage
Текущее состояние
Традиционный подход
Domain InvoiceCreated
InvoiceApproved
Invoice Finalized
Журнал всех изменений
Event Sourcing
Традиционный подход
Event Sourcing
SRP на уровне метода !
Принятие решения о возможности
перехода состояния(бизнес-правила)
Переход состояния(транзитор)
Собственно, изменение состояния(аппликатор)
И как это работает?
Ну и как это всё работает?
Восстановление текущего состояния
InvoiceCreated
InvoiceApproved
Invoice Finalized
Журнал изменений
1
2
3
Сохранение изменений
InvoiceApproved
Invoice Finalized
Буфер
Сохранение изменений
InvoiceApproved
Invoice Finalized
Буфер
InvoiceCreated
Журнал изменений
1append
2Invoice
Approved
Invoice Finalized3
Log.append(id, events)
events = Log.read(id)
Тривиально, неправда ли?
Обеспечение параллельного доступа
Параллельные модификации
InvoiceCreated
InvoiceUpdated
Invoice Finalized
update
Invoice
finalize
Оптимистическая блокировка
InvoiceCreated
Stream [ID:542]
1InvoiceCreated
Invoice[ID:542]
1load Invoice
Created
Invoice[ID:542]
1load
1
Оптимистическая блокировка
InvoiceCreated
Stream [ID:542]
1
2 InvoiceFinalized
load InvoiceCreated
Invoice[ID:542]
1
2 InvoiceFinalized
load
store
1
2
originalRevision = currentRevison
InvoiceCreated
Invoice[ID:542]
1
Оптимистическая блокировка
InvoiceCreated
Stream [ID:542]
1
2 InvoiceFinalized
22InvoiceUpdated
load
store
InvoiceCreated
Invoice[ID:542]
1
2 InvoiceFinalized
load
store
1
2
InvoiceCreated
Invoice[ID:542]
1
originalRevision != currentRevison
Допустимые параллельные модификации
Transaction Posted
Transaction Posted
Transaction Posted
post
General Ledger
post
Трекать ревизию аггрегата
недостаточно
Высокая производительность
Минимальное количество операций записи
E1
Aggregate StreamCommit
E1 E1pack
C1serialize
Минимальное количество операций записи
Commit
E1
Aggregate
E2
E3
E2
E3
Stream
C2
E2
E3
Commit
E1 E1pack
pack
C1serialize
serialize
Гибкие возможности сериализации
• JSON• Binary• Custom (ProtoBuf, .NET, whatever)
• GZip• Криптование
Оптимизация операции восстановления состояния при помощи «снимков»
Аггрегат с очень
длинным жизненным
циклом и кучей ивентов
E1
E2
…
E100500
Snapshot[rev: E100500]
E100501
restore
replay the restof events
Распределенная транзакция
С1 С2 .. Сn
Command Queue
Command Processor
Event Store
dequeue (C1)
store (E1, E2)
MSDTC
Без 2PC
С1 С2 .. Сn
Command Queue
Command Processor
Event Store
0. peek (C1)
1. store (E1, E2)
2. remove (C1) T2
T1
Без 2PC необходима поддержка идемпотентности
С1 С2 .. Сn
Command Queue
Command Processor
Event Store
0. peek (C1)
1. store (С1, [E1, E2]) 2. dup (С1)
4. remove (С1)
Commit
E1
E2
Без 2PC необходима поддержка идемпотентности
С1 С2 .. Сn
Command Queue
Command Processor
Event Store
0. peek (C1)
1. store (С1, [E1, E2]) 2. dup (С1)
4. remove (С1)
Commit
E1
E2
ID : UUID
Без 2PC необходима поддержка идемпотентности
С1 С2 .. Сn
Command Queue
Command Processor
Event Store
0. peek (C1)
1. store (С1, [E1, E2]) 2. dup (С1)
4. remove (С1)
Commit
E1
E2
ID : UUID
Command
ID : UUID
Обработка событий
Event Store
View Model
E1 E2publish update
2PC, опять?
Обработка событий (PULL)
Event Store
View Model
Get new events since (Time)
Запоминать последнее
обработанное событие
Обработка событий (PULL)
Event Store
View Model
Get new events since (Time)
Commit
E1
E2
ID : UUID
Обработка событий (PULL)
Event Store
View Model
Get new events since (Time)
Commit
E1
E2
ID : UUID
Dispatched : bool
Обработка событий (PULL)
Event Store
View Model
Get undispatched events
Commit
E1
E2
ID : UUID
Dispatched : boolmark as
dispatched
Обработка событий (PUSH)
Event Store
View Model
publish (commit)
Commit
E1
E2
ID : UUID
Dispatched : boolИдемпотентность во
View Model хранилище по-
прежнему нужна mark as
dispatched
Встроенный диспетчер событий
BUS
Command Processor
Event Store
cmd
events
commit
Dispatcher
EventPublisher
commit
events
Storage
Your App
commit mark as dispatched
OK
Встроенный диспетчер событий
BUS
Command Processor
Event Store
cmd
events
commit
Dispatcher
EventPublisher
commit
events
Storage
Your App
commit
dispatched = false
FAIL
Архитектура
CommitEvent Store
Persistence Engine
Event Stream Commit
Event MessageDispatche
r
Storage
Поддерживаемые технологии хранилища данных
Relational Databases:
• SQL Server 2005 (or later)• MySQL• Firebird• Oracle (planned)
Embedded Relational Databases:• SQL Server CE 3.5 (or later)• SQLite 3.0 (or later)• MS Access 2000 (or later)
Cloud-based Databases:• MS SQL Azure• Amazon RDS (MySQL)• Azure Tables/Blobs (in progress)
• Amazon SimpleDB/S3 (in progress)
Document Databases• RavenDB r322 (or later)• MongoDB 1.6 (or later)• CouchDB 1.0 (planned)
Расширяемость
Метаданые
Commit
Event Message
Dictionary<string, object>
Dictionary<string, object>
Office, User, PrecedingMessageId
EventId, AggregateType
Хуки
Event Store
Persistence Engine
Commit
Место для “врезки” в конвейер обработки
Hook into:• select• pre-commit• post-commit
Хуки
Диспатчер – это встроенный хук
Механизмы эволюции схемы событий
2 подхода
• Толерантный сериализатор
• Явное версионирование
Свалка аппликаторов в бизнес-аггрегате
Преемственность версий
InvoiceCreated
InvoiceCreated_v2
InvoiceCreated_v3
convert to
convert to
Хук-конвертер в Event Store
Проект CommonDomain
Базовый класс для Аггрегатов
Репозиторий - DAO для Аггрегатов
Обработка конфликтов параллельного доступа
Допустимые параллельные модификации
Transaction Posted
Transaction Posted
Transaction Posted
post
General Ledger
post
Легко создавать специализированные политики определения конфликтов параллельных изменений
Ссылочки:
• http://cqrs.wordpress.com• https://github.com/joliver/EventStore• https://github.com/joliver/CommonDomain