4、集群架构:微服务架构拆解、消息队列选型(Kafka/RabbitMQ)、服务注册与发现

好,咱们进入第四章。这一章聊的是集群架构,说白了就是ThingsBoard怎么从单机跑成分布式。我见过不少团队,一开始图省事用单机部署,结果业务一上来就崩了。嗯,这里咱们得把微服务拆明白,把消息队列选对,再把服务发现搞定。

4.1 微服务架构拆解:从单体到分布式

ThingsBoard的微服务架构,我习惯把它拆成三层来看:

  • 接入层:负责设备连接,处理MQTT、HTTP、CoAP等协议。这一层是无状态的,可以随便横向扩展。
  • 业务层:处理规则引擎、告警、数据持久化等。这一层是有状态的,需要小心设计。
  • 存储层:包括Cassandra/PostgreSQL、Kafka、Redis等。这一层是瓶颈所在,得重点优化。

具体到ThingsBoard的微服务模块,我列个表给你看:

模块名称 职责 状态 扩展方式
tb-transport 设备协议接入 无状态 直接加实例
tb-rule-engine 规则链处理 有状态 分区扩展
tb-core 核心业务逻辑 有状态 分片扩展
tb-js-executor JS脚本执行 无状态 直接加实例
tb-web-ui 前端服务 无状态 直接加实例

我在项目中遇到过一个问题:tb-rule-engine实例数加多了,反而导致规则链处理变慢。为什么?因为每个实例都要从Kafka拉取全量数据,竞争太激烈了。后来我们按租户ID做了分区,每个实例只处理特定分区的数据,问题就解决了。

核心原则:无状态服务随便扩,有状态服务要分区。别一股脑加实例,得看瓶颈在哪。

4.2 消息队列选型:Kafka vs RabbitMQ

消息队列是微服务架构的血管。ThingsBoard官方推荐Kafka,但我见过不少团队硬上RabbitMQ,结果踩坑。咱们客观对比一下:

特性 Kafka RabbitMQ
吞吐量 百万级/秒 万级/秒
消息持久化 磁盘顺序写,性能高 内存+磁盘,有瓶颈
消息顺序 分区内严格有序 需要额外配置
消费模式 拉模式(Pull) 推模式(Push)
运维复杂度 较高,依赖ZooKeeper 较低,自带管理界面

我个人习惯是:设备数据量大的场景,无脑选Kafka。你想想看,一个物联网平台每天处理几亿条数据,RabbitMQ的推模式很容易把消费者打爆。Kafka的拉模式让消费者自己控制速度,这才是正经的背压机制。

但也不是说RabbitMQ不能用。我记得有个项目,设备量不大(几千台),但业务逻辑复杂,需要灵活的路由和延迟队列。这时候RabbitMQ的交换机模型就很好用。说白了,选型要看场景:

  • 高吞吐、日志型数据:Kafka
  • 复杂路由、低延迟:RabbitMQ
  • 两者都要:可以混用,Kafka做数据管道,RabbitMQ做业务消息

避坑指南:我曾经在Kafka的topic分区数上吃过亏。分区数太少,消费者组内竞争激烈;分区数太多,ZooKeeper压力大。经验值是:分区数 = 消费者实例数 × 2~3倍,留点余量。

4.3 服务注册与发现:Eureka vs Consul vs Nacos

微服务之间怎么找到对方?这就是服务注册与发现要解决的问题。ThingsBoard官方用的是Eureka,但我建议你根据实际情况选:

组件 CAP模型 健康检查 配置管理 社区活跃度
Eureka AP(可用性优先) 心跳机制 较低(Netflix维护)
Consul CP(一致性优先) 多种检查(HTTP/TCP/脚本) 有(Key-Value) 中等
Nacos AP+CP(动态切换) 心跳+主动探测 有(动态配置) 高(阿里维护)

我个人的建议是:新项目优先考虑Nacos。为什么?因为它把服务发现和配置管理合二为一了,少维护一个组件。而且它的健康检查机制比Eureka更可靠——Eureka只靠心跳,网络抖动时容易误判;Nacos还支持主动探测,更准确。

但如果你已经在用Spring Cloud全家桶,Eureka也是个稳妥的选择。我记得有个老项目,从Eureka迁移到Nacos,花了整整两周改配置。嗯,迁移成本得算进去。

小技巧:不管用哪个组件,一定要配置多数据中心。我见过一个案例,单数据中心挂了,整个集群都找不到服务了。至少两个数据中心,异地容灾。

4.4 实战配置示例

最后,给一个ThingsBoard微服务架构的典型配置。假设我们用Kafka做消息队列,Nacos做服务发现:

# tb-core.yml 核心服务配置
server:
  port: 8080

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.100:8848,192.168.1.101:8848
        namespace: tb-prod

kafka:
  bootstrap-servers: 192.168.1.200:9092,192.168.1.201:9092
  topics:
    telemetry: tb-telemetry
    rule-engine: tb-rule-chain
  consumer:
    group-id: tb-core-group
    auto-offset-reset: earliest

thingsboard:
  cache:
    type: redis
    redis:
      host: 192.168.1.300
      port: 6379
      cluster: true

这个配置里,我特别强调一下:Kafka的bootstrap-servers一定要配多个节点。我曾经只配了一个,结果那个节点挂了,整个集群都连不上Kafka。嗯,血的教训。

好了,这一章就到这里。下一章咱们聊聊数据存储的选型,Cassandra和PostgreSQL怎么选,什么时候用TimescaleDB。到时候见。