|
| 1 | +.. _cluster_backend_zeromq: |
| 2 | + |
| 3 | +====================== |
| 4 | +ZeroMQ Cluster Backend |
| 5 | +====================== |
| 6 | + |
| 7 | +.. versionadded:: 7.1 |
| 8 | + |
| 9 | +*Experimental* |
| 10 | + |
| 11 | +Quickstart |
| 12 | +========== |
| 13 | + |
| 14 | +To switch a Zeek cluster with a static cluster layout over to use ZeroMQ |
| 15 | +as cluster backend, add the following snippet to ``local.zeek``: |
| 16 | + |
| 17 | +.. code-block:: zeek |
| 18 | +
|
| 19 | + @load frameworks/cluster/backend/zeromq/connect |
| 20 | +
|
| 21 | +
|
| 22 | +Note that the function :zeek:see:`Broker::publish` will be non-functional |
| 23 | +and a warning emitted when used - use :zeek:see:`Cluster::publish` instead. |
| 24 | + |
| 25 | +By default, a configuration based on hard-coded endpoints and cluster layout |
| 26 | +information is created. For more customization, refer to the module documentation |
| 27 | +at :doc:`cluster/backend/zeromq/main.zeek </scripts/policy/frameworks/cluster/backend/zeromq/main.zeek>`. |
| 28 | + |
| 29 | + |
| 30 | +Architecture |
| 31 | +============ |
| 32 | + |
| 33 | +Publish-Subscribe of Zeek Events |
| 34 | +-------------------------------- |
| 35 | + |
| 36 | +The `ZeroMQ <https://zeromq.org/>`_ based cluster backend uses a central |
| 37 | +XPUB/XSUB broker for publish-subscribe functionality. Zeek events published |
| 38 | +via :zeek:see:`Cluster::publish` are distributed by this central broker to |
| 39 | +interested nodes. |
| 40 | + |
| 41 | +.. figure:: /images/cluster/zeromq-pubsub.png |
| 42 | + |
| 43 | + |
| 44 | +As depicted in the figure above, each cluster node connects to the central |
| 45 | +broker twice, once via its XPUB socket and once via its XSUB socket. This |
| 46 | +results in two TCP connections from every cluster node to the central broker. |
| 47 | +This setup allows every node in the cluster to see messages from all other |
| 48 | +nodes, avoiding the need for cluster topology awareness. |
| 49 | + |
| 50 | +.. note:: |
| 51 | + |
| 52 | + Scalability of the central broker in production setups, but for small |
| 53 | + clusters on a single node, may be fast enough. |
| 54 | + |
| 55 | +On a cluster node, the XPUB socket provides notifications about subscriptions |
| 56 | +created by other nodes: For every subscription created by any node in |
| 57 | +the cluster, the :zeek:see:`Cluster::Backend::ZeroMQ::subscription` event is |
| 58 | +raised locally on every other node (unless another node had created the same |
| 59 | +subscription previously). |
| 60 | + |
| 61 | +This mechanism is used to discover the existence of other cluster nodes by |
| 62 | +matching the topics with the prefix for node specific subscriptions as produced |
| 63 | +by :zeek:see:`Cluster::nodeid_topic`. |
| 64 | + |
| 65 | +As of now, the implementation of the central broker calls ZeroMQ's |
| 66 | +``zmq::proxy()`` function to forward messages between the XPUB and |
| 67 | +XSUB socket. |
| 68 | + |
| 69 | +While the diagram above indicates the central broker being deployed separately |
| 70 | +from Zeek cluster nodes, by default the manager node will start and run this |
| 71 | +broker using a separate thread. There's nothing that would prevent from running |
| 72 | +a long running central broker independently from the Zeek cluster nodes, however. |
| 73 | + |
| 74 | +The serialization of Zeek events is done by the selected |
| 75 | +:zeek:see:`Cluster::event_serializer` and is independent of ZeroMQ. |
| 76 | +The central broker needs no knowledge about the chosen format, it is |
| 77 | +only shuffling messages between nodes. |
| 78 | + |
| 79 | + |
| 80 | +Logging |
| 81 | +------- |
| 82 | + |
| 83 | +While remote events always pass through the central broker, nodes connect and |
| 84 | +send log writes directly to logger nodes in a cluster. The ZeroMQ cluster backend |
| 85 | +leverages ZeroMQ's pipeline pattern for this functionality. That is, logger nodes |
| 86 | +(including the manager if configured using :zeek:see:`Cluster::manager_is_logger`) |
| 87 | +open a ZeroMQ PULL socket to receive log writes. All other nodes connect their |
| 88 | +PUSH socket to all available PULL sockets. These connections are separate from |
| 89 | +the publish-subscribe setup outlined above. |
| 90 | + |
| 91 | +When sending log-writes over a PUSH socket, load balancing is done by ZeroMQ. |
| 92 | +Individual cluster nodes do not have control over the decision which logger |
| 93 | +node receives log writes at any given time. |
| 94 | + |
| 95 | +.. figure:: /images/cluster/zeromq-logging.png |
| 96 | + |
| 97 | +While the previous paragraph used "log writes", a single message to a logger |
| 98 | +node actually contains a batch of log writes. The options :zeek:see:`Log::flush_interval` |
| 99 | +and :zeek:see:`Log::write_buffer_size` control the frequency and maximum size |
| 100 | +of these batches. |
| 101 | + |
| 102 | +The serialization format used to encode such batches is controlled by the |
| 103 | +selected :zeek:see:`Cluster::log_serializer` and is independent of ZeroMQ. |
| 104 | + |
| 105 | +With the default serializer (:zeek:see:`Cluster::LOG_SERIALIZER_ZEEK_BIN_V1`), |
| 106 | +every log batch on the wire has a header prepended that describes it. This allows |
| 107 | +interpretation of log writes even by non-Zeek processes. This opens the possibility |
| 108 | +to implement non-Zeek logger processes as long as the chosen serializer format |
| 109 | +is understood by the receiving process. In the future, a JSON lines serialization |
| 110 | +may be provided, allowing easier interpretation than a proprietary binary format. |
| 111 | + |
| 112 | + |
| 113 | +Summary |
| 114 | +------- |
| 115 | + |
| 116 | +Combining the diagrams above, the connections between the different socket |
| 117 | +types in a Zeek cluster looks something like the following. |
| 118 | + |
| 119 | +.. figure:: /images/cluster/zeromq-cluster.png |
| 120 | + |
0 commit comments