Dapr(**D**istributed Application Runtime)是一个开源、可移植、事件驱动的运行时。它使开发人员能够轻松地构建运行在云平台和边缘的弹性而微服务化的应用程序,无论是无状态还是有状态。Dapr 让开发人员能够专注于编写业务逻辑,而不是解决分布式系统的挑战,从而显著提高生产力并减少开发时间。此外,Dapr 也降低了大部分中小型企业基于微服务架构构建现代云原生应用的准入门槛。
Dapr 的核心构建模块如下:
- 服务调用: 弹性服务与服务之间(service-to-service)调用可以在远程服务上启用方法调用,包括重试,无论远程服务在受支持的托管环境中运行在何处。
- 状态管理:通过对键 / 值对的状态管理,可以很容易编写长时间运行、高可用性的有状态服务,以及同一个应用中的无状态服务。状态存储是可插入的,并且可以包括 Azure Cosmos 或 Redis,以及组件路线图上的其他组件,如 AWS DynamoDB 等。
- 在服务之间发布和订阅消息(Pub/Sub):使事件驱动的架构能够简化水平可扩展性,并使其具备故障恢复能力。
- 事件驱动的资源绑定:资源绑定和触发器在事件驱动的架构上进一步构建,通过从任何外部资源(如数据库、队列、文件系统、blob 存储、webhooks 等)接收和发送事件,从而实现可扩展性和弹性。例如,你的代码可以由 Azure EventHub 服务上的消息触发,并将数据写入 Azure CosmosDB。
- 虚拟角色:无状态和有状态对象的模式,通过方法和状态封装使并发变得简单。Dapr 在其虚拟角色(Virtual Actors)运行时提供了许多功能,包括并发、状态、角色激活 / 停用的生命周期管理以及用于唤醒角色的计时器和提醒。
- 服务之间的分布式跟踪:使用 W3C 跟踪上下文(W3C Trace Context)标准,轻松诊断和观察生产中的服务间调用,并将事件推送到跟踪和监视系统。
今天我们简单使用Dapr完成一个微服务的调用过程。
一 环境准备
1.1、安装Docker(windows10 必须开启默认Hyper-v)
我们准备一台Centos7.6虚拟机,docker安装比较简单,请看我另一篇文章Centos7.6安装 Docker CE
1.2、安装.NET Core SDK6.0
# 添加受信源
rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
# 安装.NET 6 SDK
yum install dotnet-sdk-6.0
详细安装步骤请看我的博文 Centos7.6安装最新的DotNet6开发环境
1.3、安装Dapr
1.3.1首先下载包文件
我们去 Dapr-CLI这个地址下载Dapr,目前最新版本是Dapr CLI v1.6.0,注意选择linux下amd64位的
wget -c https://github.com/dapr/cli/releases/download/v1.6.0/dapr_linux_amd64.tar.gz
1.3.2下载后解压
这里我们解压到 /usr/local/bin目录
tar xf /export/server/dapr_linux_amd64.tar.gz -C /usr/local/bin
解压前,只有一个sqlite3
解压后如下,注意dapr的执行权限,如果没有执行权限,需要添加 chmod x ./dapr
解压后,我们直接执行dapr,如下说明安装好了
1.3.3初始化Dapr
光安装好还不行,因为Dapr是基于Docker运行的,所以我们初始化一下Dapr
dapr init
这里因为我没有翻墙软件,所以下载包会失败,我是重试了好几次成功的,如果报错,可以实行卸载命令,再重新初始化
dapr uninstall
dapr init
检查初始化结果docker ps,有下面三个容器,证明dapr已经在运行了
二 测试接口
2.1新建webapi项目
这里建立2个api项目,一个学校api,一个专业api
接下来我们在2个项目里,用NuGet包管理器都引入Dapr.AspNetCore
我们测试的接口逻辑,是学校服务从专业服务调用专业列表数据
学校接口
专业接口,模拟5条专业信息
2.2 发布项目
发布前重要配置,我们在2个api项目的Program配置里增加把项目发布为Dapr识别的项目
builder.Services.AddControllers().AddDapr();
我们把2个api项目都发布
2.3 上传服务器
这里我用xftp,上传到dapr所在服务器
2.4 运行major微服务
我们cd到major微服务的发布根目录major_publish下,执行
dapr run --app-id MajorService --app-port 9910 --dapr-http-port 19910 -- dotnet MajorMis.Api.dll --urls "http://*:9910"
如下信息,证明启动成功了
[root@node2 bin]# cd /export/server/Net6/
You have new mail in /var/spool/mail/root
[root@node2 Net6]# ll
total 8
drwxr-xr-x 2 root root 4096 Mar 6 21:11 major_publish
drwxr-xr-x 2 root root 4096 Mar 6 21:12 school_publish
[root@node2 Net6]# cd major_publish/
[root@node2 major_publish]# dapr run --app-id MajorService --app-port 9910 --dapr-http-port 19910 -- dotnet MajorMis.Api.dll --urls "http://*:9910"
ℹ️ Starting Dapr with id MajorService. HTTP Port: 19910. gRPC Port: 40410
INFO[0003] starting Dapr Runtime -- version 1.6.0 -- commit 4bb25fab444c4f1a1bf0ffd74293dbd4fdcea580 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] log level set to: info app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] metrics server started on :44214/ app_id=MajorService instance=node2 scope=dapr.metrics type=log ver=1.6.0
INFO[0003] standalone mode configured app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] app id: MajorService app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] mTLS is disabled. Skipping certificate request and tls validation app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0004] local service entry announced: MajorService -> 192.168.88.101:43238 app_id=MajorService instance=node2 scope=dapr.contrib type=log ver=1.6.0
INFO[0004] Initialized name resolution to mdns app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0004] loading components app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] component loaded. name: pubsub, type: pubsub.redis/v1 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] waiting for all outstanding components to be processed app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] detected actor state store: statestore app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] component loaded. name: statestore, type: state.redis/v1 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] all outstanding components processed app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] enabled gRPC tracing middleware app_id=MajorService instance=node2 scope=dapr.runtime.grpc.api type=log ver=1.6.0
INFO[0008] enabled gRPC metrics middleware app_id=MajorService instance=node2 scope=dapr.runtime.grpc.api type=log ver=1.6.0
INFO[0008] API gRPC server is running on port 40410 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] enabled metrics http middleware app_id=MajorService instance=node2 scope=dapr.runtime.http type=log ver=1.6.0
INFO[0008] enabled tracing http middleware app_id=MajorService instance=node2 scope=dapr.runtime.http type=log ver=1.6.0
INFO[0008] http server is running on port 19910 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] The request body size parameter is: 4 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] enabled gRPC tracing middleware app_id=MajorService instance=node2 scope=dapr.runtime.grpc.internal type=log ver=1.6.0
INFO[0008] enabled gRPC metrics middleware app_id=MajorService instance=node2 scope=dapr.runtime.grpc.internal type=log ver=1.6.0
INFO[0008] internal gRPC server is running on port 43238 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0008] application protocol: http. waiting on port 9910. This will block until the app is listening on that port. app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0010] application discovered on port 9910 app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
== APP == info: Microsoft.Hosting.Lifetime[14]
== APP == Now listening on: http://[::]:9910
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Application started. Press Ctrl+C to shut down.
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Hosting environment: Production
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Content root path: /export/server/Net6/major_publish/
INFO[0010] application configuration loaded app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0010] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s app_id=MajorService instance=node2 scope=dapr.runtime.actor type=log ver=1.6.0
INFO[0010] dapr initialized. Status: Running. Init Elapsed 7042.741769ms app_id=MajorService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0011] placement tables updated, version: 0 app_id=MajorService instance=node2 scope=dapr.runtime.actor.internal.placement type=log ver=1.6.0
ℹ️ Updating metadata for app command: dotnet MajorMis.Api.dll --urls http://*:9910
✅ You're up and running! Both Dapr and your app logs will appear here.
我们访问浏览器,可以查到专业信息,这里有个坑注意:服务名(MajorService)区分大小写
http://192.168.88.101:19910/v1.0/invoke/MajorService/method/major
接下来,我们启动学校微服务,来调用专业微服务的这个列表数据,新开一个shell终端,cd到学校服务发布目录school_publish,终端执行:
dapr run --app-id SchoolService --app-port 9920 --dapr-http-port 19920 -- dotnet SchoolMis.Api.dll --urls "http://*:9920"
如下,看到输出You're up and running! Both Dapr and your app logs will appear here.则成功启动了
[root@node2 Net6]# cd school_publish/
[root@node2 school_publish]# dapr run --app-id SchoolService --app-port 9920 --dapr-http-port 19920 -- dotnet SchoolMis.Api.dll --urls "http://*:9920"
ℹ️ Starting Dapr with id SchoolService. HTTP Port: 19920. gRPC Port: 42086
INFO[0002] starting Dapr Runtime -- version 1.6.0 -- commit 4bb25fab444c4f1a1bf0ffd74293dbd4fdcea580 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] log level set to: info app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] metrics server started on :32846/ app_id=SchoolService instance=node2 scope=dapr.metrics type=log ver=1.6.0
INFO[0002] standalone mode configured app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] app id: SchoolService app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] mTLS is disabled. Skipping certificate request and tls validation app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] local service entry announced: SchoolService -> 192.168.88.101:37447 app_id=SchoolService instance=node2 scope=dapr.contrib type=log ver=1.6.0
INFO[0002] Initialized name resolution to mdns app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] loading components app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] component loaded. name: pubsub, type: pubsub.redis/v1 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] waiting for all outstanding components to be processed app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] detected actor state store: statestore app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] component loaded. name: statestore, type: state.redis/v1 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] all outstanding components processed app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] enabled gRPC tracing middleware app_id=SchoolService instance=node2 scope=dapr.runtime.grpc.api type=log ver=1.6.0
INFO[0002] enabled gRPC metrics middleware app_id=SchoolService instance=node2 scope=dapr.runtime.grpc.api type=log ver=1.6.0
INFO[0002] API gRPC server is running on port 42086 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] enabled metrics http middleware app_id=SchoolService instance=node2 scope=dapr.runtime.http type=log ver=1.6.0
INFO[0002] enabled tracing http middleware app_id=SchoolService instance=node2 scope=dapr.runtime.http type=log ver=1.6.0
INFO[0002] http server is running on port 19920 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] The request body size parameter is: 4 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] enabled gRPC tracing middleware app_id=SchoolService instance=node2 scope=dapr.runtime.grpc.internal type=log ver=1.6.0
INFO[0002] enabled gRPC metrics middleware app_id=SchoolService instance=node2 scope=dapr.runtime.grpc.internal type=log ver=1.6.0
INFO[0002] internal gRPC server is running on port 37447 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] application protocol: http. waiting on port 9920. This will block until the app is listening on that port. app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0002] application discovered on port 9920 app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
== APP == info: Microsoft.Hosting.Lifetime[14]
== APP == Now listening on: http://[::]:9920
ℹ️ Updating metadata for app command: dotnet SchoolMis.Api.dll --urls http://*:9920
✅ You're up and running! Both Dapr and your app logs will appear here.
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Application started. Press Ctrl+C to shut down.
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Hosting environment: Production
== APP == info: Microsoft.Hosting.Lifetime[0]
== APP == Content root path: /export/server/Net6/school_publish/
INFO[0003] application configuration loaded app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s app_id=SchoolService instance=node2 scope=dapr.runtime.actor type=log ver=1.6.0
INFO[0003] dapr initialized. Status: Running. Init Elapsed 1296.726341ms app_id=SchoolService instance=node2 scope=dapr.runtime type=log ver=1.6.0
INFO[0003] placement tables updated, version: 0 app_id=SchoolService instance=node2 scope=dapr.runtime.actor.internal.placement type=log ver=1.6.0
接下来,用学校服务调用专业微服务,我们请求学校服务的默认get接口,可以看到返回的专业列表json数据
http://192.168.88.101:19910/v1.0/invoke/SchoolService/method/school
注意学校服务get请求的代码,我们是通过daprclient调用的专业微服务
[HttpGet]
public async Task<IEnumerable<MajorInfo>> Get()
{
_logger.LogInformation("[开始] 从专业微服务查询专业信息");
// 远程调用商品微服务获取所有Sku信息
var majors = await _daprClient.InvokeMethodAsync<IEnumerable<MajorInfo>>
(HttpMethod.Get, "MajorService", "Major");
_logger.LogInformation($"[结束] 从专业微服务查询的信息为: {majors.ToArray()?.ToString()}");
return majors;
}
日志也能够证明
学校微服务日志打印如下
专业微服务日志打印如下
我们再执行命令dapr list,查看下dapr下运行的服务,可以看到2个微服务的信息
我们再访问Dapr启动的时候自带的Zipkin链路追踪 http://192.168.88.101:9411/,可以看到调用情况
查看服务依赖关系
今天的实战就到这里了,需要源码的朋友请关注我的公众号,后台回复【Dapr】,即可获取。
总结
感谢能看到这里的朋友😉
本次的分享就到这里,猫头鹰数据致力于为大家分享技术干货😎
如果以上过程中出现了任何的纰漏错误,烦请大佬们指正😅
受益的朋友或对技术感兴趣的伙伴记得点赞关注支持一波🙏
也可以扫描二维码或搜索关注我的微信公众号【猫头鹰数据分析】,留言交流🙏