CQRS LÀ GÌ

     

Micro-services các năm về trước với tới tận hiện giờ nó vẫn là một trong hot-trend chưa xuất hiện dấu hiện hạ nhiệt , công ty nhà tín đồ người đều nói về nó, và gần như micro-services vẫn thành mặc định architecture trong hồ hết dự án. Ai ai cũng biết những điểm mạnh của nó, nhưng micro-services bản chất nó là ‘distributed system’ và tất yếu đã là distributed system thì nó rất khó khăn và phức tạp. Ví như trong quá trình thiết kế không cẩn trọng thì tất cả chúng ta sẽ dễ dãi rơi vào cái gọi là ‘micro-service madness’ (cơn điên/ác mộng với tên Micro-services).

Bạn đang xem: Cqrs là gì

Để xây cất một khối hệ thống Micro-services xuất sắc thì tốt nhất bọn họ nên bao gồm hiểu biết phần nhiều khái niệm sau: DDD (Domain-driven design) CQRS (Command Query Responsibility Segregation) và Event-Sourcing.


DDD (Domain-drivent design)

Nếu các bạn đang thao tác một khối hệ thống có nghiệp vụ (business) mập và phức hợp và đặc biệt là nếu bạn có nhu cầu hệ thống của mình sẵn sàng (ready) đến micro-service trong tương lai, thì Domain-drivent design chính là phao cứu vãn sinh của bọn chúng ta. Thực tiễn thì DDD nó đã nơi đâu đó vào giới phần mềm khoảng rộng 15 năm nay rồi, cơ mà nó chỉ “nổi tiếng" với được “chú ý” nhiều khi micro-services trở bắt buộc “nở rộ".

DDD được xây dựng bao bọc một có mang (concept) call là Bounded Context, tôi chần chừ dịch ra như thế nào có thể gọi chính là ranh giới giữa `modules` hoặc `services`trong khối hệ thống theo nghiệp vụ mà nó đại diện. Có nghĩa là mỗi bounded context đại diện thay mặt cho một nghiệp vụ duy nhất với không thể núm thế trong hệ thống, ví dụ như Order fulfilment service tốt Payment service trong một hệ thống về tài bao gồm (finance). Việc xác định đúng Context là điều đầu tiên và tối quan trọng đặc biệt trong một khối hệ thống DDD.


*

Một concept đặc biệt quan trọng khác của DDD đó chính là Ubiquitous langue, có nghĩa là một ngôn ngữ bình thường được sử dụng trong những bounded contextbởi các thành viên tham gia dự án công trình như Developers, Businesspeople … nhưng trong đó toàn bộ mọi người đều làm rõ nó, nhằm tìm ra một tiếng nói chung cho tất cả các thành phần thâm nhập dự án. Câu hỏi này nhằm tăng năng lực thấu hiểu nhiệm vụ của hệ thống, và giảm thiểu các rủi ro về giao tiếp (communicate) dẫn tới các hiểu lầm ko đáng tất cả (misunderstanding). Trong DDD tất cả mọi tín đồ trong dự án không chỉ là Business-people mà bao gồm cả Developers đều phải có nghĩa vụ và bổn phận buộc phải hiểu biết và góp sức cho nghiệp vụ (business) vào hệ thống.

Aggregate cũng là 1 trong những khái niệm đặc trưng ở tầng chuyên môn (technical level) giúp cho Developer hoàn toàn có thể ánh xạ (mapping) và quy mô hóa (object oriented) những business trong khối hệ thống vào một Object duy nhất, bắng cách tập hợp những entity có liên quan tới nhau trong một Bound Context, từng Bound Context rất có thể có một hoặc nhiều Aggregate tùy trường phái. Đặc điểm nhưng một Aggregate phải đảm bảo đó là tính nhất quán (consistency)và không bao giờ thay đổi (invariants) trong giao dịch, có nghĩa là tất cả các entity vào nó buộc phải được đi cùng mọi người trong nhà trong một transaction và đảm bảo an toàn tính nhất cửa hàng (consitency) trong mỗi vắt đổi. Điều này quan trọng quan trọng trong các khối hệ thống distributed system.

Tuy nhiên bọn họ chỉ thụ hưởng mới quy mô DDD với những hệ thống có nghiệp vụ phức tạp, mà đa phần khoảng 95% các dự án cân xứng với CRUD rộng là cùng với DDD.

DDD là một trong khái niệm tuyệt ho với phức tạp, vài cái không thể nói không còn được, có thể một nội dung bài viết khác tôi đã nói thêm bỏ ra tiết, về cơ phiên bản DDD là một trong cách tiếp cận cùng mô phỏng khối hệ thống phần mềm bên dưới giống với bí quyết nghiệp vụ quản lý và vận hành bên trên. Tức là mọi lắp thêm của nó đề xuất đều có ý nghĩa sâu sắc về mặt nghiệp vụ hơn là với mặt kỹ thuật.

Monolith

Monolith là 1 trong từ cổ chỉ một khối đá khổng lồ, trong ứng dụng nó ám chỉ một hệ thống phần mềm bao hàm nhiều thành phần khác nhau được kết hợp thành một công tác duy tuyệt nhất được xúc tiến (deploy) bên trên một nền tảng gốc rễ duy nhất. Thực hiện một ứng dụng kiểu Monolith tự lâu đã trở thành một tiêu chuẩn chỉnh (standard) trong giới phần mềm. Một hệ thống kiểu Monolith trường hợp được module hóa cùng thiết kế tốt (well-designed) thì việc vận hành, gia hạn (maintain) hay tăng cấp vẫn hết sức tốt, không giống như các Micro-services “fan-boy” hay lôi ra để chê bai và dìm sản phẩm Monolith. Tuy vậy thì vào “thực chiến” nhiều số bọn họ thường không duy trì được thiết kế xuất sắc khi dự án công trình lớn dần, dẫn tới những vấn đề về bài toán maintain, nhưng mà trong trường vừa lòng xấu độc nhất hệ thống chúng ta sẽ đổi mới một trái bóng bùn (Big Ball of Mud).


*

Photo by Zoltan Tasi on Unsplash

Vậy nỗ lực nào là 1 Monolith well-designed? Làm rứa nào để họ tránh được Big Ball of Mud? Câu trả lời đó là DDD (domain-driven design), một khối hệ thống Monolith đi theo phía design của DDD sẽ bóc biệt ra các thành phần (component) tốt module ra từng bounded context theo từng nhiệm vụ của nó đại diện. Nói thì dễ nhưng để triển khai được vấn đề đó người thiết kế khối hệ thống phải là người nối liền về business của hệ thống không thua thảm kém gì các buiness-people. Điều này cũng sẽ rất thuận lợi cho việc nếu có một lý vị nào đó ta buộc phải phân bóc tách hệ thống Monolith ra những services không giống nhau (micro-services), chúng ta chỉ cần tách bóc các bounded context ra các thành phần riêng rẽ biệt.

Tuy nhiên bao gồm một vấn đề khi bọn chúng ta tách bóc Monolith thành các Micro-Services sẽ là việc tiếp xúc (communication) giữa những services. Ở khối hệ thống Monolith nó chỉ solo gian là các object calls, dẫu vậy trong Micro-Serivies thì bài toán này phải trải qua net-work bằng cách sử dụng các kỹ thuật như API Call, RPC hay sự kiện Bus thông sang 1 khái niệm điện thoại tư vấn là location transparency mà bọn họ sẽ trở lại và bàn thêm sau.

Microservices

Tới bây chừ Microservices không còn là định nghĩa gì mới mẻ và lạ mắt nữa, các concept như thể service boundaries, asynchronous message xuất xắc application database, v.V… đang là các concept danh tiếng và được sử dụng trong không ít năm qua.


*

Nguồn ảnh: https://microservices.io/patterns/microservices.html

Rất nhiều các ưu điểm để xúc tiến một hệ thống theo Microservices như là “độc lập về phạt triển, xúc tiến và mở rộng (independent development/deployment/scale) v.V… nhưng theo tôi thì ưu thế nhất của Microservices đó tương xứng với cách thao tác làm việc và tiếp xúc “giữa người với người”. Về bản chất con fan chỉ hoàn toàn có thể làm việc và tiếp xúc với nhau tốt nhất với một team dưới 10 người, bởi thật quá cực nhọc khi thao tác trên một phần mềm có không ít kỹ sư. Vị thế họ cần đề nghị làm là tạo mỗi nhóm chủ quyền trên những phần khác biệt của hệ thống, đó là tính Agility trong Agile. Vì chưng vậy không phải ngẫu nhiên một Agile team hoặc như một 1-1 vị nhỏ nhất trong quân nhóm (tiểu đội) cũng nên làm có bên dưới 10 người.

Với một khối hệ thống Micro-services được thiết kế theo phong cách tốt thì các team phụ trách từng services đã implement, deploy cùng run các ứng dụng của bản thân mình một cách độc lập và ít ảnh tận hưởng tới những team khác. Và tất nhiên nó rất tốt và phù hợp với những vấn đề về mở rộng (scalability) sau này.

Tuy nhiên như đang nói trên Micro-services là một khối hệ thống Distributed System, nó luôn đi kèm với những phức tạp trong câu hỏi vận hành, tiến hành và về phía kỹ thuật (technical) lẫn nghiệp vu (business) chính vì mỗi service không thể nào thực sự độc lập, nó luôn luôn cần dữ liệu (data) từ bỏ services, qua cách communication cùng với nhau mặc dù ít xuất xắc nhiều. Các service thì có nhiều phương pháp để giao tiếp với nhau nhưng thường thì đó là thứ hạng request-response sử dụng API qua HTTP hoặc RPC, hoặc giữ hộ message theo kiểu send-and-forget theo mô hình Pub/Sub. Cũng từ đó mà nẩy sinh ra những vấn đề khác như “data consistency” trong phong cách xây dựng Microservices.

Do đó câu hỏi xác định chuẩn chỉnh xác các bounded contexts giỏi service boundaries và cách các services tiếp xúc với nhau ngay từ đầu là một câu hỏi tối quan trọng. Chính vì việc refactoring hay dịch rời (moving) các công dụng (functionality) vào Micro-services trở ngại hơn rất nhiều lần so với trong Monolith.

Các kỹ sư thao tác làm việc lâu năm với Distributed system hay nói rằng: “Nếu các bạn không thể kiến tạo một khối hệ thống Monolith well-designed (với DDD) thì hãy quên đi bài toán xây dựng kiến trúc Microservices.”

Có thể thấy DDD nó cân xứng và đặc biệt trong Micro-services mang lại nhường nào, vì chưng vậy hãy đừng nói với tôi rằng chúng ta đang thao tác với Microservies mà không biết gì DDD nhé :D.

Event-Driven Architecture

Như đã nói ở trên rằng những service luôn luôn có nhu cầu giao tiếp với các service khác, cách tương xứng nhất cùng với việc giao tiếp này sẽ là gửi dấn message giữa các services theo một biện pháp bất đồng nhất (asynchronously). Phong cách xây dựng đó thường xuyên được hotline là Event-Drivent Architecture (EDA), trong EDA ta có mang ra bố loại message:

Event: Nó đại diện thay mặt cho một thông điệp nhắc nhở rằng đã có gì đó đã sẩy ra nơi đâu đó. Đặc điểm của sự kiện là nó không thay đổi (immutable).Command: Nó đại diện cho một hành động mà chỗ gửi (publisher) ao ước nơi nhận (consumer) thực hiện một cái gì đó, cùng kết quả của hành vi sẽ được giữ hộ lại mang đến sender. Đặc điểm của command là nó luôn luôn có ít nhất một chỗ nhận (consumer)Query: Nó đại diện cho một yêu cầu tài liệu trả về từ địa điểm gửi (publisher) cho tới một tuyệt nhiều vị trí nhận (consumer), dữ liệu sẽ được lấy cùng trả về cho publisher.

Xem thêm: Các Tác Phẩm Văn Học Viết - Thể Loại:Tác Phẩm Văn Học Việt Nam

Trong EDA ta sẽ sử dụng message kiểu event nếu quảng cáo online gửi đi (emit) message mà lại không quan tâm tới gồm consumer như thế nào lắng nghe (listening), và bao gồm cả nếu không có consumer nào lắng nghe thì quảng cáo online vẫn đang thực hiện hành vi của nó. Message hình dạng Command được thực hiện nếu advertiser mong ngóng một điều gì đấy sẽ sẩy ra ở một service khác một bí quyết bất đồng bộ (asynchronous), trước khi nó fulfilment nhiệm vụ (business task) của quảng cáo trên internet đó, bằng cách chờ đợi hiệu quả hành hễ từ consumer trả về . Bọn họ sẽ sử dụng message thứ hạng Query nếu như muốn lấy thông tin xuất phát điểm từ một hoặc những service khác. Dữ liệu cũng biến thành được trả về tự consumer tới publisher theo một cách bất đồng bộ.


*

Một lấy ví dụ như về EDA trong thực tế là trong một hệ thống về eCommerce gồm một service là Order Fulfilment, service này luôn yêu cầu deals (Order) buộc phải được giao dịch thanh toán (payment) trước lúc nó thực hiện cách hành vi khác. Lúc này Order Fulfilment service vẫn gửi một asynchronous command message cho tới Payment service, lúc ấy Payment service sẽ triển khai việc giao dịch thanh toán và trả về một event message chứa hiệu quả thành công hay thất bại. Order Fulfilment service sẽ consumer kết quả và liên tục những process tiếp sau (cancel order/shipping order).

Trong EDA mỗi sự kiện nó vẫn không phản ánh ở tầng kỹ thuật (technical level) nhưng nó phải ánh xạ với có chân thành và ý nghĩa với một hành vi của nghiệp vụ (business level) nhất thiết trong hệ thống. Lấy ví dụ như thay vì chưng sử dụng sự kiện CustomerChanged để gửi thông điệp rằng quý khách đang thay đổi add mà họ nên sử dụng sự kiện CustomerMoved, nó vẫn có ý nghĩa sâu sắc (meaningful) cùng với business hơn. Vì thế việc modelling event cũng nên tập chung vào hành động (behavioural) của nghiệp vụ nhiều hơn thế nữa là cấu trúc (structure) của model theo hơi vị trí hướng của Aggregate vào DDD. Điều này sẽ để cho ứng dụng dễ dàng nắm bắt hơn rằng nó đang làm những gì ở mắt nhìn về business, thông qua đó ta thấy rằng concept của DDD lại một lần nữa phù hợp ở đây.

Eventual Consistency

Trong mọi hệ thống trong thực tế thì sự kiện bắt buộc phải đáp ứng nhu cầu việc nhất quán và đồng bộ (Eventual Consistency). Ví như việc chuyển tiền giữa hai tài khoản của hai ngân hàng thì hai command sự kiện bắt đề nghị được triển khai một cách đồng bộ và duy nhất quán, ko thể thông tin tài khoản A bị trừ tiền và thông tin tài khoản B vẫn không sở hữu và nhận được chi phí được. Trong các số đó mọi event được dồng bộ và đồng bộ giữa một hoặc nhiều service khác biệt trong hệ thống, vấn đề này cũng kéo theo sự tinh vi không đáng có trong hệ thống, tuy tinh vi nhưng nó là điều hiển nhiên và tất yêu tránh khỏi (inevitable)trong distributed system.


*

Eventual consistency is an inevitable concept in large-scale distributed systems lượt thích … Thanos

Bởi vì một trong những quyết định vào business logic luôn luôn luôn đề nghị đưa ra dựa trên những dữ liệu đồng nhất nghiêm ngặt (data consistency) và đáng tin cậy, và công dụng các ra quyết định đó cũng phải được cập nhật tương ứng với các thành phần liên quan. Tương tự như trong DDD những Aggregate luôn luôn phải đồng nhất và không bao giờ thay đổi (consistent và invariants), những entity cùng value object vào một Aggregate phải luôn consistent cùng nhau khi nghiệp vụ cần mang ra hay nắm đổi.

Command Query Responsibility Segregation (CQRS)

CQRS thực chất là một concept rất đơn giản dễ dàng là bóc tách phần command và query (đọc&ghi) ra thành nhị thành phần (component) đơn nhất mục đích để tối ưu bài toán đọc hoặc ghi vào hệ thống.


Điểm dũng mạnh của phong cách xây dựng này là command chỉ tác động tới một Aggregate trong lúc đó query rất có thể đọc và lấy một lượng béo dữ liệu từ nhiều nguồn. Tức là ta hoàn toàn có thể hạn chế tác động (effect) của bài toán ghi tài liệu và tối ưu hóa (optimize) truy vấn (query) bỏ phần đọc. Cùng với việc tách bóc biệt (segregation) đọc&ghi (read&write) hệ thống hoàn toàn có thể dễ dàng áp dụng những data storage khác nhau cho việc tối ưu vận tốc (performant) mang lại từng loại. Mà thông thường thì bài toán read đã tốn performant hơn tác vụ write, do vậy việc tách bạch này cũng khiến cho ta thuận tiện optimized tốt scaling cho chỗ read side.

Tuy nhiên việc bóc biệt này dẫn tới câu hỏi ta cần luôn đồng nhất dữ liệu trường đoản cú write side cùng với read side. Với việc đồng hóa kiểu bất đồng nhất (asynchronously) sẽ để cho dữ liệu read side gần như là không thể phản ánh và đồng bộ tức thời (immediately) từ dữ liệu của write side. Việc phải tạo cho đọc&ghi nên synchronous cùng với nhau, hay hệ thống phải đảm bảo eventual consistency cũng có tác dụng cho hệ thống phức tạp hơn không ít lần.

Tuy nhiên CQRS cũng giống như DDD chúng ta chỉ tận hưởng với nó bên trên một vài hệ thống có nghiệp vụ tinh vi đặc thù dựa trên bản vẽ xây dựng EDA, mà phần nhiều các khối hệ thống còn lại phù hợp với dạng CRUD hơn, cùng nó nên thực hiện theo phương pháp đó. Đặc biệt là CQRS đa số chỉ cân xứng với một trong những phần cụ thể trong hệ thống (BoundContext trong DDD) rộng là trên toàn bộ hệ thống.

CQRS sẽ khiến cho hệ thống sẽ trở phải rất phức tạp, vì vậy bọn họ phải rất cẩn thận khi áp dụng CQRS, do nó tương tự như Mircoservice là một hệ thống rất cực nhọc để áp dụng tốt. Giả dụ không kiến thiết và sử lý tốt bọn họ sẽ yêu cầu trả giá đắt ngay cả khi ta tất cả một team có năng lực về công nghệ tốt.

Event sourcing

Ý tưởng của sự kiện sourcing đang có từ tương đối lâu và cũng không mới mẻ gì, trong nội bộ đa số các database đều sử dụng kiến trúc sự kiện sourcing, ví dụ bề ngoài Binlog vào MySQL hay audit Log vào Oracle.

Concept của sự kiện sourcing là lưu trữ (persisted) toàn bộ lịch sử thay đổi của business entity và được sắp sếp theo trình tự thời gian của sự biến hóa (time-ordered sequence).


Khi trạng thái của entity bị nuốm đổi, một message dạng sự kiện sẽ gửi đi mục tiêu để giữ lại lịch sử thay đổi của entity. Ta hoàn toàn có thể persisted sự chuyển đổi ngay nhanh chóng khi event tới, hoặc snapshot thời hạn nếu entity bao gồm số lượng sự kiện lớn nhưng ta hy vọng optimize. Các hệ thống như tài chủ yếu (finance), ngân hàng (banking) hay bảo hiểm (insurance) event Sourced tiếp tục được sử dụng, mục tiêu là để lưu trữ lại tất cả các chuyển đổi trong hệ thống để có thể xử lý sau này nếu cần.

Điểm mạnh của nó là ta có thể tái hiện (reconstructed) tâm trạng của entity tại một thời điểm bất kỳ, bằng cách phát lại (replaying all) tất cả các sự kiện phát sinh tới thời khắc đó. Điều này còn có hữu ích trong việc tái hiện bug hoặc rollback lại tinh thần của entity nếu tất cả lỗi xảy ra. Tuy nhiên việc replaying all này phải triển khai với sự cẩn thận, vị rất rất có thể khi phạt lại đa số command event tác động tới những service khác, ví dụ sự kiện OrderPlaced được vạc đi lại(emit) thì rất có thể event OrderFulfilled sẽ tiến hành thực hiện nhiều hơn nữa một lần.

Event sourcing hay được thực hiện như 1 phần trong CQRS để nhất quán sự biến hóa của Command cùng với Query. Tuy nhiên không phải tất cả hệ thống đều sở hữu event sourced, nhưng nó phụ thuộc vào vào business của từng bounded contexthoặc theo từng nhiệm vụ của Aggregate. Các event sourcing tránh việc publish ra ngoài bounded context của chính nó để tránh rất nhiều sự phụ thuộc không cần thiết giữa những bounded context.

Location Transparency

Một concept rất quan trọng khác trong vấn đề xậy dựng một Monolith sẵn sàng chuẩn bị cho Microservice là Location Transparency, nó để giúp đỡ việc các Context định vị được vị trí Context khác mà lại nó cần tương tác (interacts) tới. Việc này làm tinh giảm sự nhờ vào (dependency) giữa những bounded context vào một dự án Monolith, khi mà đều component mọi được deploy phổ biến trên một đơn vị (unit). Location Transparency giúp ích cho việc có thể biến đổi Monolith quý phái Microservice khi mà gần như service phần đa được deploy lên các môi trường thiên nhiên riêng biệt, nhưng không nên thay đổi ngẫu nhiên dòng code nào. Có nhiều phương pháp để cài để Location Transparency như thực hiện messaging với những dữ liệu kiểu asynchronous, hoặc HTTPS/RPC với tài liệu trao đổi mẫu mã synchronous.

Ví dụ vào một dự Monolith viết bằng Java là những bounded context sẽ hội đàm asynchronus với nhau qua sự kiện Bus hoặc thiết đặt Interface bên trên bounded context cùng Implement của chính nó sẽ nằm tại Locaiont Transparency giả dụ cần thảo luận kiểu synchronous.

Xem thêm: Số Po Là Gì ? Có Ý Nghĩa Thế Nào Trong Xuất Nhập Khẩu Purchase Order

Kết luận: các kiến trúc như Microservice, CQRS hay event Sourcing ko phải là 1 trong viên đạn bội nghĩa (silver bullet) để giải quyết và xử lý tất cả các bài toán. Nhưng mà nó chỉ tương xứng cho vài khối hệ thống đặc thù tất cả domain tuyệt business phức tạp như các khối hệ thống banking, finance, insurance hay eCommerce. Cùng nó bao gồm điểm tầm thường là đều sử dụng DDD như một cửa hàng kiến trúc cũng giống như lý luận trong hệ thống.