Since ThingsBoard v2.2, the platform supports microservices deployment mode.
This article consist of high level diagram, description of data flow between various services and some architecture choices made.
Architecture diagram
Transport Microservices
ThingsBoard provides MQTT, HTTP and CoAP based APIs that are available for your device applications/firmware.
Each of the protocol APIs are provided by a separate server component and is part of ThingsBoard “Transport Layer”.
The full list of components and corresponding documentation pages are listed below:
HTTP Transport microservice provides device APIs described here;
MQTT Transport microservice provides device APIs described here
and also enables gateway APIs described here;
CoAP Transport microservice provides device APIs described here.
Each of the transport servers listed above communicates with the main ThingsBoard Node microservices using Kafka.
Apache Kafka is a distributed, reliable and scalable persistent message queue and streaming platform.
The messages that are sent to Kafka are serialized using protocol buffers
with the messages definition available here.
Note: Starting v2.5, ThingsBoard PE is going to support alternative queue implementation: Amazon DynamoDB. See roadmap for more details.
There are two main topics that are used by the transport layer microservices.
First topic “tb.transport.api.requests” is used to execute short-living API requests to check device credentials or create device on behalf of the gateway.
Responses to this requests are sent to the topic that is specific for each transport microservice. The prefix of such “callback” topic is “tb.transport.api.responses” by default.
Second topic “tb.rule-engine” is used to store all incoming telemetry messages from devices until they are not processed by the rule engine. In case the rule engine node(s) are down
, messages will be persisted and available for later processing.
You can see a part of configuration file to specify those properties below:
transport:type:"${TRANSPORT_TYPE:local}"# local or remoteremote:transport_api:requests_topic:"${TB_TRANSPORT_API_REQUEST_TOPIC:tb.transport.api.requests}"responses_topic:"${TB_TRANSPORT_API_RESPONSE_TOPIC:tb.transport.api.responses}"rule_engine:topic:"${TB_RULE_ENGINE_TOPIC:tb.rule-engine}"
Since ThingsBoard uses very simple communication protocol between transport and core services,
it is quite easy to implement support of custom transport protocol, for example: CSV over plain TCP, binary payloads over UDP, etc.
We suggest to review existing transports implementation to get started or contact us if you need any help.
Web UI Microservices
ThingsBoard provides a lightweight component written using Express.js framework to host static web ui content. Those components are completely stateless and no much configuration available.
JavaScript Executor Microservices
ThingsBoard rule engine allows users to specify custom javascript functions to parse, filter and transform messages.
Since those functions are user defined, we need to execute them in an isolated context to avoid impact on main processing.
ThingsBoard provides a lightweight component written using Node.js to execute user defined JavaScript functions remotely to isolate them from the core rule engine components.
Note: ThingsBoard monolith app executes user defined functions in a java embedded JS engine, which does not allow to isolate resource consumption.
We recommend to launch 20+ separate JavaScript Executors that will allow certain concurrency level and load balancing of JS execution requests.
Each microservice will subscribe to “js.eval.requests” kafka topic as part of single consumer group to enable load balancing.
Requests for the same script are forwarded to the same JS executor using built-in Kafka partitioning by key (key is a script/rule node id).
It is possible to define max amount of pending JS execution requests and max request timeout to avoid single JS execution blocking the JS exector microservice.
Each ThingsBoard core service has individual blacklist for JS functions and will not invoke blocked function more then 3(by default) times.
ThingsBoard Node
ThingsBoard node is a core service written in Java that is responsible for handling:
Note: moving rule engine to a separate microservice is scheduled for ThingsBoard v2.5. See roadmap for more details.
ThingsBoard node uses Actor System to implement tenant, device, rule chains and rule node actors.
Platform nodes can join the cluster, where each node is equal. Service discovery is done via Zookeeper.
ThingsBoard nodes route messages between each other using consistent hashing algorithm based on entity id.
So, messages for the same entity are processed on the same ThingsBoard node. Platform uses gRPC to send messages between ThingsBoard nodes.
Note: ThingsBoard authors consider moving from gRPC to Kafka in the future releases for exchanging messages between ThingsBoard nodes.
The main idea is to sacrifice small performance/latency penalties in favor of persistent and reliable message delivery and automatic load balancing provided by Kafka consumer groups.
Third-party
Kafka
Apache Kafka is an open-source stream-processing software platform. ThingsBoard uses Kafka to persist incoming telemetry from HTTP/MQTT/CoAP transpots
until it is processed by the rule engine. ThingsBoard also uses Kafka for some API calls between micro-services.
Redis
Redis is an open source (BSD licensed), in-memory data structure store used by ThingsBoard for caching.
ThingsBoard caches assets, entity views, devices, device credentials, device sessions and entity relations.
Zookeeper
Zookeeper is an open-source server which enables highly reliable distributed coordination.
ThingsBoard uses Zookeeper to address requests processing from a single entity (device,asset,tenant) to a certain ThingsBoard server
and guarantee that only one server process data from particular device at a single point in time.
Note: Zookeeper is also used by Kafka, so there was almost no reasons to use two different coordination services (Consul, etcd) in parallel.
HAProxy (or other LoadBalancer)
We recommend to use HAProxy for load balancing.
You can find the reference haproxy.cfg
configuration that corresponds to the architecture diagram below:
You can find the reference docker-compose.yml
and corresponding documentation that will help you to run ThingsBoard containers in a cluster mode
(although on a single host machine)