FOUNDATION - MICROSERVICES LÀ GÌ? (PART 3)


 Hi mọi người, lại tiếp tục phần tiếp theo của "Building Microservices: Designing Fine-Grained Systems". Phần trước đã cho chúng ta hiểu biết cơ bản về Monolith cũng như lợi ích và bất lợi của nó. Phần này sẽ tương tự đến với Microservices, những lợi ích của nó, cũng như những công nghệ được phát triển theo sự đi lên của Microservices.

Bắt đầu nào!

---------------------------------------

Công nghệ hỗ trợ - Enabling Technology


Tổng hợp nhật ký và theo dõi phân tán - Log Aggregation and Distributed Tracing

Với sự gia tăng các luồng bạn đang quản lý, điều đó có thể trở nên khó khăn để biết được hệ thống của bạn hoạt động như thế nào trong môi trường sản phẩm (production setting). Nó có thể khiến việc xử lý sự cố trở nên khó khăn hơn. Tôi vô cùng ủng hộ việc triển khai một hệ thống theo dõi nhật ký hoạt động như điều kiện tiên quyết để bắt đầu với Microservices.

Những hệ thống kiểu này cho phép bạn thu thập log từ toàn bộ các service của mình, cung cấp một trung tâm mà tại đó log có thể được phân tích, và thậm chí có thể sử dụng để tạo thành cảnh báo tự động trong hệ thống. Điều này giúp cải thiện quá trình giám sát và phản ứng nhanh với các sự cố. Tôi là một fan lớn của Humio vì nhiều lý do, nhưng một dịch vụ ghi log đơn giản bởi một đơn vị cung cấp dịch vụ đám mây có thể đủ tốt để bạn bắt đầu.

Bạn có thể khiến những công cụ theo dõi log này trở nên hữu dụng hơn bởi việc sử dụng các ID. Mỗi khi log entry được ghi lại, ID ghi kèm để định danh cho tập hợp các cuộc gọi dịch vụ liên quan. Khi có sự cố hoặc lỗi xảy ra, việc theo dõi và xem xét các logs liên quan chỉ cần tìm kiếm theo ID đã được liên kết.

Khi hệ thống của bạn ngày càng phình to, một công cụ cho phép bạn xem xét kĩ hơn hệ thống đang làm gì, cung cấp khả năng phân tích truy vết qua nhiều dịch vụ là càng trở nên cần thiết. Một vài công cụ mã nguồn mở có thể cung cấp những tính năng này. Một ví dụ và Jeager, công cụ tập trung vào việc phân tích truy vết (distributed tracing). Nó được thiết kế để giúp có cái nhìn rõ hơn vào quá trình thực thi của các yêu cầu (request) khi chúng đi qua các dịch vụ khác nhau trong hệ thống.

Một số công cụ như Lightstep Honeycomb (Hình 1-9) còn có nhiều khả năng hơn thế. Chúng giúp ta dễ dàng xem được trạng thái của hệ thống đang chạy. Chúng được xây dựng từ đầu để giải quyết những vấn đề mà chính kiến trúc Microservices gặp phải.


Containers and Kubernetes

Trong điều kiện lý tưởng, bạn sẽ muốn chạy từng microservice một cách riêng biệt. Điều này đảm bảo rằng các sự cố trong một microservice không ảnh hưởng đến microservice khác - chẳng hạn như ngốn hết CPU. Cách tốt nhất để đạt được điều này là thông qua việc sử dụng kỹ thuật ảo hóa (virtualization), tức là tạo ra các môi trường thực thi ảo mà không cần phải chạy trên phần cứng thật sự. Tuy nhiên, cách tiếp cận thông thường với virtualization có thể làm hệ thống nặng nề và tiêu tốn nhiều tài nguyên. Mặt khác, Containers là cách hiệu quả hơn đáng kể so với ảo hóa thông thường. Nó giúp triển khai môi trường thực thi độc lập cho các phiên bản dịch vụ, dẫn đến thời gian khởi động nhanh hơn cho các container mới, cùng với hiệu quả chi phí cao hơn.

Sau khi bạn bắt đầu với Containers, bạn sẽ nhận ra mình cần thứ gì đó để giúp bạn quản lý những container này trên nhiều máy chủ. Các nền tảng quản lý Container như Kubernetes sẽ giúp bạn làm điều đó, nó cho phép bạn phân phối các phiên bản container một cách ổn định với lưu lượng mà dịch vụ đó cần, đồng thời cho phép bạn sử dụng hiệu quả các máy chủ.

Đừng cảm thấy vội vã cần sử dụng Kubernetes, hoặc Containers. Chúng chắc chắn mang lại lợi ích rõ rệt so với cách triển khai truyền thống, tuy nhiên nếu bạn chỉ có một vài microservice, hiệu quả là không rõ ràng. Sau khi vấn đề về chi phí triển khai bắt đầu trở thành một vấn đề nhức đầu với bạn, hãy xem xét đưa dịch vụ của bản vào container và sử dụng Kubernetes. Cuối cùng, hãy đảm bảo một ai đó (hoặc thứ gì đó) sẽ chạy cụm Kubernetes (Kubernetes cluster) cho bạn, có thể là việc tận dụng các dịch vụ đám mây. Chạy cum Kubernetes riêng bạn có thể sẽ là một lượng việc không hề nhỏ!

Truyền tải dữ liệu - Streaming

Dù đã tránh xa kiến trúc CSDL dạng Monolith, chúng ta vẫn cần tìm cách để chia sẻ dữ liệu giữa các microservice. Các tổ chức cũng mong muốn chuyển từ việc truyền dữ liệu theo đợt (batch reporting) sang phản hồi theo thời gian thực (real-time feedback) để giúp tổ chức có thể phản ứng nhanh hơn. Các sản phẩm hỗ trợ việc truyền tải và xử lý dữ liệu, thường là dữ liệu lớn, đã trở nên phổ biến trong cộng đồng sử dụng kiến trúc Microservices.

Đối với nhiều người, Apache Kafka đã trở thành lựa chọn mặc định cho vấn đề trên, và nó có lý do chính đáng. Khả năng của Kafka kể đến như lưu trữ tin nhắn (message permanence), thu gọn dữ liệu (compaction), và khả năng mở rộng để xử lý lượng lớn dữ liệu là vô cùng hữu ích. Kafka đã thêm khả năng xử lý dòng (streaming-processing) thông qua KSQLDB (một dự án của Apache Kafka cung cấp một lớp truy vấn SQL để xử lý dữ liệu trực tiếp trong Kafka, cho phép thực hiện các truy vấn SQL trực tiếp trên luồng dữ liệu). Tuy nhiên bạn cũng có thể sử dụng Apache Flink như một giải pháp chuyên biệt hóa cho streaming-processing. Debezium là công cụ mã nguồn mở được phát triển để hỗ trợ truyền dữ liệu từ nguồn dữ liệu hiện tại qua Kafka, giúp đảm bảo nguồn dữ liệu truyền thống có thể trở thành một phần của dữ liệu dựa trên dòng (streaming).

Public Cloud and Serverless

Dịch vụ điện toán đám mây, với 3 nhà cung cấp chính - Google Cloud, Microsoft Azure, Amazon Web Services (AWS), có thể mang đến một loạt các dịch vụ quản lý và tùy chọn triển khai cho ứng dụng của bạn. Khi ứng dụng Microservices của bạn phình to dần lên, công việc để quản lý hệ thống cũng tăng lên. Dịch vụ điện toán đám mây có thể cung cấp nhiều dịch vụ quản lý để giảm áp lực cho nhóm vận hành và phát triển. Cụ thể như dịch vụ quản lý cơ sở dữ liệu, quản lý cụm Kubernetes hay quản lý hệ thống tệp phân tán. Bằng cách tận dụng những dịch vụ này, bạn có thể giảm tải được lượng lớn công việc cho một bên thứ 3 (Google, Microsoft, Amazon đó). Và chắc chắn rằng họ sẽ có khả năng xử lý những công việc đó hiệu quả hơn.

Trong số các sản phẩm điện toán đám mây, sản phẩm nào thuộc serverless được quan tâm hơn cả. Những sản phẩm đó sẽ giúp che giấu các máy chủ, cho phép bạn làm việc ở mức độ trừu tượng cao hơn. Ví dụ sản phẩm về serverless kể đến như message broker (module trung gian trung chuyển message từ người gửi đến người nhận), giải pháp lưu trữ và CSDL. Các nền tảng Chức năng như một dịch vụ (Function as a Service - FaaS) đặc biệt được quan tâm vì chúng mang đến mức độ trừu tượng tốt xung quanh việc triển khai mã. Thay vì phải lo lắng về việc bạn cần bao nhiêu máy chủ để chạy dịch vụ của mình, bạn chỉ cần triển khai mã nguồn và để nền tảng xử lý việc khởi tạo các phiên bản của mã nguồn theo yêu cầu của bạn. Những phần này sẽ được tìm hiểu chi tiết hơn và các chương sau.

Advantages of Microservices

Ưu điểm của Microservices là vô cùng nhiều, trong số này là những lợi ích mà một hệ thống phân tán sẽ có. Tuy nhiên, với việc kết hợp yếu tố che giấu thông tin (information hiding) và Domain-Driven Design với sức mạnh của một hệ phân tán, Microservices mang lại những lợi ích đáng kể so với các kiến trúc phân tán khác.

Độc lập về công nghệ - Technology Heterogeneity

Với hệ thống kết hợp của vô số các microservice, chúng ta có thể quyết định sử dụng đa dạng các công nghệ trong nó. Điều này giúp ta chọn đúng công nghệ cho từng nghiệp vụ, thay vì chọn một công nghệ chung, một quy chuẩn hay one-size-fits-all.

Nếu một phần hệ thống của chúng ta cần được nâng cấp về hiệu suất, bạn có thể chọn một stack công nghệ khác thỏa mãn được yêu cầu của mình. Bạn cũng có thể quyết định cách mà mỗi phần của hệ thống lưu trữ dữ liệu của riêng chúng. Ví dụ, với mạng xã hội (Social Network), bạn nên lưu dữ liệu về việc tương tác của người dùng trong một CSDL hướng đồ thị (Graph-Oriented database), còn dữ liệu về các bài viết thì chắc chắn là một CSDL hướng tài liệu rồi (Document-Oriented database). Hãy xem Hình 1-10 ở dưới để rõ hơn.


Với Microservices, chúng ta cũng có nhiều khả năng hơn trong việc thử và áp dụng các công nghệ mới và xem xét các cải tiến của chúng. Rào cản lớn nhất trong việc áp dụng một công nghệ mới là rủi ro liên quan đến nó. Với một ứng dụng Monolith chẳng hạn, bất kỳ công nghệ mới nào được áp dụng sẽ tác động đến toàn bộ hệ thống. Microservices với rất nhiều các service, mỗi service là một phòng thí nghiệm cho công nghệ mới của bạn. Việc của bạn đơn giản là chọn service nào ít rủi ro nhất và sử dụng công nghệ mới ở đó. Việc tưởng chừng như đơn giản này mang đến rất nhiều lợi thế, đó là điều mà rất nhiều tổ chức nhận ra.

Tất nhiên, áp dụng nhiều công nghệ không phải là toàn năng. Nhiều tổ chức đặt ra vài hạn chế với việc lựa chọn ngôn ngữ. Netflix Twitter chẳng hạn, họ chủ yếu sử dụng Java Virtual Machine (JVM) là nền tảng bởi họ hiểu rõ nó. Họ cũng phát triển các thư viện và công cụ chuyên biệt cho JVM để khiến việc mở rộng dễ dàng hơn rất nhiều, nhưng phụ thuộc vào các thư viện chuyên biệt cho JVM khiến mọi  thứ khó khăn hơn với những service không phải base Java. Nhưng dù sao cả NetflixTwitter cũng không sử dụng duy nhất một công nghệ cho tất cả nghiệp vụ.

Thực tế rằng công nghệ được triển khai ẩn hoàn toàn với người dùng khiến việc nâng cấp công nghệ dễ dàng hơn. Kiến trúc Microservices của bạn có thể dựa trên Spring Boot chẳng hạn, nhưng bạn cũng có thể thay đổi JVM version hoặc Framework version cho một microservice chuyên biệt, việc quản lý rủi ro cho việc nâng cấp là vô cùng dễ dàng.

Sự bền bỉ - Robustness

Để nâng cao sự bền bỉ, đáng tin cậy của ứng dụng, bạn cần biết đến khái niệm vách ngăn (bulkhead). Một phần của hệ thống có thể bị lỗi, nhưng miễn nó không tràn ra ngoài hệ thống, bạn có thể cách ly vấn đề và phần còn lại có thể tiếp tục hoạt động. Ranh giới các Service bỗng trở thành một vách ngăn tự nhiên. Với ứng dụng dạng Monolith, một dịch vụ lỗi, cả hệ thống sẽ dừng. Với hệ thống Monolith, bạn có thể chạy ứng dụng trên nhiều server để tránh khả năng lỗi, còn với Microservices, bạn có thể xây dựng hệ thống có thể xử lý các lỗi phát sinh từ các thành phần tương ứng của nó.

Tuy nhiên, chúng ta cần rất cẩn thận. Để đảm bảo rằng hệ thống có thể sử dụng được sự bền bỉ này, chúng ta cần nắm bắt được những nguồn gây lỗi mới cần giải quyết. Vấn đề về mạng, vấn đề về phần cứng, về server,... Chúng ta cần biết cách xử lý những lỗi đó cũng như ảnh hưởng của nó đến người dùng cuối. Không hiếm những team tôi đã làm việc cùng sau khi chuyển sang Microservices nhưng lại có độ bền bỉ kém hơn trước, đó là do họ không để tâm đến những vấn đề trên.

Mở rộng - Scaling

Với những dịch vụ trong Monolith application, ta cần mở rộng chúng cùng nhau. Trong một hệ thống Microservices, chúng ta có thể mở rộng riêng những dịch vụ cần mở rộng, cho phép chúng ta chạy những phần khác của hệ thống trên những phần cứng nhỏ và kém mạnh mẽ hơn. Như Hình 1-11.


Gilt, một nhà bán lẻ thời trang online, đã áp dụng Microservices vì lý do trên. Bắt đầu từ 2008 với một ứng dụng Rails dạng Monolith, đến 2009, hệ thống của Gilt đã không thể xử lý lượng tải lớn lên nó. Bằng cách chia nhỏ những phần cốt lõi của hệ thống, Gilt bây giờ đã có khả năng xử lý tình trạng tăng đột biến lưu lượng truy cập. Hiện tại, Gilt có hơn 450 microservice, mỗi dịch vụ chạy trên một máy chủ riêng biệt.

Kết lại, chúng ta có thể mở rộng ứng dụng của mình bằng nhiều cách, và Microservices chắc chắn là một cách hiệu quả trong số đó. Chương 13 ở phía sau chúng ta sẽ tìm hiểu kĩ hơn về phần này.

Dễ dàng triển khai - Ease of Deployment

Với Monolith application, thay đổi chỉ một dòng code trong hàng triệu dòng cũng đòi hỏi việc triển khai toàn bộ ứng dụng để áp dụng thay đổi đó. Điều này tạo ra một quy trình triển khai rủi ro cao, ảnh hưởng đến toàn hệ thống. Do đó, hệ thống thường không được triển khai thường xuyên. Việc tích lũy sự thay đổi giữa các phiên bản phát hành khiến sự thay đổi giữa 2 bản phát hành là rất lớn. Mỗi khi có sự chênh lệch lớn giữa các phiên bản, khả năng rủi ro gặp lỗi sẽ tăng lên.

Với Microservices, chúng ta đơn giản là thay đổi một dịch vụ đơn lẻ và triển khai nó độc lập với phần còn lại của hệ thống. Nó cho phép ta triển khai code nhanh hơn và xử lý nếu có vấn đề xảy ra khi triển khai. Nó cũng đồng nghĩa với việc khách hàng sẽ nhanh chóng nhận được những tính năng mới hơn. Đó cũng là một trong những lý do khiến Amazom Netflix sử dụng kiến trúc này.

Cấu trúc tổ chức - Organizational Alignment

Chúng ta đều hiểu những vấn đề với một team quá lớn và codebase quá khổng lồ. Vấn đề sẽ thật thảm họa nếu team bị chia nhỏ ra. Tuy nhiên, team nhỏ hơn sẽ làm việc hiệu quả với codebase nhỏ hơn.

Microservices cho phép đưa cấu trúc code ra cấu trúc tổ chức. Cho phép ta thay đổi thay đổi quyền sở hữu service khi cách tổ chức thay đổi, cho phép ta duy trì sự liên kết giữa kiến trúc hệ thống và cấu trúc tổ chức trong tương lai.

Khả năng kết hợp - Composability

Trong hệ thống Microservices, chúng ta có khả năng sử dụng chức năng của hệ thống một cách linh hoạt theo nhiều cách khác nhau và cho nhièu mục đích khác nhau. Không còn thời kỳ chúng ta chỉ nghỉ về web máy tính hay app điện thoại nữa. Bây giờ, chúng ta cần xem xét kết hợp chức năng của web, app trên máy tính, điện thoại, máy tính bảng, thiết bị đeo,...

Trong ngữ cảnh của Microservices, tác giả mô tả việc mở rộng các kết nối trong hệ thống, có thể được truy cập bởi bên thứ ba. Điều này mang lại linh hoạt, giúp chúng ta xây dựng ứng dụng theo các cách khác nhau khi hoàn cảnh thay đổi. Trong khi với ứng dụng Monolith, chúng ta thường chỉ có một kết nối thô sơ mà bên ngoài có thể sử dụng.

=======================================================
Vậy là đã kết thúc phần 3 ở đây. Nội dung khá dài nên nếu mọi người đọc có thể đọc lướt chút để tóm lược nội dung chính. Phần tới sẽ là phần cuối của chương 1. 

Hẹn gặp lại mn ở phần tới. See ya!!

--- NeO ---

Nhận xét

Bài đăng phổ biến