微软开源微服务运行时Dapr,赋能云原生应用开发
Dapr
是一个可移植的、由事件驱动的
Serverless
运行时,用于跨云和边缘构建分布式应用程序。
10
月
9
日,正式以
MIT
协议开源。
Dapr 使开发人员能够轻松地构建弹性、无状态和有状态的微服务,让它们在云和边缘位置上运行,并包含了开发语言和框架的多样性。
Dapr 将构建微服务应用程序的最佳实践编纂成开放、独立的构建基块,使您能够使用您选择的语言(已同时发布.NET、Java、JS、Go、Python的SDK)和框架构建可移植应用程序。每个构建基块都是独立的,您可以在应用程序中使用其中一个、部分或全部。
为什么
要用
Dapr
?
Dapr 在线程和状态一致性模型中是灵活的。如果愿意,则可以利用多线程,也可以选择不同的一致性模型。这种灵活性使得实现高级方案时没有人为的限制。您还可以选择使用其他 Actor 框架中熟悉的单线程调用。Dapr 是独一无二的,因为您可以在这些模型之间看似无问题地转换,而无需重写代码。
举例来说,在构建包含多项服务的电子商务应用程序时,大家可能希望使用有状态服务表示购物车功能,同时通过无状态服务实现付款与配送功能。编写这类应用程序往往需要使用多种语言、开发者框架以及基础设施平台,同时还必须与外部服务相集成。了解及管理如此复杂的技术栈需要占用大量时间与精力,导致开发人员无暇建立真正的商业价值。
而Dapr 的目标正是要简化各种基础设施的集成过程和对系统的侵入,解决开发人员构建微服务应用程序所面临的难题,让开发人员更加专注于业务的实现。
Dapr
:面向云端与边缘的微服务构建单元
Dapr是一套开源可移植事件驱动型运行时,能够帮助开发人员轻松构建起能够运行在云端及边缘位置的高弹性、微服务、无状态/有状态应用程序。Dapr当中包含多种编程语言与开发者框架,同时显著简化了应用程序(例如示例中提到的电子商务应用)的构建流程。
Dapr由一系列可通过标准HTTP或gRPC
API由任意编程语言调用的基础构建单元组成。这些构建单元为开发人员提供行之有效的行业最佳实践,且各个组件之间彼此独立,供您根据需求任意选用。此外,Dapr属于开源项目,因此欢迎技术社区为项目添加新的构建单元或者贡献新的组件。Dapr具有全面的平台中立性,大家可以在任意Kuberenetes以及与Dapr集成的其他托管环境当中实现应用程序的原生运行。如此一来,开发人员即可快速构建起无需变更代码即顺畅运行在云端及边缘位置上的微服务应用程序。
经由标准API调用Dapr构建单元,开发人员即可使用任意语言及框架构建应用程序
- 使开发人员能够使用任何语言或框架编写分布式应用程序
- 通过提供最佳实践构建块,解决开发人员构建微服务应用程序所面临的难题
- 成为社区驱动、开放和供应商中立者,寻找新的贡献者
-
通过开放式
API
提供一致性和可移植性 -
跨云和边缘
,
与平台无关 - 拥抱可扩展性,提供可插拔组件,无需供应商锁定
-
通过高性能、轻量功能实现
IoT
和边缘方案 - 从现有代码中增量采用,没有运行时依赖项
工作原理
Dapr 将 side-car 式的(Service Mesh中代指无侵入地扩展能力)容器/进程注入每个计算单元。通过标准 HTTP 或gRPC 协议,side-car 式地与事件触发器交互并与计算单元通信。这使 Dapr 能够支持所有现有甚至未来的编程语言,而无需您导入框架和库。
Dapr 通过标准HTTP 谓词或 gRPC 接口提供内置的状态管理、可靠的消息传递(至少一次传递)、触发器和绑定。这允许您按照相同的编程范例编写无状态、有状态和类似参与者的服务。您可以自由选择一致性模型、线程模型和消息传递模式。
Dapr 在Kubernetes 上原生地运行,作为独立的二进制文件在您的机器上、 IoT 设备上、或作为容器运行,而不是将二进制文件注入到任何系统、云中或本地。
Dapr 使用可插拔状态存储和消息总线(如 Redis 和 gRPC)来提供广泛的通信方法,包括使用 gRPC 直接dapr 对 dapr 方式和具有保证传递和至少一次语义的异步发布订阅(Pub-Sub)方式。
特征
-
事件驱动的
Pub-Sub
系统,
利用可
插拔
的组件
和
“
至少一次语
”
义
实现 -
具有
可插拔
组件的
输入和输出绑定 -
具有可插
拔
数据存储的状态管理 -
一致的服务到服务
(
service-to-servic
)的
发现和调用 -
可
选择
的
有状态模型:强
/
最终一致性
,或者
首次写入
/
最后写入获胜
方式 -
跨平台虚拟
Actor
(类似
Orleans
) -
具有流量
限制
功能 -
内置了使用开放式遥测
(
Open Telemetry
)进行
分布式跟踪 -
利用
专用
的
Operator
和
CRD
在
Kubernetes
上
原生
运行 -
通过
HTTP
和
gRPC
支持所有编程语言 -
支持混合云,适配
来自
Azure
、
AWS
、
GCP
的
各种
开放组件(绑定、
pub-sub
、状态) -
可
在任何地方运行
——以
进程或容器化
的方式 -
轻量(
58MB
二进制
文件
,
4MB
物理内存) -
作为
Side Car
运行
——
无需特殊的
SDK
或库 -
专用
CLI——
易于调试
,拥有
开发人员友好的体验 -
拥有
.NET
、
Java
、
Dotnet
、
Go
、
Java
脚本和
Python
的客户端
拥有可移植性与可扩展性的标准
API
那么,我们要如何使用这些Dapr构建单元?举例来说,假设大家正在使用一款已经部署在Kubernetes集群中的微服务应用程序内的Azure Functions运行时,且希望利用发布/订阅模式在不同服务之间传递消息,具体该怎样操作?目前,Azure Functions运行时尚不提供内置消息传递功能,但利用Dapr发布/订阅构建单元,大家完全可以经由http轻松实现这项新功能。领先一步,就这么简单!
此外,Dapr发布/订阅构建单元还提供一套可插拔组件模式,意味着大家可以动态选择不同的消息发送方式,且无需进行任何代码修改。举例来说,您可以根据喜好或需求随意选择Redis、Kafka或者Azure Service Bus作为Dapr发布/订阅组件。无论如何选择,您的代码都不会受到影响,消息收发机制本身可利用标准API在不同受支持基础设施之间直接移植。
为了同时实现可移植性以及与现有代码的轻松集成,Dapr通过http或gRPC提供标准API。与发布/订阅示例一样,以下节点代码所示为如何使用
http:///dapr/subscribe
端点订阅名称为“A”和“B”的主题,同时在这些主题收到新消息时向您的应用程序发出通知。
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); const port = 3000; app.get( '/dajgr/subscribe', (_req, res) => { res.json([ 'A', 'B' ]); }); app.post('/A', (req, res) => { console.log("A:", req.body); res.sendStatus(200); }); app.post('/B', (req, res) => { console.log("B:", req.body); res.sendStatus(200); }); app.listen(port, () => console.log('Node App listening on port ${port}!'))
作为比较,以下为使用UseStartup()处理程序从ASP.NET Core CreateWebHostBuilder() 处调用的C#代码。
using System.Collections.Generic; using System.Text.Json; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Dependencylnjection; using Microsoft.Extensions.Hosting; using System.IO; namespace DaprPubSub { public class Startup { // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseEndpoints(endpoints => { // Route called by Dapr runtime to get topics this app subscribes to. endpoints.MapGet("dagr/subscribe", async context => { // Returns list of topics to subscribe to as json in response. var topicsToSubscribe = new List() { "TopicA", "TopicB" >; await JsonSerializer.SerializeAsync(context.Response.Body, topicsToSubscribe); });
// Route to handle events published to TopicA endpoints.MapPost("A", async context => { // Read the event form request body. using (var streamReader = new StreamReader(context.Request.Body)) { var json = await streamReader.ReadToEndAsync(); Console.WriteLine("Received event for TopicA."); Console.WriteLine($"Event Data: {json}'); } }); // Route to handle events published to TopicB endpoints.MapPost("B", async context => { // Read the event form request body. using (var streamReader = new StreamReader(context.Request.Body)) { var json = await streamReader.ReadToEndAsync(); Console.WriteLine("Received event for TopicB."); Console.WriteLine($"Event Data: {json}"); } }); }); } } }
经由各个主题向已订阅服务发布事件,就像使用主题名称及载荷调用Dapr本地http发布API一样简单。以下节点代码示例即为如何利用Dapr发布API(本地端口3500)实现发布,当然大家也可以使用curl命令达成同样的效果:
curl -X POST http://localhost:3500/vl.0/publish/A \ -H "Content-Type: application/json" \ -d '{"status": "completed"}'
const express = require('express'’); const path = require('path'); const request = require('request'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); const port = 8080; const daprllrl = 'http://localhost:${process.env.DAPR_HTTP_PORT || 3500}/vl.0'; app.post('/publish', (req, res) => { console.log("Publishing: ", req.body); const publishUrl = '${daprUrl}/publish/${req.body.messageType}'; request( { uri: publishUrl, method: ’POST', json: req.body } ); res.sendStatus(200); }); app.listen(process.env.PORT || port, () => console.log('Listening on port ${port}!' 根据以上示例,在服务中使用Dapr并不涉及编译时间依赖性,只需要直接利用消息正文构建URL即可。
Sidecar
架构与受支持基础设施
Dapr将其API作为Sidecar架构以容器或者进程的形式公开,因此不需要在应用程序代码当中包含任何Dapr运行时代码。正因为如此,Dapr能够轻松与其他运行时相集成,同时通过应用程序逻辑分离显著提高了支持能力。
Dapr以side-car进程的形式运行
在Kubernetes等容器托管环境内,Dapr以side-car容器的形式运行在应用程序容器所在的Pod当中。
Dapr以side-car容器的形式运行在Kubernetes
Pod当中
Dapr的CLI使得上手体验更轻松,同时支持在开发者自有设备、任意Kubernetes集群(包括minikube),以及IoT Edge、Service Fabric等现有或即将推出的基础设施平台之上运行。要开始您的Dapr之旅,只需要运行:
dapr init
(for local deployment)
dapr init --kubernetes
(for Kubernetes deployment)
开发者语言
SDK
与框架
为了使Dapr对不同语言更自然,它还包括适用于Go、Java、JavaScript、.NET和Python的语言特定的SDK。
这些 SDK 通过类型化的语言 API 公开 Dapr 构建基块中的功能,例如保存状态、发布事件或创建 Actor,而不是调用 http/gRPC API。
这使开发人员能够用他们选择的语言编写无状态和有状态函数与 Actor
的组合。
由于这些 SDK 共享 Dapr 运行时,您甚至可以获得跨语言执行组件和函数支持!
此外,Dapr 还可以与任何开发框架集成。
例如,在 Dapr .NET SDK 中,您
会发现 ASP.NET Core 的集成
,它带来了有状态的路由控制器,可以响应来自其他服务的pub/sub事件,使ASP.NET Core 成为 更
好
的构建微服务 Web 应用程序的框架。
参考并翻译:
https://github.com/dapr/dapr/blob/master/README.md
https://cloudblogs.microsoft.com/opensource/2019/10/16/announcing-dapr-open-source-project-build-microservice-applications/
完。