event sourcing la gi

CQRS (viết tắt của cụm Command/Query Responsibility Segregation) khái niệm nguyên sơ là cơ hội phân tích trách móc nhiệm truy vấn mệnh lệnh, nhằm mục tiêu tối ưu hóa việc ghi nhập & phát âm kể từ hạ tầng tài liệu.

Motivation

Ngày phổ thông lượt phát âm và ghi phức tạp trong mỗi khối hệ thống rộng lớn, kéo theo lỗi, ùn tắc service.

Bạn đang xem: event sourcing la gi

Việc phần mềm CQRS tiếp tục giải quyết:

  • Tranh chấp dữ liệu
  • Quản lý quyền và bảo mật thông tin phức tạp Lúc và một object sở hữu cả quyền phát âm và ghi

Ngoài đi ra còn tồn tại những lợi ích:

  • Chia vận tải tùy nhu yếu, ví dụ, phần mềm các bạn sẽ cần thiết phát âm nhiều hơn thế ghi.
  • Chia thực hiện nhiều loại view mang lại query không giống nhau tùy use case.

Cách hoạt động

CQRS thông thường cút cộng đồng với Event Sourcing. Trong văn cảnh của pattern này:

  • Model cho những lệnh ghi (INSERT/UPDATE/DELTE/…) được xem là source mang lại model của những mệnh lệnh phát âm.
  • Model cho những lệnh đọc được xem là những view hiện tại thực tài liệu.

Thật đi ra, chỉ implement CQRS tiếp tục rất rất đơn giản và giản dị, việc tích hợp ý Event Sourcing nhập nhằm cởi rộnng tài năng xử lý mới nhất thực hiện Việc trở thành phức tạp. Vậy nên, nên chính thức cút kể từ Event Sourcing trước.

Event sourcing là gì?

Trong Event sourcing, tao chứa chấp những sự kiện nhập DB, ko lưu những hiện trạng bị lost của những đối tượng người dùng. Event là những loại đang được xẩy ra nhập vượt lên trước khứ. Trạng thái thời điểm hiện tại của một thực thể, các bạn nên apply toàn bộ sự kiện vô một object mới nhất. Nó được gọi là Rehydration (thẩm thấu lại) hoặc Event replay.

Khi người sử dụng sự kiện sourcing, chúng ta có thể xây dựng:

  • Trace of events – mang lại từng đối tượng người dùng nhằm coi đúng mực điều gì đang được xẩy ra mang lại đối tượng người dùng tê liệt,
  • Audit trail – để hiểu ai và vật gì đang được trigger lên nó.
  • Dùng ngôn từ business nhập sự kiện sourcing, và sau cùng là
  • Event trả lời – Lúc sở hữu bug xày đi ra nhập quy trình xử lý sự kiện tê liệt, tao rất có thể fix issue tê liệt và lượt sau tao trả lời lại sự kiện.

Giờ bản thân tiếp tục map diagram nhập folder phía bên dưới nhằm dễ dàng hình dung:

Ta cút kể từ diagram, từng Object nhập hình tiếp tục có một list Events theo đòi và Handler mang lại từng loại sự kiện. Các Object này nằm trong folder Domain\Entities. Mỗi object đều nên sở hữu cấu tạo như nhau nhằm chứa chấp list sự kiện và những handler ứng, bản thân đặt điều nó nhập class thương hiệu là EventSourced, một implement của IEventSourced.

public interface IEventSourced
{
    Guid Id { get; }
    int Version { get; }
    IEnumerable<VersionedEvent> PendingEvents { get; }
}

Id là tấp tểnh danh của object. Version là độ quý hiếm tăng dần dần cho thấy số lượt object được update. PendingEvents chứa chấp list sự khiếu nại thực hiện thay cho thay đổi đối tượng người dùng.

Tiếp theo đòi là pseudocode mang lại Event Sourced:

public abstract class EventSourced : IEventSourced
{
	private readonly Dictionary<Type, Action<VersionedEvent>> _handlers = new Dictionary<Type, Action<VersionedEvent>>();
	private readonly List<VersionedEvent> _pendingEvents = new List<VersionedEvent>();

	protected EventSourced(Guid id)
	{
		Id = id;
	}

	public Guid Id { get; }
	public int Version { get; protected set; } = -1;
	public IEnumerable<VersionedEvent> PendingEvents => _pendingEvents;
	protected void Handles<TEvent>(Action<TEvent> handler) where TEvent : VersionedEvent { }
	protected void LoadFrom(IEnumerable<VersionedEvent> pastEvents){ }
	protected void Update(VersionedEvent e){ }
}

Không phân tích và lý giải lại phụ vương tính chất đang được thưa nhập IEventSourced: Id, Version, và PendingEvents.

Tiếp tục, tao sở hữu _handlers dùng làm chứa chấp những hành vi ứng mang lại ứng loại Event không giống nhau. Danh sách thành phần nhập _handlers sẽ tiến hành tăng vào sinh sống hàm constructor trải qua mệnh lệnh gọi cho tới Handles<Tênsựkiện>(Hànhđộngtươngứng). và sẽ tiến hành Invoke mọi khi đối tượng người dùng được update nhập trải qua mệnh lệnh gọi Update(). Bên cạnh đó nhập class này còn chứa chấp hàm LoadFrom() được cho phép lấy list sự khiếu nại nhập vượt lên trước khứ của một đối tượng người dùng.

Tiếp theo đòi là nội dung một class chứa chấp đối tượng người dùng chủ yếu của tất cả chúng ta (ta gọi là đối tượng người dùng Event Sourced – dịch nôm mãng cầu theo đòi giờ đồng hồ Việt, là xuất xứ của những sự kiện), ở phía trên bản thân người sử dụng code của đối tượng người dùng Booking nhằm phân tích và lý giải cơ hội implement:

Xem thêm: yêu phải kẻ ngốc

public class Booking : EventSourced
{
	private Booking(Guid id) : base(id)
	{
		Handles<TourBooked>(OnTourBooked);
		Handles<BookingCanceled>(OnBookingCanceled);
	}

	public Booking(Guid id, int tourId, string name, string tin nhắn, bool transport) : this(id)
	{
		Update(new TourBooked
		{ 
			TourId = tourId, 
			Name = name, 
			Email = tin nhắn, 
			Transport = transport 
		});
	}

	public Booking(Guid id, IEnumerable<VersionedEvent> history) : this(id)
	{
		LoadFrom(history);
	}

	public void Cancel(string reason)
	{
		Update(new BookingCanceled 
		{ 
			Email = Thư điện tử, 
			Name = Name, 
			TourId = TourId, 
			Reason = reason });
	}

	private void OnTourBooked(TourBooked tourBooked)
	{
		TourId = tourBooked.TourId;
		Name = tourBooked.Name;
		Email = tourBooked.Email;
		Transport = tourBooked.Transport;
	}

	private void OnBookingCanceled(BookingCanceled bookingCanceled)
	{
		IsCanceled = true;
		CancellationReason = bookingCanceled.Reason;
	}

	public string Name { get; private set; }
	public string Thư điện tử { get; private set; }
	public bool Transport { get; private set; }
	public int TourId { get; private set; }
	public bool IsCanceled { get; private set; }
	public string CancellationReason { get; private set; }
}

Trong phía trên sở hữu phụ vương công thức khởi tạo ra tuy nhiên triệu tập tư vấn 2 behavior chính: Khởi tạo ra mới nhất đối tượng người dùng Booking và load lại một đối tượng người dùng Booking đang được đã có sẵn trước.

  • Khởi tạo ra mới nhất đối tượng người dùng (xem dòng sản phẩm số 9): nhằm thực hiện điều này bước thứ nhất nhằm ý tiếp tục thấy các bạn nên trả list những handlers ứng cho những sự khiếu nại nhập Booking, tiếp sau đó là gọi hàm Update() nhằm tăng sự khiếu nại thứ nhất mang lại nó (ở đó là sự kiên TourBooked).
  • Load list sự kiện đang được sở hữu (xem dòng sản phẩm số 20): trước tiên các bạn cũng nên trả list Handler ứng cho những sự khiếu nại, tiếp sau đó gọi hàm LoadFrom() (hàm này và được implement ở base class EventSourced).

Tiếp theo đòi là cho tới những Repositories.

Để hiểu về kiểu cách repo hoạt động và sinh hoạt. Ta phải ghi nhận lúc nào nó được gọi. Trong văn cảnh của Event sourcing, Lúc mong muốn update kể từ UI, phần mềm thứ nhất sẽ tạo nên đối tượng người dùng EventSourced (có thể từ trên đầu hoặc từ là một list sự kiện nhập vượt lên trước khứ) tiếp sau đó gửi đối này cho tới repository nhằm thực thi đua công việc tiếp theo sau, ví dụ là, ví dụ: AbcRepository.Save().

Đi nhập class IEventSourcedRepository trước

public interface IEventSourcedRepository<T> where T : IEventSourced
{
	T Get(Guid id);
	void Save(T eventSourced);
}

Ta sở hữu 2 công thức Get và Save thay mặt đại diện mang lại 2 loại thao tác xuống DB: Read và Write. Lưu ý ở đó là Repo này tiếp tục chỉ tương tác với đối tượng người dùng của IEventSourced chứ không hề tương tác với những loại Data Model không giống.

Tiếp cho tới tiếp tục coi một repo sẽ tiến hành implement thế nào, bản thân triệu tập nhập pseudocode nhằm các bạn tưởng tượng được cơ hội nó hoạt động và sinh hoạt trước nhé:

public class EventSourcedRepository<T> : IEventSourcedRepository<T> where T : class, IEventSourced
{
	private string _connectionString;
	private JsonSerializerSettings _jsonSettings;
	private IEnumerable<IEventHandler> _eventHandlers;

	public EventSourcedRepository(IEnumerable<IEventHandler> eventHandlers)
	{
		_connectionString = "Data Source=AppData/EventSourcing-database.db;";
		_jsonSettings = new JsonSerializerSettings
		{
			TypeNameHandling = TypeNameHandling.All,
			TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
		};

		_eventHandlers = eventHandlers;
	}

	public T Get(Guid id) { }

	public void Save(T eventSourced) { }

	private EventRecord Serialize(VersionedEvent e) { }

	private VersionedEvent Deserialize(EventRecord e) { }
}

_connectionString dùng làm trỏ cho tới DB. _jsonSettings qui tấp tểnh cơ hội parse tài liệu thân ái string & object trước lúc Serialize và Deserialize. _eventHandlers là list được inject Lúc chính thức phần mềm, cụ thể phía bên trong từng handler sẽ tiến hành phân tích và lý giải sau.

Tiếp theo đòi là công thức Get(Guid): Nhiệm vụ của hàm này là trả về đối tượng người dùng EventSourced sở hữu Id và list Events.

Kế tiếp là công thức Save(T eventSourced): công thức này nhận nhập là 1 trong đối tượng người dùng eventSourced nên trách nhiệm sở hữu nó là store lại những sự kiện vô database tiếp sau đó mò mẫm handler tương ứng

Cách setup CQRS và Event Sourcing

Figure-3

Trong diagram này, tao cần phải biết trách nhiệm của những trở nên phần:

  • Command Queue tiếp tục lưu Command nhập bảng Logs
  • Command Subscriber tiếp tục lắng tai Command Queue và phụ trách tạo nên aggregate và gọi cho tới những công thức Lúc aggregate được thực thi đua. Command Subscriber cũng lưu aggregate bên dưới dạng stream nhập bảng Logs. Đồng thời tiếp tục publish sự kiện lên Event Queue.
  • Các sự kiện này sẽ tiến hành xử lý bên cạnh đó vày Event subcriberProcess Manager.
  • Process Manager tiếp tục gửi command cho tới Command Queue nhằm vấn đáp lại sự kiện.
  • Còn Event Subcriber tạo ra và update tham ô chiếu lên Query store.
  • Ngoài đi ra, định nghĩa Query search là 1 trong lớp data access dạng lightweight nhằm phát âm kể từ những tham ô chiếu
  1. Cấu trúc folder mang lại phần CQRS tiếp tục như sau:

Ta tiếp tục phân chia rõ nét Domain đi ra thực hiện nhị thư mục: ReadModel và WriteModel. Mỗi folder tiếp tục chứa chấp những model người sử dụng nhập Query và Command.

Xem thêm: truyện hàn tổng anh là đồ khốn

Trong folder Data Access tao cũng phân chia 2 folder con cái tương tự động nhằm chứa chấp Repository mang lại việc read và write như sau. Lưu ý: toàn bộ repository nhập trong suốt DataAccess\ReadModel chỉ tương tác với những model phía bên trong Domain\ReadModel và tương tự; toàn bộ repository nhập trong suốt DataAccess\WriteModel chỉ tương tác với những model phía bên trong Domain\WriteModel và tương tự động.

Đây là cấu tạo folder nhằm setup riêng biệt mang lại Event Sourcing:

TBD