事件溯源模式 Event Sourcing Pattern
关于事件溯源#
事件溯源是由Greg Young提出的一种架构模式,是一种以事件为中心的编写业务逻辑和持久化领域对象的方法。
- 它要求不存储系统的当前状态,而是存储导致该状态的事件。
- 共享成员在各自的界限上下文中都分别建自己的类和数据库,而不是共享。数据通过同步保持一致性。
- 通常整个应用程序只有一个 Event Store, 不同的微服务都通过向 Event Store 发送和接受消息而互相通信。
描述#
存储数据变动的所有状态,而不仅仅是当前的状态,从而使存储可以被用来实现领域对象的动作事件。该模式可以提高性能,可扩展性和响应能力,提供交易数据的一致性,并且保持完整的审计跟踪和记录,可能使补偿措施。
背景和问题#
大多数应用程序只保持数据的当前状态。在 CRUD 系统直接执行更新操作会影响性能和响应能力。
解决方案#
不是保存数据当前的状态,而是保存每个动作的事件。
注意事项#
- 考虑数据之间的信息交互使用同步还是异步。
- 事件存储是信息是不可变的。
- 考虑事件存储发生并发的处理机制。
- 提取唯一条件作为事件流的事件标识符。
- 重放数据可以考虑创建特定间隔的快照。
- 尽管活动减少了冲突,但是应用程序仍然可能出现最终一致性和缺乏交易的不一致。
- 事件发布可能会导致多次消费者的事件,所以消费者消费事件必须幂等。
何时使用#
- 数据非常重要,需要记录下数据的整个生命周期的,例如银行交易数据,Git 版本管理。
- 需要尽量减少或完全避免更新导致冲突的数据。
- 能够重放它们来恢复系统的状态;
- 与 CQRS 一起使用和最终一致性是可以接受的情况下。
结构中包含的角色#
- EventStore 事件仓库
- Event 抽象事件
- OrderPayEvent 订单支付事件
- Observer 抽象观察者
- OrderEntity 订单实体
- UserEntity 用户实体
可用到的设计模式思维#
每个事件都会引起这个事件关联数据的变动,可以用观察者模式处理,这里的观察者有可能是同步,也有可能是异步的。
每一个动作,可以抽象成一个命令,使用命令模式, 这里不展示命令模式了。
最小可表达代码#
// 事件仓库
class EventStore
{
public function append(Event $event)
{
var_dump("追加事件");
}
}
// 抽象事件
abstract class Event
{
protected $observers = [];
public abstract function notify();
public function addObserver(Observer $observer)
{
$this->observers[] = $observer;
}
}
// 具体目标
class OrderPayEvent extends Event
{
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
// 观察者
interface Observer {
public function update(Event $event);
}
// 订单实体
class OrderEntity implements Observer
{
public function pay()
{
$event = new OrderPayEvent();
$event->addObserver($this);
$event->addObserver(new UserEntity);
(new EventStore())->append($event);
$event->notify();
}
public function update(Event $event)
{
if ($event instanceof OrderPayEvent) {
var_dump('支付成功, 订单更新');
}
}
}
// 用户实体
class UserEntity implements Observer
{
public function update(Event $event)
{
if ($event instanceof OrderPayEvent) {
var_dump('扣除用户的订单费用');
}
}
}
$orderEntity = new OrderEntity();
$orderEntity->pay();
推荐文章: