21025026 TranMinhDuc TRƯỜNG ĐẠI HỌC CÔNG NGHỆ KHOA CÔNG NGHỆ THÔNG TIN BÀI TIỂU LUẬN TÌM HIỂU KIẾN TRÚC MICROSERVICES TRONG PHÁT TRIỂN HỆ THỐNG ĐA DỊCH VỤ Giảng viên GS Nguyễn Thanh Thủy Học phần Trí tuệ nhân tạo nâng cao Học viên Trần Minh Đức Mã học viên 21025026 Hà Nội, 2022 1 Mục lục Phần 1 Giới thiệu 2 1 Kiến trúc nguyên khối truyền thống monolithic architecture 2 2 Kiến trúc microservices 5 Phần 2 Thiết kế và triển khai hệ thống microservices 11 2 1 Thiết kế hệ thống microservices 11 2 1 1.
Trang 1TRƯỜNG ĐẠI HỌC CÔNG NGHỆ KHOA CÔNG NGHỆ THÔNG TIN
BÀI TIỂU LUẬN
TÌM HIỂU KIẾN TRÚC MICROSERVICES TRONG PHÁT TRIỂN HỆ THỐNG ĐA DỊCH VỤ
Giảng viên: GS Nguyễn Thanh Thủy
Học phần: Trí tuệ nhân tạo nâng cao
Học viên: Trần Minh Đức
Mã học viên: 21025026
Hà Nội, 2022
Trang 22.1.3 Vấn đề giao tiếp giữa các microservices 12
2.2.1 Các hình thức triển khai microservices 15 2.2.2 Các hệ thống lớn sử dụng microservices 15 2.2.3 Triển khai hệ thống bằng Kubernetes? 17
Trang 3Phần 1 Giới thiệu
Nói đến kiến trúc phần mềm, có lẽ hầu hết các kỹ sư phần mềm đều quen
thuộc với kiến trúc nguyên khối (monolithic architecture) Với đặc tính là một
kiểu kiến trúc đơn giản, dễ phát triển, dễ kiểm thử và dễ triển khai, vậy nên kiến trúc nguyên khối cũng đã được sử dụng để phát triển các hệ thống phần mềm trong hàng chục năm qua, gần như bất kỳ lập trình viên nào cũng được tiếp xúc với kiến trúc nguyên khối này ít nhất một lần Tuy nhiên, đến một thời điểm nào
đó, kiến trúc monolithic sẽ bộc lộ ra nhiều điểm hạn chế, đặc biệt khi chúng ta
cần phát triển một hệ thống lớn Do vậy mà trong khoảng 5 năm trở lại đây, kiến trúc microservices đã và đang trở nên phổ biến và được ưa chuộng hơn bao giờ
hết bởi những ưu điểm của nó cũng như cách nó giải quyết những nhược điểm của kiến trúc monolithic Về cơ bản, thay vì gom tất cả các chức năng, logic trong một codebase duy nhất, tư tưởng của kiến trúc microservices là chia hệ thống phần mềm thành nhiều các service nhỏ hơn nhằm gia tăng tính độc lập và giảm thiểu sự ràng buộc lẫn nhau giữa các service trong hệ thống, qua đó việc phát triển và nâng cấp cũng dễ dàng và giảm thiểu chi phí hơn
1 Kiến trúc nguyên khối truyền thống - monolithic architecture
Để có thể hiểu rõ hơn về kiến trúc microservices cũng như những ưu điểm của nó, chúng ta sẽ nhìn lại một chút về kiến trúc monolithic truyền thống Khái
niệm "monolithic" trong tiếng Anh có nghĩa là một khối đá khổng lồ Trong lĩnh
vực phát triển phần mềm, một mẫu nguyên khối ám chỉ một đơn vị phần mềm khó có thể tách ra thành các đơn vị nhỏ hơn Thông thường, một ứng dụng nguyên khối (monolithic application) bao gồm cơ sở dữ liệu, giao diện người dùng cho client và ứng dụng phía server Tất cả những thành phần này của phần mềm được hợp nhất cũng như tất cả các chức năng của phần mềm được phát triển, quản lý trong một nơi duy nhất (single codebase)
Giả sử chúng ta có yêu cầu phát triển một dịch vụ đặt xe taxi qua ứng dụng
di động nhằm cạnh tranh với Grab Sau một số buổi họp thu thập yêu cầu và phân tích thiết kế, chúng ta sẽ chọn các công nghệ phù hợp cho dự án rồi bắt đầu phát triển hệ thống sử dụng các framework như Spring Boot, Laravel, Hệ thống này
sẽ có kiến trúc dạng khối lục giác (hexagonal architecture) hay tổng quát hơn là khối đa diện Kiến trúc đa diện giúp ứng dụng của chúng ta chuyên biệt mô hình
Trang 4Hình 1 Ví dụ xây dựng một hệ thống đặt xe theo kiến trúc nguyên khối
Nhìn vào lõi của ứng dụng, ta thấy business logic được thể hiện bởi các khối dịch vụ (services), đối tượng cho từng vùng nghiệp vụ (domain objects) và các sự kiện (events) Xung quanh lõi là các adapter để kết nối vào cơ sở dữ liệu, gửi nhận message, các web services hoặc front-end web application
Một kiến trúc nguyên khối phù hợp cho các hệ thống không quá phức tạp,
do đó mà các công ty nhỏ từ xưa tới nay vẫn thường chuộng kiến trúc này hơn Các thành phần của phần mềm nguyên khối được kết nối với nhau và phụ thuộc lẫn nhau, giúp phần mềm được khép kín Kiến trúc này là một giải pháp truyền thống để xây dựng các ứng dụng, nhưng ngày nay khi doanh nghiệp cần giải quyết nhiều bài toán lớn hơn, hệ thống trở nên phức tạp và thường xuyên cần những sự nâng cấp, kiến trúc monolithic sẽ bộc lộ ra nhiều hạn chế
Vậy cụ thể ưu điểm, nhược điểm của kiến trúc monolithic và khi nào thì nên áp dụng kiểu kiến trúc này, chúng ta hãy cùng phân tích
Trang 5Hình 2 Kiến trúc monolithic
Ưu điểm của kiến trúc monolithic:
● Phát triển và triển khai đơn giản: Hệ thống monolithic sẽ tương đối dễ
phát triển vì các công nghệ được sử dụng một cách thống nhất trong các layer Ngoài ra, toàn bộ source code được để chung trong một package, giúp chúng ta dễ dàng chạy test integration cũng như triển khai dễ dàng hơn
● Hiệu suất tốt hơn: Nếu được xây dựng đúng cách, các ứng dụng nguyên
khối thường có hiệu suất cao hơn các ứng dụng xây dựng theo kiến trúc microservices Ứng dụng có kiến trúc microservices có thể cần thực hiện hàng chục lệnh gọi API đến hàng chục microservices khác nhau để có thể tải dữ liệu hiển thị lên mỗi màn hình, điều này rõ ràng dẫn đến hiệu suất chậm hơn Đổi lại, các ứng dụng nguyên khối cho phép giao tiếp nhanh hơn giữa các thành phần phần mềm do code và bộ nhớ được chia sẻ
Nhược điểm của kiến trúc monolithic:
● Codebase trở nên cồng kềnh theo thời gian: Theo thời gian, hầu hết các
sản phẩm phát triển gia tăng, phạm vi và cấu trúc trở nên rất khó kiểm soát Các đoạn code bắt đầu trông thực sự đồ sộ và trở nên khó hiểu và khó sửa đổi, đặc biệt là đối với các lập trình viên mới tham gia dự án sẽ cần rất nhiều thời gian để hiểu được chương trình và thực hiện các sửa đổi, nâng cấp Điều đó có thể dẫn đến sự sụt giảm về chất lượng mã nguồn cũng như
tăng mức độ rủi ro cho hệ thống hơn
● Khó áp dụng công nghệ mới: Nếu có nhu cầu thêm một số công nghệ mới
Trang 6dụng Thêm công nghệ mới có nghĩa là viết lại toàn bộ ứng dụng, việc này rất tốn kém và mất thời gian
● Kém linh hoạt: Trong các ứng dụng nguyên khối, mỗi bản cập nhật nhỏ
yêu cầu deploy lại đầy đủ toàn bộ ứng dụng đó, mà đôi khi thời gian để build và khởi động lại ứng dụng là không hề ít Bên cạnh đó, khả năng mở rộng cũng không được linh hoạt Ví dụ: một mạng xã hội được xây dựng theo kiến trúc monolithic với các thành phần chính như chia sẻ ảnh, gợi ý kết bạn, nhắn tin, quảng cáo, nhưng lưu lượng người dùng lại đổ dồn rất nhiều vào tính năng nhắn tin; khi đó, để gia tăng khả năng đáp ứng của website, chúng ta sẽ cần triển khai toàn bộ ứng dụng với đầy đủ các thành phần kể trên lên các server khác, rõ ràng đây là một sự tiêu tốn tài nguyên rất lớn
Khả năng áp dụng của kiến trúc monolithic: Có thể kiến trúc monolithic bộc
lộ nhiều điểm hạn chế, song nó không phải là lỗi thời, miễn là chúng ta cân nhắc
sử dụng nó vào đúng trường hợp để phát huy được điểm mạnh của nó cũng như cân bằng được nguồn lực và chi phí Kiến trúc phần mềm nguyên khối có thể có lợi nếu công ty đang ở giai đoạn sáng lập, đang xây dựng một sản phẩm chưa được chứng minh và không có kinh nghiệm với microservices Monolithic khá hoàn hảo cho các công ty khởi nghiệp cần có một sản phẩm có thể chạy với thời gian gấp rút Nhìn chung, kiến trúc monolithic được khuyến nghị sử dụng trong những trường hợp như:
● Phạm vi hệ thống nhỏ và được xác định rõ, khả năng các tính năng được
Trang 7gian sẽ có nhiều nhóm phát triển cùng làm việc trên ứng dụng đó Mỗi nhóm phát triển sẽ chịu trách nhiệm các phần khác nhau của ứng dụng và đôi khi là những khách hàng cụ thể mà họ đang làm việc cùng với phần chức năng tương ứng nào
đó Ví dụ tại một công ty tài chính lớn, họ có một ứng dụng quản lý quan hệ khách hàng (CRM) nội bộ, được xây dựng tùy chỉnh, liên quan đến sự phối hợp của nhiều nhóm bao gồm nhóm chuyên phụ trách về giao diện người dùng, nhóm chuyên làm việc với khách hàng, nhóm xây dựng kho dữ liệu và nhóm quỹ tương
hỗ Hình 3 dưới đây sẽ mô tả kiến trúc của hệ thống này
Hình 3 Kiến trúc tổng thể một hệ thống CRM
Vấn đề ở đây là khi quy mô và độ phức tạp của ứng dụng CRM sử dụng kiến trúc monolithic ngày càng phình to, và mỗi khi một nhóm phát triển muốn thực hiện một vài thay đổi nào đó thì bắt buộc toàn bộ ứng dụng phải được build lại, thực hiện kiểm thử và triển khai lại lên máy chủ
Trang 8Khái niệm microservices ban đầu xuất hiện trong cộng đồng phát triển phần mềm vào khoảng năm 2014 và được coi là câu trả lời để đối mặt với nhiều thách thức trong việc mở rộng quy mô cả về mặt kỹ thuật, công nghệ cũng như tổ chức cho các hệ thống lớn đang áp dụng kiến trúc monolithic lớn Ở đây chúng ta cần ghi nhớ rằng mỗi một microservice là một dịch vụ nhỏ, không bị ràng buộc chặt chẽ với nhau Microservices cho phép chúng ta đưa một ứng dụng lớn và phân rã
nó thành các thành phần nhỏ hơn nhằm dễ quản lý với các chức năng đã được định nghĩa, phân tách rõ ràng Khái niệm quan trọng nhất mà chúng ta cần ghi nhớ khi nghĩ về microservices là phân chia các nhóm chức năng trong hệ thống của chúng ta sao cho chúng hoàn toàn độc lập với nhau Nếu chúng ta xem xét ứng dụng quản lý quan hệ khách hàng CRM được mô tả trong hình 3 và phân tách nó thành các microservices, chúng ta sẽ được một hệ thống được trình bày trong hình 4 sau đây
Hình 4 Sử dụng kiến trúc microservices, ứng dụng CRM sẽ được phân tách thành một tập hợp các microservice hoàn toàn độc lập với nhau, cho phép mỗi nhóm phát triển có thể làm việc với tốc độ của riêng họ
Trang 9Nhìn vào hình 4, chúng ta có thể thấy rằng mỗi nhóm phát triển các chức năng khác nhau hoàn toàn làm chủ mã nguồn và cơ sở hạ tầng dịch vụ của mình
Họ có thể phát triển, triển khai và kiểm thử một cách độc lập vì mã nguồn, repo lưu trữ mã nguồn và cơ sở hạ tầng (máy chủ và cơ sở dữ liệu) hoàn toàn độc lập với các phần khác của hệ thống
Nhìn chung, kiến trúc microservices có những đặc điểm như sau:
● Logic ứng dụng được chia thành các thành phần nhỏ hơn với ranh giới về mặt chức năng, mỗi microservice đảm nhiệm công việc gì được xác định
rõ ràng, các microservice này phối hợp với nhau để đem lại một giải pháp hoàn chỉnh;
● Mỗi thành phần có một phạm vi về mặt chức năng, công việc vừa đủ và được triển khai hoàn toàn độc lập với nhau Các microservices phải chịu trách nhiệm xử lý một miền nghiệp vụ cụ thể nào đó Ngoài ra, một microservice cũng có khả năng tái sử dụng cho nhiều hệ thống khác nhau
● Các microservices giao tiếp với nhau dựa trên một số nguyên tắc cơ bản và
sử dụng các giao thức như HTTP và JSON (JavaScript Object Notation) để trao đổi dữ liệu giữa phía dùng dịch vụ và phía cung cấp dịch vụ
● Việc sử dụng công nghệ gì để phát triển một microservice không phải là vấn đề vì các ứng dụng luôn giao tiếp với nhau thông qua một giao thức trung lập (trong đó JSON là phổ biến nhất) Điều này có nghĩa là một hệ thống phát triển theo hướng microservices có thể được phát triển bằng nhiều ngôn ngữ lập trình và các công nghệ khác nhau
● Microservices — với bản chất là nhỏ, độc lập và phân tán — cho phép các
tổ chức có các đội ngũ phát triển với team size nhỏ với các miền nghiệp vụ
và trọng trách công việc được xác định rõ ràng Các nhóm này có thể làm việc hướng tới một mục tiêu duy nhất, nhưng mỗi nhóm chỉ cần phải chịu trách nhiệm với các dịch vụ mà họ đang phát triển mà thôi
Trang 10Hình 5 Kiến trúc microservices
Ưu điểm của kiến trúc microservices
So sánh với kiến trúc nguyên khối, rõ ràng kiến trúc microservices đã giải quyết được nhiều vấn đề, qua đó trở thành những ưu điểm của kiểu kiến trúc này:
● Các service có thể được phát triển cũng như bảo trì hoàn toàn độc lập:
Các service đảm nhiệm các chức năng, nghiệp vụ riêng, vì vậy khi có một service được bảo trì thì thường nó không làm ảnh hưởng tới các service khác Không ảnh hưởng ở đây là không làm “chết” các service khác nếu chẳng may service đang bảo trì gặp sự cố, chứ không phải là thiếu service
mà hệ thống vẫn hoạt động đầy đủ tính năng
● Dễ dàng nắm bắt logic nghiệp vụ: Mỗi service xử lý một nghiệp vụ riêng,
vì vậy mà bất kỳ ai cũng có thể dễ dàng nắm bắt được các logic nghiệp vụ,
kể cả một thành viên mới tham gia vào đội dự án cũng sẽ không mất nhiều thời gian để nắm được nghiệp vụ của 1 service
● Khả năng linh hoạt về mặt công nghệ: Mỗi service hoàn toàn có thể coi
như một dự án riêng, do đó chúng ta có thể sử dụng các công nghệ khác nhau (ngôn ngữ lập trình, cơ sở dữ liệu, framework, ) Chúng chỉ cần đảm bảo tuân theo chuẩn giao tiếp được đặt ra từ trước, còn bên trong chúng thực hiện ra sao và sử dụng công nghệ gì không ảnh hưởng tới các service còn lại Ví dụ một hệ thống với phần lớn các service được viết bằng Java, nhưng riêng service thực hiện gửi và nhận thông báo theo thời gian thực
Trang 11lại được viết bằng NodeJS Trên thực tế, một hệ thống phần mềm triển khai theo kiến trúc microservices mà có các service phát triển trên các nền công nghệ khác nhau là chuyện thường xuyên xảy ra
● Dễ dàng mở rộng khi hệ thống phình to: Kiến trúc microservices khá
tương đồng với kiến trúc của một hệ phân tán, nên nó cũng có khả năng
mở rộng theo chiều ngang Chúng ta có thể hiểu đơn giản là nếu chúng ta cần mở rộng hệ thống, chúng ta chỉ cần bổ sung thêm service
Các mặt hạn chế của kiến trúc microservices
Có thể thấy, kiến trúc microservices đem lại cho chúng ta rất nhiều lợi ích to lớn, song nó không thực sự hoàn hảo mà đánh đổi lại chúng ta cũng sẽ có những hạn chế như sau:
● Có độ trễ cao: Các service giao tiếp với nhau thông qua môi trường mạng,
nên sẽ có độ trễ cao hơn so với kiến trúc monolithic Để giảm độ trễ xuống mức tối thiểu, buộc các developer phải thiết kế sao cho chúng chỉ thật sự gọi tới nhau khi cần, đây cũng là một bài toán khó khi thiết kế hệ thống theo kiến trúc microservices
● Khó phát triển và quản lý: Để có thể phát triển thì các developer phải kéo
toàn bộ hệ thống về máy local để phát triển, trong khi một hệ thống microservices rất phức tạp, sẽ tương đối khó để giả lập được trên môi trường local Ngoài ra, với kiến trúc được chia nhỏ và vấn đề giao tiếp giữa các service cũng khiến các lập trình viên khó debug hơn
● Khó đảm bảo tính toàn vẹn dữ liệu: Vì dữ liệu có thể được lưu trên nhiều
service khác nhau, nên khó có thể đảm bảo được tính toàn vẹn Giả sử khi tạo đơn hàng, thì thông tin khách hàng phải tạo trước rồi mới tạo thông tin đơn hàng Với kiến trúc monolithic, database được lưu tập trung và chúng thường được ràng buộc khóa ngoại để đảm bảo tính toàn vẹn Nhưng với microservices, khi “khách hàng” và “đơn hàng” là hai service khác nhau thì không gì có thể để đảm bảo rằng dữ liệu phải được tạo ra theo đúng thứ
tự cả
Trang 12Phần 2 Thiết kế và triển khai hệ thống microservices
2.1 Thiết kế hệ thống microservices
2.1.1 Một số lưu ý
Trên thực tế, sẽ có những trường hợp chúng ta có cơ hội phát triển một hệ thống theo kiến trúc microservices ngay từ đầu, tuy nhiên cũng có khi chúng ta cần chuyển đổi mô hình hệ thống sẵn có đang sử dụng kiến trúc monolithic sang kiến trúc microservices Dù là trường hợp nào thì việc xác định phạm vi, tính năng của một microservice là hết sức quan trọng, thậm chí nó là bài toán khó nhất khi phát triển một hệ thống microservices trên thực tế
Khi chia nhỏ hệ thống thành các service nhỏ hơn, chúng ta nên lưu ý một
số điểm như sau:
● Tuân thủ nguyên tắc Single Responsibility: một service nên có phạm vi và chức năng giới hạn, tập trung vào một nghiệp vụ duy nhất;
● Cần đảm bảo mỗi service đều có thể phát triển và triển khai một cách độc lập;
● Mục tiêu của microservices là chia hệ thống thành các service nhỏ độc lập với nhau, đảm nhiệm các nghiệp vụ khác nhau, chứ không phải càng chia nhỏ service càng tốt
2.1.2 API Gateway
Một hệ thống microservices trung bình sẽ có một vài cho tới hàng trăm services khác nhau, nếu như client giao tiếp trực tiếp với các services này thì sơ
đồ giao tiếp giữa client và hệ thống của chúng ta sẽ vô cùng rối rắm và phức tạp,
và khi đó chúng ta phải đối mặt với rất nhiều vấn đề, tiêu biểu là vấn đề ràng buộc giữa client và các service, và những rủi ro về bảo mật sẽ leo thang hơn vì khi đó toàn bộ tất cả các service trong hệ thống của chúng ta được phơi ra ngoài Internet
Do đó, chúng ta cần phải có một API gateway làm cổng trung gian, tiếp nhận các request từ client, xác thực và điều hướng chúng tới đúng API của các service phía sau (hình 6)
Sử dụng API gateway sẽ đem lại những lợi ích đáng chú ý sau:
● Che giấu được các service nằm trong hệ thống với bên ngoài Internet:
Client sẽ tương tác với hệ thống của chúng ta thông qua API gateway chứ không gọi trực tiếp tới một service cụ thể nào cả, và các service sẽ gọi nhau
Trang 13trong một cách nội bộ Do đó, phía client không cần thiết và cũng không thể biết được các service phía sau hệ thống được tổ chức như thế nào
● Dễ dàng theo dõi và quản lý traffic hơn: Phần lớn các API gateway trong
các hệ thống microservices hiện nay đều sẽ đi kèm tính năng theo dõi và quản lý lượng traffic bằng GUI hoặc thông qua các API của hệ thống Gateway Việc có một cổng trung gian tiếp nhận các request từ client sẽ giúp chúng ta dễ dàng theo dõi, giám sát traffic hệ thống hơn
● Tăng cường bảo mật: Rõ ràng, việc để cho client giao tiếp với hệ thống
thông qua API gateway và các service giao tiếp với nhau trong mạng nội
bộ sẽ giúp hạn chế được các cuộc tấn công như DDOS, SQL injection, API gateway có thể được coi là một lớp bảo vệ cho hệ thống
● API gateway có thể thay thế authentication service: API gateway
thường cung cấp nhiều cơ chế xác thực, chúng ta có thể sử dụng nó để xác thực người dùng, qua đó giúp tiết kiệm thời gian và làm hệ thống trở nên đơn giản hơn
Hình 6 Trong kiến trúc microservices, thành phần API Gateway sẽ đóng vai trò
là một cổng trung gian giữa client và hệ thống microservices phía sau
2.1.3 Vấn đề giao tiếp giữa các microservices
Giao tiếp giữa các microservices phải hiệu quả và bền bỉ, chịu tải tốt Với rất nhiều microservice tương tác với nhau để có thể tạo thành một luồng hoàn chỉnh xử lý một hoạt động business nào đó, việc thiết kế giao tiếp giữa các