目录
Dapr 学习笔记 3 - Runtime
我感觉 runtime 应该是 dapr 的核心。从 runtime 的代码入手,我们可以更快的把握 dapr 的整体思路。
runtime 的初始化
说实话我感觉 dapr 的核心逻辑并不是特别复杂。初始化 runtime 无非就是读取 components 配置,然后根据配置初始化所有的组件。通过阅读 pkg/runtime/runtime.go
的 Run
函数,就可以验证我们的想法。Run
和 initRuntime
的主干如下:
1 | func (a *DaprRuntime) Run(opts ...Option) error { |
Registry - 工厂集合
Registry 为 component 提供了各种实现类型的注册。每一种 component 的每一个实现,都需要提供工厂方法。daprd
在创建 runtime 的时候,会将所有支持的 component 实现都以参数的形式传入。在上面描述的 initRuntime
方法中,又会把这些传入的实现注册到 registry 中。在我们处理 component 的时候,会根据配置中指定的类型,寻找对应的工厂方法并加以调用。下面,我们用 state store 为例子,看看具体的调用链路:
1 | // 在 initRuntime 中被调用,处理 pendingComponents |
Subscribing - 屏蔽消息实现
在 initRuntime
的最后,它调用了 startSubscribing
和 startReadingFromBindings
。这两个我个人觉得有点类似。binding 更多的是为了建立和外部(i.e. 不被 dapr 所管理)服务通讯通道,例如读或者写一个外部部署的 Kafka。如果这个 Kafka 已经包含在了 component 配置中,我们则应该使用 subscribing。
startSubscribing
主要做的事情就是遍历所有注册了的 pubsub
,对于每一个订阅的 topic,就启动一个 go routine。这个 go routine 会不断地将收到的消息通过 RPC 调用,转发给应用程序。应用程序只需要提供一个回调接口即可。这样设计的一个好处就是,应用程序完全不需要考虑底层的实现到底是 pull 还是 push 模式,dapr 会自动使用对应的模式获取消息进行转发。
总结
runtime 的结构非常简单。它的主要职责就是根据配置来创建各种 component,从而构建完整的运行时环境。