Microservice trong .NET Core sử dụng Ocelot

Danh Luu | 4/5/2022 4:41:47 PM

Bài viết này của tác giả chủ yếu để tác giả học, viết ra thì sẽ học được nhiều hơn là chỉ đọc

Upstream: Request gửi từ Client tới GateWay API
DownStream: Request từ GatewayAPI tới 1 Service

Đại khái là Client sẽ gửi 1 request, request này đi qua thằng gateway, thằng gateway lấy dữ liệu từ 1 service (API) khác

 

 

BÌnh thường thằng Client (Postman) truy cập API sẽ dùng localhost:12345, nhưng qua thằng gateway, nó sẽ đổi thành localhost:5000
Ví dụ có 2 thằng api, 1 thằng cổng :12345, 1 thằng :54321, Postman muốn truy cập cả 2 thì phải dùng cả 2 cổng, nhưng giờ có thằng gateway này, sẽ gộp 2 cổng kia lại, chuyển về thằng :5000, vì vậy thằng Postman chỉ cần gọi tới thằng :5000 là đc

Thằng Gateway này là Ocelot API Gateway

 

SO SÁNH MÔ HÌNH MICROSERVICE VÀ MONOLITH

MONOLITICMICROSERVICE
Một solution xử lý tất cả các nghiệp vụ, logicMỗi Service thực hiện một chức năng nhất định
Chỉ một DatabaseMỗi service có thể có một database khác nhau
Một project là một ngôn ngữ lập trình duy nhấtMỗi service có thể là một ngôn ngữ lập trình/công nghệ khác nhau
Solution sẽ được triển khai tại một server nhất định và duy nhất, Mỗi service có thể deploy ở bất cứ server nào mà vẫn có thể call tới nhau
Services will be tightly coupled to the application itself.Losely Coupled Architecture.

GETTING START

Trong bài viết này, mình sẽ sử dụng ASP.NET Core 3.1 Web API

Khởi động visual studio, tạo một Blank Solution, bạn có thể tìm từ khoá blank, sau đó chọn Blank Solution, bấm next

Hãy chắc chắn bạn sử dụng ASP.NET Core 3.1 hoặc phiên bản cao hơn như .NET 5, .NET 6

Tiếp theo, đặt tên cho project, ở đây mình sẽ đặt là Microservices.WebApi

 

Visual studio sẽ tạo một Solution rỗng cho bạn, Tiếp theo tạo mới một Folder trong solution, đặt tên nó là gì cũng đc, mình đặt là Microservices. Trong folder này, ta sẽ Add tất cả các project service, mỗi project sẽ là một service để thực hiện một chức năng nhất định. CLick chuột phải vào Folder vừa tạo, chọn Add a new Project, Đầu tiên tạo Product Microservice trước. Project này sẽ là WebAPI, Mình sẽ đặt tên nó là Product.Microservice.

Tương tự, ta tạo một service tên là Customer.Microservice (Tên ở đây đặt như nào cũng đc, mỗi project sẽ là một service)

Tiếp theo, một Project khá quan trọng, nó sẽ là cầu nối, kếtt  nối tất cả các service với nhau, đặt tên nó là Gateway.API. Project này sẽ là project rỗng, ta sẽ cấu hình nó sau

Kết quả, Solution của bạn sẽ trông như sau:

Về cơ bản, tất cả các chức năng liên quan tới quản lý khách hàng, ta sẽ giao cho Service(Project) Customer quản lý, mọi thứ liên quan tới Sản phẩm sẽ do Service Product quản lý. Người dùng phía máy khách (Trình duyệt) sẽ truy cập vào API Gateway để có thể sử dụng các dịch vụ của Product và Customer thông qua API Gateway's Url, máy khách sẽ không thể truy cập tới Customer và Product nếu không thông qua API Gateway

Cài đặt Microservices

Tiếp theo, mình sẽ tạo các chức năng cơ bản CRUD (Create/read/update/delete) cho từng service

Sử dụng Entity Framework Core để truy nhập database. Mình sẽ tự hiểu là các bạn biết code các chức năng CRUD cho một bảng trong cơ sở dữ liệu nào đó rồi, sử dụng EF Core, thực hiện viết API gồm các phương thức Get/Get(id)/Post(object)/Put(object)/Delete(id) . Mĩnh sẽ skip bước này, nếu bạn nào chưa biết thì hay bỏ qua bài viết này và tìm hiểu về vấn đề đó trước, sau đó quay lại đây đọc sau cũng chưa muộn. Mình cũng gợi ý bạn sử dụng Swagger để quản lý api dễ dàng hơn

Nếu bạn muốn thực hiện chức năng CRUD như trên, mình sẽ gợi ý bạn đọc bài viết này, tuy nhiên sẽ toàn tiếng Anh thôi, có thời gian mình sẽ dịch sau
1. ASP.NET Core căn bản sử dụng Entity Framework Core

2. Kiến trúc CQRS và MediatR trong .NET Core

Oke, tiếp nhé, để thiết thực hơn về tác dụng của Microservices, mình sẽ sử dụng 2 database khác nhau, thậm chí là mỗi database một server khác nhau cho từng service. Sau khu tạo các phương thức CRUD, swaggers của mình sẽ như sau:

Customer Service

Bạn hay để ý rằng, mỗi service sẽ có URL khác nhau, 2 service sẽ là như này khi chưa thông qua gateway, vì là 2 url khác nhau nên khá bất tiện đúng ko, chúng ta sẽ gộp chúng về 1 url trong bước tiếp theo

Giới thiệu về Ocelot API Gateway

Ocelot là một mã nguồn mở API Gateway của nển tảng .NET/Core. Ocelot sẽ tích hợp các đường dẫn mà máy khách gửi đi, và chuyển hướng nó tới từng service nhất định

Oclot cũng đc sử dụng bới một số công ty công nghệ lớn, phiên bản mới nhất của Oclot chỉ hỗ trợ .NET Core 3.1 trở lên, ko hỗ trợ .net framework. Việc tích hợp Ocelot vào project của bạn khá đơn giản, bằng cách cấu hình trong file JSON

Upstream và Downstream là hai khái niệm bạn cần nắm bắt và hiểu rõ.

Như để cập ở đầu bài viết, Upstream là Request được gửi lên từ người dùng, gửi tới API Gateway. Downstream là các request (yêu cầu) gửi từ API Gateway tới Từng service.

Mô hình Upstream/Downstream đơn giản như sau:

Mô hình này sẽ giúp bạn hiểu hơn, API Gateway có cổng là 5000. Trong khi Microservice có cổng là 12345. Bây giờ người dùng sẽ không thể truy cập trực tiếp vào cổng 12345 mà chỉ được phép vào 5000. Như vậy người dùng sẽ gửi Request vào côngtr 5000, ví dụ người dùng truy cập localhost:5000/api/weather để xem thời tiết thế nào. Những gì Ocelot làm sẽ là nhận Request từ người dùng và gửi một HTTP Request khác tới Microservice, Microservice sẽ phản hồi lại Ocelot một Response, có thể dưới dạng JSON, sau khi Ocelot Gateway nhận được Response từ Microservice, Sẽ bắn lại cho người dùng. Người dùng sẽ chỉ biết về Upstream là đường dẫn localhost:5000. Còn localhost:12345 sẽ là Downstream mà chỉ API Gateway mới biết

Bằng cách này, Ocelot Gateway có thể  điều hướng các request từ người dùng tới service. Tiếp theo mình sẽ cấu hình các route để Ocelot Gateway có thể điều hướng tới các Services

Một số đặc tính đáng chú ý của Ocelot

  1. Routing the Incoming Request to the required Microsrvice
  2. Authentication
  3. Authorization
  4. Load Balance for Enterprise Applications.

Xây dựng Ocelot API Gateway

Chúng ta cùng chuyển hướng tập trung vào project Gateway.WebApi đã tạo ở trên
Đầu tiên hãy tải package Ocelot

Install-Package Ocelot

Chạy câu lệnh này trong PM (Package management Console) hoặc bạn có thể vào Nuget Package tìm Ocelot và install về, cứ tải bản mới nhất ấy

Tiếp theo ta sẽ cấu hình Ocelot, mở file Program.cs trong project Gateway.WebApi và sửa hàm CreateHostBuilder thành như sau:

public static IHostBuilder CreateHostBuilder(string[] args) =>
	Host.CreateDefaultBuilder(args)
		.ConfigureWebHostDefaults(webBuilder =>
		{
			webBuilder.UseStartup();
		})
	.ConfigureAppConfiguration((hostingContext, config) =>
	{
		config
		.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
		.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
	});

Dòng gần cuối, Ocelot sẽ đọc file oclot.json, file này sẽ cấu hình đường dẫ để trỏ tới các services. Trước đó, ta cần cấu hình Ocelot Middleware cho project

Chuyển tới file Startup.cs

Trong hàm ConfigureServices hãy thêm 1 dòng này

services.AddOcelot();

Tiếp theo, chuyển tới hàm Configure

await app.UseOcelot();

Thêm dòng này vào cuối hàm

Cấu hình Ocelot Routes

Một trong những điều quan trọng nhất trong bài viết này, là cấu hình cho Ocelot để điều hướng Request từ khách hàng tới Microservice hay còn gọi là Upstream/Downstream như trên

Hãy bắt đầu với Product Microservice. Giả sử người dùng muốn lấy danh sách khách hàng thông qua API Gateway

Đầu tiên, trong swagger UI của Product Microservice, Hãy thêm một vài Product vào, sử dụng phương thức post ấy. Sau đó sử dụng phương thức Get để lấy ra danh sách Product vừa thêm vào để làm mẫu

Chú ý đường dẫn URL của Product hiện tại nhé

Tiếp theo tạo file ocelot.json như đã cấu hình ở trên File Program ấy. File này sẽ chứa nội dung để cấu hình Ocelot, nội dung file sẽ như sau:

{
	"Routes": [
		{
			"DownstreamPathTemplate": "/api/product",
			"DownstreamScheme": "https",
			"DownstreamHostAndPorts": [
				{
				"Host": "localhost",
				"Port": 44337
				}
			],
			"UpstreamPathTemplate": "/gateway/product",
			"UpstreamHttpMethod": [ "POST", "PUT", "GET" ]
		}
	]
}

Ocelot sẽ nhận một danh sách các Routes

Route đầu tiên sẽ trỏ tới Phương thức GetAllProduct, tiếp theo sẽ là Creare, Update và Delete

DownstreamPathTemplate sẽ là route mà Ocelot trỏ đến Microservice

DownstreamScheme sẽ là HTTP hoặc HTTPS, ở đây mình dùng https, hãy xem url của product thì bạn sẽ thấy ở đây dùng https

DownstreamHostAndPorts định nghĩa địa chỉ, ở đây sẽ là localhost và port, port của Product Microservice là 44337, nhớ nhé

UpstreamPathTemplate sẽ là địa chỉ mà máy khách client trỏ tới, nghĩa là người dùng sẽ gọi tới đường dẫn này để gửi request tới server Ocelot API Gateway

UpstreamHttpMethod sẽ cấu hình để có thể hỗ trợ các phương thức POST, PUT, GET, nếu người dùng gửi 1 HTTP GET tới Ocelot thì Ocelot sẽ gửi 1 phương thức GET tới Microservice, kiểu đấy

Để không trùng cổng thì mình sẽ đặt Gateway có cổng 44382 (nhớ nhé), đường dẫn sẽ là: localhost:44382/gateway/product và mình mong đợi nó sẽ lấy được kết quả từ microservice ( địa chỉ localhost:44337)

Hmm, bạn có thể đổi cổng của Gateway trong File Appsettings.json trong project Gateway như sau

Thực hiện build solution trước, nếu không lỗi thì mới chạy đc. Tuy nhiên, bây giờ ta có tới tận 3 API. Phải cấu hình để cả 3 cái này cùng chạy 1 lúc nhé, lý do thì bạn cứ tưởng tượng 3 cái này là 3 server khác nhau, chúng cần gọi tới nhau nên phải chạy thì mới gọi đc chứ

Để cấu hình chạy cả 3 project thì bạn làm như sau;
Chuột phải vào solution, chọn properties. Ở đây chọn như hình nhé, nhớ chọn Multiple Startup Projects, chỉnh cả 3 về start là đc, thứ tự ko quan trọng đâu

Tiếp theo bạn run Solution lên, và thực hiện gửi 1 request tới đường dẫn localhost:44382/gateway/product. Kết quả nhận được sẽ như sau

Well, vậy là đã thành công như mong đợi rồi, rõ ràng bạn đang truy cập tới Ocelot mà lại lấy đc dữ liệu của Product, Microservice là vậy đó

Để test được nhiều hơn thì bạn sử dụng Postman nhé, ai k có thì tải đi

Bạn có thể test các phương thức như POST/PUT để thêm hoặc update data, 2 cái này cùng đường dẫn với GetAll ấy, chỉ khác phương thức thôi

Tuy nhiên 2 phương thức GetByID và Delete thì khác, chúng cần thêm Id trong params nên sẽ khác đường dẫn, thế thì phải cấu hình thêm thôi

 

{
	"Routes": [
		{
			"DownstreamPathTemplate": "/api/product",
			"DownstreamScheme": "https",
			"DownstreamHostAndPorts": [
				{
					"Host": "localhost",
					"Port": 44337
				}
			],
			"UpstreamPathTemplate": "/gateway/product",
			"UpstreamHttpMethod": [ "POST", "PUT", "GET" ]
		},
		{
			"DownstreamPathTemplate": "/api/product/{id}",
			"DownstreamScheme": "https",
			"DownstreamHostAndPorts": [
				{
					"Host": "localhost",
					"Port": 44337
				}
			],
			"UpstreamPathTemplate": "/gateway/product/{id}",
			"UpstreamHttpMethod": [ "GET", "DELETE" ]
		}
	]
}

Cấu hình tương tự thôi. Và cùng test nào: localhost:44382/gateway/2

Như vậy là xong rồi đó, còn phần cấu hình Customer cũng sẽ tương tư, mình sẽ nhờ bạn làm hộ nhé

Mình sẽ kết thúc bài viết ở đây, bạn có góp ý gì comment giúp mình bên dưới nhé, có gì mình sửa, mình hy vọng các bạn sẽ hiểu hơn về Microservice trong ASP.NET Core sau bài viết này, Trong bài tiếp theo ta sẽ tìm hiểu về RabbitMQ, một Message Queue tuyệt vời trong Microservice

À Link bài viết này mình dịch từ đây nhé, ko phải tự viết đâu :>>


Tags: C# Microservice
Web hosting by Somee.com