Files
crawlab/documentation/Architecture/NodeCommunication.md
2019-12-05 12:06:38 +08:00

47 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 节点通信
这里的通信主要是指节点间的即时通信,即没有显著的延迟([爬虫部署](./SpiderDeployment.md)和[任务执行](./TaskExecution.md)是通过轮训来完成的,不在此列)。
通信主要由Redis来完成。以下为节点通信原理示意图。
![](https://crawlab.oss-cn-hangzhou.aliyuncs.com/v0.3.0/node-communication.png)
各个节点会通过Redis的`PubSub`功能来做相互通信。
所谓`PubSub`简单来说是一个发布订阅模式。订阅者Subscriber会在Redis上订阅Subscribe一个通道其他任何一个节点都可以作为发布者Publisher在该通道上发布Publish消息。
在Crawlab中主节点会订阅`nodes:master`通道,其他节点如果需要向主节点发送消息,只需要向`nodes:master`发布消息就可以了。同理,各工作节点会各自订阅一个属于自己的通道`nodes:<node_id>``node_id`是MongoDB里的节点ID是MongoDB ObjectId如果需要给工作节点发送消息只需要发布消息到该通道就可以了。
一个网络请求的简单过程如下:
1. 客户端前端应用发送请求给主节点API
2. 主节点通过Redis `PubSub``<nodes:<node_id>`通道发布消息给相应的工作节点;
3. 工作节点收到消息之后,执行一些操作,并将相应的消息通过`<nodes:master>`通道发布给主节点;
4. 主节点收到消息之后,将消息返回给客户端。
不是所有节点通信都是双向的也就是说主节点只会单方面对工作节点通信工作节点并不会返回响应给主节点所谓的单向通信。以下是Crawlab的通信类型。
操作名称 | 通信类别
--- | ---
获取日志 | 双向通信
获取系统信息 | 双向通信
取消任务 | 单向通信
通知工作节点向GridFS获取爬虫文件 | 单向通信
### `chan`和`goroutine`
如果您在阅读Crawlab源码会发现节点通信中有大量的`chan`语法这是Golang的一个并发特性。
`chan`表示为一个通道在Golang中分为无缓冲和有缓冲的通道我们用了无缓冲通道来阻塞协程只有当`chan`接收到信号(`chan <- "some signal"`),该阻塞才会释放,协程进行下一步操作)。在请求响应模式中,如果为双向通信,主节点收到请求后会起生成一个无缓冲通道来阻塞该请求,当收到来自工作节点的消息后,向该无缓冲通道赋值,阻塞释放,返回响应给客户端。
`go`命令会起一个`goroutine`(协程)来完成并发,配合`chan`,该协程可以利用无缓冲通道挂起,等待信号执行接下来的操作。任务取消就是`go`+`chan`来实现的。有兴趣的读者可以参考一下[源码](https://github.com/tikazyq/crawlab/blob/master/backend/services/task.go#L136)。
### Redis PubSub
这是Redis版发布订阅消息模式的一种实现。其用法非常简单
1. 订阅者利用`SUBSCRIBE channel1 channel2 ...`来订阅一个或多个频道;
2. 发布者利用`PUBLISH channelx message`来发布消息给该频道的订阅者。
Redis的`PubSub`可以用作广播模式即一个发布者对应多个订阅者。而在Crawlab中我们只有一个订阅者对应一个发布者的情况主节点->工作节点:`nodes:<node_id>`)或一个订阅者对应多个发布者的情况(工作节点->主节点:`nodes:master>`)。这是为了方便双向通信。
参考https://redis.io/topics/pubsub