Tips:本篇已加入系列文章閱讀目錄,可點擊查看更多相關文章,
前言
寫這篇博客主要目的是記錄一下自己的學習程序,只能是簡單入門級別的,因為水平有限就寫到哪算哪吧,寫的不對之處歡迎指正,
代碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo
什么是微服務?
關于微服務的概念解釋網上有很多...
個人理解,微服務是一種系統架構模式,它和語言無關,和框架無關,和工具無關,和服務器環境無關...
微服務思想是將傳統的單體系統按照業務拆分成多個職責單一、且可獨立運行的介面服務,至于服務如何拆分,沒有明確的定義,
幾乎任何后端語言都能做微服務開發,
微服務也并不是完美無缺的,微服務架構會帶來更多的問題,增加系統的復雜度,引入更多的技術堆疊...
創建專案

一個客戶端,一個產品服務,一個訂單服務,3個專案都是asp.net core web應用程式,創建專案的時候記得啟用一下Docker支持,或者后面添加也行,
為產品、訂單服務添加一些基礎代碼,就簡單的回傳一下 服務名稱,當前時間,服務的ip、埠,


在Docker中運行服務
為了方便,我使用Docker來運行服務,不用Docker也行,關于docker的安裝及基本使用就不介紹了,
- build鏡像:
在專案根目錄打開PowerShell視窗執行:docker build -t productapi -f ./Product.API/Dockerfile .


Successfully代表build成功了,
- 運行容器:
執行:docker run -d -p 9050:80 --name productservice productapi

執行:docker ps查看運行的容器:

沒問題,使用瀏覽器訪問一下介面:

也沒問題,其中的ip埠是Docker容器內部的ip埠,所以埠是80,這個無所謂,
- 產品服務部署好了,下面部署一下訂單服務,也是同樣的流程,就把指令簡單貼一下吧:
build鏡像:docker build -t orderapi -f ./Order.API/Dockerfile .
運行容器:docker run -d -p 9060:80 --name orderservice orderapi
瀏覽器訪問一下:

OK,訂單服務也部署完成了,
客戶端呼叫
客戶端我這里只做了一個web客戶端,實際可能是各種業務系統、什么PC端、手機端、小程式,,,這個明白就好,為了簡單就不搞那么多了,
-
因為客戶端需要http請求服務端介面,所以需要一個http請求客戶端,我個人比較習慣RestSharp,安利一波:https://github.com/restsharp/RestSharp

-
添加基礎代碼:

IServiceHelper.cs:
public interface IServiceHelper
{
/// <summary>
/// 獲取產品資料
/// </summary>
/// <returns></returns>
Task<string> GetProduct();
/// <summary>
/// 獲取訂單資料
/// </summary>
/// <returns></returns>
Task<string> GetOrder();
}
ServiceHelper.cs:
public class ServiceHelper : IServiceHelper
{
public async Task<string> GetOrder()
{
string serviceUrl = "http://localhost:9060";//訂單服務的地址,可以放在組態檔或者資料庫等等...
var Client = new RestClient(serviceUrl);
var request = new RestRequest("/orders", Method.GET);
var response = await Client.ExecuteAsync(request);
return response.Content;
}
public async Task<string> GetProduct()
{
string serviceUrl = "http://localhost:9050";//產品服務的地址,可以放在組態檔或者資料庫等等...
var Client = new RestClient(serviceUrl);
var request = new RestRequest("/products", Method.GET);
var response = await Client.ExecuteAsync(request);
return response.Content;
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
//注入IServiceHelper
services.AddSingleton<IServiceHelper, ServiceHelper>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
HomeController.cs:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IServiceHelper _serviceHelper;
public HomeController(ILogger<HomeController> logger, IServiceHelper serviceHelper)
{
_logger = logger;
_serviceHelper = serviceHelper;
}
public async Task<IActionResult> Index()
{
ViewBag.OrderData = https://www.cnblogs.com/xhznl/p/await _serviceHelper.GetOrder();
ViewBag.ProductData = await _serviceHelper.GetProduct();
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
Index.cshtml:
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>
@ViewBag.OrderData
</p>
<p>
@ViewBag.ProductData
</p>
</div>
代碼比較簡單,這里就不用docker了,直接控制臺啟動,使用瀏覽器訪問:

- 一切正常,進行到這里,各個服務也獨立運行了,客戶端也能正常呼叫了,貌似算是完成一個簡易的微服務了,但是,微服務架構最重要的原則就是——“高可用”,以上的做法明顯不能滿足高可用性,因為任何一個服務掛掉,所有依賴這個服務的業務系統都會受影響,
停止一下訂單服務:docker stop orderservice


訂單服務停止,導致客戶端業務系統無法獲取訂單資料,
要解決這個問題,很容易想到:集群,
簡單的服務集群
既然單個服務實體有掛掉的風險,那么部署多個服務實體就好了嘛,只要大家不同時全掛就行,
- 使用docker運行多個服務實體:
docker run -d -p 9061:80 --name orderservice1 orderapi
docker run -d -p 9062:80 --name orderservice2 orderapi
docker run -d -p 9051:80 --name productservice1 productapi
docker run -d -p 9052:80 --name productservice2 productapi
現在訂單服務和產品服務都增加到3個服務實體,
- 那么稍微改造一下客戶端代碼吧:
ServiceHelper.cs:
public class ServiceHelper : IServiceHelper
{
public async Task<string> GetOrder()
{
string[] serviceUrls = { "http://localhost:9060", "http://localhost:9061", "http://localhost:9062" };//訂單服務的地址,可以放在組態檔或者資料庫等等...
//每次隨機訪問一個服務實體
var Client = new RestClient(serviceUrls[new Random().Next(0, 3)]);
var request = new RestRequest("/orders", Method.GET);
var response = await Client.ExecuteAsync(request);
return response.Content;
}
public async Task<string> GetProduct()
{
string[] serviceUrls = { "http://localhost:9050", "http://localhost:9051", "http://localhost:9052" };//產品服務的地址,可以放在組態檔或者資料庫等等...
//每次隨機訪問一個服務實體
var Client = new RestClient(serviceUrls[new Random().Next(0, 3)]);
var request = new RestRequest("/products", Method.GET);
var response = await Client.ExecuteAsync(request);
return response.Content;
}
}
當然拿到這些服務地址可以自己做復雜的負載均衡策略,比如輪詢,隨機,權重等等 都行,甚至在中間弄個nginx也可以,這些不是重點,所以就簡單做一個隨機吧,每次請求來了隨便訪問一個服務實體,
-
瀏覽器測驗一下:

可以看到請求被隨機分配了,但是這種做法依然不安全,如果隨機訪問到的實體剛好掛掉,那么業務系統依然會出問題,
簡單處理思路是:
1.如果某個地址請求失敗了,那么換一個地址接著執行,
2.如果某個地址的請求連續多次失敗了,那么就移除這個地址,下次就不會訪問到它了,
,,,,,,
業務系統實作以上邏輯,基本上風險就很低了,也算是大大增加了系統可用性了, -
然后思考另一個問題:
實際應用中,上層的業務系統可能非常多,為了保證可用性,每個業務系統都去考慮服務實體掛沒掛掉嗎?
而且實際應用中服務實體的數量或者地址大多是不固定的,例如雙十一來了,流量大了,增加了一堆服務實體,這時候每個業務系統再去組態檔里配置一下這些地址嗎?雙十一過了又去把配置刪掉嗎?顯然是不現實的,服務必須要做到可靈活伸縮,
- 這時候就引入一個名詞:服務注冊與發現
未完待續...
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/13538.html
標籤:.NET Core
