做微商网站公司,WordPress中文版如何下载,怎么开发一个自己的网站,重庆秀山网站建设报价一、前言这篇文章本来是继续分享IdentityServer4 的相关文章#xff0c;由于之前有博友问我关于微服务相关的问题#xff0c;我就先跳过IdentityServer4的分享#xff0c;进行微服务相关的技术学习和分享。微服务在我的分享目录里面是放到四月份开始系列文章分享的#xff… 一、前言这篇文章本来是继续分享IdentityServer4 的相关文章由于之前有博友问我关于微服务相关的问题我就先跳过IdentityServer4的分享进行微服务相关的技术学习和分享。微服务在我的分享目录里面是放到四月份开始系列文章分享的这里就先穿越下提前安排微服务应用的开篇文章 电商系统升级之微服务架构的应用。本博客以及公众号坚持以架构的思维来分享技术不仅仅是单纯的分享怎么使用的Demo。二、场景先来回顾下我上篇文章 Asp.Net Core 中IdentityServer4 授权中心之应用实战 中电商架构由单体式架构拆分升级到多网关架构升级之前升级之后:然而升级之后问题又来了由于之前增加了代理商业务并且把授权中心和支付网关单独拆出来了这使得公司的业务订单量翻了几十倍这个时候整个电商系统达到了瓶颈如果再不找解决方案系统又得宕机了。2.1 问题及解决方案经过技术的调研及问题分析导致这个瓶颈的问题主要有以下几个原因只需要把下面问题解决就可以得到很大的性能提升每天的订单量暴增导致订单数据太大然而整个电商系统数据存储在一个数据库中并且是单表、单数据库未进行读写分离以致于订单数据持续暴增。相关业务需要依赖订单查询订单数据查询慢以至于拖垮数据库整个电商系统连接数达到瓶颈已经分布式部署在多加服务器会损耗更多的经费而达不到最佳性价比为了一劳永逸的解决以上问题经过技术的调研决定对订单业务做如下升级改造拆分独立的订单微服务本章节着重分享使用ES进行数据迁移按年进行划分并且进行读写分离这里就不着重讲下次来跟大家一起学习和分享增加分布式缓存 也不是本次的重点后续再来跟大家学习和分享经过升级后的架构图如下架构图说明右边同一颜色的代表还是原先电商系统的单体式架构为拆分的单体架构业务其中在业务处理上夹杂了一层分布式缓存的处理左边的是微服务的架构是这次升级拆分后的架构其中数据库也已经从原有的数据库拆分并且数据迁移到了ES集群中并进行了读写分离。订单服务可以随意扩容成分布式服务通过一些工具动态扩展服务及服务器的支持。右边的业务后续也可以进行拆分拆分成不同的业务服务。后续升级还可以考虑消息队列等相关方面,架构图中未构思后续再来分享升级用到的相关技术这里还是回归到本文的核心微服务三、微服务概述微服务的相关概念我就不多说了以下就先简单概况下微服务带来的利和弊。3.1 微服务的优势使大型的复杂应用程序可以持续交付和持续部署持续交付和持续部署是DevOps的一部分DevOps是一套快速、频繁、可靠的软件交付实践。高效的DevOps组织通常将软件部署到生产环境时面临更少的问题和故障。DevOps工具有Docker、Kubernets、Jenkins、Git等。每个服务相对较小并容易维护微服务架构相比单体应用要小的多开发者理解服务中的逻辑代码更容易。代码库小打包启动服务速度也快。服务可以独立部署每个服务都可以独立于其他服务进行部署服务可以独立扩展服务可以独立扩展不论是采用X轴扩展的实例克隆还是Z轴的流量分区方式。此外每个服务都可以部署到适合它们需求的硬件之上微服务架构可以实现团队的自治可以根据服务来把开发团队拆分。每个团队都有自己负责的微服务而不用关心不属于他们负责的服务。更容易实验和采纳新的技术最后微服务可以消除对某个技术栈的长期依赖。因为服务更小使用更换的编程语言和技术来重写一项服务变得有可能这也意味着对一项新技术尝试失败后可以直接丢弃这部分工作而不至于给整个应用带来失败的风险。更好的容错性微服务架构也可以实现更换的故障隔离。例如某个服务引发的致命错误不会影响其他服务。其他服务仍然正常运行。服务可以独立扩容对于整个架构来说可以随意选择相关业务进行扩容和负载通过相关技术工具动态进行随意扩容3.2 微服务的劣势服务拆分和定义是一项挑战采用微服务架构首当其冲的问题就是根本没有一个具体的、良好定义的算法可以完成服务的拆分工作。与软件开发一样服务的拆分和定义更像一门艺术。更糟糕的是如果对系统的服务拆分出现了偏差很有可能会构建出一个分布式的单体应用一个包含了一大堆互相之间紧耦合的服务却又必须部署在一起的所谓分布式系统。这将会把单体架构和微服务架构两者的弊端集于一身。分布式系统带来的各种复杂性、使开发、测试和部署变得更困难使用微服务架构的另一个问题是开发人员必须处理创建分布式系统的额外复杂性。服务必须是进程间通信。这比简单的方法调用要复杂的多。当部署跨越多个服务的功能时需要谨慎地协调更多的开发团队使用微服务架构的另外一项挑战在于当部署跨越多个服务的功能时需要谨慎地协调更多开发团队。必须制定一个发布计划把服务按照依赖关系进行排序。这跟单体架构下部署多个组件的方式截然不同。开发者需要思考到底应该在应用的什么阶段使用微服务架构使用微服务架构的另一个问题是决定在应用程序生命周期的哪个阶段开始使用这种架构。跨服务数据的问题在单体应用中所有的数据都在一个数据库中而在微服务架构中每个服务都有自己的数据库想要获取操作其他服务的数据只能通过该服务提供API进行调用这样就带来一个问题进程通信的问题如果涉及到事务那么还需要使用Saga来管理事务增加了开发的难度。3.3 微服务拆分原则说到单体架构拆分那也不是随意拆分是要有一定的原则拆分的好是优势拆分的不好是混乱。以下是我查阅资料以及我的经验总结出来的拆分原则1、单一职责、高内聚低耦合2、微服务粒度适中3、考虑团队结构4、以业务模型切入5、演进式拆分6、避免环形依赖与双向依赖7、DDD可以考虑使用领域驱动设计去进行底层服务的设计,后续会单独分析该设计的相关文章四、微服务实战好了到这里大家已经对微服务有了一定的理解就不继续详细概述相关理念的东西下面来直接撸代码让大家熟悉微服务的应用。这里我使用 莫堇蕈 在github 上开源的微服务框架框架源代码地址 https://github.com/overtly/core-grpc 我这里强烈推荐该框架目前已经比较成熟的用于公司生产环境4.1 core-grpc 微服务框架的优势集成Consul 实现服务发现和注册以及健康检查等机制实时监听服务状态多节点 轮询机制故障转移拉入黑名单支持.Net Core 和Framework 两种框架实现基于Grpc的微服务部署支持环境变量4.2 实战创建Jlion.NetCore.OrderService 订单微服务我们用vs2019 创建控制台应用程序 选择框架.Net Core 3.1 命名为Jlion.NetCore.OrderService 后面简称订单服务创建完后我们通过nuget包引入 core-grpc微服务框架如下图目前core-grpc微服务框架最新正式发布版本是 1.0.3引用了core-grpc 后我们还需要安装一个工具VS RPC Menu这个工具也是大神免费提供的图片如下由于微软官方下载比较慢我这里共享到 百度网盘百度网盘下载地址如下链接: https://pan.baidu.com/s/1twpmA4_aErrsg-m0ICmOPw 提取码: cshs如果通过下载后安装不是vs 集成安装方式下载完成后需要关闭vs 2019相关才能正常安装。VS RPC Menu 工具说明如下用于客户端代码生成 支持Grpc 和Thrift 我们再在 订单服务项目 中创建OrderRequest.proto文件这个是Grpc 的语法,不了解该语法的同学可以 点击 gRPC 官方文档中文版_V1.0 进行学习地址http://doc.oschina.net/grpc?t56831OrderRequest.proto代码如下syntax proto3;
package Jlion.NetCore.OrderService.Service.Grpc;//定义订单查找参数实体
message OrderSearchRequest{string OrderId 1; //定义订单IDstring Name 2;
}//定义订单实体
message OrderRepsonse{string OrderId 1;string Name 2;double Amount 3;int32 Count 4;string Time 5;
}//定义订单查找列表
message OrderSearchResponse{bool Success 1;string ErrorMsg 2;repeated OrderRepsonse Data 3;
}上面主要是定义了几个消息实体 我们再创建JlionOrderService.proto代码如下syntax proto3;
package Jlion.NetCore.OrderService.Service.Grpc;import OrderRequest.proto;service JlionOrderService{rpc Order_Search(OrderSearchRequest) returns (OrderSearchResponse){}
}上面的代码中都可以看到最上面有 package Jlion.NetCore.OrderService.Service.Grpc 代码这是声明包名也就是后面生成代码后的命名空间这个很重要。同时定义了JlionOrderService服务入口并且定义了一个订单搜索的方法Order_Search到这里我们已经完成了一小部分了。生成客户端代码再在JlionOrderService.proto文件里面右键 》选择Grpc代码生成》Grpc 代码 会自动生存微服务客户端代码 。生存工具中具有如下功能生存Grpc客户端代码Grpc 编译不常用Grpc 打包常用用来把客户端dll发布到nuget服务器上还可以对Thrift 代码进行生成和打包创建Jlion.NetCore.OrderService.Grpc 类库把刚刚通过工具生成的Grpc客户端代码直接copy到 Jlion.NetCore.OrderService.Grpc这个类库中必须和上面Grpc 的代码声明的package 一致以下简称订单服务客户端并且需要通过Nuget包添加Overt.Core.Grpc 的依赖代码结构如下Jlion.NetCore.OrderService.Grpc类库已经构建完成现在让 Jlion.NetCore.OrderService 服务引用Jlion.NetCore.OrderService.Grpc 类库订单服务中 实现自己的IHostedService创建HostService类继承IHostedService代码如下public class HostedService : IHostedService
{readonly ILogger _logger;readonly JlionOrderServiceBase _grpcServImpl;public HostedService(ILoggerHostedService logger,JlionOrderServiceBase grpcService){_logger logger;_grpcServImpl grpcService;}//服务的启动机相关配置public Task StartAsync(CancellationToken cancellationToken){return Task.Factory.StartNew(() {var channelOptions new ListChannelOption(){new ChannelOption(ChannelOptions.MaxReceiveMessageLength, int.MaxValue),new ChannelOption(ChannelOptions.MaxSendMessageLength, int.MaxValue),};GrpcServiceManager.Start(BindService(_grpcServImpl), channelOptions: channelOptions, whenException: (ex) {_logger.LogError(ex, ${typeof(HostedService).Namespace.Replace(., )}开启失败);throw ex;});System.Console.WriteLine(服务已经启动);_logger.LogInformation(${nameof(Jlion.NetCore.OrderService.Service).Replace(., )}开启成功);}, cancellationToken);}//服务的停止public Task StopAsync(CancellationToken cancellationToken){return Task.Factory.StartNew(() {GrpcServiceManager.Stop();_logger.LogInformation(${typeof(HostedService).Namespace.Replace(., )}停止成功);}, cancellationToken);}}
上面代码主要是创建宿主机并且实现了StartAsync 服务启动及StopAsync 服务停止方法。我们创建完HostedServicce代码再来创建之前定义的Grpc服务的方法实现类JlionOrderServiceImpl代码如下public partial class JlionOrderServiceImpl : JlionOrderServiceBase
{private readonly ILogger _logger;private readonly IServiceProvider _serviceProvider;public JlionOrderServiceImpl(ILoggerJlionOrderServiceImpl logger, IServiceProvider provider){_logger logger;_serviceProvider provider;}public override async TaskOrderSearchResponse Order_Search(OrderSearchRequest request, ServerCallContext context){//TODO 从底层ES中查找订单数据//可以设计成DDD 方式来进行ES的操作这里我就为了演示直接硬编码了var response new OrderSearchResponse();try{response.Data.Add(new OrderRepsonse(){Amount 100.00,Count 10,Name 订单名称测试,OrderId DateTime.Now.ToString(yyyyMMddHHmmss),Time DateTime.Now.ToString()});response.Data.Add(new OrderRepsonse(){Amount 200.00,Count 10,Name 订单名称测试2,OrderId DateTime.Now.ToString(yyyyMMddHHmmss),Time DateTime.Now.ToString()});response.Data.Add(new OrderRepsonse(){Amount 300.00,Count 10,Name 订单名称测试2,OrderId DateTime.Now.ToString(yyyyMMddHHmmss),Time DateTime.Now.ToString()});response.Success true;}catch (Exception ex){response.ErrorMsg ex.Message;_logger.LogWarning(异常);}return response;}}
再修改Program代码并把HostedService和JlionOrderServiceImpl 注入到容器中代码如下 class Program{static void Main(string[] args){var host new HostBuilder().UseConsoleLifetime() //使用控制台生命周期.ConfigureAppConfiguration((context, configuration) {configuration.AddJsonFile(appsettings.json, optional: true).AddEnvironmentVariables();}).ConfigureLogging(logger {logger.AddFilter(Microsoft, LogLevel.Critical).AddFilter(System, LogLevel.Critical);}).ConfigureServices(ConfigureServices).Build();AppDomain.CurrentDomain.UnhandledException (sender, e) {var logFactory host.Services.GetServiceILoggerFactory();var logger logFactory.CreateLoggerProgram();logger.LogError(e.ExceptionObject as Exception, $UnhandledException);};host.Run();}/// summary/// 通用DI注入/// /summary/// param namecontext/param/// param nameservices/paramprivate static void ConfigureServices(HostBuilderContext context, IServiceCollection services){//HostedService 单例注入到DI 中services.AddSingletonIHostedService, HostedService();services.AddTransientJlionOrderServiceBase, JlionOrderServiceImpl();}}
到了这里简单的微服务已经编码完成但是还缺少两个配置文件我们创建appsettings.json配置文件和consulsettings.json 服务注册发现的配置文件consulsettings.json配置文件如下{ConsulServer: {Service: {Address: 127.0.0.18500// 你的Consul 服务注册及发现配置地址}}
}
上面的地址配置只是简单的例子我这里假定我的Consul服务地址是 127.0.0.18500 等下服务启动会通过这个地址进行注册。appsettings.json配置文件如下{GrpcServer: {Service: {Name: JlionOrderService,Port: 10001,HostEnv: serviceaddress,Consul: {Path: dllconfigs/consulsettings.json}}}
}
我这里服务监听了10001 端口后面注册到Consul中也会看到该端口 官方完整的配置文件如下{GrpcServer: {Service: {Name: OvertGrpcServiceApp, // 服务名称使用服务名称去除点OvertGrpcServiceAppHost: service.g.lan, // 专用注册的域名 可选格式ip[:portdefault]HostEnv: serviceaddress, // 获取注册地址的环境变量名字可选优先环境变量值格式ip[:portdefault]Port: 10001, // 端口自定义Consul: {Path: dllconfigs/consulsettings.json // Consul路径}}}
}
好了订单服务已经全部完成了订单服务服务整体结构图如下好了我们这里通过命令行启动下JlionOrderService服务生产环境你们可以搭建在Docker 容器里面我们可以来看下我之前搭建好的Consul服务 打开管理界面如图图片中可以发现刚刚启动的服务已经注册进去了但是里面有一个健康检查未通过主要是由于服务端不能访问我本地的订单服务所有健康检查不能通过。你可以在你本地搭建 Consul服务用于测试。我本地再来开启一个服务配置中的的端口号由10001 改成10002再查看下Consul的管理界面如下图:发现已经注册了两个服务端口号分别是10001 和10002这样可以通过自定化工具自动添加服务及下架服务分布式服务也即完成。到这里订单服务的启动已经完全成功了我们接下来是需要客户端也就是上面架构图中的电商业务网关或者支付网关等等要跟订单服务进行通讯了。创建订单网关跟订单服务进行通信创建订单网关之前我先把上面的 订单服务客户端 类库发布到我的nuget包上这里就不演示了。我发布的测试包名称JlionOrderServiceDemo nuget官方可以搜索找到。你们也可以直接搜索添加到你们的Demo中进行测试。我通过VS 2019 创建Asp.Net Core 3.1 框架的WebApi 取名为Jlion.NetCore.OrderApiService 下面简称订单网关服务现在我把前面发布的微服务客户端依赖包 JlionOrderServiceDemo 添加到订单网关服务中如下图现在在订单网关服务中添加OrderController api控制器代码如下namespace Jlion.NetCore.OrderApiService.Controllers
{[Route([controller])][ApiController]public class OrderController : ControllerBase{private readonly IGrpcClientOrderService.Service.Grpc.JlionOrderService.JlionOrderServiceClient _orderService;public OrderController (IGrpcClientOrderService.Service.Grpc.JlionOrderService.JlionOrderServiceClient orderService){_orderService orderService;}[HttpGet(getlist)]public async TaskListOrderRepsonse GetList(){var respData await _orderService.Client.Order_SearchAsync(new OrderService.Service.Grpc.OrderSearchRequest(){Name test,OrderId ,});if ((respData?.Data?.Count ?? 0) 0){return new ListOrderRepsonse();}return respData.Data.ToList();}}
}
代码中通过构造函数注入 OrderService 并且提供了一个GetList的接口方法。接下来我们还需要把OrderService.Service.Grpc.JlionOrderService注入到容器中代码如下public void ConfigureServices(IServiceCollection services)
{services.AddControllers();//注册Grpc 客户端具体可以查看源代码services.AddGrpcClient();
}
现在整个订单网关服务项目结构如下图项目中有两个最重要的配置dllconfig//Jlion.NetCore.OrderService.Grpc.dll.json 和consulsettings.json 他们分别是干什么的呢我们先分别来看我本地这两个配置的内容Jlion.NetCore.OrderService.Grpc.dll.json 配置如下{GrpcClient: {Service: {Name: JlionOrderService, // 服务名称与服务端保持一致MaxRetry: 0, // 最大可重试次数默认不重试Discovery: {Consul: { // Consul集群,集群优先原则Path: dllconfigs/consulsettings.json}EndPoints: [ // 单点模式{Host: 127.0.0.1,Port: 10001}]}}}
}
Jlion.NetCore.OrderService.Grpc.dll.json 配置主要是告诉订单网关服务和订单服务应该怎样进行通信以及通信当中的一些参数配置。我为了测试本地使用单点模式不使用Consul模式consulsettings.json 配置如下{ConsulServer: {Service: {Address: 127.0.0.1:8500}}
}
有没有发现这个配置和之前服务端的配置一样主要是告诉订单网关服务客户端调用者和订单服务服务端服务发现的集群地址如果上面的配置是单点模式则这个配置不会起作用。到这里订单网关服务 客户调用端编码完成我们开始启动它我这里固定5003端口现在完美的启动了我们访问下订单接口看下是否成功。访问结果如下图微服务完美的运行成功。上面的构建微服务还是比较麻烦官方提供了比较快速构建你需要的微服务方式不需要写上面的那些代码那些代码全部通过模板的方式进行构建你的微服务有需要学习的可以到点击微服务项目构建模板使用教程教程地址https://www.cnblogs.com/jlion/p/12494525.html为了更好的维护开源项目以及技术交流特意创建了一个交流群QQ群号1083147206 有兴趣者可以加入交流文章中的Demo 代码已经提交到github 上代码地址https://github.com/a312586670/IdentityServerDemo微服务框架开源项目地址https://github.com/overtly/core-grpc ♥ 给个[在看]是对我最大的支持 ♥