结合前三期 Dapr(一) 基于云原生了解Dapr(Dapr(一) 基于云原生了解Dapr-CSDN博客) Dapr(二) 分布式应用运行时搭建及服务调用(Dapr(二) 分布式应用运行时搭建及服务调用-CSDN博客) Dapr(三) Dapr核心组件的使用一(Dapr(三) Dapr核心组件的使用一-CSDN博客)。下一期使用Dapr中的Actor实现秒杀功能,以及Kubernetes部署Dapr。
目录
1.0 使用外部提供的注册组件(服务的注册与发现)
2.0 组件的绑定
2.1.0 绑定概述
2.2.0 创建绑定(以kafka为例)
2.2.0 输入绑定
2.2.1 使用输入绑定来触发应用程序
2.2.3 监听传入事件
2.3.0 输出绑定
2.3.1 发送事件
3.0 Actor
3.1.0 Actor 概述
3.2.0 Dapr 中的 Actor
3.3.0 Dapr Actors vs. Dapr 工作流程
3.4.0 Actor 生命周期
3.5.0 工作原理
3.6.0 .NET CORE使用Dapr Actor
3.6.1 Nuget引入
3.6.2 Actor接口--抽象
3.6.3 Actor接口实现--细节
3.6.4 Program.cs注册Actor
3.6.5 Actor控制器
总结:
1.0 使用外部提供的注册组件(服务的注册与发现)
docker启动一个consul。
docker run -d -p 8500:8500 --name=consul consul:latest agent -server -bootstrap -ui -node=1 -client='0.0.0.0'
切换组件。
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:name: daprConfig
spec:tracing:samplingRate: "1"zipkin:endpointAddress: http://localhost:9411/api/v2/spansnameResolution:component: "consul"configuration:client:address: "192.168.157.157:8500"selfRegister: true
2.0 组件的绑定
2.1.0 绑定概述
使用 Dapr 的绑定 API,你可以使用来自外部系统的事件触发应用,并与外部系统交互。 使用绑定 API,可以:
- 避免与队列和消息总线等消息系统连接和轮询的复杂性。
- 关注业务逻辑,而不是与系统交互的执行细节。
- 让您的代码远离 SDK 或库。
- 处理重试和故障恢复。
- 在运行时切换绑定
- 利用特定环境绑定设置构建可移植应用程序,无需更改代码。
例如,有了绑定,您的应用程序就可以响应传入的 Twilio/SMS 消息,而不需要
- 添加或配置第三方 Twilio SDK
- 担心来自 Twilio 的轮询(或使用 WebSockets 等)
在上图中
- 输入绑定会触发应用程序的一个方法。
- 在组件上执行输出绑定操作,如
"create"
。
绑定功能说白了就是可以无缝连接不同的第三方组件,在不修改代码的前提下随意切换组件。之前的微服务架构如果要切换不同的组件都是要修改代码的,现在把这个事情交给dapr,dapr与不同的组件之间进行边车通信。
2.2.0 创建绑定(以kafka为例)
zookeeper。
version: '2'
services:zookeeper:image: wurstmeister/zookeeper:latestports:- "2181:2181"kafka:image: wurstmeister/kafka:latestports:- "9092:9092"environment:KAFKA_ADVERTISED_HOST_NAME: 192.168.157.157KAFKA_CREATE_TOPICS: "topic"KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
docker启动一个kafka。
docker run -d -p 8080:8080 -v /opt/kafka-map/data:/usr/local/kafka-map/data -e DEFAULT_USERNAME=admin -e DEFAULT_PASSWORD=admin --name kafka-map --restart always dushixiang/kafka-map:latest
编写绑定配置文件。组件名称为sampletopic。
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: sampletopic
spec:type: bindings.kafkaversion: v1metadata:# Kafka broker connection setting- name: brokersvalue: 192.168.157.157:9092# consumer configuration: topic and consumer group- name: topicsvalue: sample- name: consumerGroupvalue: group1# publisher configuration: topic- name: publishTopicvalue: sample- name: authRequiredvalue: "false"
2.2.0 输入绑定
通过输入绑定,可以在外部资源发生事件时触发应用程序。 可选择随请求发送有效载荷和元数据。
2.2.1 使用输入绑定来触发应用程序
通过输入绑定,您可以在外部资源发生事件时触发应用程序。一个外部资源可以是队列、消息管道、云服务、文件系统等。可选择随请求发送有效载荷和元数据。
输入绑定对于事件驱动的处理,数据管道或通常对事件作出反应并执行进一步处理非常理想。Dapr 输入绑定允许您:
- 接收不包含特定 SDK 或库的事件
- 在不更改代码的情况下替换绑定
- 关注业务逻辑而不是事件资源实现
2.2.3 监听传入事件
using System.Collections.Generic;
using System.Threading.Tasks;
using System;
using Microsoft.AspNetCore.Mvc;namespace CheckoutService.controller
{[ApiController]public class SampletopicServiceController : Controller{[HttpPost("/sampletopic")]public ActionResult GetSampletopic([FromBody] string message){Console.WriteLine("Received Message: " + message);}}
}
2.3.0 输出绑定
使用输出绑定,您可以调用外部资源。调用请求可发送可选的有效载荷和元数据。
2.3.1 发送事件
[Route("api/[controller]")][ApiController]public class BindingsController : ControllerBase{private readonly ILogger<BindingsController> _logger;private readonly DaprClient _daprClient;public BindingsController(ILogger<BindingsController> logger, DaprClient daprClient){_logger = logger;_daprClient = daprClient;}[HttpPost("create")]public async Task SendMessageAsync([FromServices] DaprClient daprClient){var message = "binging功能"; //执行绑定操作:create操作await daprClient.InvokeBindingAsync("sampletopic", "create", message);}}
3.0 Actor
3.1.0 Actor 概述
Actor 模式 将 actor 描述为最低级别的"计算单元"。 换句话说,您将代码写入独立单元 ( 称为actor) ,该单元接收消息并一次处理消息,而不进行任何类型的并行或线程处理。(单线程)
当代码处理消息时,它可以向其他参与者发送一条或多条消息,或者创建新的 Actor。 底层运行时将管理每个 actor 的运行方式,时机和位置,并在 actor 之间传递消息。
大量 actor 可以同时执行,但他们之间是相互独立执行的。
3.2.0 Dapr 中的 Actor
Dapr 包括一个专门实现了虚拟 Actor 模式的运行时。 通过 Dapr 的实现,您可以根据 Actors 模型编写 Dapr Actor,而 Dapr 利用底层平台提供的可扩展性和可靠性保证。
每个 actor 都定义为 actor 类型的一个实例,这与对象作为类的实例的方式相同。 例如,可能存在实现计算器功能的 actor 类型,并且该类型的许多 Actor 分布在集群的各个节点上。 每个此类 actor 都由一个 actor ID 唯一标识。
3.3.0 Dapr Actors vs. Dapr 工作流程
Dapr actors 以状态管理和服务调用 API 为基础,创建有状态的、长期运行的、具有身份标识的对象。 Dapr 工作流和 Dapr Actors 是相关的,工作流建立在 Actors 之上,提供了更高层次的抽象,可以协调一组 Actors,实施常见的工作流模式,并代表您管理 Actors 的生命周期。
Dapr Actors 旨在提供一种在分布式系统中封装状态和行为的方法。 客户端应用程序可根据需要激活 actor。 当一个 actor 被激活时,它会被分配一个唯一的身份,这样它就能在多次调用中保持自己的状态。 这使得 Actors 在构建有状态、可扩展和容错的分布式应用程序时非常有用。
另一方面,Dapr 工作流提供了一种定义和协调复杂工作流的方法,这些工作流涉及分布式系统中的多个服务和组件。 工作流允许你定义一系列需要按特定顺序执行的步骤或任务,可用于实施业务流程、事件驱动工作流和其他类似场景。
如上所述,Dapr 工作流建立在 Dapr Actors 的基础上,管理它们的激活和生命周期。
3.4.0 Actor 生命周期
Dapr Actors 是虚拟的,意思是他们的生命周期与他们的 in - memory 表现不相关。 因此,它们不需要显式创建或销毁。 Dapr Actors 运行时在第一次接收到该 actor ID 的请求时自动激活 actor。 如果 actor 在一段时间内未被使用,那么 Dapr Actor 运行时将回收内存对象。 如果以后需要重新激活,它还将保持对 actor 的一切原有数据。
调用actor方法、定时器和提醒会重置actor的空闲时间。 例如,一个提醒触发会保持actor处于活动状态。
- 提醒器无论 actor 是活动的还是非活动的都会触发。 如果为非活动 actor 触发,它会首先激活该 actor。
- Actor 计时器触发会重置空闲时间;然而,计时器只会在 actor 处于活动状态时触发。
空闲超时和扫描间隔是可配置的,Dapr 运行时使用它们来查看 actor 是否可以垃圾回收。 当 Dapr 运行时调用 actor 服务以获取受支持的 actor 类型时,这些信息可以被传递。
由于虚拟 actor 模型的原因,虚拟 actor 生命周期抽象带有一些注意事项,而事实上,Dapr actor 的实现有时会偏离这个模型。
Actor 在第一次有消息发送到它的 actor ID 时就会被自动激活(导致 actor 对象被构建)。 经过一段时间后,actor 对象将被垃圾回收。 在未来,再次使用 actor ID,将导致构建新的 actor 对象。 Actor 的状态比对象的生命周期更久,因为状态存储在 Dapr 运行时的配置状态提供程序中(也就是说 actor 即使不在活跃状态,仍然可以读取它的状态)。
3.5.0 工作原理
Dapr启动app时,Sidecar调用Actors获取配置信息,之后Sidecar将Actors的信息发送到**安置服务**(Placement Service),安置服务会将不同的Actor类型根据其**Id和Actor类型**分区,并将Actor信息**广播到所有dapr实例**。
在客户端调用某个Actor时,安置服务会根据其Id和Actor类型,找到其所在的dapr实例,并执行其方法。
什么时候用Actors
- 需要单线程执行,比如需要加锁
- 逻辑可以被划分为小的执行单元
3.6.0 .NET CORE使用Dapr Actor
3.6.1 Nuget引入
<PackageReference Include="Dapr.Actors.AspNetCore" Version="1.13.0" />
3.6.2 Actor接口--抽象
using Dapr.Actors;namespace Dapr_ServiceA.Actors
{/// <summary>/// 定义接口,继承IActor/// </summary>public interface ITestActor : IActor{Task<string> Test();}
}
3.6.3 Actor接口实现--细节
using Dapr.Actors.Runtime;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;namespace Dapr_ServiceA.Actors
{/// <summary>/// 实现这个Actor接口/// </summary>public class TestActor : Actor, ITestActor{public TestActor(ActorHost host) : base(host){}public Task<string> Test(){return Task.FromResult("TestActor");}}
}
3.6.4 Program.cs注册Actor
using Dapr_ServiceA.Actors;namespace Dapr_ServiceA
{public class Program{public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers().AddDapr();builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();//注册Actorbuilder.Services.AddActors(options => {options.Actors.RegisterActor<TestActor>();});var app = builder.Build();if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}//引用Actorapp.MapActorsHandlers();app.UseAuthorization();app.MapControllers();app.Run();}}
}
3.6.5 Actor控制器
using Dapr.Actors;
using Dapr.Actors.Client;
using Dapr_ServiceA.Actors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;namespace Dapr_ServiceA.Controllers
{[Route("api/[controller]")][ApiController]public class ActorController : ControllerBase{private readonly IActorProxyFactory _actorProxyFactory;public ActorController(IActorProxyFactory actorProxyFactory){_actorProxyFactory = actorProxyFactory;}/// <summary>/// 操作同一个资源就要同一个key。/// </summary>/// <param name="Id"></param>/// <returns></returns>[HttpGet("/ActorGet")]public async Task<string> GetAsync(string Id){ITestActor proxy = _actorProxyFactory.CreateActorProxy<ITestActor>(new ActorId("myid-" + Id), "TestActor");return await proxy.Test();}}
}
总结:
Dapr的绑定允许应用与各种外部服务和服务间通信,如数据库、消息队列等,无需关注具体的实现细节。绑定可以用于输入(接收事件)和输出(发布事件)。
对于Actor功能,Dapr提供了Actor模型,它基于Virtual Actors概念,有以下几个关键特性:
- 单线程执行:每个Actor实例都在自己的线程中运行,确保操作是原子性的且互不影响。
- 无锁并发:内部实现了同步机制,避免开发者手动添加锁,减少死锁的风险。
- 资源管理:闲置的Actor会被自动卸载,节省资源;如果节点故障,Actor的状态会迁移到健康节点,保持高可用。
- Timer和Reminder:Timer用于定时任务,而Reminder则用于周期性任务且能保证即使Actor重启也能继续执行。
总结起来,Dapr的Actors适合处理具有独立状态和操作的并发场景,并且简化了定时和周期任务的管理。但在某些情况下,如需要低延迟读取Actor状态或高并发的读写操作时,可能需要权衡性能和设计选择。