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é.
MicroServices đôi khi không phải sự lựa chọn hoàn hảo
MicroServices đôi khi không phải sự lựa chọn hoàn hảo

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).

rancher-blog-microservices-and-monolithic-architectures.jpeg

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.png

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

Comments

Bài viết nổi bật

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é.
PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Có khá nhiều bạn đã yêu cầu mình một bài viết về Repository Design Pattern. Vậy mục đích của nó là gì? Nó có thực sự cần thiết cho ứng dụng của bạn hay không? Những điểm mạnh, điểm yếu của nó là gì? Chúng ta cùng đi sâu tìm hiểu qua bài viết này nhé.
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
Ở bài viết này mình sẽ hướng dẫn bạn bắt đầu xây dựng một ứng dụng HMVC với Laravel, và tận dụng sức mạnh của Composer khi quản lí modules.

Mục lục

Related posts

Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.
Đây là một khái niệm rất quan trọng trong Functional Programming. Ở đây mình sẽ cho ví dụ dựa trên Javascript, cụ thể là TypeScript, do đó mình hi vọng các bạn đã có một số kiến thức nhất định về JS trước. Điều này sẽ giúp bạn nắm bắt nội dung bài viết dễ dàng hơn.
NestJS - Providers
1211
Providers là thành phần cơ bản và cực kỳ quan trọng trong Nest để thực hiện Dependency Injection.
Một số design patterns chính đang được sử dụng bởi NestJS mà bạn cần nắm rõ để làm việc với NestJS hiệu quả hơn.
Một số design patterns chính đang được sử dụng bởi NestJS mà bạn cần nắm rõ để làm việc với NestJS hiệu quả hơn.
NestJS - Controllers
1477
Trách nhiệm chính của controllers là xử lý các requests và phản hồi lại cho phía client.
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
NestJS là một NodeJS framework tiến bộ để xây dựng các ứng dụng server-side hiệu quả, đáng tin cậy cùng với khả năng mở rộng dễ dàng.
Qua series này, các bạn sẽ hiểu hơn về sức mạnh của NodeJS cũng như xây dựng một kiến trúc ứng dụng xanh sạch đẹp hết sức có thể, thỏa mãn tinh thần Test - Driven Development.

Tin mới nhất

Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
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é.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Bài viết này sẽ hướng dẫn các bạn cài đặt LEMP stack trên CentOS Stream 9 mới nhất trên Vultr Cloud VPS.
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.
Đây là một khái niệm rất quan trọng trong Functional Programming. Ở đây mình sẽ cho ví dụ dựa trên Javascript, cụ thể là TypeScript, do đó mình hi vọng các bạn đã có một số kiến thức nhất định về JS trước. Điều này sẽ giúp bạn nắm bắt nội dung bài viết dễ dàng hơn.
Bài hướng dẫn này sẽ hướng dẫn các bạn cài đặt LEMP stack (Linux - Nginx - MySQL - PHP) trên CentOS 8.
NestJS - Providers
1211
Providers là thành phần cơ bản và cực kỳ quan trọng trong Nest để thực hiện Dependency Injection.
Một số design patterns chính đang được sử dụng bởi NestJS mà bạn cần nắm rõ để làm việc với NestJS hiệu quả hơn.
Một số design patterns chính đang được sử dụng bởi NestJS mà bạn cần nắm rõ để làm việc với NestJS hiệu quả hơn.
NestJS - Controllers
1477
Trách nhiệm chính của controllers là xử lý các requests và phản hồi lại cho phía client.
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
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é.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.