写点什么

Dapr 简介 - 分布式应用运行时

作者:久歌
  • 2022-10-11
    浙江
  • 本文字数:8261 字

    阅读完需:约 27 分钟

Dapr简介-分布式应用运行时

Dapr 简介-分布式应用运行时

简介

What's Dapr?

Dapr = Distributed Application Runtime (分布式应用运行时)看到这个词,不知道大家想到了什么?是不是类似于 java runtime,c runtime 这类词汇。网上找到了一个 应用程序、运行时库和 OS 之间的关系图,其中 Runtime 库处于中间,屏蔽了应用程序至于 OS 的差异性。想想 JVM 是不是就是干这个事儿的,因为有了 JVM 所以才可以让 java 编译一次 anywhere 运行。



现在的情况是,有了一套应用系统,要运行起来,首先应用要做一些事:程序中配置依赖度 DB 库配置依赖的缓存,需指明 redis 还是 memcache 显示的调用 RPC 库,如 dubbo 等等显示的调用各种状态代码,各种 API 诸如此类....如果有一天,这些东西都不需要关注了,我们仅仅要做的事情就是调用统一的 API 编写业务逻辑,而忽略是调用 dubbo,还是 db,亦或是 cache api,然后把应用程序部署到一个机器上,其他都自动的有了会是什么场景~~


基于这样的一个思路,你可以想到 Dapr 所向往的就很宏大了:我们什么时候可以编写一套应用系统,可以忽略机器、操作系统、中间件、存储、状态等等技术的差异而可以 anywhere 运行。

Dapr 官方解释

先引用一下 Dapr 官方的解释:

Dapr 是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。


愿景是:Any Language, Any Framework, Any where 总的来说,Dapr 希望提供一系列通用的能力,来帮助使用任意语言、任意框架的开发者,能够轻松地构建出运行在上的分布式应用


其中最重要的核心是:借助 Dapr 让开发者只专注于业务应用程序的逻辑,而不再关注语言,框架,存储,中间件等等。听起来非常美好,那么 Dapr 是如何实现这一伟大愿景的呢?

Sidecar 架构

先回顾一下云原生发展历程中一个重要的里程碑 —— Service Mesh,它是为了治理分布式应用架构下,服务之间错综复杂的流量调用关系而产生的。ServiceMesh 最大的一个创新,是引入了 Sidecar 架构:



对于流量的鉴权、限流等一系列通用逻辑,服务网格将他们从应用中剥离出来,放到一个独立的进程之中,称之为 Sidecar,每个服务实例都有自己对应的 Sidecar,当他们需要与其他服务进行交互时,他们不是直接去调用对应的服务,而是将请求发送给自己的 Sidecar(有时候流量是被 Sidecar 自动拦截的,服务本身无感知),再由 Sidecar 之间互相通信,把流量转发给对应的服务。这么一来,一系列的通用流量治理逻辑,就都可以下沉到 Sidecar 进程之中,上层的应用无需感知这些内容,也不需要配合改造,通过对 Sidecar 下发命令,我们就可以对一个非常复杂的分布式服务系统进行各种治理。



Sidecar 架构的核心思想是** 将与业务无关的逻辑 抽离到独立的进程中,独立维护。服务网格使用这一思想将服务间调用这一业务无关的逻辑独立出来,目的是在上层应用尽可能无感的情况下实现流量治理。而 Sidecar 架构的作用不止于此,进一步发展,就演变成了实现 Serverless 理念的一种重要手段:将与业务无关的 中间件 能力抽离,让上层的业务研发可以专注于业务逻辑的实现(Only Focus on Business)**,这就是 Dapr:



Dapr 为分布式应用制定了一套标准的 API,涵盖了从服务间调用、状态储存、消息订阅等一系列基础能力,并且提供了 Sidecar 的能力。Dapr 整体是可插拔的设计,可以随意替换各种能力的实现,在强大的社区支撑下,各种常见的中间件能力都有涵盖:你可以随时将底层储存的实现从 MySQL 切换到 MongoDB,而不需要修改应用中的任何一行代码。不难看出,Dapr 整体的设计思路非常 Cloud Native,尤其是云原生发展到现在,很多的技术都是偏向运维侧的(比如 OAM,GitOPS 甚至是 K8S),而 Dapr 可能是第一个真正面向开发侧,解决开发侧问题的技术,作为开发同学,我们可以期待一下它的伟大愿景。

Dapr 的问题域

Dapr 面对的问题域是什么?

Announcing Distributed Application Runtime (Dapr), an open source project to make it easier for every developer to build microservice applications 可了解到,dapr 面对的问题域是 _如何开发可靠的无状态和有状态微服务应用_:

To enable all developers using any language and any framework to easily build portable microservices applications, whether writing new code or migrating existing code, we are excited to announce Announcing Distributed Application Runtime (Dapr).


  • 该问题域中包含如下核心问题:

  • 如何逐步迁移存量应用到微服务架构?

  • 如何提供语言无关的开发最佳实践?

  • 如何应用事件驱动架构?

  • 如何处理状态?

  • 如何做到可扩展?

  • 如何在易扩展的同时确保高性能?

  • etc.

Dapr 解决的问题是什么?

面对上述问题域,Dapr 并没有尝试解决所有问题,而是将重点放在 如何_提供语言无关的开发最佳实_践。这个解决问题的过程,一方面是将开发过程抽象化,将 存取状态、访问数据库_、_获取消息_、_处理消息 等转换为抽象的流程,以高度抽象的 API 呈现,一方面将通用的能力服务化,使得服务发现、服务访问、流控、日志、监控等通用能力通过独立的应用提供,通过 sidecar 的方式赋能业务开发。

即,Dapr 主要在两个维度解决问题:

  • 能力的实现

  • 能力的传递

Dapr 如何解决的?

能力的实现

在能力的实现方面,Dapr 针对微服务开发过程中的通用需求,提供了相应的实现,对应 Dapr 的 Components 概念 (link):

Service discovery

State

Pub/sub

Bindings

Middleware

Secret stores

Tracing exporters

能力的传递

在能力的传递方面,Dapr 通过 HTTP/gRPC/SDK 三种方式与开发语言进行交互,前两者可以做到语言无关,SDK 针对具体的语言提供了语言相关的调用。此类 API,被 Dapr 称为 Building Blocks。Dapr 内置的 Building Blocks 可通过该 link 查询到:



对于所有的 API Spec,可参考:DAPR API


Dapr 应用 运行时有 self-hosted 和 Kubernetes 两种模式:

self-hosted 模式下,dapr 应用由 用户应用进程daprd 进程 两部分构成。daprd 进程 提供外部访问接口,当外部有请求时,daprd 进程 调用 用户应用进程 进行响应,同时也被 用户应用进程 调用,提供如服务发现、中间件等能力 Kubernetes 模式同 self-hosted 模式,区别在于 dapr 应用是通过 Pod 方式呈现,用户应用dapr runtime 是 container 的形态。

开发者在部署的时候,可通过 Dapr 中的 Configurations 概念对 dapr runtime 进行配置。

综合起来,即:


Quick Start

快速上手

下面以官方的入门教程为例子,快速体验一下 dapr。此教程使用 self-hosted(自托管)模式运行 dapr,即在本地启动一个 daprd 进程,适合于绝大多数开发者的使用场景。


首先安装 dapr CLI 工具:

ShellOSX:curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bashLinux:wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bashPowershell:powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"
复制代码



安装完毕后执行 dapr 命令,可以看到 dapr 的 LOGO 和选项,说明安装成功:



使用 dapr init 命令初始化 dapr 环境,注意需要本地安装并启动 docker,执行完毕后,使用 docker ps 命令,你可以查看到以下三个正在运行的容器:


CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                  PORTS                              NAMES19667a857ab6        daprio/dapr         "./placement"            4 days ago          Up 15 hours             0.0.0.0:50005->50005/tcp           dapr_placementfb71cc6595c6        openzipkin/zipkin   "start-zipkin"           4 days ago          Up 15 hours (healthy)   9410/tcp, 0.0.0.0:9411->9411/tcp   dapr_zipkinb6790121afde        redis               "docker-entrypoint.s…"   4 days ago          Up 15 hours             0.0.0.0:6379->6379/tcp             dapr_redis
复制代码



其中 redis 提供默认的状态储存和事件通信能力,zipkin 用于提供分布式链路追踪。


接下来,我们可以使用 dapr run 命令,快速启动一个 dapr sidecar 实例,这一步需要指定一个 app id,用于唯一标记:


| dapr run --app-id myapp --dapr-http-port 3500


上述命令执行完毕后,我们将得到一个运行在 3500 端口的 dapr 进程,app id 为 myapp,我们可以使用 HTTP Restful API 与之进行交互,以最简单的 state 状态读写为例。


通过 HTTP API 调用 dapr 的 state store,向状态储存中写入一个 kv 对:


| curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "ddd"}]' http://localhost:3500/v1.0/state/statestore



写入成功后,仍然通过 HTTP API,我们可以读取对应的数据:


curl http://localhost:3500/v1.0/state/statestore/name

"ddd"



你可以使用一些工具来更加直观的查看 dapr 及应用的状态,使用 dapr dashboard 命令,可以在 8080 端口启动一个面板,能够看到一些简要的信息:


使用多语言 SDK

除了 HTTP API,Dapr 还提供了各种语言的 SDK,我们以目前比较常见的 Go 和 Java 为例来复现一下上面的例子。go 语言:


|

Gopackage mainimport (        "context"        "fmt"        dapr "github.com/dapr/go-sdk/client"        "log")
func main() { client, err := dapr.NewClientWithPort("3500"); if err != nil { log.Fatal("fail to create client, " + err.Error()) return } ctx := context.Background() data := []byte("haha") // write err = client.SaveState(ctx, "statestore", "testKey", data) if err != nil { log.Fatal("fail to save state, " + err.Error()) } // read item, err := client.GetState(ctx, "statestore", "testKey") if err != nil { log.Fatal("fail to get state, " + err.Error()) }
// print fmt.Printf("data [key:%s etag:%s]: %s", item.Key, item.Etag, string(item.Value))}
复制代码


golang 版本的 SDK 使用的是 grpc 协议,因此我们需要更换 dapr sidecar 的启动方式:


| dapr run --app-id myapp --dapr-grpc-port 3500



通过上面的命令启动 sidecar 后,再运行程序,就可以看到执行效果:


| dapr client initializing for: 127.0.0.1:3005



再来看一下 java 版本:

Javapublic class Main {
public static void main(String[] args) { DaprClient daprClient = (new DaprClientBuilder()) .withObjectSerializer(new DefaultObjectSerializer()) .withStateSerializer(new DefaultObjectSerializer()) .build(); String data = "hahahahahah"; Mono<Void> saveMono = daprClient.saveState("statestore", "key-haha", data); // dapr java sdk全部使用reactive方式 saveMono.block();
Mono<State<String>> readMono = daprClient.getState("statestore", "key-haha", String.class); State<String> state = readMono.block(); System.out.println(state.getValue()); }}
复制代码


java 的 sdk 启动时从环境变量 DAPR_GRPC_PORT 中获取 dapr sidecar 端口,配置为 3500 后运行结果如下:


| hahahahahah


构建块和组件

构建块

构建块(Building-block)是 Dapr 中最核心的概念,是对分布式应用能力的抽象,目前官方一共定义了 7 种构建块:



  • 服务间调用(service-to-service invocation):用于提供应用 RPC 功能

  • 状态管理(State management):用于为应用储存状态,支持一些有状态服务的持久化诉求

  • 发布与订阅(Publish and subscribe):用于实现消息通知

  • 资源绑定(Resource bindings and triggers):提供与外部 API 的双向连接,使应用可以调用外部 API,并且也可以被外部 API 调用

  • Actor:提供基于 Actor 模式的多线程管理和并发支持

  • 可观测性(Observability):记录日志、trace、metrics,为外部使用者提供可观测性

  • 密钥(Secrets):提供密钥储存能力,保证安全性


每一种构建块都代表了一种能力,通过 dapr 标准的 API 向应用提供。整个构建块体系是可插拔式的,你可以定义任意的构建块实现(称为 component,组件),通过 config 文件配置注册到系统中后就可以直接被使用。通过构建块的抽象,dapr 彻底将分布式应用的业务逻辑基础能力解耦开来,上层的业务开发可以专心于实现自己的业务逻辑,基础中间件的维护者则也可以专心于提供各种基础能力,这种思路和架构的出现,是 serverless 理念发展到一定程度的必然,我们可以大胆的猜测,未来面向云原生的架构分层,都会按照这个基本思想进行,而 sidecar 将会成为中间件能力交付的新标准。

组件和中间件

组件(component)是某一种构建块的具体实现,每个构建块下都可以有多个组件。在上面快速上手的例子中,我们使用 redis 定义了一个名为 statestore 的 state 组件,并注册到 app-id 为 myapp 的 dapr sidecar 中,那么,任何使用了该 sidecar 的应用,都可以通过/v1.0/state/statestore 所提供的 API 来使用 redis 能力。



中间件(middleware)是一种特殊的组件,它不应用于某一个特定的构建块,而是用于处理一些通用逻辑。你可以将中间件应用到任意一个构建块 API 上,应用后,所有访问该构建块的请求都会通过你所定义的中间件,你可以在中间件中处理登陆鉴权、CORS 等通用逻辑。


自定义一个组件

目前社区已经提供了非常多的构建块组件实现,基本涵盖了各种常见的开源中间件,如 redis、MySQL、kafka 等,这些组件都使用 GO 语言开发。我们可以使用这些开源的实现来定义组件,让我们以 MySQL 为实现定义一个状态储存实现。


编写一个组件的 yaml 定义文件,将组件命名为 mysqlstore,type 使用 state.mysql,通过连接串配置数据库连接,并且指定表名:

apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: mysqlstorespec:  type: state.mysql  version: v1  metadata:  - name: connectionString    value: "root:123456@tcp(127.0.0.1:3306)/?allowNativePasswords=true"  - name: tableName    value: "testStateStore"
复制代码

在 self-hosted 模式中,将该文件放置在~/.dapr/components 目录下,然后启动 dapr sidecar 即可:


| dapr run --app-id myapp --dapr-grpc-port 5001 --dapr-http-port 3500


依然使用最简单的 HTTP API 方式来测试:

# savecurl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne"}]' http://localhost:3500/v1.0/state/mysqlstore# readcurl http://localhost:3500/v1.0/state/mysqlstore/name"Bruce Wayne"
复制代码


在对应 MySQL 数据库的 dapr_state_store.testStateStore 表中,我们可以看到储存的数据:


+-------------+---------------+---------------------+---------------------+--------------------------------------+| id          | value         | insertDate          | updateDate          | eTag                                 |+-------------+---------------+---------------------+---------------------+--------------------------------------+| myapp||name | "ddd" | 2021-03-23 03:28:12 | 2021-03-23 03:28:12 | 539b3a90-f560-4a0a-8bad-a49672a5c391 |+-------------+---------------+---------------------+---------------------+--------------------------------------+
复制代码


部署方式

Dapr 目前提供两种部署方式:

self-hosted(自托管)

自托管模式适用于一些小规模场景,以及本地的开发调试。这种模式下 dapr 以一个本地进程提供服务,并和对应的服务部署在同一个实例上(容器或是物理机),我们上面的 quick start 就是采用这种模式:


k8s-hosted

适用于 k8s 集群,大规模的生产环境,在这种模式下,Dapr Sidecar 运行在一个独立的容器中,并和应用容器一起组成一个 POD:



在 K8S 模式中,Dapr 还提供了一系列管理控制平面的功能,包括 Dapr Sidecar 集群状态管理,Runtime Sidecar 注入,加密验证以及 Components 实现管理等。


Dapr 未来会怎么样

Dapr 会带来什么?

从短中期落地的角度看,Dapr 能够解决的问题:

多语言支持

中间件能力通过 Sidecar 架构标准化之后,就彻底和编程语言解耦了,上层的业务逻辑可以使用任意语言进行开发,这对于采用多语言架构的公司来说是一个非常好的消息,中间件团队也不需要费心去为每种语言提供实现和支持了。


业务研发的更多可能性

随着中间件、服务治理、监控剥离到 Sidecar 之后,上层的业务应用会变得越来越轻量,这有助于把一些场景迁移成 FaaS 等 Serverless 解决方案,并且实现更好的资源弹性伸缩。更近一步的,随着业务应用的服务化或者能力标准化,业务层开发可能会越来越趋向于 Lowercode,但是最终业务的复杂性可能决定了一切~


研发角色的再分化

如我们上面所说的,无论是 dapr 还是 serviceMesh,Sidecar 都将会成为中间件能力交付的新标准,而上层业务研发对这些基础能力的感知将会越来越弱,研发人员逐渐分化成“基础研发工程师”和“业务研发工程师”,正如 Serverless 理念所展示的那样,大部分研发人员的关注点将“Only Focus on Business”,从大局看,这会带来很多好处,比如研发效能的提升,但就业务研发工程师个体来说,他的可替代性变得更强,这对于广大从业者来说可能不是一个好消息。可以庆幸的是这应该还有一段时间要走。


云应用时代加速到来

随着中间件,存储等等的标准化并沉淀到 SideBar 之下,中小厂是不是还有必要自建机房、自建数据中心就变得可以商榷了,毕竟经过了这十几年云的快速发展,从业者们基本认同了上云已经成为必然,以前所关心的数据安全等问题已经逐渐消弭。同时云开发在一些大厂也已经在实践,相信很快就能见到成功的实践。


云厂商的新阶段

当所有的开发者都开始面向 Dapr 的标准进行应用开发时,应用和底层能力完全解耦,而所有云平台的产品都会需要适配 Dapr 的标准提供 API。举个例子,如果今天我的应用在阿里云上跑的不爽,那我随时可以把它迁移到腾讯云或者华为云上去:不需要改动任何一行代码。这将使各大云厂商之间的竞争进入到一个新的阶段,往大了说也许会改写整个云计算产业的格局。

Dapr 和 ServiceMesh 的区别是什么?


这是一个非常常见的问题,Dapr 和 Service Mesh 的区别是什么?两者都采用了 Sidecar 架构,并且功能上存在一定的重合。实际上两者确实是一个交集关系,但他们并不冲突。Service Mesh,以 Istio 为例,更多的关注点还是在基础设施层,服务的流量治理上,而 Dapr 更多关注的是上层应用。两者目前可以融合在一起使用。

目前 Dapr 发展到什么程度?

Dapr 2019 年由微软开源,2020 年阿里巴巴加入 Dapr 组织并成为第二大贡献者,目前整个项目主要由这两家公司主导。在阿里内部我曾看到已经有比较完善的组织在推进,并且尝试在一些应用中落地。


2021 年 2 月,Dapr 发布了第一个正式版本 v1.0,标志 Dapr 进入了生产可用阶段。目前主要还是微软和阿里两家公司内部在进行落地,但从社区的反馈情况来看,热度非常高,开源社区已经出现了大量的组件实现并且有了 AWS 和 Azure 的集成(估计阿里云的马上也会出现),未来几年 Dapr 很有可能会蓬勃发展。


Dapr 会成为标准码?其实我也不知道,如果 dapr 成为事实的标准后,很多云计算公司应该也会发生一些变化,比如所有开发者再也关注不到 docker,K8S 了,这些东西都被屏蔽掉了。现在是微软在主推,但也不排除哪天 google 再次搞出一个像 K8S 降维打击 Docker-Swarm 的事儿。中国互联网行业会不会推出更牛掰的东西,从近 10 几年互联网行业的基础设施、AI、架构等等轮子推陈出新的格局来看,中国互联网圈短期应该不会出现更牛的东西,风口跟上就很好了。

参考

https://blog.csdn.net/ysj1163620987/article/details/113904640dapr 官网Announcing Distributed Application Runtime (Dapr), an open source project to make it easier for every developer to build microservice applicationszipkin 官网dapr component typesGitHub: dapr/daprDapr Aims to Simplify the Creation of Resilient and Portable Microserviceswikipedia: Actor modelSidecar patternAmbassador patterndapr docs: Sequence of Events on a dapr run in Self Hosting Modedapr/docs: apiOrleans – Virtual Actorsdapr/docs: howto


更多内容见微信公众号:数字化农民工


发布于: 2022-10-11阅读数: 46
用户头像

久歌

关注

还未添加个人签名 2018-12-05 加入

还未添加个人简介

评论

发布
暂无评论
Dapr简介-分布式应用运行时_架构_久歌_InfoQ写作社区