zoukankan      html  css  js  c++  java
  • ABP VNext从单体切换到微服务

    注:此处的微服务只考虑服务部分,不考虑内外层网关、认证等。

    ABP VNext从单体切换到微服务,提供了相当大的便利性,对于各模块内部不要做任何调整,仅需要调整承载体即可。

    ABP can help you in that point by offerring a microservice-compatible, strict module architecture where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application.

    分层架构

    1. ABP VNext自身提供的分层方式如下图,核心部分是Application、Domain与EntityFrameworkCore层,至于HttpApi.Client与HttpApi都是属于将应用去承载到其他系统之上的。

    图片

    1. Controller层在ABP VNext中被削弱了,VNext提供了将Application提供动态Controller,所以可能习惯了将部分逻辑写在控制器中的会有些唐突,但理解就行。

    图片

    规划层次结构

    1. 新建空文件夹,取名随意(本次取名GravelService),用于存放整体项目。
    2. 在上一步的空文件夹内新建空白解决方案,可以用VS去生成或是按照dotnet的命令生成。

    图片

    1. 习惯上按照ABP VNext给定的微服务Demo中的格式创建三个文件夹,思路清晰。当然提供的微服务Demo还有更多文件夹,但是这次只关注这三个。

    图片

    增加三个模块

    1. 设计三个限界上下文并绘制上下文映射。依照常见的订单、产品与客户划分成三个限界上下文。并规划好订单作为下游依赖产品与客户作为的上游。

    图片

    1. 从官网直接下载三个模块,或是按照命令行去生成(前提是已经安装了ABP CLI),无论哪种方式,确保准备好就行,依照模块化思想,将其存到modules文件夹下。

    图片

    1. 如本次准备了三个模块Product,Order,Customer,依照实际需要,可以去精简一下内部文件,此处各模块内部我只留着src和test文件夹。

    图片

    1. 对于customer模块的src内部,具体生成的文件夹如下,对于其中的HttpApi、HttpApi.Client及MongoDB,我采取了剔除,无需这部分(在稍后的承载体中有同等功能)。

    图片

    清理之后变得简简单单的。

    图片

    对于test内部,同样采取剔除无需的HttpApi.CLient、MongoDB文件夹(注:此处的无需只是针对我而言,如果有需要还是留着吧)。

    图片

    清理之后,层次划分变得简简单单的。

    图片

    1. 改造下各模块内给定的Sample案例,改造成各模块命名开头,方便加以区分。以Customer模块为例,将自带的Sample案例更名成Customer,仅作该项改动。

    图片

    模拟服务调用

    1. 对于Order与Product模块内增加一个下游访问上游服务的链路,方便验证从单体跨越到微服务,底层服务的无需任何改动。对于下游访问上游服务的调用形式,了解到的有两种方式。
    • 当前上下文的应用层直接依赖其他上下文的应用服务;
    • 当前上下文设定出防腐层(在限界上下文间增加一层隔离,方便保证依赖限界上下文存在变动时只需更改隔离层),在防腐层的实现中去依赖或远程调用其他上下文的应用服务;
    1. 我个人倾向于增加防腐层,虽然在VNext中并无相关说法。具体使用时,在领域层或应用层增加防腐层接口,及在EF Core层给与防腐层实现,此时的EF Core层,更应该更名为基础设施层,而不单单是作为资源库的形式。

    图片

    1. 在Order中Domain层增加ServiceClients文件夹用于存放防腐层接口,而在EntityFrameworkCore层增加ServiceClients文件夹用于存放防腐层实现。
    • 在防腐层接口中增加IProductServiceClient。
    public interface IProductServiceClient : ITransientDependency
    {
        Task<int> GetProductId();
    }
    
    • 在防腐层实现中增加ProductServiceClient。
    • 在Order中的EntityFrameworkCore层引用Product模块内的Application.Contracts层。
    • 依赖ProductAppService并完成调用。
    public class ProductServiceClient : IProductServiceClient
    {
        private readonly IProductAppService _productAppService;
        public ProductServiceClient(IProductAppService productAppService)
        {
            _productAppService = productAppService;
        }
        public async Task<int> GetProductId()
        {
            var productDto = await _productAppService.GetAsync();
            return productDto.Value;
        }
    }
    
    • 在OrderAppService中依赖防腐层接口,并完成调用。
    public class OrderAppService : OrderManagementAppService,   IOrderAppService
    {
        private readonly IProductServiceClient _productServiceClient;
        public OrderAppService(IProductServiceClient productServiceClient)
        {
            _productServiceClient = productServiceClient;
        }
        public async Task<OrderDto> GetAsync()
        {
            var productId = await _productServiceClient.GetProductId();
            ...
        }
    }
    
    1. 这样一来,在防腐层实现中便可以使用到Product上下文的应用服务了,对于这个应用服务的请求是当前进程内的还是进程间的,由具体的承载方式而决定。

    图片

    大单体承载

    将依照如下图,将三个模块承载到GravelService.Host上。

    图片

    1. 新建一个GravelService.Host的项目,采用WebApi类型即可。存放到microservices文件夹下,这样方便理解整个层级划分。

    图片

    1. 其次依赖一些基本的Nuget包,诸如ABP自身的及方便展示Api的Swagger。本次不考虑实体的创建,也就不考虑EF Core包的依赖了。
    • Volo.Abp
    • Volo.Abp.AspNetCore.MultiTenancy
    • Volo.Abp.AspNetCore.Mvc
    • Volo.Abp.Autofac
    • Swashbuckle.AspNetCore
    1. 引用各模块内的Application层及EntityFrameworkCore层。模仿着给定的微服务Demo,完成一波CV操作。增加一个类出来承担着服务与中间件的配置。

    图片

    1. 在其中依赖引用的各Application层及EntityFrameworkCore层中的Module,这样一来模块依赖就搞定了。
    [DependsOn(
        typeof(AbpAutofacModule),
        typeof(AbpAspNetCoreMvcModule),
        typeof(AbpAspNetCoreMultiTenancyModule),
        typeof(CustomerManagementApplicationModule),
        typeof(CustomerManagementEntityFrameworkCoreModule),
        typeof(OrderManagementApplicationModule),
        typeof(OrderManagementEntityFrameworkCoreModule),
        typeof(ProductManagementApplicationModule),
        typeof(ProductManagementEntityFrameworkCoreModule)
       )]
    public class GravelServiceHostModule : AbpModule
    {
      ...
    }
    
    1. 增加服务配置,将各模块中的应用服务动态转换成Api控制器。
    Configure<AbpAspNetCoreMvcOptions>(options =>
    {
        options.ConventionalControllers
            .Create(typeof(CustomerManagementApplicationModule).Assembly,       
            opts =>
            {
                opts.RootPath = "CustomerManagement";
            })
            .Create(typeof(OrderManagementApplicationModule).Assembly, 
            opts =>
            {
                opts.RootPath = "OrderManagement";
            })
            .Create(typeof(ProductManagementApplicationModule).Assembly, 
            opts =>
            {
                opts.RootPath = "ProductManagement";
            });
    });
    
    1. 然后,启动即可,所有模块中的接口都承载到了该承载体中。

    图片

    1. 通过访问Order的api/OrderManagement/order接口获得返回的9527,也就验证了,防腐层内去访问Product上下文的应用服务。

    图片

    此时是在同一进程内,使用到的是ProductAppService的具体实现,断点查看也可看出当前进程内的请求,依赖其他上下文服务的应用服务为ApplicationServiceProxy。

    图片

    多服务承载

    依照如下图开始切换承载模式,只更改承载体,将一个大的承载体切分成各上下文独自承载体。

    图片

    1. 新建三个和GravelService.Host同等的WebApi项目。在GravelService.Host上裁剪即可,每个独立的承载体只拥有自身的上下文。

    图片

    1. 依据上下文映射关系,对处于下游的Order承载体增加对上游Product的依赖,在Order承载体中增加对Product模块中Application.Contracts层的依赖。并在服务配置中完成依赖(第7行)。
    [DependsOn(
        typeof(AbpAutofacModule),
        typeof(AbpAspNetCoreMvcModule),
        typeof(AbpAspNetCoreMultiTenancyModule),
        typeof(OrderManagementApplicationModule),
        typeof(OrderManagementEntityFrameworkCoreModule),
        typeof(ProductManagementApplicationContractsModule)
        )]
    public class OrderServiceHostModule : AbpModule
    {
    ...
    }
    
    1. 配置远程服务代理,在服务配置中设置从Order承载体到Product承载体的远程服务请求。在Order承载体中增加Volo.Abp.Http.Client包并在服务配置中完成依赖。
    [DependsOn(
        ...
        typeof(AbpHttpClientModule),
        ...
        )]
    public class OrderServiceHostModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var configuration = context.Services.GetConfiguration();
            ...                       
            context.Services.AddHttpClientProxies(         typeof(ProductManagementApplicationContractsModule).Assembly);
            ...
        }
    }
    
    1. 在配置源appsettings文件中加入对Product承载体的远程调用地址
     {
      "RemoteServices": {
        "Default": {
          "BaseUrl": "http://localhost:57687"
        }
    }
    
    1. 更改项目配置,启动多个文件,一并启动三个独立承载体,再次调用Order中的Get请求,同样获得了从Product上下文的应用服务中的数据

    图片

    1. 这次采用的不同进程间的承载方式,通过防腐层,然后经ABP提供的Http代理服务调用Product承载体,可以断点查看当前在防腐层中的AppService类型,已经不再是直接使用ProductAppService了。

    图片

    真香

    从大单体承载切换多服务承载,Modules部分不需要做任何更改,着实方便。至于内部的远程调用,本身ABP VNext还存在一些问题像类似集合的Get请求在3.1的版本中才做了修复,但是这丝毫不影响这一巨人的前行。

    码云仓库

    2020-09-26,望技术有成后能回来看见自己的脚步

  • 相关阅读:
    mycat测试
    hive数据倾斜原因以及解决办法
    hive设置参数的方法
    hive文件格式
    hive 测试
    spark sql
    leetcode:Inver Binary Tree
    leetcode:Insertion Sort List
    leetcode:Insert Node in a Binary Search Tree
    leetcode:insert interval
  • 原文地址:https://www.cnblogs.com/CKExp/p/13735261.html
Copyright © 2011-2022 走看看