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é ^_^
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é.
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại 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é.

Mục lục

Related posts

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
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.

Tin mới nhất

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong phần này, chúng ta sẽ tìm hiểu một số khái niệm cơ bản nhất về AWS là gì và một số lợi ích khi sử dụng AWS.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Thông tin được định nghĩa dưới dạng dữ liệu, kiến thức về thông tin, và trí tuệ về tri thức.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
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
Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.