5

一行代码让你的项目轻松使用Dapr - 磊_磊

 2 years ago
source link: https://www.cnblogs.com/zhenlei520/p/16157625.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一行代码让你的项目轻松使用Dapr

Dapr简化了云原生开发,让开发可以把焦点放在应用的业务逻辑上,从而让代码简单、可移植,那作为一个.Net开发者,我们也希望项目可以快速用上dapr,那究竟应该如何做呢?

Dapr提出了Sidecar(边车)的概念,在启动项目时再额外启动一个Sidecar, 通过Sidecar可以解决进程间通信,为此官方提供了两种部署方式

  1. 自托管方式下运行Dapr
  2. 在 Kubernetes 模式中部署和运行 Dapr

其中Kubernetes模式部署是通过Kubernetes来完成的,在开发中我们更多的是通过自托管模式使用Dapr,那自托管模式是怎么做的呢?

使用命令行工具,在项目根目录输入:

dapr run --app-id assignment-server --app-port 5038 dotnet run

详细文档参考:手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序

参考以上详细文档操作后,我们就可以在命令行工具中执行dapr invoke --app-id assignment-server --method hello或者Http请求来调用对应的应用的方法

看似好像也不是很复杂,但如果你需要调试dotnet项目呢?再复杂一点的需要启动多个项目进行调试呢?端口一多起来的确会显得很麻烦。

有没有什么办法可以解决呢?有,docker-compose。

但我还不想用这么重的东西,我想像平时开发项目一样直接在windows上运行可不可以?

Masa.Utils.Development.Dapr.AspNetCore 它来了

协助管理dapr进程,用于开发时减少对docker compose的依赖

瞌睡了就有人送枕头,一句话让我们了解到了它的作用,正好解决了我们需要通过命令行来启动dapr的问题,那下面我们看看这个怎么用:

本着绝对不多写一行代码的心态,我们准备出发了……

  1. 从大佬doddgu的博客的链接中发现一份源码地址,为防止后期文档调整,先fork一份到自己仓库

    git clone https://github.com/zhenlei520/dapr-study-room.git
    
  2. 使用命令行工具打开目录dapr-study-room\Assignment03,然后执行命令

    dotnet add package Masa.Utils.Development.Dapr.AspNetCore --version 0.4.0-preview.3
    

    或使用Visual Studio打开解决方案Assignment03,选中Assignment.Server并安装Masa.Utils.Development.Dapr.AspNetCore

  3. 打开Program.cs,并添加DaprStarter(注意看有注释的那一行)

    using Masa.Utils.Development.Dapr.AspNetCore;
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddDaprStarter();//添加DaprStarter即可
    var app = builder.Build();
    
    app.Map("/hello", () => Console.WriteLine("Hello World!"));
    
    app.Run();
    
  4. 使用命令行工具执行命令验证dapr是否启动成功

    dapr invoke --app-id Assignment-Server-00D861D0C0B7 --method hello
    

此时会有小伙伴问了,为什么app-id是Assignment-Server-00D861D0C0B7?

查看文档后发现Masa.Utils.Development.Dapr.AspNetCore的app-id生成规则为:AppId + AppIdDelimiter + AppIdSuffix,其中

  • AppId默认:项目名.Replace(".","-")
  • AppIdSuffix默认:网卡地址

由于我们的项目名为Assignment.Server,当前电脑的网卡地址是00D861D0C0B7,所以dapr最终的appid为Assignment-Server-00D861D0C0B7,到这里,Masa.Utils.Development.Dapr.AspNetCore的使用讲解已经完成了

冷知识,为什么 . 要换成 - ?

因为Dapr的AppId采用FQDN:(Fully Qualified Domain Name)全限定域名:同时带有主机名和域名的名称。(通过符号“.”)

为什么要加网卡地址作为后缀?

因为目前自托管默认采用mDNS,会导致局域网内用户的AppId互相污染。你的同事和你一起在开发,都启动了A应用,你俩就自动负载了,那后果自然就是请求也到处跑了。

如果我希望自己指定AppId而不是使用默认的规则怎么办呢?目前支持三种写法:

  • 根据规则(配置默认装配)
  • 根据规则 + 代码指定(配置自定义装配)
  • 根据配置文件(根据IConfiguration配置生成)

配置默认装配(也是上面介绍的一行代码的方式)

修改Program.cs文件

// 省略上述代码
builder.Services.AddDaprStarter(); 

根据规则 + 代码指定(配置自定义装配)

修改Program.cs文件

// 省略上述代码
builder.Services.AddDaprStarter(opt =>
{
    opt.AppId = "masa-dapr-test";
    opt.AppPort = 5001;
    opt.AppIdSuffix = "";
    opt.DaprHttpPort = 8080;
    opt.DaprGrpcPort = 8081;
});

基于默认装配的升级版,在默认装配基础上通过指定特殊参数完成特殊需求,未配置的参数将使用默认值

根据IConfiguration配置生成

  1. 修改appsettings.json
{
  "DaprOptions": {
    "AppId": "masa-dapr-test",
    "AppPort": 5001,
    "AppIdSuffix": "",
    "DaprHttpPort": 8080,
    "DaprGrpcPort": 8081
  }
}
  1. 修改Program.cs
builder.Services.AddDaprStarter(builder.Configuration.GetSection("DaprOptions"));

优势:更改appsettings.json配置后,dapr sidecar会自动更新,项目无需重启

Masa.Utils.Development.Dapr.AspNetCore的设计思路

设计思路基于两个方面,其一本机自动启动dapr sidecar还可以正常调试.Net项目,其二简化配置

我们有两种启动dapr slidecar的方式:

  1. dapr run
  2. daprd

两者之间的差别如下所示:image.png

完整的对比可查看:https://docs.dapr.io/reference/arguments-annotations-overview/

通过对比我们发现,我们的目标使用daprd与Dapr CLI都可以实现,那为什么Masa.Utils.Development.Dapr选择的是Dapr CLI,而不是daprd呢?

核心的原因是dapr可以通过dapr list命令很简单的就获取到当前运行的所有dapr程序,而daprd无法获取。如果使用daprd,那我们就需要使用C#代码通过操作dll获取具体执行的dapr命令,且多平台支持不好,所以暂时用了Dapr CLI

更优秀的Dapr管理需要做到什么?

  • 参数可配置
  • 功能支持选择性启动
  • Dapr保活
  • 配置支持动态更新

为了能更方便的使用,我们做了以下约定:

  1. 针对dapr的非必填项,默认关闭不启用,手动配置参数后开启
  2. 针对dapr的必填项: app-id、app-port、dapr-http-port、dapr-grpc-port 自动生成并配置

app-id 生成规则

其中dapr的app-id默认生成规则为:AppId + AppIdDelimiter + AppIdSuffix,其中

  • AppId默认:项目名.Replace(".","-")
  • AppIdDelimiter默认:-
  • AppIdSuffix默认:当前机器网卡地址

当AppIdSuffix赋值为空字符串,dapr的AppId的生成规则为:AppId

app-port 获取

private ushort GetAppPort(DaprOptions options)
{
  var server = _serviceProvider.GetRequiredService<IServer>();
  var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses;
  if (addresses is { IsReadOnly: false, Count: 0 })
      throw new Exception("Failed to get the startup port, please specify the port manually");

  return addresses!
      .Select(address => new Uri(address))
      .Where(address
          => (options.EnableSsl is true && address.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
          || address.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
      .Select(address => (ushort)address.Port).FirstOrDefault();
}

为了防止启动过程中修改端口,过早的获取到被弃用的端口。因此我们使用后台任务启动dapr sidecar

dapr-http-port、dapr-grpc-port获取

因为支持用户配置,所以我们遵循下面的顺序

  1. 如果指定端口,被占用则自动kill port所在进程,保证可以sidecar可以正常启动

    为什么端口占用就要先kill,复用不行吗?

    因为sidecar有初始化配置,程序调整的代码影响到sidecar配置变更我们无法检测,所以启动时保证是最新的是比较合适的选择

  2. 如果未指定端口,则交还给dapr,通过Dapr CLI的规则生成对应的http-port或grpc-port

Dapr保活

为了保证dapr进程是活跃的,我们在库中建立了一个心跳检查任务用来检测当前的dapr进程是否是活跃的,当dapr进程意外停止后会被重启,且配置信息与上一次成功的dapr配置保持不变

如果不需要保活机制的话可以将EnableHeartBeat改为false,则不启用dapr保活机制

配置支持动态更新

我们通过IOptionsMonitor的OnChange方法来监听配置的变更,当配置变更后我们会通过IDaprProcess 提供的Refresh方法来重启dapr进程,并重新调整环境变量信息

Assignment03

https://github.com/zhenlei520/dapr-study-room

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks

MASA.Contrib:https://github.com/masastack/MASA.Contrib

MASA.Utils:https://github.com/masastack/MASA.Utils

MASA.EShop:https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

16373211753064.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK