Dubbo 生态添新兵,Dubbo Admin 发布 v0.1

  为了提升 Dubbo 里程碑版本2.7.0的使用体验,我们于去年年中启动了 Dubbo Admin 的重构计划,并作为Dubbo生态的子项目,于近期发布了v0.1,重构后的项目在结构上的变化如下:
  
  将后端框架从webx替换成spring boot
  
  前端采用Vue和Vuetify.js作为开发框架
  
  移除velocity模板
  
  集成swagger,提供api管理功能
  
  当前版本的Dubbo Admin包含了之前版本中的绝大部分功能,包括服务治理,服务查询等,同时支持了Dubbo2.7中服务治理的新特性。
  
  配置规范
  
  由于在Dubbo2.7中,配置中心和注册中心做了分离,并且增加了元数据中心,因此Dubbo Admin的配置方式也做了更新,application.properties中的配置如下:
  
  admin.registry.address=zookeeper://127.0.0.1:2181
  
  admin.config-center=zookeeper://127.0.0.1:2181
  
  admin.metadata.address=zookeeper://127.0.0.1:2181
  
  也可以和Dubbo2.7一样,在配置中心指定元数据和注册中心的地址,以zookeeper为例,配置的路径和内容如下:
  
  # /dubbo/config/dubbo/dubbo.properties
  
  dubbo.registry.address=zookeeper://127.0.0.1:2181
  
  dubbo.metadata-report.address=zookeeper://127.0.0.1:2181
  
  配置中心里的地址会覆盖掉本地application.properties的配置
  
  功能介绍
  
  功能上,主要延续了之前版本的功能,包括服务查询和服务治理,2.7版本在服务治理的功能上有了很大的改进,这些改进也大部分都会以Dubbo Admin作为入口来体现。
  
  标签路由
  
  标签路由是Dubbo2.7引入的新功能,配置以应用作为维度,给不同的服务器打上不同名字的标签,配置如下图所示:
  
  1548675129621_1f2f3f68_4f35_4105_97e2_c4a0d7dc62c8_jpeg
  
  调用的时候,客户端可以通过setAttachment的方式,来设置不同的标签名称,比如本例中,setAttachment(tag1),客户端的选址范围就在如图所示的三台机器中,可以通过这种方式来实现流量隔离,灰度发布等功能。
  
  应用级别的服务治理
  
  在Dubbo2.6及更早版本中,所有的服务治理规则都只针对服务粒度,如果要把某条规则作用到应用粒度上,需要为应用下的所有服务配合相同的规则,变更,删除的时候也需要对应的操作,这样的操作很不友好,因此Dubbo2.7版本中增加了应用粒度的服务治理操作,对于条件路由(包括黑白名单),动态配置(包括权重,负载均衡)都可以做应用级别的配置:
  
  1548675095660_2abe00e4_7a3c_4c49_8649_0cc81e00e324_jpeg
  
  上图是条件路由的配置,可以按照应用名,服务名两个维度来填写,也可以按照这两个维度来查询。
  
  1548675169501_57b22613_ba3a_462b_b3ba_af34ea778589_jpeg
  
  条件路由,标签路由和动态配置都采用了yaml格式的文本编写,其他的规则配置还是采用了表单的形式。
  
  关于兼容性
  
  Dubbo2.6到Dubbo2.7,服务治理发生了比较大的变化,Dubbo Admin兼容两个版本的用法:
  
  对于服务级别的配置,会按照Dubbo2.6(URL)和Dubbo2.7(配置文件)两种格式进行写入,保证Dubbo2.6的客户端能够正确读取,解析规则
  
  对于应用级别的配置,包括标签路由,只会按照Dubbo2.7的格式进行写入,因为Dubbo2.6无此功能,不需要做向前兼容。
  
  Dubbo Admin只会按照Dubbo2.7的格式进行配置读取,因此,所有在Dubbo Admin上做的配置都可以被读到,但是之前遗留的,Dubbo2.6格式的URL无法被读取。
  
  对于同一个应用或者服务,每种规则只能够配置一条,否则新的会覆盖旧的。
  
  配置管理
  
  配置管理也是配合Dubbo2.7新增的功能,在Dubbo2.7中,增加了全局和应用维度的配置。
  
  全局配置:
  
  1548675196442_4611bfd9_5077_4bd2_a2b1_ad89c5eefc13_jpeg
  
  全局配置里可以指定注册中心,元数据中心的地址,服务端和客户端的超时时间等,这些配置在全局内生效。除了配置写入,也可以用来查看。如果使用zookeeper作为注册中心和元数据中心,还可以看到配置文件所在位置的目录结构。
  
  应用和服务配置
  
  1548675223170_772fd97b_f49f_4cf6_be40_34355f8159a1_jpeg
  
  应用级别的配置可以为应用或者应用内的服务指定配置,在服务维度上,需要区分提供者和消费者。dubbo.reference.{serviceName}表示作为该服务消费者的配置,dubbo.provider.{servcieName}表示作为该服务提供者的配置。优先级服务 > 应用 > 全局。其中注册中心和元数据中心的地址,只能在全局配置中指定,这也是Dubbo2.7中推荐的使用方式。
  
  元数据和服务测试
  
  元数据是Dubbo2.7中新引入的元素,主要的使用场景就在Dubbo Admin中,主要体现在两个地方:
  
  服务详情展示:
  
  1548675234502_67cefa2f_e180_4715_a203_a98bf515fe4f_jpeg
  
  跟之前版本相比,Dubbo2.7中增加了对服务方法完整签名的记录,因此服务详情中也增加了方法信息的详情,可以看到方法名,方法参数列表以及返回值信息。
  
  服务测试:
  
  1548675056214_730b7a7b_d4af_4a57_ab3f_380c5afcdabb_jpeg
  
  更重要的,元数据为服务测试提供了数据基础,可以在页面上调用真实的服务提供者,方便测试,也不需要为了调用服务去搭建一套Dubbo环境以及编写消费端代码。服务测试的详细使用方式可通过点击这里进行了解。
  
  添加 SessionController 用于用户登录,内容如下:
  
  using System.ComponentModel.DataAnnotations;
  
  using System.Net.Http;
  
  using System.Threading.Tasks;
  
  using IdentityModel.Client;
  
  using Microsoft.AspNetCore.Mvc;
  
  namespace ServiceA.Controllers
  
  {
  
  [Route("api/[controller]")]
  
  [ApiController]
  
  public class SessionController : ControllerBase
  
  {
  
  public async Task<string> Login(UserRequestModel userRequestModel)
  
  {
  
  // discover endpoints from metadata
  
  var client = new HttpClient();
  
  DiscoveryResponse disco = await client.GetDiscoveryDocumentAsync("http://127.0.0.1:8021");
  
  if (disco.IsError)
  
  {
  
  return "认证服务器未启动";
  
  }
  
  TokenResponse tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
  
  {
  
  Address = disco.TokenEndpoint,
  
  ClientId = "ServiceAClient",
  
  ClientSecret =dasheng178.com "ServiceAClient",
  
  UserName = userRequestModel.Name,
  
  Password = userRequestModel.Password
  
  });
  
  return tokenResponse.IsError ? tokenResponse.Error : tokenResponse.AccessToken;
  
  }
  
  }
  
  public class UserRequestModel
  
  {
  
  [Required(ErrorMessage = "用户名称不可以为空")]
  
  public string Name {www.078886.cn get; set; }
  
  [Required(ErrorMessage = "用户密码不可以为空")]
  
  public string Password { get; set; }
  
  }
  
  }
  
  添加 HealthController 用于 Consul 进行服务健康检查,内容如下:
  
  using Microsoft.AspNetCore.Mvc;
  
  namespace ServiceA.Controllers
  
  {
  
  [Route("api/[controller]"), ApiController]
  
  public class HealthController : ControllerBase
  
  {
  
  /// <summary>
  
  /// 健康检查
  
  /// </summary>
  
  /// <returns>www.yongshiyule178.com</returns>
  
  [HttpGet]
  
  public IActionResult Get()
  
  {
  
  return Ok();
  
  }
  
  }
  
  }
  
  更改 ValuesController.cs 内容如下:
  
  using System.Collections.Generic;
  
  using Microsoft.AspNetCore.Authorization;
  
  using Microsoft.AspNetCore.Mvc;
  
  namespace ServiceA.Controllers
  
  {
  
  [Authorize] //添加 Authorize Attribute 以使该控制器启用认证
  
  [Route("api/[controller]")]
  
  [ApiController]
  
  public class ValuesController : ControllerBase
  
  {
  
  // GET api/values
  
  [HttpGet]
  
  public ActionResult<IEnumerable<string>> Get()
  
  {
  
  return new[] { "value1", "value2" };
  
  }
  
  }
  
  }
  
  注意,以上基本完成了 ServiceA 的服务构建,但在实际应用中应做一些修改,例如:IdentityServer 地址应在 appsettings.json 中进行配置,不应把地址分散于项目中各处;认证服务启用最好在全局启用,以防止漏写等等。ServiceB 的内容与 ServiceA 大致相似,因此文章中将不再展示 ServiceB 的构建过程。
  
  Gateway 构建
  
  添加ASP.Net Web
  
  添加空项目
  
  打开程序包管理器控制台输入命令:
  
  csharp install-package Ocelot //添加 Ocelot
  
  csharp install-package Ocelot.Provider.Consul // 添加 Consul 服务发现
  
  添加 ocelot.json 文件,内容如下
  
  {
  
  "ReRoutes": [
  
  {
  
  "DownstreamPathTemplate": "/api/{everything}",
  
  "DownstreamScheme": "http",
  
  "UpstreamPathTemplate": "/ServiceA/{everything}",
  
  "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
  
  "ServiceName": "ServiceA", //consul 服务中 ServiceA 的名称
  
  "LoadBalancerOptions": {
  
  "Type": "LeastConnection"
  
  }
  
  },
  
  {
  
  "DownstreamPathTemplate": "/api/{everything}",
  
  "DownstreamScheme": "http",
  
  "UpstreamPathTemplate": "/ServiceB/{everything}",
  
  "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
  
  "ServiceName": "ServiceB", //consul 服务中 ServiceB 的名称
  
  "LoadBalancerOptions": {
  
  "Type": "LeastConnection"
  
  }
  
  }
  
  ],
  
  "GlobalConfiguration": {
  
  "ServiceDiscoveryProvider": { // Consul 服务发现配置
  
  "Host": "localhost", // Consul 地址
  
  "Port": 8500,
  
  "Type": "Consul"
  
  }
  
  }
  
  }
  
  删除 StartUp.cs 文件,在 Program.cs 文件中添加如下内容
  
  using System.IO;
  
  using Microsoft.AspNetCore.Hosting;
  
  using Microsoft.Extensions.Configuration;
  
  using Ocelot.DependencyInjection;
  
  using Ocelot.Middleware;
  
  using Ocelot.Provider.Consul;
  
  namespace ApiGateway
  
  {
  
  public class Program
  
  {
  
  public static void Main(string[] args)
  
  {
  
  new WebHostBuilder()
  
  .UseKestrel()
  
  .UseContentRoot(Directory.GetCurrentDirectory())
  
  .ConfigureAppConfiguration((hostingContext, config) =>
  
  {
  
  config
  
  .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
  
  .AddJsonFile("appsettings.json", true, true)
  
  .AddJsonFile($"appsettings.www.ouyi3pt1.cn{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
  
  .AddJsonFile(www.dituyule.org"ocelot.json")
  
  .AddEnvironmentVariables(www.yingxionghui1.cn);
  
  })
  
  .ConfigureServices(services =>
  
  {
  
  services.AddOcelot().AddConsul();
  
  })
  
  .ConfigureLogging((hostingContext, logging) =>
  
  {
  
  //add your logging
  
  })
  
  .UseIISIntegration()
  
  .Configure(app =>
  
  {
  
  app.UseOcelot().Wait();
  
  })
  
  .Build()
  
  .Run();
  
  }
  
  }
  
  }
  
  注意:打开 Gateway.csproj 文件,更改
  
  <PropertyGroup>
  
  <TargetFramework>netcoreapp2.2</TargetFramework>
  
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  
  </PropertyGroup>
  
  为
  
  <PropertyGroup>
  
  <TargetFramework>netcoreapp2.2</TargetFramework>
  
  <AspNetCoreHostingModel>www.fengshen157.com/ OutOfProcess</AspNetCoreHostingModel>
  
  </PropertyGroup>
  
  至此,一个基础网关基本构建完成。
  
  构建 Consul 服务
  
  使用 Chocoletey 安装 Consul,
  
  choco install consul
  
  新建一个文件夹以保存 Consul 服务配置
  
  在 consul.d 文件夹中添加配置文件,内容如下:
  
  {
  
  "services": [{
  
  "ID": "ServiceA",
  
  "Name": "ServiceA",
  
  "Tags": [
  
  "ServiceAWebApi", "Api"
  
  ],
  
  "Address": "127.0.0.1",
  
  "Port": 8010,
  
  "Check": {
  
  "HTTP": "http://127.0.0.1:8010/Api/health",
  
  "Interval": "10s"
  
  }
  
  }, {
  
  "id": "ServiceB",
  
  "name": "ServiceB",
  
  "tags": [
  
  "ServiceBWebApi","Api"
  
  ],
  
  "Address": "127.0.0.1",
  
  "Port": 8011,
  
  "Check": [{
  
  "HTTP": "http://127.0.0.1:8011/Api/health",
  
  "Interval": "10s"
  
  }
  
  ]
  
  }
  
  ]
  
  }
  
  启动 consul 服务
  
  consul agent -dev -config-dir=./consul.d
  
  启动后在浏览器中输入 http://localhost:8500/ui/ 以查看Consul服务
  
  Postman 验证
  
  F5 启动 Gateway 项目,启动 Postman 发送请求到 ServiceA 获取 Token。
  
  使用 Token 请求 ServiceA Values 接口
  
  当尝试使用 ServiceA 获取到的 Token 去获取 ServiceB 的数据时,请求也如意料之中返回 401
  
  总结
  
  至此,一个由 .NET Core、IdentityServer4、Ocelot、Consul实现的基础架构搭建完毕。源码地址

上一篇:Python学习-第二天-字符串和常用数据结构


下一篇:Oracle Sales Cloud:报告和分析(BIEE)小细节1——创建双提示并建立关联(例如,部门和子部门提示)