• dapr入门学习


    一、安装

    我这里直接下载的二进制文件

    https://github.com/dapr/dapr/releases/download/v1.3.0/daprd_linux_amd64.tar.gz
    tar zxvf dapr_linux_amd64.tar.gz
    cp dapr /usr/bin/
    chmod +x /usr/bin/dapr
    dapr init
    默认安装1.3.0版本

    二、本地运行程序
    编写Demo程序,一个很简单的Asp.net core 程序

    using DaprTest.Controllers;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace DaprTest
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers().AddDapr();
                
                services.AddActors(options =>
                {
                    options.Actors.RegisterActor<IncrActorOne>();
                });
            }
    
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                app.UseRouting();
                app.UseCloudEvents();
                app.UseAuthorization();
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapSubscribeHandler();
                    endpoints.MapControllers();
                    endpoints.MapActorsHandlers();
                });
            }
        }
    }
    

      

      1 using Dapr;
      2 using Dapr.Actors;
      3 using Dapr.Actors.Client;
      4 using Dapr.Actors.Runtime;
      5 using Dapr.Client;
      6 using Microsoft.AspNetCore.Mvc;
      7 using Microsoft.Extensions.Logging;
      8 using System.Threading.Tasks;
      9 
     10 namespace DaprTest.Controllers
     11 {
     12     [ApiController]
     13     [Route("[controller]/[action]")]
     14     public class DaprController : ControllerBase
     15     {
     16         private readonly ILogger<DaprController> _logger;
     17         
     18         public DaprController(ILogger<DaprController> logger)
     19         {
     20             _logger = logger;
     21         }
     22         
     23         private static object _lockOjbect = new object();
     24         public static int incr = 0;
     25 
     26         [HttpGet]
     27         public async Task<int> Incr()
     28         {
     29             int value = 0;
     30             lock(_lockOjbect)
     31             {
     32                 value= ++incr;
     33             }
     34 
     35             return await Task.FromResult(value);
     36         }
     37 
     38         [HttpGet]
     39         public async Task<int> IncrActor()
     40         {
     41             var actorId = new ActorId("123");
     42             var actor =  ActorProxy.Create<IIncrActor>(actorId,nameof(IncrActorOne));
     43             var counterValue= await actor.IncrAcor();
     44 
     45             return counterValue;
     46         }
     47 
     48         [Topic("redis-pubsub", "daprpub")]
     49         [HttpGet]
     50         public async Task<int> Pub([FromServices] DaprClient daprClient)
     51         {
     52             var eventData = new EnventData { Id = "17", Amount = 10m, };
     53             await daprClient.PublishEventAsync("redis-pubsub", "daprpub", eventData);
     54             return await Task.FromResult(4);
     55         }
     56 
     57         
     58         [HttpPost]
     59         public string Sub([FromBody]EnventData enventData)
     60         {
     61             _logger.LogInformation($"来啦,小老弟!{enventData.Amount},{enventData.Id}");
     62             return "123";
     63         }
     64 
     65         [Route("/kafka-binding")]
     66         [HttpPost]
     67         public string KafkaBinding([FromBody] EnventData enventData)
     68         {
     69             _logger.LogInformation($"来啦,小老弟!{enventData.Amount},{enventData.Name}");
     70             return "123";
     71         }
     72     }
     73 
     74     public class EnventData
     75     {
     76         public string Name { get; set; }
     77 
     78         public decimal Amount { get; set; }
     79     }
     80     public interface IIncrActor: IActor
     81     {
     82         Task<int> IncrAcor();
     83     }
     84 
     85     public class IncrActorOne : Actor, IIncrActor
     86     {
     87         private static int COUNT = 0;
     88         public IncrActorOne(ActorHost host) : base(host) { }
     89 
     90         public async Task<int> IncrAcor()
     91         {
     92             return await Task.FromResult(++COUNT);
     93         }
     94 
     95         public async Task<int> IncrStateAcor()
     96         {
     97             var currntScore = await StateManager.AddOrUpdateStateAsync("score", 1,(key, currentScore) => currentScore + 1);
     98             return currntScore;
     99         }
    100     }
    101 }
    View Code
    dapr run --app-id DaprTest --app-port 5000 dotnet run
    

      这里要注意 --app-port参数,我之前没指定这个参数一直报无法通信。

    三、k8s运行demo

          要在k8s中运行dapr首先要在k8s中安装dapr相关的组件

    dapr init -k
    

      首先要确保执行命令的服务器上能够连接上k8s服务器,等待安装成功。

    截图中使用的k8s管理工具kuboard,在测试k8s集群中安装了Dapr、Istio(后续一定要记一些istio、Envoy的知识点)。

    安装成功后就可以将Demo程序打镜像发布到k8s中了。

    FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
    WORKDIR /app
    EXPOSE 80
    
    FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
    WORKDIR /src
    COPY ["DaprTest/DaprTest.csproj", "DaprTest/"]
    RUN dotnet restore "DaprTest/DaprTest.csproj"
    COPY . .
    WORKDIR "/src/DaprTest"
    RUN dotnet build "DaprTest.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "DaprTest.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    RUN ls
    ENTRYPOINT ["dotnet", "DaprTest.dll"]
    docker build -t 镜像名
    docker push //推送镜像
    

      

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: dotnet-daprtest
      namespace: dapr-test
    spec:
      hosts:
      - "*"
      gateways:
      - dapr-test-gateway
      http:
      - match:
        - uri:
            prefix: /betadaprtest/
        rewrite:
          uri: /
        route:
        - destination:
            host: dotnet-daprtest
            port:
              number: 80
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: dapr-test-gateway
      namespace: dapr-test
    spec:
      selector:
        istio: ingressgateway
      servers:
        - hosts:
            - xxx.xxx.com
          port:
            name: http
            number: 80
            protocol: HTTP
    apiVersion: v1
    kind: Service
    metadata:
      name: dotnet-daprtest
      namespace: dapr-test
      labels:
        app: dotnet-daprtest
        service: dotnet-daprtest
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: dotnet-daprtest
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: dapr-test
      name: dotnet-daprtest
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: dotnet-daprtest
      template: 
        metadata:
          labels:
            app: dotnet-daprtest
          annotations:
            dapr.io/enabled: "true"
            dapr.io/app-id: "dotnet-daprtest"
            dapr.io/app-port: "80"
        spec:
          imagePullSecrets:
          - name: xxxx
          restartPolicy: Always
          containers:
          - name: dotnet-daprtest
            image: xxxxx
            ports:
            - containerPort: 80

    virtualservice、gateway 定义如何访问服务。

    出于测试目的就没有在命名空间级别启用dapr 注入,直接在metadata -》annotaions 中启用dapr。

    pod启动成功后就可以看到Pod中启动了两个容器,一个是Demo本身,还有一个就是daprd的边车容器

    可以看下daprd容器中的日志,看看这个容器在启动时都做了些什么

    可以看到都是一些初始化,加载component组件等,这里要注意,如果发现daprd容器启动失败,可以从这个容器日志看到一些信息,一般都是一些组件加载失败,找到对应的组件修改即可。

    也可以用命令查看daprd容器日志,kubectl logs -f --tail=100 -n 命名空间  podId  -c daprd

    上面两张图就是因为kafka组件无法正确的连接到kafka服务端导致容器无法启动,进而导致整个Pod无法正常被调度。

    四、StatusDemo

    dapr在初始化k8s组件时并不会初始化Status组件(单机初始化时会创建一个redis 作为status实现),所以需要我们自行安装redis或者其他dapr支持的存储组件,Demo里使用自建的redis

    ---
    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: statestore
      namespace: dapr-test
    spec:
      metadata:
        - name: redisHost
          value: 'xxx:6379'
        - name: actorStateStore
          value: 'true'
        - name: redisDB
          value: '17'
      type: state.redis
      version: v1

    五、Actor编程模型

    对于Actor并发编程模型的定义就不过多赘述了。

    对于Actor只需要在代码中预先定义好,并注册即可

    [httpGet]
    public async Task<int> IncrActor()
    {
      var actorId=new ActorId("123");
    var actor= ActorProxy.Create<IIncrActor>(actorId,nameof(IncrActorOne));
    var counterValue = await actor.incrAcor();
    }
    public
    interface IIncrActor: IActor { Task<int> IncrAcor(); } public class IncrActorOne : Actor, IIncrActor { private static int COUNT = 0; public IncrActorOne(ActorHost host) : base(host) { } public async Task<int> IncrAcor() { return await Task.FromResult(++COUNT); } public async Task<int> IncrStateAcor() { var currntScore = await StateManager.AddOrUpdateStateAsync("score", 1,(key, currentScore) => currentScore + 1); return currntScore; } } public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddDapr(); services.AddActors(options => { options.Actors.RegisterActor<IncrActorOne>(); }); }

    Actor是动态,可以根据实际情况动态添加,例如根据用户id等标识一个Actor,可以在Dapr自带的Dashboard中查看Actor

    它在redis中的存储结构

    六、发布订阅

    发布订阅也同样需要定义Component组件

    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: redis-pubsub
      namespace: dapr-test
    spec:
      type: pubsub.redis
      version: v1
      metadata:
      - name: redisHost
        value: xxxx:6379
      - name: consumerID
        value: "myGroup"
      - name: enableTLS
        value: "false"
      - name: redisPassword
        value: 12345678
    ---
    apiVersion: dapr.io/v1alpha1
    kind: Subscription
    metadata:
      name: dotnet-subscription
      namespace: dapr-test
    spec:
      pubsubname: redis-pubsub
      topic: daprpub
      route: /Dapr/Sub
    scopes:
    - dotnet-daprtest

    这里定义了 发布组件、订阅组件,使用Redis实现。使用方式如下

            [HttpGet]
            public async Task<int> Pub([FromServices] DaprClient daprClient)
            {
                var eventData = new EnventData { Id = "17", Amount = 10m, };
                await daprClient.PublishEventAsync("redis-pubsub", "daprpub", eventData);//redis-pubsub 要使用的组件名称,daprpub topic
                return await Task.FromResult(4);
            }

    如果想更改实现组件,例如从redis切换到kafka,只需要更改一下 发布组件即可

    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: redis-pubsub
      namespace: dapr-test
    spec:
      type: pubsub.kafka
      version: v1
      metadata:
      - name: brokers
        value: "xxxxx:9092"
      - name: consumerGroup
        value: "daprtest"
      - name: clientID
        value: "dotnet-daprtest"
      - name: authRequired
        value: "false"
      - name: maxMessageBytes
        value: 1024

    组件名称依旧是 redis-pubsub,但是实现已经更改为了 kafka。需要注意的是,这里虽然更改了组件但是因为daprd容器并没有监听这种变化,这就导致了要手动去重启pod,这里dapr官方后期应该会被优化掉。

    这里需要注意的是,发布订阅的数据格式一定要正确,不能通过其他客户端直接向发布组件发送不正确的消息格式,一旦发送错误格式的数据会导致daprd容器报错,订阅方无法收到消息。

    正确的数据格式如下:

    {"traceid":"00-86b349b9b127754792b69a6bba049c40-4489f813ea9fab64-00","id":"9f5fc119-60ee-4fef-b7a7-b2ecd31e7da7","datacontenttype":"application/json","type":"com.dapr.event.sent","pubsubname":"redis-pubsub","data":{"name":"17","amount":10},"specversion":"1.0","source":"dotnet-daprtest","topic":"daprpub"}

    我在测试时使用了kafka 客户端工具发送了错误的数据导致daprd容器一直报错,订阅端死活收不到消息。查看daprd容器日志发现是有错误的数据。查看daprd容器日志是排查错误的一个有效方法。

    七、bindings

    bindings同样也是添加component即可

    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: kafka-binding
      namespace: -test
    spec:
      metadata:
        - name: topics
          value: daprtest
        - name: brokers
          value: 'ffffff:9092'
        - name: consumerGroup
          value: daprtest
        - name: publishTopic
          value: daprtest
        - name: authRequired
          value: false
        - name: maxMessageBytes
          value: 1024
      type: bindings.kafka
      version: v1

    这里需要注意的是 bindings是通http通信的  这就需要http的url要与bindings组件名一致,当然也有可能是我理解的不到位。

    测试时可以用kafka测试工具发送消息

    bin/kafka-console-producer.sh --broker-list localhost:9092 --topic daprtest  这个命令会卡住shell,并接收用户输入的数据

    输入对应的数据,就可以在程序中看到Demo的方法有没执行。

  • 相关阅读:
    为什么JSP的内置对象不需要声明
    什么不能输?
    可采用两种方法得到一个EJB对象
    EJB
    J2EE之JPA
    Application、Activity Stack 和 Task的区别
    关于 android屏幕适配
    JSP 向 JavaScript 中传递数组
    Android 图片异步加载 加载网络图片
    Android 显示意图和隐式意图的区别
  • 原文地址:https://www.cnblogs.com/pjjwpc/p/15196435.html
Copyright © 2020-2023  润新知