逻辑图解
上图来自Dapr
官网教程,其中Checkout
是一个服务,负责生成订单号, Order Processor
是另一个服务,负责处理订单。Checkout
服务需要调用Order Processor的API
, 让Order Processor
获取到其生成的订单号并进行处理。
本地测试(Self-Hosted)
按照官网教程进行实验的过程中,用python的代码测试,发现Order Processor
没有任何的输出信息。 改用golang
的代码测试, 发现Order Processor
依然没有任何的输出, 但是checkout
服务出现以下错误:
== APP == Order passed: {"errorCode":"ERR_DIRECT_INVOKE","message":"fail to invoke, id: order-processor, err: timeout waiting for address for app id order-processor"}
表明没有解析到请求的app id(oder-processor)
. 教程中并没有其他说明,但是观察上图,Service Invokation
的图解告诉我们, dapr
进行服务调用时, 需要Name resolution component
, 本地模式中, dapr
默认会使用mDNS
进行域名解析, 这个错误表明mDNS
解析失败。
查阅域名解析相关文档, 替代方案可以是在本地部署consul, 作为域名解析的组件。在dapr
的配置文件~/.dapr/config.yaml
中添加consul
组件(以下代码中的最后4行)
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: daprConfig
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: http://localhost:9411/api/v2/spans
nameResolution:
component: "consul"
configuration:
selfRegister: true
重新安装dapr环境:
dapr uninstall
dapr init
注意,此处只是将consul
注册为dapr
的一个组件,但consul
的示例还需要我们自己创建, 此时,我们还没有创建consul
的实例, 如果此时运行checkout
的代码,则会报错:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x10536808c]
goroutine 119 [running]:
github.com/dapr/dapr/pkg/messaging.(*directMessaging).getRemoteApp(0x14000ada600, {0x140003d78e0?, 0x0?})
/Users/runner/work/dapr/dapr/pkg/messaging/direct_messaging.go:309 +0x7c
github.com/dapr/dapr/pkg/messaging.(*directMessaging).Invoke(0x14000ada600, {0x10700d988, 0x1400034b800}, {0x140003d78e0?, 0x14000c41538?}, 0x102354dc0?)
/Users/runner/work/dapr/dapr/pkg/messaging/direct_messaging.go:126 +0x3c
github.com/dapr/dapr/pkg/http.(*api).onDirectMessage.func1({0x10700d988?, 0x1400034b800?})
/Users/runner/work/dapr/dapr/pkg/http/api.go:1390 +0x88
github.com/dapr/dapr/pkg/resiliency.(*NoOp).EndpointPolicy.func1(0x1053e137c?)
/Users/runner/work/dapr/dapr/pkg/resiliency/noop.go:36 +0x30
github.com/dapr/dapr/pkg/http.(*api).onDirectMessage(0x1400053a300, 0x1400034b800)
/Users/runner/work/dapr/dapr/pkg/http/api.go:1389 +0x598
github.com/fasthttp/router.(*Router).Handler(0x14000b4f5e0, 0x1400034b800)
/Users/runner/go/pkg/mod/github.com/fasthttp/router@v1.4.12/router.go:427 +0x7f0
github.com/dapr/dapr/pkg/diagnostics.(*httpMetrics).FastHTTPMiddleware.func1(0x1400034b800)
/Users/runner/work/dapr/dapr/pkg/diagnostics/http_monitoring.go:227 +0x104
github.com/dapr/dapr/pkg/diagnostics.HTTPTraceMiddleware.func1(0x1400034b800)
apiVersion: dapr.io/v1alpha1
/Users/runner/work/dapr/dapr/pkg/diagnostics/http_tracing.go:56 +0x138
github.com/valyala/fasthttp.(*Server).serveConn(0x14000e7e900, {0x1070211f0?, 0x140005a31f0})
/Users/runner/go/pkg/mod/github.com/valyala/fasthttp@v1.40.0/server.go:2311 +0xde4
github.com/valyala/fasthttp.(*workerPool).workerFunc(0x140005d15e0, 0x140004ea320)
/Users/runner/go/pkg/mod/github.com/valyala/fasthttp@v1.40.0/workerpool.go:224 +0x70
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
/Users/runner/go/pkg/mod/github.com/valyala/fasthttp@v1.40.0/workerpool.go:196 +0x38
created by github.com/valyala/fasthttp.(*workerPool).getCh
/Users/runner/go/pkg/mod/github.com/valyala/fasthttp@v1.40.0/workerpool.go:195 +0x220
❌ The daprd process exited with error code: exit status 2
ℹ️
terminated signal received: shutting down
❌ Error exiting Dapr: exit status 2
✅ Exited App successfully
如上, 即使我们运行的是python
版本的测试代码, 报错仍然是golang
的panic
, 这是因为这个异常是dapr
抛出的,而不是app
的代码抛出的, 原因是连接不上dapr
注册的nameResolution
组件。
用下面的命令启动一个consul
容器:
docker run -d --name=dev-consul -e CONSUL_BIND_INTERFACE=eth0 consul
再运行教程中的代码,则可以得到正确的结果了。
k8s中的名字解析
上面一节解释了在本地测试时, dapr
是如何通过app id
找到相应的应用。在k8s
集群中, dapr
默认会使用k8s
集群的DNS
进行域名解析。那么在k8s
中, dapr
具体是怎么使用DNS
的呢?
在官网教程中, 创建了两个应用,分别是nodeapp
和pythonapp
, 他们的yaml
文件中,分别定义了各自的dapr.io/app-id
, 分别是nodeapp
和pythonapp
, 在部署了这两个应用后,我们会发现多了两个k8s service
: nodeapp-dapr
和pythonapp-dapr
➜ checkout git:(master) ✗ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 3d14h
nodeapp LoadBalancer 10.0.253.82 52.188.179.178 80:30807/TCP 75m
nodeapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 75m
pythonapp-dapr ClusterIP None <none> 80/TCP,50001/TCP,50002/TCP,9090/TCP 8m40s
redis-headless ClusterIP None <none> 6379/TCP 86m
redis-master ClusterIP 10.0.244.122 <none> 6379/TCP 86m
redis-replicas ClusterIP 10.0.141.54 <none> 6379/TCP 86m
由此可知, k8s
会识别dapr.io/app-id
, 并根据其值x
, 创建一个名为x-dapr
的service
,则可以以解析service
域名同样的方式,对dapr
的app id
进行解析了。