Xử lý đồng thời ES / CQRS


20

Gần đây tôi đã bắt đầu đi sâu vào CQRS / ES vì tôi có thể cần phải áp dụng nó trong công việc. Nó có vẻ rất hứa hẹn trong trường hợp của chúng tôi, vì nó sẽ giải quyết rất nhiều vấn đề.

Tôi đã phác thảo sự hiểu biết sơ bộ của mình về cách ứng dụng ES / CQRS trông giống như được bối cảnh hóa trong trường hợp sử dụng ngân hàng đơn giản hóa (rút tiền).

ES / CQRS

Chỉ cần tổng hợp, nếu người A rút một số tiền:

  • một lệnh được ban hành
  • lệnh được bàn giao để xác nhận / xác minh
  • một sự kiện được đẩy đến một cửa hàng sự kiện nếu việc xác thực thành công
  • một trình tổng hợp loại bỏ sự kiện để áp dụng các sửa đổi trên tổng hợp

Từ những gì tôi hiểu, nhật ký sự kiện là nguồn gốc của sự thật, vì nó là nhật ký của FACTS, sau đó chúng ta có thể rút ra bất kỳ phép chiếu nào từ nó.


Bây giờ, những gì tôi không hiểu, trong sơ đồ lớn này, là những gì xảy ra trong trường hợp này:

  • quy tắc: số dư không thể âm
  • người A có số dư 100e
  • người A phát hành Rút tiền cộng đồng 100e
  • xác thực vượt qua và sự kiện MoneyWithdrewEvent of 100e được phát ra
  • trong khi đó, người A phát hành một khoản rút tiền khác là 100e
  • MoneyWithdrewEvent đầu tiên chưa được tổng hợp do đó xác thực vượt qua, vì kiểm tra xác thực đối với tổng hợp (chưa được cập nhật)
  • MoneyWithdrewEvent của 100e được phát ra vào lúc khác

==> Chúng tôi đang ở trạng thái không nhất quán của số dư ở mức -100e và nhật ký chứa 2 MoneyWithdrewEvent

Theo tôi hiểu, có một số chiến lược để đối phó với vấn đề này:

  • a) đặt id phiên bản tổng hợp cùng với sự kiện trong cửa hàng sự kiện để nếu có phiên bản không khớp khi sửa đổi, không có gì xảy ra
  • b) sử dụng một số chiến lược khóa, ngụ ý rằng lớp xác minh phải bằng cách nào đó tạo ra một

Các câu hỏi liên quan đến các chiến lược:

  • a) Trong trường hợp này, nhật ký sự kiện không còn là nguồn gốc của sự thật nữa, làm thế nào để đối phó với nó? Ngoài ra, chúng tôi đã trả lại cho khách hàng OK trong khi việc cho phép rút tiền là hoàn toàn sai, trong trường hợp này sử dụng khóa có tốt hơn không?
  • b) Khóa == bế tắc, bạn có hiểu biết gì về các thực tiễn tốt nhất không?

Nhìn chung, sự hiểu biết của tôi có đúng về cách xử lý đồng thời không?

Lưu ý: Tôi hiểu rằng cùng một người rút tiền hai lần trong một cửa sổ thời gian ngắn như vậy là không thể, nhưng tôi lấy một ví dụ đơn giản, để không bị lạc vào chi tiết


Tại sao không cập nhật tổng hợp ở bước 4 thay vì đợi đến bước 7?
Erik Eidt

Vì vậy, ý bạn là trong trường hợp này, cửa hàng sự kiện chỉ là một bản ghi chỉ được đọc khi bắt đầu ứng dụng để tạo lại tổng hợp / các phép chiếu khác?
Louis F.

Câu trả lời:


19

Tôi đã phác thảo sự hiểu biết sơ bộ của mình về cách ứng dụng ES / CQRS trông giống như được bối cảnh hóa trong trường hợp sử dụng ngân hàng đơn giản hóa (rút tiền).

Đây là ví dụ hoàn hảo của một ứng dụng có nguồn gốc sự kiện. Hãy bắt đầu.

Mỗi khi một lệnh được xử lý hoặc thử lại (bạn sẽ hiểu, hãy kiên nhẫn) các bước sau đây được thực hiện:

  1. lệnh đạt đến một trình xử lý lệnh, tức là một dịch vụ trong Application layer.
  2. trình xử lý lệnh xác định Aggregatevà tải nó từ kho lưu trữ (trong trường hợp này việc tải được thực hiện bằng cách new-ing một Aggregatethể hiện, tìm nạp tất cả các sự kiện được phát ra trước đó của tập hợp này và áp dụng lại chúng cho chính Tập hợp; phiên bản Tổng hợp được lưu trữ cho sử dụng sau này, sau khi các sự kiện được áp dụng, Tổng hợp ở trạng thái cuối cùng - tức là số dư tài khoản hiện tại được tính là một số)
  3. trình xử lý lệnh gọi phương thức thích hợp trên Aggregate, thích Account::withdrawMoney(100)và thu thập các sự kiện mang lại, nghĩa là MoneyWithdrewEvent(AccountId, 100); nếu không có đủ tiền trong tài khoản (số dư <100) thì Ngoại lệ được nêu ra và tất cả bị hủy bỏ; mặt khác, bước tiếp theo được thực hiện.
  4. trình xử lý lệnh cố gắng duy trì Aggregatekho lưu trữ (trong trường hợp này là kho lưu trữ Event Store); nó làm như vậy bằng cách nối thêm các sự kiện mới vào Event streamnếu và chỉ khi sự versionkiện Aggregatevẫn là sự kiện Aggregateđã được tải. Nếu phiên bản không giống nhau, thì lệnh được thử lại - chuyển đến bước 1 . Nếu versiongiống nhau, thì các sự kiện sẽ được thêm vào Event streamvà máy khách được cung cấp Successtrạng thái.

Kiểm tra phiên bản này được gọi là khóa lạc quan và là một cơ chế khóa chung. Một cơ chế khác là khóa bi quan khi các bài viết khác bị chặn (như chưa bắt đầu) cho đến khi cơ chế hiện tại hoàn thành.

Thuật ngữ Event streamnày là một sự trừu tượng xung quanh tất cả các sự kiện được phát ra bởi cùng một Tập hợp.

Bạn nên hiểu rằng đó Event storechỉ là một loại kiên trì khác, nơi được lưu trữ tất cả các thay đổi đối với một Tập hợp, không chỉ là trạng thái cuối cùng.

a) Trong trường hợp này, nhật ký sự kiện không còn là nguồn gốc của sự thật nữa, làm thế nào để đối phó với nó? Ngoài ra, chúng tôi đã trả lại cho khách hàng OK trong khi việc cho phép rút tiền là hoàn toàn sai, trong trường hợp này sử dụng khóa có tốt hơn không?

Cửa hàng tổ chức sự kiện luôn là nguồn gốc của sự thật.

b) Khóa == bế tắc, bạn có hiểu biết gì về các thực tiễn tốt nhất không?

Bằng cách sử dụng khóa lạc quan, bạn không có khóa, chỉ cần thử lại.

Dù sao, Khóa! = Bế tắc


2
Có một số tối ưu hóa liên quan đến việc tải một Aggregatenơi mà bạn không áp dụng tất cả các sự kiện nhưng bạn vẫn giữ một ảnh chụp nhanh Aggregateđến một điểm trong quá khứ và chỉ áp dụng các sự kiện xảy ra sau thời điểm đó.
Constantin Galbenu

Ok tôi nghĩ rằng sự nhầm lẫn của tôi xuất phát từ thực tế là cửa hàng sự kiện == xe buýt sự kiện (tôi có ý định về kafka) do đó việc xây dựng lại tổng hợp có thể tốn kém vì bạn có thể cần phải đọc lại RẤT NHIỀU sự kiện. Trong trường hợp có ảnh chụp nhanh Aggregate, khi nào thì ảnh chụp nhanh được cập nhật? Là cửa hàng ảnh chụp nhanh giống như cửa hàng sự kiện hay là một chế độ xem cụ thể có nguồn gốc từ xe buýt sự kiện?
Louis F.

Có một số chiến lược về việc tạo ảnh chụp nhanh. Một là tạo một ảnh chụp nhanh mỗi n sự kiện. Bạn nên lưu trữ ảnh chụp nhanh cùng với các sự kiện, trong cùng một địa điểm / tính bền vững / cơ sở dữ liệu, trên cùng một cam kết. Ý tưởng là ảnh chụp nhanh có liên quan chặt chẽ đến phiên bản của Uẩn.
Constantin Galbenu

Ok, tôi nghĩ rằng tôi có một tầm nhìn rõ ràng hơn về cách xử lý việc này. Bây giờ câu hỏi cuối cùng, vai trò của xe buýt sự kiện cuối cùng là gì? Nếu tổng hợp được cập nhật đồng bộ?
Louis F.

1
Có, bạn có thể sử dụng RabbitMQ hoặc bất kỳ kênh nào bạn muốn gửi các sự kiện đến các mô hình đọc không đồng bộ nhưng chỉ sau khi bạn duy trì chúng đến cửa hàng sự kiện. Thật vậy, không có xác nhận sự kiện nào được thực hiện sau khi chúng được duy trì: các sự kiện đại diện cho các sự kiện đã xảy ra; một mô hình đọc có thể hoặc không thích điều gì đó đã xảy ra nhưng nó không thể thay đổi lịch sử.
Constantin Galbenu

1

Tôi đã phác thảo sự hiểu biết sơ bộ của mình về cách ứng dụng ES / CQRS trông giống như được bối cảnh hóa trong trường hợp sử dụng ngân hàng đơn giản hóa (rút tiền).

Gần. Vấn đề là logic để cập nhật "tổng hợp" của bạn ở một nơi kỳ lạ.

Việc triển khai thông thường hơn là mô hình dữ liệu mà trình xử lý lệnh của bạn lưu trong bộ nhớ và luồng sự kiện trong kho sự kiện được giữ đồng bộ.

Một ví dụ dễ mô tả là trường hợp trình xử lý lệnh ghi đồng bộ vào kho sự kiện và cập nhật bản sao mô hình cục bộ của nó nếu kết nối đến kho lưu trữ sự kiện chỉ ra rằng việc ghi thành công.

Nếu trình xử lý lệnh cần đồng bộ hóa với cửa hàng sự kiện (vì mô hình bên trong của nó không khớp với cửa hàng), thì nó sẽ làm như vậy bằng cách tải lịch sử từ cửa hàng và xây dựng lại trạng thái bên trong của chính nó.

Nói cách khác, mũi tên 2 & 3 (nếu có) thường sẽ được kết nối với cửa hàng sự kiện, không phải với cửa hàng tổng hợp.

đặt id phiên bản tổng hợp cùng với sự kiện trong kho sự kiện để nếu có phiên bản không khớp khi sửa đổi, không có gì xảy ra

Biến thể của trường hợp này là trường hợp thông thường - thay vì nối thêm vào luồng trong luồng sự kiện, chúng tôi thường PUT đến một vị trí cụ thể trong luồng; nếu thao tác đó không tương thích với trạng thái của cửa hàng, ghi thất bại và dịch vụ có thể chọn chế độ thất bại thích hợp (không thành công cho máy khách, thử lại, hợp nhất ....). Sử dụng idempotent write giải quyết một số vấn đề trong nhắn tin phân tán, nhưng tất nhiên nó đòi hỏi phải có một cửa hàng hỗ trợ viết idempotent.


Hmm tôi nghĩ rằng tôi đã hiểu nhầm thành phần cửa hàng sự kiện. Tôi nghĩ rằng mọi thứ nên đi qua nó và được truyền phát. Điều gì xảy ra nếu cửa hàng sự kiện của tôi là một kafka và chỉ đọc? Tôi không thể đủ khả năng ở bước 2 và 3 để xem lại tất cả các tin nhắn. Có vẻ như tổng thể tầm nhìn của tôi phù hợp với điều này: Medium.com/t Technology
Louis F.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.