Serio? Kolejna prezentacja o Event Sourcingu? I tak, i nie. Zamiast na gloryfikacji tej jakże zacnej koncepcji, skoncentrujemy się na możliwych problemach przy jej implementacji. Co może wybuchnąć (często z opóźnionym zapłonem)? Gdzie i jak przechowywać eventy? Jak osiągnąć najwyższy poziom wtajemniczenia i skalowalności? Jak żyć z eventual consistency? I wiele innych pytań, z którymi spróbujemy się zmierzyć. Postaram się unikać jednoznacznych odpowiedzi - każde rozwiązanie jest dobre, dopóki “działa”. Przerywniki z doświadczeniami słuchaczy będą bardzo mile widziane.
6. History
● 9000 BC, Mesopotamian Clay Tablets,
e.g. for market transactions
7. History
● 2005, Event Sourcing
“Enterprise applications that use Event Sourcing
are rarer, but I have seen a few applications (or
parts of applications) that use it.”
8. Why Event Sourcing?
● complete log of every state change
● debugging
● performance
● scalability
9. ES and CQRS
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
10. ES and CQRS level 1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Transaction
11. ES and CQRS level 1
● Entry-level, synchronous & transactional event sourcing
● slick-eventsourcing
12. ES and CQRS level 1
+ easy to implement
+ easy to reason about
+ 0 eventual consistency
- performance
- scalability
13. ES and CQRS level 2
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
Transaction
14. ES and CQRS level 2
+/- performance
+/- scalability
- eventual consistency
- increased events DB load
- lags
15. ES and CQRS level 3
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
Transaction
event
bus
16. ES and CQRS level 3.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
17. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
18. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
At-least-once delivery
19. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
20. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
21. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
22. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
23. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
24. ES and CQRS level 3.1.1
Command Service
Domain
Events
Client
Query Service
Data access
Commands Queries
Read
modelRead
modelRead
models
Updater
event
bus
Transaction
?
25. ES and CQRS level 3.2
Events
Client
Query Service
Data access
Commands
Queries
Read
modelRead
modelRead
models
Updater
event
bus
Command Service
Domain
Command Service
Domain
Command Service
Domain
Transaction
Sharded
Cluster
26. ES and CQRS level 3.x
+ performance
+ scalability
- eventual consistency
- complex implementation
27. ES and CQRS alternatives
● Change Capture Data (CDC) logging instead of message queue?
● message queue instead of DB?
29. ES from domain perspective
● commands, events, state
● 2 main methods on state
○ process(command: Command): List[Event]
○ apply(event: Event): State
30. ES from application perspective
● snapshotting
● fail-over
● recover
● debugging
● sharding
● serialization & schema evolution
● concurrency access
● etc.
31. import javax.persistence.*;
import java.util.List;
@Entity
public class Issue {
@EmbeddedId
private IssueId id;
private String name;
private IssueStatus status;
@OneToMany(cascade = CascadeType.MERGE)
private List<IssueComment> comments;
...
public void changeStatusTo(IssueStatus newStatus) {
if (this.status == IssueStatus.DONE
&& newStatus == IssueStatus.NEW || this.status == IssueStatus.NEW
&& newStatus == IssueStatus.DONE) {
throw new RuntimeException(String.format("Cannot change issue status from %s to %s",
this.status, newStatus));
}
this.status = newStatus;
}
...
}
32. import org.axonframework.commandhandling.*
import org.axonframework.eventsourcing.*
@Aggregate(repository = "userAggregateRepository")
public class User {
@AggregateIdentifier
private UserId userId;
private String passwordHash;
@CommandHandler
public boolean handle(AuthenticateUserCommand cmd) {
boolean success = this.passwordHash.equals(hashOf(cmd.getPassword()));
if (success) {
apply(new UserAuthenticatedEvent(userId));
}
return success;
}
@EventSourcingHandler
public void on(UserCreatedEvent event) {
this.userId = event.getUserId();
this.passwordHash = event.getPassword();
}
private String hashOf(char[] password) {
return DigestUtils.sha1(String.valueOf(password));
}
}
40. Event storage for Akka Persistence
● file
● RDBMS
● Event Store
● MongoDB
● Kafka
● Cassandra
41. akka-persistence-jdbc trap
val theTag = s"%$tag%"
sql"""
SELECT "#$ordering", "#$deleted", "#$persistenceId", "#$sequenceNumber",
"#$message", "#$tags"
FROM (
SELECT * FROM #$theTableName
WHERE "#$tags" LIKE $theTag
AND "#$ordering" > $theOffset
AND "#$ordering" <= $maxOffset
ORDER BY "#$ordering"
)
WHERE rownum <= $max"""
43. Cassandra perfect for ES?
● partitioning by design
● replication by design
● leaderless (no single point of failure)
● optimised for writes (2 nodes = 100 000 tx/s)
● near-linear horizontal scaling
44. ScyllaDB ?
● Cassandra without JVM
○ same protocol, SSTable compatibility
● C++ and Seastar lib
● 1,000,000 IOPS
● not fully supported by Akka Persistence
48. Plain text Binary
human-readable deserialization required
problems with precision (JSON IEEE 754) -
storage consumption compress
49. Plain text Binary
human-readable deserialization required
problems with precision (JSON IEEE 754) -
storage consumption compress
slow fast
50. Plain text Binary
human-readable deserialization required
problems with precision (JSON IEEE 754) -
storage consumption compress
slow fast
poor schema evolution support full schema evolution support
80. ES and CQRS level 3.2
Events
Client
Query Service
Data access
Commands
Queries
Read
modelRead
modelRead
models
Updater
event
bus
Command Service
Domain
Command Service
Domain
Command Service
Domain
Transaction
Sharding
Clustering
86. Cluster best practises
● very good monitoring & alerting
● a lot of failover tests
● cluster also on dev/staging
● keep it as small as possible (code base, number of nodes, etc.)
87. Summary
● understand event/state schema evolution
● eventual consistency is your friend
● scaling is complex
● log-based processing mindset