Tái cấu trúc Monolith thành Microservices

Tổng quan về cách tái cấu trúc thành Microservices

Phương pháp chuyển đổi monolithic application( Ứng dụng một khối ) thành microservices( Nhiều phần nhỏ ) là một phương thức hiện đại hóa ứng dụng. Đó là điều mà các lập trình viên đã làm trong nhiều thập kỷ. Kết quả là, có một số ý tưởng mà chúng ta có thể sử dụng khi tái cấu trúc một ứng dụng thành microservices.

Một bài học đó là chúng ta không nên viết lại từ đầu ứng dụng theo hướng microservices, tuy nghe rất hấp dẫn nhưng việc đó rất nguy hiểm và chúng ta có thể thất bại bất cứ lúc nào.

Thay vì viết lại từ đầu, bạn nên điều chỉnh lại các monolithic application của bạn. Bạn dần dần build một ứng dụng mới phù hợp với microservices, và chạy nó cùng với monolithic application. Theo thời gian, số lượng các chức năng được thực hiện bởi các monolithic application giảm xuống cho đến khi nó biến mất hoàn toàn hoặc nó được thực hiện bởi một microservice khác.

Martin Fowler đề cập đến chiến lược hiện đại hóa ứng dụng này như là Strangler Application. Cái tên này xuất phát từ cây strangler vine “Cây sung sống bám ” (a.k.a. strangler fig) được tìm thấy trong rừng nhiệt đới. Loài cây này bám chặt xung quanh một cái cây khác để đạt được ánh sáng mặt trời trên tán rừng. Đồng thời hút chất dinh dưỡng của cây chính để chết. Áp dụng cho quá trình hiện đại hóa theo cách tương tự. Chúng tôi sẽ xây dựng một ứng dụng mới bao gồm microservices xung quanh các ứng dụng nền tảng, cho đến khi chúng bị thay thế hoàn toàn.

Cây sung sống bám (Strangler Fig)

Chiến lược 1 – Ngừng nạp code mới vào monolithic application

Luật lỗ hổng nói rằng bất cứ khi nào bạn đang ở trong một hố sâu, bạn nên ngừng đào. Đây là lời khuyên tuyệt vời để theo dõi khi monolithic application của bạn đã vượt tầm kiểm soát. Nói cách khác, bạn nên ngừng việc làm monolith lớn hơn. Điều này có nghĩa là khi bạn đang triển khai các chức năng mới, bạn không nên nạp code vào monolith. Thay vào đó, ý tưởng của chiến lược này là đưa code mới vào một microservice độc lập. Biểu đồ sau cho thấy kiến trúc hệ thống sau khi áp dụng cách tiếp cận này.

Cũng như các new service và legacy monolith, có hai thành phần khác. Đầu tiên là request router, nó xử lý các request đến (HTTP). Router gửi request tương ứng với chức năng mới đến new service. Còn các legacy request sẽ chuyển vào monolith.

Có ba cách mà một service có thể sử dụng để truy cập dữ liệu của monolith:

  • Gọi remote API được cung cấp bởi monolith
  • Truy cập trực tiếp vào cơ sở dữ liệu của monolith
  • Duy trì bản sao của dữ liệu, được đồng bộ với cơ sở dữ liệu của monolith

Glue code đôi khi được gọi là anti‑corruption layer. Bởi vì glue code bảo vệ service, có mô hình domain riêng, không bị ảnh hưởng bởi các khái niệm từ mô hình domain legacy monolith. Glue code chuyển đổi giữa hai mô hình khác nhau. Thuật ngữ anti‑corruption layer lần đầu tiên xuất hiện trong cuốn sách Domain Driven Design của Eric Evans. Phát triển anti‑corruption layer có thể là một quyết định không tầm thường. Nhưng đó là điều cần thiết để thoát khỏi địa ngục nguyên khối.

Thực hiện các chức năng mới như là lightweight service có một vài lợi ích. Nó ngăn chặn việc tăng khối lượng đến mức không thể quản lý nữa. Service này có thể được phát triển, triển khai, và mở rộng một cách độc lập với monolith. Bạn trải nghiệm những lợi ích của kiến trúc microservices mỗi khi service mới được tạo ra.

Tuy nhiên, cách tiếp cận này không giải quyết được các vấn đề với monolith. Để khắc phục những vấn đề bạn cần phải phá vỡ cấu trúc monolith. Hãy dựa vào các chiến lược để làm điều đó.

Chiến lược 2 – Tách Frontend và Backend

Một chiến lược thu nhỏ monolithic application là tách lớp Presentation, Business Logic, và Data Access. Một enterprise application điển hình bao gồm ít nhất ba loại thành phần khác nhau:

  • Lớp Presentation: Là thành phần xử lý các yêu cầu HTTP và triển khai một API (REST) hoặc một giao diện web HTML. Trong một ứng dụng có một giao diện hiệu quả thân thiện với người dùng , lớp presentation thường là một phần cơ bản của code.
  • Lớp Business logic: Là thành phần cốt lõi của ứng dụng và hoàn thiện các quy tắc.
  • Lớp Data‑access: Là thành phần truy cập các thành phần cơ sở hạ tầng như cơ sở dữ liệu và message broker (mô giới thông điệp).

Thường có sự tách biệt logic rõ ràng giữa presentation ở một phía và business và truy cập data‑access ở phía bên kia. Các lớp business có một API “thô”(coarse-grained) bao gồm một hoặc nhiều facade, bao gồm các thành phần business logic . API này là một natural seam dọc theo đó bạn có thể phân chia monolith thành hai ứng dụng nhỏ hơn. Một ứng dụng chứa lớp presentation. Các ứng dụng khác có business logic và data‑access logic. Sau khi tách, ứng dụng presentation logic thực hiện lệnh gọi đến ứng dụng business logic. Sơ đồ sau đây cho thấy kiến trúc trước và sau khi tái cấu trúc.

Tách monolith bằng cách này có hai lợi ích chính. Nó cho phép bạn phát triển, triển khai, và scale hai ứng dụng độc lập với nhau. Đặc biệt, nó cho phép các lập trình viên nhanh chóng lặp lại lớp presentation trên giao diện người dùng và dễ dàng thực hiện kiểm thử A | B. Một lợi ích khác là nó cho thấy một remote API có thể được gọi bởi các microservices mà bạn phát triển.

Tuy nhiên đây chỉ là một phần giải pháp. Rất có thể một hoặc cả hai ứng dụng sẽ là monolith khó quản lý được. Bạn cần phải sử dụng chiến lược thứ ba để loại bỏ các monolith còn lại.

Chiến lược 3 – Giải nén Services

Chiến lược tái cấu trúc thứ ba là chuyển các module hiện có trong monolith thành các microservices độc lập. Mỗi lần bạn giải nén một module và biến nó thành một service, monolith sẽ thu nhỏ lại. Một khi bạn đã chuyển đổi đủ các module, monolith sẽ không còn là vấn đề nữa. Hoặc nó biến mất hoàn toàn hoặc nó trở nên nhỏ tới mức bằng một service.

Ưu tiên các module để chuyển đổi thành services

Một ứng dụng monolithic lớn, phức tạp bao gồm hàng chục hoặc hàng trăm module, tất cả đều là đối tượng để giải nén. Tìm ra những module nào để chuyển đổi đầu tiên thường là thử thách. Một cách tiếp cận tốt là bắt đầu với một vài module dễ dàng giải nén. Điều này sẽ bổ sung cho bạn kinh nghiệm với microservices nói chung và quá trình giải nén nói riêng. Sau đó bạn nên giải nén các module sẽ mang lại cho bạn lợi ích lớn nhất.

Chuyển đổi module thành một service thường mất thời gian. Bạn muốn sắp xếp các module theo lợi ích mà bạn sẽ nhận được. Nó thường có ích trong việc lấy các module thay đổi thường xuyên. Một khi bạn đã chuyển đổi một module thành một service, bạn có thể phát triển và triển khai nó một cách độc lập với monolith, điều này sẽ thúc đẩy sự phát triển.

Nó cũng có lợi cho việc giải nén module có yêu cầu về tài nguyên đáng kể so với các khối còn lại của monolith. Ví dụ, để biến một module có cơ sở dữ liệu trong bộ nhớ vào một service, sau đó có thể được triển khai trên máy chủ với lượng lớn bộ nhớ. Tương tự như vậy, có thể giải nén các module thực hiện các thuật toán phức tạp, bởi vì service này có thể được triển khai trên các máy chủ có nhiều CPU. Bằng cách chuyển các module có yêu cầu tài nguyên cụ thể sang các service, bạn có thể làm cho ứng dụng của bạn dễ dàng hơn nhiều để scale.

Khi tìm ra các module nào cần giải nén, sẽ rất hữu ích để tìm kiếm ranh giới “thô” (a.k.a seam). Chúng giúp việc biến các module thành các service dễ dàng và đỡ tốn kém hơn. Một ví dụ về ranh giới, là một module chỉ giao tiếp với phần còn lại của ứng dụng thông qua các thông báo không đồng bộ. Nó làm đơn giản hoá việc chuyển module thành microservice.

Giải nén Module như thế nào

Bước đầu tiên của việc giải nén một module là xác định giao diện cơ bản giữa module và monolith. Hầu như đấy chắc chắn là một API hai chiều, vì monolith sẽ cần dữ liệu thuộc sở hữu của service và ngược lại. Thường rất khó để thực hiện API như vậy vì tính phụ thuộc lẫn lộn và các mô hình tương tác phức tạp giữa module và phần còn lại của ứng dụng. Business logic được thực hiện bằng cách sử dụng mô hình Domain Model đặc biệt khó để tái cấu trúc bởi vì sự liên kết giữa rất nhiều lớp domain model. Bạn thường cần phải thực hiện những thay đổi code quan trọng để phá bỏ những tính phụ thuộc. Sơ đồ dưới đây cho thấy việc tái cấu trúc.

Một khi bạn thực hiện các giao diện “thô”, sau đó chuyển các module vào một service độc lập. Để làm điều đó, bạn phải viết code để cho phép monolith và service liên kết qua một API sử dụng cơ chế kết nối giữa các quá trình (IPC). Biểu đồ sau cho thấy cấu trúc trước, trong và sau khi tái cấu trúc.

Trong ví dụ này, Module Z là module cần giải nén. Các thành phần của nó được sử dụng bởi Module X và sử dụng Module Y. Bước tái cấu trúc đầu tiên là xác định một cặp API “thô”. Giao diện đầu tiên là một giao diện inbound được sử dụng bởi Module X để gọi Module Z. Thứ hai là một giao diện outbound được sử dụng bởi Module Z để gọi Module Y.

Bước tái cấu trúc thứ hai biến module thành một service độc lập. Các giao diện trong và ngoài được thực hiện bằng code sử dụng cơ chế IPC. Bạn rất có thể sẽ cần phải xây dựng service bằng cách kết hợp Module Z với Microservice Chassis framework để giải quyết các mối quan tâm xuyên suốt như tìm service.

Một khi bạn đã trích xuất một module, bạn còn có một service khác có thể được phát triển, triển khai, và được scaled độc lập với các monolith và bất kỳ service nào khác. Bạn thậm chí có thể viết lại service từ đầu; Trong trường hợp này, mã API tích hợp service với monolith sẽ trở thành một lớp anti‑corruption chuyển đổi giữa hai mô hình domain. Mỗi lần bạn giải nén một service, bạn đi theo hướng microservices. Theo thời gian, monolith sẽ giảm lại và số lượng microservices ngày càng tăng.

Tóm tắt

Quá trình chuyển một ứng dụng hiện có sang microservices là một hình thức hiện đại hóa ứng dụng. Bạn không nên chuyển thành microservices bằng cách viết lại ứng dụng của bạn từ đầu. Thay vào đó, bạn nên điều chỉnh lại ứng dụng của bạn phù hợp với microservices. Có ba chiến lược bạn có thể sử dụng: triển khai các chức năng mới trên microservices; Tách các thành phần presentation từ các thành phần business và data access; Và chuyển đổi các module hiện có trong monolith thành các service. Theo thời gian số lượng microservices sẽ phát triển, và sự nhanh nhẹn và tốc độ của team lập trình của bạn sẽ tăng lên.

Techtalk via Nginx