.NetCore部署微服务(一)

news/2024/9/12 18:23:20/

目录

前言

什么是微服务

微服务的优势

微服务的原则

创建项目

在Docker中运行服务

 客户端调用

简单的集群服务


前言

写这篇文章旨在用最简单的代码阐述一下微服务

什么是微服务

微服务描述了从单独可部署的服务构建分布式应用程序的体系结构流程,同时这些服务会执行特定业务功能并通过 Web 接口进行通信,DevOps 团队通过将微服务(如构建块)组合在一起,从而将单个功能纳入微服务中以及构建更大的系统。

微服务的优势

微服务采用了某一开放/封闭原则:

  • 它们会开放以便进行扩展(使用它们公开的接口)
  • 它们会关闭以便进行修改(每个修改都会独立执行并进行版本控制)

微服务为整体体系结构提供了众多优势:

  • 它们可以通过确保一个服务中的问题不会崩溃或影响应用程序的其他部分来移除单一故障点 (SPOF)
  • 可独立扩展单个微服务,以提供额外的可用性和容量。
  • DevOps 团队可通过添加新微服务来扩展功能,而无需不必要的影响应用程序的其他部分。

使用微服务可提高团队速度。微服务通过允许软件开发团队利用事件驱动的编程和自动缩放等场景,很好地补充基于云的应用程序体系结构。 微服务组件通常会通过 REST 协议公开 API(应用程序编程接口),以便与其他服务通信。

微服务的原则

        顾名思义,微服务体系结构是一种将服务器应用程序生成为一组小型服务的方法。 这意味着微服务体系结构主要面向后端,虽然该方法也会用于前端。 每个服务都在自己的进程中运行,并使用 HTTP/HTTPS、WebSocket 或 AMQP 等协议与其他进程进行通信。 每个微服务在特定的上下文边界内实现特定的端到端域或业务功能,每个微服务都必须自主开发,并且可以独立部署。 最后,每个微服务都应拥有其自己的相关域数据模型和域逻辑(主权和分散式数据管理),并且可以基于不同的数据存储技术(SQL、NoSQL)和不同的编程语言。

        微服务应该有多大? 在开发微服务时,大小不应成为重点。 相反,重点应该是创建松散耦合的服务以便自主地为每个服务进行开发、部署和缩放。 当然,在标识和设计微服务时,只要与其他微服务不存在过多的直接依赖项,就应尝试让它们尽可能地小。 比微服务的大小更重要的是,它必须具有内部内聚,并且独立于其他服务。

创建项目

 我们在项目中新建两个文件夹,Client跟Service。Client文件夹用于管理我们的客户端,Service文件夹用于管理我们的Api.

项目结构目录如下:

三个项目都是Asp.Net Core Web API。

我们为ForumProductApi以及ForumOrderApi添加一些基础代码,我们返回接口名称以及当前时间,服务的IP地址,端口等信息,以让我们更好的区分接口。

我们修改OrderApi的代码如下:

[ApiController]
[Route("order")]
public class OrderController : ControllerBase
{private readonly ILogger<OrderController> _logger;public OrderController(ILogger<OrderController> logger){_logger = logger;}[HttpGet(Name = "GetOrder")]public Task<OrderEntity> GetOrder(){return Task.FromResult(new OrderEntity(){date_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),ip_address = Request.HttpContext.Connection.LocalIpAddress?.ToString(),ip_port = Request.HttpContext.Connection.LocalPort.ToString(),service_name = "订单服务"});}
}public class OrderEntity
{/// <summary>/// 当前时间/// </summary>public string? date_time { get; set; }/// <summary>/// Ip地址/// </summary>public string? ip_address { get; set; }/// <summary>/// Ip端口/// </summary>public string? ip_port { get; set; }/// <summary>/// 服务名称/// </summary>public string? service_name { get; set; }}

同理我们修改ProductApi的代码如下

[ApiController]
[Route("product")]
public class ProductController : ControllerBase
{private readonly ILogger<ProductController> _logger;public ProductController(ILogger<ProductController> logger){_logger = logger;}[HttpGet(Name = "GetOrder")]public Task<ProductEntity> GetOrder(){return Task.FromResult(new ProductEntity(){date_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),ip_address = Request.HttpContext.Connection.LocalIpAddress?.ToString(),ip_port = Request.HttpContext.Connection.LocalPort.ToString(),service_name = "产品服务"});}
}public class ProductEntity
{/// <summary>/// 当前时间/// </summary>public string? date_time { get; set; }/// <summary>/// Ip地址/// </summary>public string? ip_address { get; set; }/// <summary>/// Ip端口/// </summary>public string? ip_port { get; set; }/// <summary>/// 服务名称/// </summary>public string? service_name { get; set; }}

在Docker中运行服务

发布Product服务。

修改Dockerfile如下

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
#For more information, please see https://aka.ms/containercompatFROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443COPY ./ ./ENTRYPOINT ["dotnet", "ForumProductApi.dll"]

 打开prowershell,使用Docker编译项目并发布,

进入发布目录,build Api

 docker build -t productcontainer:1.0 .

这就表示编译成功。

然后我们运行容器

 docker run -d -p 8050:80 --name productapi productcontainer:1.0

 然后我们在浏览器中访问该项目

http://localhost:8050/swagger/index.html

访问结果如下:

我们以同样的方式部署Order服务。

同样我们也需要修改Dockerfile如下:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
#For more information, please see https://aka.ms/containercompatFROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443COPY ./ ./ENTRYPOINT ["dotnet", "ForumOrderApi.dll"]

 打开prowershell,使用Docker编译项目并发布,

进入发布目录,build Api

 docker build -t ordercontainer:1.0 .

运行项目

 docker run -d -p 8060:80 --name ordertapi ordercontainer:1.0

  然后我们在浏览器中访问该项目

http://localhost:8060/swagger/index.html

访问结果如下: 

 客户端调用

客户端我们需要http请求服务端接口,所以我们需要http请求,这里我使用了HttpClientFactory,代码很简单,可用于参考

Program代码

var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();#region 注册IHttpClientFactorybuilder.Services.AddHttpClient("local", config =>
{config.BaseAddress = new Uri("http://localhost");
});
builder.Services.AddHttpClient();#endregionvar app = builder.Build();// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{app.UseSwagger();app.UseSwaggerUI();
//}app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();

ClientController代码如下:

[ApiController]
[Route("client")]
public class ClientController:ControllerBase
{private readonly ILogger<ClientController> _logger;private readonly IHttpClientFactory _httpClientFactory;public ClientController(IHttpClientFactory httpClientFactory, ILogger<ClientController> logger){_httpClientFactory = httpClientFactory;_logger = logger;}[HttpGet(Name = "GetData")]public async Task<string> GetData(){var client = _httpClientFactory.CreateClient("local"); //string order_url = "http://localhost:8060/order";string product_url = "http://localhost:8050/product";var order_result = await client.GetStringAsync(order_url);var product_result = await client.GetStringAsync(product_url);return $"订单服务:{order_result}========================产品服务:{product_result}";}
}

直接运行看结果:

 我们的接口都可以请求成功。

一切正常,进行到这里,各个服务都可以独立运行,客户端也可以正常调用,貌似我们已经完成一个简易的微服务了,但是微服务架构最重要的原则是,高可用,以上的做法并不能满足高可用性,因为我么的服务一旦挂掉,所有依赖这个服务的业务系统就会受到影响。

如,我们现在停止订单服务。

docker stop orderapi

我们再次使用客户端请求获取数据的接口:

出现如下结果:

要解决这个问题,我们很容易想到的解决方案就是,集群。

简单的集群服务

既然单个服务有挂掉的风险,那么部署多个服务实例就好了,只要大家不同时挂掉我们的请求就没有问题。

ok,我们使用docker运行多个服务实例

 我们的Order服务运行三个实例,端口从60到62

 docker run -d -p 8060:80 --name orderapi1 ordercontainer:1.0docker run -d -p 8061:80 --name orderapi2 ordercontainer:1.0docker run -d -p 8062:80 --name orderapi3 ordercontainer:1.0

同样的我们的product服务也运行三个实例,端口从50到52

 docker run -d -p 8050:80 --name productapi1 productcontainer:1.0docker run -d -p 8051:80 --name productapi2 productcontainer:1.0docker run -d -p 8052:80 --name productapi3 productcontainer:1.0

那么也稍稍的改动一下我们的Client代码吧

[ApiController]
[Route("api/[controller]/[action]")]
public class ClientController:ControllerBase
{private readonly ILogger<ClientController> _logger;private readonly IHttpClientFactory _httpClientFactory;public ClientController(IHttpClientFactory httpClientFactory, ILogger<ClientController> logger){_httpClientFactory = httpClientFactory;_logger = logger;}public async Task<string> GetProduct(){var client = _httpClientFactory.CreateClient("local"); //string[] arr_product_url = { "http://localhost:8050/product", "http://localhost:8051/product", "http://localhost:8052/product" } ;var product_result = await client.GetStringAsync(arr_product_url[new Random().Next(0, 3)]);return $"产品服务:{product_result}";}public async Task<string> GetOrder() {var client = _httpClientFactory.CreateClient("local"); //string[] arr_order_url = { "http://localhost:8060/order", "http://localhost:8061/order", "http://localhost:8062/order" };var order_result = await client.GetStringAsync(arr_order_url[new Random().Next(0, 3)]);return $"订单服务:{order_result}";}
}

当然拿到这些服务地址可以自己做复杂的负载均衡策略,比如轮询,随机,权重等等 都行,甚至在中间弄个nginx也可以。这些不是重点,所以就简单做一个随机吧,每次请求来了随便访问一个服务实例。

我们尝试多次调用该接口,发现我们已经实现了随机的效果。

但是,这种做法依然不安全,如果随机访问到的实例刚好挂掉,那么业务依然会出现问题,简单处理思路是什么呢?

1.如果某个地址请求失败了,那么换一个地址接着执行。
2.如果某个地址的请求连续多次失败了,那么就移除这个地址,下次就不会访问到它了。

业务系统实现以上逻辑,基本上风险就很低了,也算是大大增加了系统可用性了。

然而:

实际应用中,上层的业务系统可能非常多,为了保证可用性,每个业务系统都去考虑服务实例挂没挂掉吗?
而且实际应用中服务实例的数量或者地址大多是不固定的,例如双十一来了,流量大了,增加了一堆服务实例,这时候每个业务系统再去配置文件里配置一下这些地址吗?双十一过了又去把配置删掉吗?显然是不现实的,服务必须要做到可灵活伸缩。

这时候就需要引入一个问题,服务注册与发现。


http://www.ppmy.cn/news/1296136.html

相关文章

开发板VS评估板

共性 该设计是围绕特定组件构建的&#xff0c;使设计人员能够在已知可以正常工作的组装板上对该组件进行试验。所有数字和模拟接口都暴露在连接器和/或测试点处&#xff0c;以便可以连接外围设备和其他评估/开发板。基本功能所需的其他支持电路&#xff08;例如电源调节或天线…

x-cmd pkg | trdsql - 能对 CSV、LTSV、JSON 和 TBLN 执行 SQL 查询的工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trdsql 是一个使用 sql 作为 DSL 的强大工具: 采用 SQL 对 CSV、LTSV、JSON 和 TBLN 文件执行查询与 MySQL&#xff0c;Postgresql&#xff0c;Sqlite 的 Driver 协同&#xff0c;可以实现对应数据库的表与文件的 JO…

速卖通店铺销量飙升:掌握自养号测评(补单),轻松提升销售量

很多卖家在经营速卖通店铺时&#xff0c;都希望能提高自己店铺的曝光率。但对于一些新手卖家来说&#xff0c;可能不太清楚曝光率的具体含义以及如何提升。那么&#xff0c;让我们一起来探讨一下这个问题。 曝光率&#xff0c;简而言之&#xff0c;是指您的店铺和产品展示给顾…

echart图表

首先我们要知道ECharts是什么,它是怎么用的&#xff1f; ECharts是一个使用JavaScript实现的开源可视化库&#xff0c;它涵盖各行业图表&#xff0c;满足各种需求。它提供了丰富的图表类型和交互能力&#xff0c;使用户能够通过国简单的配置生成各种各样的图表&#xff0c;包括…

《异侠传S1赛季侠义九州》公测版本三端互通PC客户端与IOS下载地址!!!

尊敬的各位异侠玩家们&#xff1a; 我们怀着无比激动的心情&#xff0c;充满感激地向大家宣布&#xff1a;今天上午10&#xff1a;00我们即将迎来《异侠传S1赛季&#xff1a;侠义九州》的首发公测&#xff01;在这个特殊的时刻&#xff0c;我们想将我们最诚挚的感谢献给每一位…

数据透明化是什么意思,什么是透明管理?

一、透明管理是什么 透明管理专注工业数据可视化分析与呈现&#xff0c;为企业提供一站式数据可视化分析解决方案。聚焦工业BI&#xff0c;基于工业管理特点&#xff0c;打造“指标监控-异常发现-根因溯源-举措拆解-效果监控”管理闭环&#xff0c;实现工业全层级的透明管理。…

Java集合-ArrayList

Java集合-ArrayList 特性 实现了三个标记接口&#xff1a;RandomAccess&#xff0c;Cloneable&#xff0c;java.io.Serializable public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable1…

深信服技术认证“SCSA-S”划重点:文件包含漏洞

为帮助大家更加系统化地学习网络安全知识&#xff0c;以及更高效地通过深信服安全服务认证工程师考核&#xff0c;深信服特别推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…

apply与call

概述&#xff1a; 它们共同的含义: 都是一个对象劫持另一个对象的方法&#xff0c;继承另一个对象的属性 相同点&#xff1a; 都可以改变this的指向 不同点&#xff1a; 他们的参数call可以写多个参数 apply只能有两个参数&#xff08;所以第二个参数可以放置数组或伪数组argum…

k8s的集群调度

schedule&#xff1a;负责调度资源&#xff0c;把pod调度到node节点 1、List-watch k8s集群当中&#xff0c;通过list-watch的机制进行每个组件的协作&#xff0c;保持数据同步&#xff0c;保持数据同步&#xff0c;每个组件之间的解耦 kubectl 配置文件&#xff0c;向APIse…

数字化妆,销量爆灯:美妆个护行业的直播营销新姿势

“ 直播电商走进全域营销驱动增长的时代 ” 文&#xff5c;欣桐&凯丰 编辑 | 靳淇 出品&#xff5c;极新 过去几年&#xff0c;美妆个护是直播电商平台中冲锋最猛的行业之一。李佳琦、薇雅等头部主播的“疯狂带货”下&#xff0c;美妆个护品牌脱颖而出&#xff0c;花…

建筑模板每平方价格怎么算?

在建筑行业中&#xff0c;建筑模板是一种常用的辅助材料&#xff0c;主要用于浇筑混凝土时形成所需的结构形状。了解建筑模板的定价方式对于预算控制和成本估算至关重要。本文将详细介绍建筑模板每平方米价格的计算方法。 1. 建筑模板的类型和特点建筑模板的种类繁多&#xff0…

网络名称解读 -入门5

WAN: Wide Area Network(跨区域&#xff09;&#xff0c;LAN&#xff1a; Local Area NetworkWAN MAC&#xff0c; 用来连接上级网络&#xff0c; LAN MAC&#xff0c; 用于内部网路。 LAN & WAN 3.1&#xff0c;LAN表示子网&#xff0c;通过掩码来筛选子网内主机数量&…

LED驱动芯片SM901K:可用于消除led无极调光频闪

LED驱动芯片SM901K/KF是一款专门用于消除100/120Hz LED电流纹波的芯片。当LED灯串中的LED电流发生纹波时&#xff0c;会影响到LED的亮度和寿命&#xff0c;因此消除这种电流纹波对于LED灯串的稳定工作非常重要。 SM901K LED驱动芯片SM901K/KF采用了先进的控制技术&#xff0c;…

AI-数学-初中-1.1二次函数图像及顶点式

一元二次方程ax^2bxc0&#xff08;a≠0&#xff09;的根的判别式是b^2-4ac&#xff0c;用“Δ”表示(读做“delta”) 实数根就是指方程式的解为实数&#xff0c;实数根也经常被叫为实根。 判别式Δb^2-4ac 若Δb^2-4ac&#xff1c;0,二次方程无实数根 若Δb^2-4ac0,二次方程有…

Unity 了解Input Manage下默认的输入轴

在Unity菜单Edit->Project Settings->Input Manager->Axes下有一些默认的输入轴&#xff0c;如 这些输入轴代表不同类型的输入&#xff0c;其中&#xff1a; Horizontal&#xff1a;水平移动输入轴。通常与键盘的左右箭头键、A和D键、游戏手柄的左摇杆水平轴等相关联…

Spring Boot中进行分库编程

在Spring Boot中使用分库&#xff08;Sharding&#xff09;需要根据具体情况而定。分库是一种解决单数据库性能瓶颈和数据量大的解决方案&#xff0c;通过将数据分散到多个数据库中&#xff0c;可以提升数据库的读写性能和数据存储能力。但是&#xff0c;分库也会带来一些复杂性…

Vue3+Pinia实现持久化动态主题切换

PC端主题切换大家都用过&#xff0c;下面用Vue3Pinia实现一下这个过程; 【源码地址】 1、准备工作 npm install pinia npm install pinia-plugin-persist2、基础配置 // main.js import { createApp } from vue import App from ./App.vue import bootstrap from "../bo…

centos通过yum安装redis

1. 安装yum添加epel源(此步根据环境&#xff0c;如果有源则可跳过&#xff0c;在阿里去可跳过&#xff09; yum install epel-release 2 使用yum安装Redis yum install redis 出现如下图所示的内容&#xff0c;默认的安装路径是在 /usr/bin目录下&#xff1a; 文件安装路径…

如何快速掌握Spring Cloud Alibaba微服务架构的核心原理?

另外我的新书RocketMQ消息中间件实战派上下册&#xff0c;在京东已经上架啦&#xff0c;目前都是5折&#xff0c;非常的实惠。 https://item.jd.com/14337086.html​编辑https://item.jd.com/14337086.html “RocketMQ消息中间件实战派上下册”是我既“Spring Cloud Alibaba微…