FOUNDATION - Microservices là gì? (Part 1)
Lời mở
Xin chào mọi người, mình đã quay lại với trang blog này sau một thời gian khá dài.
Chuyện là thời gian qua mình đang học và làm về Back-end, cụ thể liên quan khá nhiều đến kiến trúc Microservices. Và đó cũng chính là định hướng làm đồ án tốt nghiệp cũng như đi sâu về lâu dài của mình. Ngoài những nguồn lượm nhặt khá rời rạc trên Internet và những video hướng dẫn trên Youtube thì mình nhận ra kiến thức về Microservices của mình rất lỏng lẻo và thiếu sót. Vậy nên mình đã quyết định sẽ xây một cái nền thật chắc bằng cách tìm hiểu thật kỹ một quyển sách kinh điển về Microservices "Building Microservices: Designing Fine-Grained Systems".
Trong quá trình tìm hiểu những nội dung trong sách, mình nhận ra việc diễn đạt lại sang một ngôn ngữ khác và truyền đạt lại cho mọi người cũng là một cách để xác nhận và củng cố kiến thức của bản thân. Thật tuyệt vời khi một công đôi việc phải không nào!
Nếu mọi người có hứng thú với chủ đề này, rất mong mọi người có thể theo dõi, thảo luận, nhận xét và góp ý. Từ đó mình có thể sửa chữa, rút kinh nghiệm trong khi chúng ta có thể có những hiểu biết sâu sắc và chính xác hơn về Microservices. Vậy thì còn chờ đợi gì nữa, hãy đến với nội dung chính của "Building Microservices: Designing Fine-Grained Systems".
-----------------------------------
Chapter 1: What are Microservices?
Microservices at a Glance - Sơ lược về Microservices
Microservices là một kiến trúc phần mềm mà các chức năng của hệ thống được chia thành những dịch vụ (Service) có thể được phát triển, triển khai và mở rộng một cách độc lập. Các dịch vụ này được mô hình hóa xung quanh một miền kinh doanh (Business domain) cụ thể. Mỗi dịch vụ cung cấp một phạm vi chức năng nhất định và có thể giao tiếp với nhau thông qua giao thức và mạng (Network). Từ đó chúng ta có thể xây dựng một hệ thức phức tạp hơn từ những dịch vụ độc lập này.
Một Microservce có thể đại diện cho một hoặc một phần chức năng cụ thể của hệ thống. Ví dụ như đại diện cho chức năng quản lý hàng tồn kho (Inventory management), quản lý đơn hàng (Order management) hoặc quản lý vận chuyển (Shipping management). Mỗi microservice hoạt động độc lập, có thể được phát triển và triển khai độc lập. Khi kết hợp chúng lại với nhau, ta tạo ra được một hệ thống thương mại điện tử (Ecommerce system) hoàn chỉnh. Kiến trúc Microservices giúp ta có nhiều tùy chọn để giải quyết các vấn đề đặc biệt phức tạp trong quá trình phát triển và quản lý hệ thống.
Microservices là một loại kiến trúc dựa trên dịch vụ (Service-Oriented Architecture), mặc dù có quan điểm về việc làm sao để xác định ranh giới giữa các dịch vụ để phân chia cho hợp lý. Một trong những lợi ích mà kiến trúc này mang lại đó là khả năng không phụ thuộc hay ràng buộc bởi bất kỳ công nghệ nào, nghĩa là nó có thể sử dụng công nghệ phù hợp nhất cho từng dịch vụ.
Từ góc nhìn bên ngoài hệ thống, mỗi microservice được xem như một hộp đen. Các chức năng của nó được truy cập thông qua một hoặc nhiều điểm truy cập (network endpoints), ví dụ như hàng đợi (queue) hoặc REST API. Người dùng cuối, hoặc các microservice khác phải truy cập thông qua những endpoints này. Những chi tiết bên trong microservice như công nghệ, database được hoàn toàn che giấu. Điều này dẫn đến việc kiến trúc Microservices tránh việc sử dụng chung CSDL trong hầu hết các trường hợp, thay vào đó, mỗi microservice cần có một CSDL của riêng nó.
Liệu Service-Oriented Architecture (SOA) và Microservices có khác nhau?
Kiến trúc hướng dịch vụ (Service-oriented) là thiết kế hướng đến việc kết hợp nhiều dịch vụ để cung cấp một tập hợp nhất định các khả năng. Giao tiếp giữa các dịch vụ diễn ra thông qua các cuộc gọi mạng (network call) thay vì là một phương thức (method).
SOA xuất hiện như một cách thức để đối phó với những ứng dụng lớn, những ứng dụng nguyên khối (Monolithic). Phương pháp này nhằm thúc đẩy khả năng tái sử dụng phần mềm; 2 hoặc nhiều ứng dụng người dùng cuối, có thể sử dụng các dịch vụ giống nhau. SOA tạo điều kiện cho việc bảo trì hoặc viết lại phần mềm vì theo lý thuyết, chúng ta có thể thay thế một dịch vụ bằng một dịch vụ khác mà không ai biết, miễn là chức năng chính, cách thức hoạt động của dịch vụ đó không thay đổi quá nhiều.
SOA, về mặt lý thuyết, và một ý tưởng hợp lý. Tuy nhiên, dù đã trải qua nhiều nỗ lực, vẫn thiếu sự đồng thuận về một cách thực hiện thật sự tốt SOA. Những vấn đề được đặt ra cho SOA như Giao thức truyền thông (Ví dụ SOAP), các phần mềm trung gian để hỗ trợ triển khai hệ thống hay thiếu hướng dẫn về cách chia nhỏ hệ thống. Một số hoài nghi còn cho rằng các nhà cung cấp phần mềm trung gian đã lợi dụng, thậm chí thúc đẩy SOA để bán được nhiều sản phẩm hơn. Vấn đề xuất hiện khi những sản phẩm này không đáp ứng được các yêu cầu của SOA về tính linh hoạt, độc lập và khả năng tương tác giữa các dịch vụ. Thậm chí chúng còn tạo nên các ràng buộc và hạn chế trong việc triển khai và quản lý các dịch vụ. Cuối cùng, chính chúng đã làm suy yếu tính hữu hiệu và hiệu quả của SOA.
Tôi (tác giả) đã thấy rất nhiều ví dụ về SOA, trong đó các nhóm cố gắng để làm những dịch vụ nhỏ hơn, và sau đó lại kết nối chúng với cùng một CSDL. Sau đó bắt buộc phải triển khai tất cả cùng nhau. Đó chính là hướng dịch vụ, tuy nhiên đó không phải là Microservices.
Kiến trúc Microservices đã nổi lên từ việc thực tế sử dụng SOA, dựa trên sự hiểu biết tốt hơn về hệ thống và kiến trúc để thực hiện SOA một cách tốt hơn. Bạn nên xem Microservices như một phương pháp cụ thể thay cho SOA, tương tự như Extreme Programming (XP) hoặc Scrum là một phương pháp cụ thể để phát triển phần mềm dựa trên nguyên tắc Agile.
Các khái niệm chính trong Microservices
Sau đây sẽ là một số khái niệm bạn cần phải hiểu trước khi khám phá sâu hơn về Microservices. Một số khía cạnh quan trọng thường bị bỏ qua, tuy nhiên nó lại đóng góp vai trò quan trọng trong những khái niệm phức tạp hơn về sau. Những khái niệm sau sẽ đảm bảo bạn hiểu điều gì giúp Microservices hoạt động.
Triển khai độc lập (Independent Deployability)
Khả năng triển khai độc lập cho phép thay đổi một microservice, triển khai sự thay đổi cho người dùng mà không cần triển khai bất kỳ microservice nào khác (độc lập). Đây thực sự là cách bạn quản lý việc triển khai trong hệ thống Microservices của mình. Tuy là một ý tưởng đơn giản nhưng việc thực thi lại vô cùng phức tạp.
Để đảm bảo cho việc triển khai độc lập, các microservice cần được kết nối lỏng lẻo (loose coupling). Chúng ta cần thay đổi một dịch vụ mà không cần thay đổi bất kỳ điều gì khác. Điều này nghĩa là chúng ta cần thiết lập việc kết nối, giao tiếp, phản hồi giữa các dịch vụ một cách ổn định và rõ ràng. Ví dụ nếu như 2 dịch vụ chia sẻ chung một CSDL, việc triển khai độc lập có thể trở nên khó khăn.
Việc tập trung vào khả năng triển khai độc lập mang đến nhiều lợi ích đáng giá. Tuy nhiên, để đáp ứng nó cũng cần đánh đổi nhiều yếu tố khác.
Xây dựng dựa trên một lĩnh vực kinh doanh (Modeled Around a Business Domain)
Các kỹ thuật như thiết kế dựa trên miền (Domain-Driven Design) cho phép tổ chức mã nguồn một cách tốt hơn để phản ánh lĩnh vực thực tế mà phần mềm đó hoạt động. Kiến trúc Microservices cũng sử dụng ý tưởng này để xác định ranh giới phân chia của từng dịch vụ.
Với một kiến trúc điển hình 3 tầng (Three-tiered architecture) như hình 1-2, mỗi tầng đại diện cho một chức năng kỹ thuật liên quan. Ví dụ khi cần thay đổi ở tầng giao diện (Presentation Layer), điều này khá hiệu quả. Tuy nhiên kinh nghiệm cho thấy việc thay đổi thường bao phủ nhiều tầng. Vấn đề này sẽ còn nghiêm trọng hơn nếu kiến trúc này có nhiều tầng hơn so với ví dụ đơn giản kia, nếu mỗi tầng lại được chia thành các tầng con.
Giả sử bạn xây dựng một hệ thống Ecommerce. Trong lĩnh vực này, có nhiều chức năng khác nhau như quản lý sản phẩm, quản lý đơn hàng, thanh toán, quản lý khách hàng, và giao hàng. Thay vì tổ chức các dịch vụ theo cấu trúc kỹ thuật như "Database", "Front-end", "Back-end", chúng ta sẽ tổ chức các dịch vụ theo các lĩnh vực kinh doanh như "Dịch vụ quản lý sản phẩm", "Dịch vụ quản lý đơn hàng", "Dịch vụ thanh toán", "Dịch vụ quản lý khách hàng", "Dịch vụ giao hàng".
Tự quản lý trạng thái (Owning Their Own State)
Một trong những khía cạnh mà tôi (tác giả) thấy mọi người gặp khó khăn nhất là ý tưởng rằng các microservice nên tránh sử dụng chung CSDL. Nếu một microservice muốn truy cập vào dữ liệu của microservice khác, nó nên yêu cầu microservice đó để lấy dữ liệu. Điều này cho phép các microservice quyết định những gì sẽ chia sẻ, và những gì sẽ ẩn đi. Điều đó cũng giúp phân tách rõ ràng những chức năng có thể thay đổi tự do (chức năng nội bộ) và những chức năng ít thay đổi hơn (những kết nối, giao tiếp với bên ngoài).
Ẩn trạng thái nội bộ trong một microservice tương tự như việc ẩn thông tin trong lập trình hướng đối tượng (OOP). Việc đóng gói dữ liệu trong các hệ thống hướng đối tượng là một ví dụ về việc ẩn thông tin.
Kích thước (Size)
"How big should a microservice be?" - Một microservice nên có độ lớn như thế nào - là một câu hỏi thường thấy. Khi đi sâu hơn vào cách để làm cho hệ thống Microservices hoạt động, khái niệm về kích thước thật ra lại là một khía cạnh ít thú vị nhất.
Làm sao để đo lường kích thước? Bằng cách đếm số dòng code? Điều đó là vô nghĩa. Một phương thức có thể yêu cầu 25 dòng code với Java có thể viết chỉ với 10 dòng code bằng Clojure. Điều đó không có nghĩa là Clojure tốt hơn Java, thực thế là một vài ngôn ngữ đơn giản nhiều ký tự biểu diễn hơn những ngôn ngữ khác.
James Lewis, giám đốc kĩ thuật tại Thoughtworks, đã nói rằng "a microservice should be as big as my head". Điều này nghe có vẻ vô ích, đơn giản bởi chính xác "head" của James Lewis to như thế nào? Thực tế, ý nghĩa câu này nên được hiểu là, một microservice nên được giữ ở mức có thể dễ dàng hiểu nó. Vấn đề ở đây xuất hiện khi khả năng để hiểu một thứ gì đó với từng người là khác nhau. Một team lập trình viên (LTV) kinh nghiệm có thể quản lý tốt một codebase so với một team ít kinh nghiệm khác.
Tôi (tác giả) nghĩ rằng khái niệm gần nhất với "size" trong ngữ cảnh của microservice là điều được Chris Richarson, tác giả của "Microservice Patterns" đã chia sẻ rằng mục tiêu của Microservices là có "as small an interface as possible". Trong kiến trúc microservices, giao diện đại diện cho cách mà các microservice tương tác với nhau. Việc thiết kế giao diện nhỏ gọn có ý nghĩa là giới hạn số lượng và phạm vi các phương thức, thông điệp hoặc tài nguyên mà một microservice tiếp xúc với các microservice khác.
Chung quy lại, vấn đề về "size" mang tính tương đối, tùy theo ngữ cảnh. Với một người kinh nghiệm hơn 15 năm, họ sẽ thấy hệ thống với 100.000 dòng code vẫn là dễ hiểu. Còn với những tay mơ (mình), hệ thống đó là quá sức. Tương tự, với công ty vừa mới bắt đầu với Microservices chỉ có trên dưới 10 microservice và một công ty đã triển khai Microservices lâu năm có cả trăm microservice, suy nghĩ của họ sẽ là khác nhau.
Vậy nên, đừng lo lắng về vấn đề kích thước. Khi mới bắt đầu, điều quan trọng cần tập trung là 2 vấn đề. Đầu tiên, bao nhiêu microservice bạn có thể kiểm soát? Thứ 2, bạn định nghĩa ranh giới để phân chia microservice để bao quát toàn bộ chúng mà không khiến chúng trở thành một mớ hỗn độn? Những chủ đề này mới thật sự cần thiết khi bắt đầu hành trình.
Tính linh hoạt - Flexibility
Một câu trích dẫn khác của Jame Lewis là "microservices buy you options.", nghĩa là chúng mua cho bạn các lựa chọn, một câu với từ ngữ rất cẩn thận. Chúng có chi phí và bạn phải quyết định xem chi phí đó có đáng để bạn lựa chọn không. Sự linh hoạt trên nhiều mặt - tổ chức, kỹ thuật, quy mô, độ bền - có thể sẽ vô cùng hấp dẫn.
Chúng ta không biết tương lai gì sẽ đón chờ, vì vậy mong đợi một kiến trúc có thể giúp giải quyết những vấn đề tiềm năng trong tương lai là một mong muốn hợp lý. Sự cân bằng giữa việc giữ kiến trúc hiện tại và trả giá để chọn một kiến trúc tương lai hơn thật sự là một lựa chọn quan trọng.
Áp dụng kiến trúc Microservices không phải việc bật/tắt công tắc, mà giống như việc vặn núm điều chỉnh. Khi bạn vặn núm lên, microservice nhiều lên, bạn có tính linh hoạt, nhưng cũng tăng lên các điểm đau đơn (pain points). Đây là lý do cần áp dụng Microservices dần dần, trong quá trình vặn dần núm, bạn có thể đánh giá tác động của nó và dừng lại nếu cần.
Sự liên kết của kiến trúc và tổ chức (Alignment of Architecture and Organization)
MusicCorp, một công ty thương mại điện tử bán CD online, sử dụng kiến trúc đơn giản - 3 lớp (three layer) như ở hình 1-2. Cty có giao diện người dùng, tầng logic kinh doanh dưới dạng monolithic backend và CSDL lưu truyền thống. Tiếp theo hãy đến với những khó khăn và thử thách của MusicCorp.
Chúng ta cần thực hiện một cập nhật đơn giản, cho phép người dùng chỉ định thể loại âm nhạc yêu thích của họ. Cập nhật này yêu cầu thay đổi ở cả 3 lớp: UI, backend và database. Những thay đổi này cần được quản lý bởi từng team và triển khai theo trình tự hợp lý như hình 1-3:
Định luật nổi tiếng của Conway nêu rõ như sau:
"Organizations which design systems...are constrained to produce designs which are copies of the communication structures of these organizations."— Melvin Conway, "How Do Committees Invent?
Đại khái câu trên nói về việc tổ chức thiết kế hệ thống bị ràng buộc để giống như cấu trúc giao tiếp của tổ chức đó.
Kiến trúc ba tầng là một ví dụ tốt về việc áp dụng định luật này. Trước đây, cách chính mà các tổ chức CNTT nhóm người lại là dựa trên năng lực chính của thành viên: Quản trị CSDL được nhóm với các quản trị CSDL khác; Java Dev vào cùng với các Java Dev;... Chúng ta nhóm người dựa trên năng lực của chính họ, từ đó tạo ra các sản phẩm IT tương ứng với cấu trúc đó.
Điều đó giải thích vì sao kiến trúc đó (3 tầng) lại phổ biến đến vậy. Nó không tệ, nó chỉ đơn giản tối ưu dựa vào việc nhóm các nhân sự như thế nào. Nhưng hiện tại, động lực đã thay đổi. Mong muốn của chúng ta với phần mềm đã thay đổi. Chúng ta đã nhóm nhân sự dựa trên kỹ năng để giảm thiểu sự chuyển giao và thiếu sót. Chúng ta muốn cung cấp phần mềm nhanh hơn bao giờ hết. Từ đó thúc đẩy việc đưa ra những lựa chọn khác về việc tổ chức nhân sự của mình, tương tự như cách đưa họ vào ứng với từng phần của hệ thống.
Bây giờ hãy quay lại với Hình 1-3, đây là một kiến trúc có độ liên kết cao về công nghệ liên quan nhưng độ liên kết thấp về chức năng kinh doanh. Hãy so sánh với một kiến trúc thay thế tiềm năng, được minh họa trong Hình 1-4. Thay vì một kiến trúc theo chiều ngang, chúng ta chia nhỏ và kiến trúc theo chiều dọc của các chức năng kinh doanh. Ví dụ như một nhóm chuyên dụng có trách nhiệm toàn diện cho việc thay đổi các khía cạnh trong hồ sơ khách hàng (Customer Profile Team).
Điều này có thể được thực hiện thông qua một microservice duy nhất thuộc sở hữu của Customer Profile Team. Tất cả những thay đổi ở 3 mức Frontend, Backend và DB đều được thực hiện một cách nội bộ. Trong Hình 1-5, danh sách các thể loại cũng có thể lấy từ một microservice Catalog có sẵn, microservice Recommendation để gợi ý những thể loại yêu thích của người dùng cũng có thể dễ dàng triển khai sau này.
Trong trường hợp này, microservice bao hàm hoàn bộ một lát cắt mỏng dọc của cấu trúc 3 tầng. Nó có một chút UI, một chút logic backend, một chút CSDL. Chức năng kinh doanh trở thành động lực chính thúc đẩy kiến trúc hệ thống, điều này khiến dễ dàng trong việc thay đổi, cũng như dễ dàng để sắp xếp các nhóm phù hợp với ngành nghề kinh doanh trong tổ chức.
Thông thường, Giao diện (UI) thường không được cung cấp trực tiếp bởi microservice, kể cả trong trường hợp đó, chúng ta có thể kỳ vọng phần giao diện liên quan vẫn được sở hữu bởi Customer Profile Team, như Hình 1-4 đề cập. Khái niệm về nhóm sở hữu một phần chức năng từ đầu đến cuối đang thu hút được nhiều sự chú ý.
Nhóm nhân sự như Hình 1-4 được sắp xếp theo luồng, khái niệm này sẽ được khám phá sâu hơn và các chương 14, 15.
-----------------------------------
Bài viết là phần 1 của chương "What are microservices?". Nội dung đã được mình dịch sát nhất và dễ hiểu nhất trong khả năng. Do hơi lười nên nhiều đoạn cảm thấy không cần thiết mình có lược bỏ qua.
Nếu mọi người đã đọc đến đây thì rất cảm ơn mọi người vì đã dành thời gian của mình. Rất mong mọi người sẽ cho nhận xét để mình có thêm động lực viết các bài tiếp theo.
Cảm ơn và hẹn gặp lại! See ya!
---NeO---
Nhận xét
Đăng nhận xét