MicroServices đôi khi không phải sự lựa chọn hoàn hảo
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Monolith Application là gì?
Nó là cách phát triển ứng dụng kiểu truyền thống từ xưa tới nay, chỉ vậy thôi :D các modules của ứng dụng sẽ được phát triển và triển khai trong cùng một khối (monolith).
Hiểu nôm na giống như Laravel Botble CMS của bác Sang Nguyễn, toàn bộ modules (database, services, views, notifications…) đều được gom chung vào một bộ source code. Mặc dù có cấu trúc modular khá hợp lý, nhưng nó được đóng gói và cài đặt thành một monolithic duy nhất. Khi deploy, chúng ta chỉ cần ném cái cục monolithic bự này lên server, xong rồi làm một vài cấu hình là nó cứ thế mà chạy thôi :D
Monolith Application có một số tính chất cơ bản:
- monolith: được phát triển và triển khai theo một khối duy nhất, sử dụng chung một công nghệ hoặc framework.
có thể gặp nhiều khó khăn hơn khi áp dụng quy trình làm việc theo agile. - unscalable: Chỉ có thể scale toàn bộ hệ thống, trong khi các service có yêu cầu tài nguyên khác nhau (service này cần nhiều RAM hơn trong khi service kia cần nhiều CPU hơn…)
- unreliable: một module lỗi có thể kéo sập toàn bộ ứng dụng.
- inflexible: vì sử dụng chung công nghệ – framework nên rất khó thay đổi, nâng cấp.
- không phù hợp cho các application phức tạp.
Còn MicroServices lại là sao
Ngược lại với monolith, microservices là một cách thiết kế phần mềm theo hướng phân tách ứng dụng thành từng service (hay module) nhỏ (micro). Mỗi services được phát triển, triển khai và hoạt động hoàn toàn độc lập với nhau.
MicroServices có một số tính chất cơ bản:
- modular – có thể hoạt động độc lập, giảm bớt khó khăn khi chuyển đổi, nâng cấp công nghệ.
- scalable – dễ dàng mở rộng và scale lớn từng service mà không cần scale toàn bộ hệ thống.
- fault tolerant – khả năng dung lỗi và tránh break ứng dụng.
- không phụ thuộc vào công nghệ. Mỗi team có thể phát triển các service theo từng công nghệ – ngôn ngữ khác nhau (.NET, PHP, NodeJs, React, Angular…). Bạn có thể dễ dàng outsource từng phần nhỏ và thuê team bên ngoài phát triển.
- áp dụng được các quy trình tự động hóa, automated testing, CI/CD…
- bảo mật source code. Cái này chỉ tương đối thôi, như công ty mình thì áp dụng monorepos nhằm giảm chi phí phát triển các dependencies và đem lại sự phối hợp tốt hơn giữa các team.
Rất tuyệt phải không nào :D
Rồi thì…
Chà, đọc lý thuyết thì thấy microservices quá tốt rồi. Rất nhiều công ty đã thành công khi áp dụng nó vào thực tiễn, khiến nó trở nên vượt trội và luôn được gợi ý khi bạn nghiên cứu phát triển ứng dụng mới.
Tuy nhiên 😀
Microservices cũng tồn tại rất nhiều nhược điểm:
- Việc communication giữa các interservices khó khăn hơn, do chúng chỉ có thể truyền tải thông qua các transport protocols (TCP, WebSocket, Redis…)
- Do thông qua các giao thức mạng bên ngoài nên tốc độ truyền tải không nhanh bằng monolith. Cần xử lý thêm các sự cố khi nghẽn mạng, kết nối chậm, lỗi message không được gửi đi – hoặc ngu hơn là message bị gửi đi nhiều lần… 😀
- Xử lý lỗi phức tạp hơn khi một request cần đi qua nhiều service layers.
- Quy trình deployment phức tạp hơn so với monolith. Cần áp dụng CI/CD (tốn tiền thuê thêm vài anh DevOps chẳng hạn :D)
- Việc đảm bảo database consistency/aggregation khó khăn hơn rất nhiều.
- Mỗi service cần tự đảm bảo về security, transactions, monitoring, error logs,…
Một service chỉ nên phục vụ một bounded context hay nghiệp vụ cụ thể. Đừng nhìn cái chữ “micro” mà lầm tưởng là “service càng nhỏ càng tốt” nha, sai hoàn toàn đó 😀
Microservices chỉ phù hợp với các sản phẩm đã được định hình và trưởng thành
Rất nhiều công ty thành công với mô hình microservices nhưng lại không sử dụng kiến trúc này từ đầu, bởi lẽ khi startup, thứ quan trọng nhất là định hình mô hình kinh doanh – sản phẩm chứ không phải là ngồi tìm công nghệ – kiến trúc tốt nhất.
Monolith phát triển và định hình business rất nhanh và dễ dàng. Việc áp dụng microservices vào thời điểm này sẽ làm chậm lại quá trình phát triển cũng như đội thêm chi phí.
Con mèo tốt là con mèo biết bắt chuột.
Theo mình nghĩ, thời gian đầu nên consider áp dụng monolith. Sau một vài phiên bản, khi mà bạn đã xác định được hướng đi của sản phẩm cũng như thứ người dùng cần, lúc này chuyển qua microservices cũng không muộn. Việc tái cấu trúc các microservices khó khăn hơn rất nhiều so với monolith.
Microservices phù hợp cho các ứng dụng SAAS
Việc deploy microservices cần rất nhiều quy trình tự động hóa như CI/CD… nên rất khó khi triển khai cho các sản phẩm on-premise (cài đặt trên hệ thống riêng của khách hàng). Làm thì vẫn làm được thôi, nhưng tốn nhiều công sức và cần đội ngũ DevOps giàu kinh nghiệm hơn.
Quá trình quản lý versioning, release cũng đòi hỏi nhiều bước nghiêm ngặt hơn. Bạn cũng cần monitoring từng service riêng lẻ trong mỗi bản release, phân tích kỹ lưỡng và thực hiện các quy trình e2e testing.
Việc khắc phục sự cố cũng khó hơn nhiều do bạn gặp nhiều hạn chế về quyền truy cập vào môi trường production.
Do đó, theo mình thì microservices phù hợp hơn cho các ứng dụng SAAS hoạt động online trên môi trường internet :D
Thời điểm cho sự thay đổi
Sản phẩm nào cũng có vòng đời riêng. Theo mình thấy, có 2 thời điểm bạn cần cân nhắc để chuyển sang microservices:
- Codebase quá lớn: sản phẩm đã phát triển được một khoảng thời gian dài, business cũng đã được định hình rõ ràng. Lúc này, bạn cảm thấy khó thay đổi hoặc thêm tính năng mà không ảnh hưởng tới các chức năng khác.
- Hiệu năng: bạn gặp khó khăn khi scale ứng dụng. Có mỗi cái module xử lý orders cần scale up thôi, mà nó bắt phải scale up toàn hệ thống. Nhà nghèo tiền đâu ra mà trả :(
Nếu bạn có ý định phân tách và triển khai microservices cho ứng dụng monolith hiện tại, bạn có thể cân nhắc module hóa cái cục monolith application hiện tại trước. Buổi Laravel Meetup lần trước bác Lưu Thanh Sang cũng có chia sẻ về cách triển khai này rồi.
Bạn có thể tham khảo thêm ở đây Laravel Meetup tháng 8 – HCMC – Slides.
Module hóa sẽ tốn nhiều thời gian, nhưng cũng đem lại nhiều giá trị. Nó giúp codebase bạn dễ đọc, dễ phát triển và dễ maintenance hơn. Các bạn dev mới join vào sẽ chưa cần phải biết toàn bộ ứng dụng, họ chỉ cần làm quen và focus vào một vài modules trước.
Module hóa sẽ phần nào giúp cho cục monolith của bạn cảm giác nhỏ hơn xíu :( đây cũng có thể coi như là một bước bắt buộc trước khi chuyển sang microservices.
Hành trang chuẩn bị
Khi bạn đã quyết định áp dụng microservices cho dự án mới hoặc chuyển đổi từ monolith application, bạn nên chuẩn bị một số thứ sau đây:
- Cài đặt CI/CD cho việc tự động hóa quy trình deployment.
- Nghiên cứu triển khai Quick Provisioning để xây dựng cơ sở hạ tầng một cách nhanh chóng.
- Học thêm về containers, Kubernetes, serverless…
- Về codebase, cần làm quen với các design patterns như Domain-Driven Design (DDD), Test-Driven Development (TDD), Behavior-Driven Development (BDD), Command and Query Responsibility Segregation (CQRS)…
- Modular hóa các services/modules.
- Consider áp dụng monorepos để sharing các dependencies cũng như xóa nhòa khoảng cách giữa các teams.
- Cung cấp môi trường – kiến thức thêm về DevOps cho các team members.
Kết luận
Nói chung đừng có đua đòi áp dụng microservices khi bạn chưa có lý do chính đáng. Có rất nhiều thứ cũng như kiến thức cần chuẩn bị trước để bạn có thể khởi đầu tốt với nó.
Thay vào đó, việc nghiên cứu modular hóa ứng dụng, refactor codebase hiện tại là một ý tưởng không tồi :D