NỘI DUNG BÀI VIẾT
Trong nhiều năm gần đây, chúng ta đang xây dựng ngày càng nhiều cấc hệ thống và làm cho nó ngày một tốt hơn. Một số các công nghê, các mô hình kiến trúc và các phương pháp mới đã xuất hiện trong khoảng thời gian gần đây. Và Microservice là một trong những mẫu kiến trúc xuất hiện từ domain-driven design, continuous delivery (liên túc đóng gói), tự động hóa các nền tảng và cơ sở hạ tầng.
Microservice là gì ?
Robert C. Martin đã đặt ra thuật ngữ Single responsibility priciple trong nguyên lý SOLID và trong đó có chỉ rõ rằng:“gather together those things that change for the same reason, and separate those things that change for different reasons.” (Tập hợp lại những thứ thay đổi do cùng một nguyên nhân với nhau và tách những thứ thay đổi do nguyên nhân khác nhau).
Kiến trúc microservice có cùng cách tiếp cận như trên và kế thừa nó để các service không phụ thuộc quá nhiều vào nhau để từ đó chúng ta có thể dễ dàng phát triển, triển khai và duy trì hệ thống một cách độc lập. Mỗi service này sẽ chịu trách nhiệm với những nhiệm vụ riêng biệt với các service khác thông qua các API đơn giản để giải quyết các vấn đề phức tạp hơn.
Những lợi ích chính của việc sử dụng Microservice
Vì các service được cấu thành có quy mô nhỏ nên chúng có thể được xây dựng bởi một hoặc nhiều các service nhỏ hơn ngay từ đầu nên sẽ giúp cho chúng ta có thể dễ dàng mở rộng và phát triển ứng dụng hơn.
Sau khi được phát triển, các service này cũng có thể được triển khai với nhau một cách độc lập đo đó dễ dàng xác định được các service quan trọng và mở rộng quy mô của chúng một cách độc lập với ứng dụng của chúng ta. Microservice cũng có khả năng cung cấp cho chúng ta khả năng cô lập các issue (lỗi) của hệ thống nên do đó khi xảy ra lỗi trong 1 service bất kỳ, hệ thống của chúng ta sẽ không bị ảnh hưởng do service đó lỗi và do đó hệ thông cũng không nhất thiết phải tạm ngừng hoạt động. Khi lỗi được khắc phục, nó có thể sẽ được triển khai bởi các service tương ứng thay vi được triển khai lại toàn bộ ứng dụng của chúng ta.
Một lợi thế khác của việc sử dụng kiến trúc Microservice đó là nó sẽ sắp xếp mọi thứ dưới dạng bảng giúp bạn dễ dàng lựa chọn các công nghệ (ngôn ngữ lập trình, cơ sở dữ liệu,…) phù hợp với các chức năng (service) được yêu cầu nhất thay vì chúng ta bắt buộc phải thực hiện cách tiếp cận tiêu chuản, phải phù hợp với tất cả.
Làm thế nào để có thể bắt đầu sử dụng kiến trúc Microservice ?
Hy vọng rằng giờ đây bạn có thể tin rằng kiến trúc Microservice có thể mang lại một số lợi thế độc đáo so với kiến trúc truyền thống và bạn đã bắt đầu nghĩ về kiểu tiếp cận này cho dự án tiếp theo của mình.
Và câu hỏi tiếp theo của mọi người sẽ là làm thế nào để có thể bắt đầu ? Và có bộ nguyên tắc tiêu chuẩn nào mà tôi có thể tuân theo để xây dựng được dự án theo kiến trúc microservice theo cách tốt hơn hay không ? Tôi e rằng câu trả lời sẽ là không.
Mặc dù điều đó nghe có vẻ không hứa hẹn gì nhiều, nhưng tuy nhiên, vẫn có một số chủ đề phổ biến mà nhiều tổ chức đã áp dụng kiến trúc Microservice đã tuân theo và cuối cùng họ đã tìm thấy thành công. Tôi sẽ thảo luận về một số chủ đề phổ biến bên dưới.
1. Làm thế nào để có thể Decompose (phân giải)
Một trong những cách để giúp công việc của chúng ta dễ dàng hơn có thể là xác định các service tương ứng với khả năng kinh doanh. Năng lực kinh doanh là điều mà một doanh nghiệp thực hiện để cung cấp giá trị cho người dùng cuối của mình.
Việc xác định khả năng kinh doanh và các service tương ứng đòi hỏi sự hiểu biết ở mức độ cao về doanh nghiệp. Ví dụ: các khả năng kinh doanh cho một ứng dụng mua sắm trực tuyến có thể bao gồm những điều sau đây:
- Danh mục quản lý sản phẩm
- Quản lý hàng tồn kho
- Quản lý các đơn đặt hàng
- Quản lý vận chuyển
- Quản lý người dùng
- Sản phẩm nên dùng
- Quản lý review sản phẩm
Khi các khả năng kinh doanh đã được xác định, các service có thể được xây dựng tương ứng với từng khả năng kinh doanh đã được xác định này.
Mỗi service có thể được sở hữu bởi một nhóm khác nhau, những người trở thành chuyên gia trong lĩnh vực cụ thể đó và chuyên gia trong các công nghệ phù hợp nhất cho các service cụ thể đó. Điều này thường dẫn đến ranh giới API ổn định hơn và các nhóm ổn định hơn.
2. Build và Deploy
Sau khi quyết định ranh giới service của các service nhỏ này, chúng có thể được phát triển bởi một hoặc nhiều nhóm nhỏ bằng cách sử dụng các công nghệ phù hợp nhất cho từng mục đích. Ví dụ: bạn có thể chọn xây dựng User Service bằng Java với cơ sở dữ liệu MySQL và Product Recommendation Service với Scala / Spark.
Sau khi được phát triển, CI / CD có thể được cài đặt với bất kỳ máy chủ CI nào có sẵn (ví dụ như Jenkins, TeamCity, Go, …) để chạy các automation test case và deploy các service này một cách độc lập cho các môi trường khác nhau (Integration, QA, Staging, Production, …)
3. Thiết kế các Service cẩn thận
Khi thiết kế các Service, hãy xác định cẩn thận chúng và suy nghĩ về những gì sẽ được hiển thị, những giao thức nào sẽ được sử dụng để tương tác với service đó.
Điều này rất quan trọng vì phải che giấu mọi sự phức tạp và sự triển khai chi tiết của service và chỉ tiết lộ những gì khách hàng của service cần. Nếu các chi tiết không cần thiết bị lộ, rất khó để thay đổi service sau này vì sẽ có rất nhiều công việc khó khăn để xác định ai đang dựa vào các phần khác nhau của service. Ngoài ra, tính linh hoạt có thể sẽ bị mất khi triển khai service một cách độc lập.
Sơ đồ dưới đây sẽ cho chúng ta thấy một trong những lỗi phổ biến khi thiết kế MicroService:
Như bạn có thể thấy trong sơ đồ, ở đây chúng ta đang sử dụng một service (Service 1) và lưu trữ tất cả thông tin cần thiết của Service vào cơ sở dữ liệu. Khi một service khác (Service 2) được tạo cần cùng dữ liệu đó, chúng ta truy cập dữ liệu đó trực tiếp từ cơ sở dữ liệu.
Cách tiếp cận này có vẻ hợp lý và hợp lý trong một số trường hợp nhất định – có thể dễ dàng truy cập dữ liệu trong cơ sở dữ liệu SQL hoặc ghi dữ liệu vào cơ sở dữ liệu SQL hoặc có thể không có sẵn các API cần thiết cho Service 2.
Ngay sau khi cách tiếp cận này được áp dụng, quyền kiểm soát ngay lập tức bị mất trong việc xác định điều gì bị che giấu và điều gì không. Sau đó, nếu lược đồ cần thay đổi, tính linh hoạt để thực hiện thay đổi đó sẽ mất đi, vì bạn sẽ không biết ai đang sử dụng cơ sở dữ liệu và liệu thay đổi có phá vỡ Service 2 hay không.
Dưới đây là một cách tiếp cận thay thế và tôi sẽ đưa ra cách phù hợp để giải quyết vấn đề này:
Service 2 nên truy cập Service 1 và tránh truy cập trực tiếp vào cơ sở dữ liệu, do đó duy trì tính linh hoạt tối đa cho các thay đổi lược đồ khác nhau có thể được yêu cầu. Lo lắng về các phần khác của hệ thống sẽ bị loại bỏ miễn là bạn đảm bảo rằng các test case đối với các API được sử dụng sẽ pass.
Như đã đề cập, hãy chọn các giao thức giao tiếp giữa các service một cách cẩn thận. Ví dụ: nếu Java RMI được chọn, không chỉ người dùng API bị hạn chế sử dụng ngôn ngữ dựa trên JVM mà ngoài ra, bản thân giao thức này khá dễ hỏng vì khó duy trì khả năng tương thích ngược với các API.
Cuối cùng, khi cung cấp thư viện client cho khách hàng sử dụng service, hãy suy nghĩ kỹ về điều đó, vì tốt nhất bạn nên tránh lặp lại integration code. Nếu mắc lỗi này, nó cũng có thể hạn chế các thay đổi được thực hiện trong API nếu khách hàng dựa vào các chi tiết không cần thiết.
4. Phân quyền mọi thứ
Có những tổ chức đã thành công với microservices và đã tuân theo một mô hình trong đó các nhóm xây dựng dịch vụ đảm nhận mọi thứ liên quan đến dịch vụ đó. Họ là những người phát triển, triển khai, duy trì và hỗ trợ nó. Không có nhóm hỗ trợ hoặc bảo trì riêng biệt.
Một cách khác để đạt được điều tương tự là có một mô hìnhmã nguồn mở. Bằng cách thực hiện phương pháp này, nhà phát triển cần thay đổi trong một service có thể kiểm tra mã, làm việc trên một tính năng và tự mình gửi PR thay vì đợi chủ sở hữu dịch vụ nhận và thực hiện các thay đổi cần thiết.
Để mô hình này hoạt động bình thường, cần có tài liệu kỹ thuật phù hợp cùng với hướng dẫn thiết lập và hướng dẫn cho từng service để mọi người có thể dễ dàng nhận và làm việc với service.
Một ưu điểm tiềm ẩn khác của phương pháp này là nó giúp các nhà phát triển tập trung vào việc viết mã chất lượng cao vì họ biết rằng những người khác sẽ nhìn vào nó.
Ngoài ra còn có một số mẫu kiến trúc có thể giúp phân cấp mọi thứ. Ví dụ, bạn có thể có một kiến trúc mà tập hợp các dịch vụ đang giao tiếp thông qua một xe buýt thông điệp trung tâm.
Bus này xử lý việc định tuyến các thông điệp từ các dịch vụ khác nhau. Các nhà môi giới tin nhắn như RabbitMQ là một ví dụ điển hình.
Điều có xu hướng xảy ra theo thời gian là mọi người bắt đầu đưa ngày càng nhiều logic vào xe buýt trung tâm này và nó bắt đầu ngày càng biết nhiều hơn về miền của bạn. Khi nó trở nên thông minh hơn, điều đó thực sự có thể trở thành một vấn đề vì rất khó thực hiện những thay đổi đòi hỏi sự phối hợp giữa các nhóm chuyên dụng riêng biệt.
Lời khuyên chung của tôi cho những loại kiến trúc đó là giữ chúng tương đối “câm” và để chúng xử lý việc định tuyến. Các kiến trúc dựa trên sự kiện dường như hoạt động khá tốt trong các tình huống đó.