Configure core MQTT broker settings
Important
Azure IoT Operations Preview – enabled by Azure Arc is currently in preview. You shouldn't use this preview software in production environments.
You'll need to deploy a new Azure IoT Operations installation when a generally available release is made available. You won't be able to upgrade a preview installation.
See the Supplemental Terms of Use for Microsoft Azure Previews for legal terms that apply to Azure features that are in beta, preview, or otherwise not yet released into general availability.
The Broker resource is the main resource that defines the overall settings for MQTT broker. It also determines the number and type of pods that run the Broker configuration, such as the frontends and the backends. You can also use the Broker resource to configure its memory profile. Self-healing mechanisms are built in to the broker and it can often automatically recover from component failures. For example, a node fails in a Kubernetes cluster configured for high availability.
You can horizontally scale the MQTT broker by adding more frontend replicas and backend chains. The frontend replicas are responsible for accepting MQTT connections from clients and forwarding them to the backend chains. The backend chains are responsible for storing and delivering messages to the clients. The frontend pods distribute message traffic across the backend pods, and the backend redundancy factor determines the number of data copies to provide resiliency against node failures in the cluster.
Configure scaling settings
Important
At this time, the Broker resource can only be configured at initial deployment time using the Azure CLI, Portal or GitHub Action. A new deployment is required if Broker configuration changes are needed.
To configure the scaling settings MQTT broker, you need to specify the mode
and cardinality
fields in the specification of the Broker custom resource. For more information on setting the mode and cardinality settings using Azure CLI, see az iot ops init.
The mode
field can be one of these values:
auto
: This value indicates that MQTT broker operator automatically deploys the appropriate number of pods based on the cluster hardware. The default value is auto and used for most scenarios.distributed
: This value indicates that you can manually specify the number of frontend pods and backend chains in thecardinality
field. This option gives you more control over the deployment, but requires more configuration.
The cardinality
field is a nested field that has these subfields:
frontend
: This subfield defines the settings for the frontend pods, such as:replicas
: The number of frontend pods to deploy. This subfield is required if themode
field is set todistributed
.workers
: The number of workers to deploy per frontend, currently it must be set to1
. This subfield is required if themode
field is set todistributed
.
backendChain
: This subfield defines the settings for the backend chains, such as:redundancyFactor
: The number of data copies in each backend chain. This subfield is required if themode
field is set todistributed
.partitions
: The number of partitions to deploy. This subfield is required if themode
field is set todistributed
.workers
: The number of workers to deploy per backend, currently it must be set to1
. This subfield is required if themode
field is set todistributed
.
Configure memory profile
Important
At this time, the Broker resource can only be configured at initial deployment time using the Azure CLI, Portal or GitHub Action. A new deployment is required if Broker configuration changes are needed.
To configure the memory profile settings MQTT broker, specify the memoryProfile
fields in the spec of the Broker custom resource. For more information on setting the memory profile setting using Azure CLI, see az iot ops init.
memoryProfile
: This subfield defines the settings for the memory profile. There are a few profiles for the memory usage you can choose:
Tiny
When using this profile:
- Maximum memory usage of each frontend replica is approximately 99 MiB but the actual maximum memory usage might be higher.
- Maximum memory usage of each backend replica is approximately 102 MiB but the actual maximum memory usage might be higher.
Recommendations when using this profile:
- Only one frontend should be used.
- Clients shouldn't send large packets. You should only send packets smaller than 4 MiB.
Low
When using this profile:
- Maximum memory usage of each frontend replica is approximately 387 MiB but the actual maximum memory usage might be higher.
- Maximum memory usage of each backend replica is approximately 390 MiB multiplied by the number of backend workers, but the actual maximum memory usage might be higher.
Recommendations when using this profile:
- Only one or two frontends should be used.
- Clients shouldn't send large packets. You should only send packets smaller than 10 MiB.
Medium
Medium is the default profile.
- Maximum memory usage of each frontend replica is approximately 1.9 GiB but the actual maximum memory usage might be higher.
- Maximum memory usage of each backend replica is approximately 1.5 GiB multiplied by the number of backend workers, but the actual maximum memory usage might be higher.
High
- Maximum memory usage of each frontend replica is approximately 4.9 GiB but the actual maximum memory usage might be higher.
- Maximum memory usage of each backend replica is approximately 5.8 GiB multiplied by the number of backend workers, but the actual maximum memory usage might be higher.
Default broker
By default, Azure IoT Operations Preview deploys a default Broker resource named broker
. It's deployed in the azure-iot-operations
namespace with cardinality and memory profile settings as configured during the initial deployment with Azure portal or Azure CLI. To see the settings, run the following command:
kubectl get broker broker -n azure-iot-operations -o yaml
Modify default broker by redeploying
Only cardinality and memory profile are configurable with Azure portal or Azure CLI during initial deployment. Other settings and can only be configured by modifying the YAML file and redeploying the broker.
To delete the default broker, run the following command:
kubectl delete broker broker -n azure-iot-operations
Then, create a YAML file with desired settings. For example, the following YAML file configures the broker with name broker
in namespace azure-iot-operations
with medium
memory profile and distributed
mode with two frontend replicas and two backend chains with two partitions and two workers each. Also, the encryption of internal traffic option is disabled.
apiVersion: mqttbroker.iotoperations.azure.com/v1beta1
kind: Broker
metadata:
name: broker
namespace: azure-iot-operations
spec:
memoryProfile: medium
mode: distributed
cardinality:
backendChain:
partitions: 2
redundancyFactor: 2
workers: 2
frontend:
replicas: 2
workers: 2
encryptInternalTraffic: false
Then, run the following command to deploy the broker:
kubectl apply -f <path-to-yaml-file>
Configure MQTT broker advanced settings
The following table lists the properties of the broker advanced settings that include client configurations, encryption of internal traffic, certificate rotation, and node tolerations.
Name | Type | Description |
---|---|---|
clients | ClientConfig | Configurations related to all clients |
clients.maxKeepAliveSeconds | integer |
Upper bound of a client's keep alive, in seconds |
clients.maxMessageExpirySeconds | integer |
Upper bound of message expiry interval, in seconds |
clients.maxReceiveMaximum | integer |
Upper bound of receive maximum that a client can request in the CONNECT packet |
clients.maxSessionExpirySeconds | integer |
Upper bound of session expiry interval, in seconds |
clients.subscriberQueueLimit | SubscriberQueueLimit |
The limit on the number of queued messages for a subscriber |
clients.subscriberQueueLimit.length | integer |
The maximum length of the queue before messages are dropped |
clients.subscriberQueueLimit.strategy | SubscriberMessageDropStrategy |
The strategy for dropping messages from the queue |
clients.subscriberQueueLimit.strategy.DropOldest | string |
The oldest message is dropped |
clients.subscriberQueueLimit.strategy.None | string |
Messages are never dropped |
encryptInternalTraffic | Encrypt | The setting to enable or disable encryption of internal traffic |
encryptInternalTraffic.Disabled | string |
Disable internal traffic encryption |
encryptInternalTraffic.Enabled | string |
Enable internal traffic encryption |
internalCerts | CertManagerCertOptions | Certificate rotation and private key configuration |
internalCerts.duration | string |
Lifetime of certificate. Must be specified using a Go time.Duration format (h, m, s). For example, 240h for 240 hours and 45m for 45 minutes. |
internalCerts.privateKey | CertManagerPrivateKey |
Configuration of certificate private key |
internalCerts.renewBefore | string |
Duration before renewing a certificate. Must be specified using a Go time.Duration format (h, m, s). For example, 240h for 240 hours and 45m for 45 minutes. |
internalCerts.privateKey.algorithm | PrivateKeyAlgorithm | Algorithm for private key |
internalCerts.privateKey.rotationPolicy | PrivateKeyRotationPolicy | Cert-manager private key rotation policy |
internalCerts.privateKey.algorithm.Ec256 | string |
Algorithm - EC256 |
internalCerts.privateKey.algorithm.Ec384 | string |
Algorithm - EC384 |
internalCerts.privateKey.algorithm.Ec521 | string |
Algorithm - EC521 |
internalCerts.privateKey.algorithm.Ed25519 | string |
Algorithm - Ed25519 |
internalCerts.privateKey.algorithm.Rsa2048 | string |
Algorithm - RSA2048 |
internalCerts.privateKey.algorithm.Rsa4096 | string |
Algorithm - RSA4096 |
internalCerts.privateKey.algorithm.Rsa8192 | string |
Algorithm - RSA8192 |
internalCerts.privateKey.rotationPolicy.Always | string |
Always rotate key |
internalCerts.privateKey.rotationPolicy.Never | string |
Never rotate key |
tolerations | NodeTolerations | The details of tolerations that are applied to all Broker pods |
tolerations.effect | string |
Toleration effect |
tolerations.key | string |
Toleration key |
tolerations.operator | TolerationOperator |
Toleration operator. For example, "Exists" or "Equal". |
tolerations.value | string |
Toleration value |
tolerations.operator.Equal | string |
Equal operator |
tolerations.operator.Exists | string |
Exists operator |
Here's an example of a Broker with advanced settings:
apiVersion: mqttbroker.iotoperations.azure.com/v1beta1
kind: Broker
metadata:
name: broker
namespace: azure-iot-operations
spec:
advanced:
clients:
maxSessionExpirySeconds: 282277
maxMessageExpirySeconds: 1622
subscriberQueueLimit:
length: 1000
strategy: DropOldest
maxReceiveMaximum: 15000
maxKeepAliveSeconds: 300
encryptInternalTraffic: Enabled
internalCerts:
duration: 240h
renewBefore: 45m
privateKey:
algorithm: Rsa2048
rotationPolicy: Always
tolerations:
effect: string
key: string
operator: Equal
value: string
Configure MQTT broker diagnostic settings
Diagnostic settings allow you to enable metrics and tracing for MQTT broker.
- Metrics provide information about the resource utilization and throughput of MQTT broker.
- Tracing provides detailed information about the requests and responses handled by MQTT broker.
To override default diagnostic settings for MQTT broker, update the spec.diagnostics
section in the Broker resource. Adjust the log level to control the amount and detail of information that is logged. The log level can be set for different components of MQTT broker. The default log level is info
.
You can configure diagnostics using the Broker custom resource definition (CRD). The following table shows the properties of the broker diagnostic settings and all default values.
Name | Format | Default | Description |
---|---|---|---|
logs.exportIntervalSeconds | integer | 30 | How often to export the logs to the open telemetry collector |
logs.exportLogLevel | string | error | The level of logs to export |
logs.level | string | info | The log level. For example, debug , info , warn , error , trace |
logs.openTelemetryCollectorAddress | string | The open telemetry collector endpoint where to export | |
metrics.exportIntervalSeconds | integer | 30 | How often to export the metrics to the open telemetry collector |
metrics.mode | MetricsEnabled | Enabled | The toggle to enable/disable metrics. |
metrics.openTelemetryCollectorAddress | string | The open telemetry collector endpoint where to export | |
metrics.prometheusPort | integer | 9600 | The prometheus port to expose the metrics |
metrics.stalenessTimeSeconds | integer | 600 | The time used to determine if a metric is stale and drop from the metrics cache |
metrics.updateIntervalSeconds | integer | 30 | How often to refresh the metrics |
selfcheck.intervalSeconds | integer | 30 | The self check interval |
selfcheck.mode | SelfCheckMode | Enabled | The toggle to enable/disable self check |
selfcheck.timeoutSeconds | integer | 15 | The timeout for self check |
traces.cacheSizeMegabytes | integer | 16 | The cache size in megabytes |
traces.exportIntervalSeconds | integer | 30 | How often to export the metrics to the open telemetry collector |
traces.mode | TracesMode | Enabled | The toggle to enable/disable traces |
traces.openTelemetryCollectorAddress | string | The open telemetry collector endpoint where to export | |
traces.selfTracing | SelfTracing | The self tracing properties | |
traces.spanChannelCapacity | integer | 1000 | The span channel capacity |
Here's an example of a Broker custom resource with metrics and tracing enabled and self-check disabled:
apiVersion: mqttbroker.iotoperations.azure.com/v1beta1
kind: Broker
metadata:
name: broker
namespace: azure-iot-operations
spec:
mode: auto
diagnostics:
logs:
exportIntervalSeconds: 220
exportLogLevel: nym
level: debug
openTelemetryCollectorAddress: acfqqatmodusdbzgomgcrtulvjy
metrics:
stalenessTimeSeconds: 463
mode: Enabled
exportIntervalSeconds: 246
openTelemetryCollectorAddress: vyasdzsemxfckcorfbfx
prometheusPort: 60607
updateIntervalSeconds: 15
selfCheck:
mode: Enabled
intervalSeconds: 106
timeoutSeconds: 70
traces:
cacheSizeMegabytes: 97
mode: Enabled
exportIntervalSeconds: 114
openTelemetryCollectorAddress: oyujxiemzlqlcsdamytj
selfTracing:
mode: Enabled
intervalSeconds: 179
spanChannelCapacity: 47152
Configure encryption of internal traffic
Important
At this time, this feature can't be configured using the Azure CLI or Azure portal during initial deployment. To modify this setting, you need to modify the YAML file and redeploy the broker.
The encryptInternalTraffic feature is used to encrypt the internal traffic between the frontend and backend pods. To use this feature, cert-manager must be installed in the cluster, which is installed by default when using the Azure IoT Operations.
The benefits include:
Secure internal traffic: All internal traffic between the frontend and backend pods is encrypted.
Secure data at rest: All data at rest is encrypted.
Secure data in transit: All data in transit is encrypted.
Secure data in memory: All data in memory is encrypted.
Secure data in the message buffer: All data in the message buffer is encrypted.
Secure data in the message buffer on disk: All data in the message buffer on disk is encrypted.
By default, the encryptInternalTraffic feature is enabled. To disable the feature, set the encryptInternalTraffic
field to false
in the spec of the Broker custom resource when redeploying the broker.
Configure disk-backed message buffer behavior
Important
At this time, this feature can't be configured using the Azure CLI or Azure portal during initial deployment. To modify this setting, you need to modify the YAML file and redeploy the broker.
The diskBackedMessageBufferSettings feature is used for efficient management of message queues within the MQTT broker distributed MQTT broker. The benefits include:
Efficient queue management: In an MQTT broker, each subscriber is associated with a message queue. The speed a subscriber processes messages directly impacts the size of the queue. If a subscriber processes messages slowly or if they disconnect but request an MQTT persistent session, the queue can grow larger than the available memory.
Data preservation for persistent sessions: The diskBackedMessageBufferSettings feature ensures that when a queue exceeds the available memory, it's seamlessly buffered to disk. This feature prevents data loss and supports MQTT persistent sessions, allowing subscribers to resume their sessions with their message queues intact upon reconnection. The disk is used as ephemeral storage and serves as a spillover from memory. Data written to disk isn't durable and is lost when the pod exits, but as long as at least one pod in each backend chain remains functional, the broker as a whole doesn't lose any data.
Handling connectivity challenges: Cloud connectors are treated as subscribers with persistent sessions that can face connectivity challenges when unable to communicate with external systems like Event Grid MQTT broker due to network disconnect. In such scenarios, messages (PUBLISHes) accumulate. The MQTT broker intelligently buffers these messages to memory or disk until connectivity is restored, ensuring message integrity.
Understanding and configuring the diskBackedMessageBufferSettings feature maintains a robust and reliable message queuing system. Proper configuration is important in scenarios where message processing speed and connectivity are critical factors.
Configuration options
Tailor the broker message buffer options by adjusting the following settings:
Configure the volume: Specify a persistent volume claim template to mount a dedicated storage volume for your message buffer.
Select a storage class: Define the desired StorageClass using the
storageClassName
property.Define access modes: Determine the access modes you need for your volume. For more information, see persistent volume access modes.
Use the following sections to understand the different volume modes.
Ephemeral volume is the preferred option. Persistent volume is preferred next then emptyDir volume. Both persistent volume and ephemeral volume are generally provided by the same storage classes. If you have both options, choose ephemeral. However, ephemeral requires Kubernetes 1.23 or higher.
Disabled
If you don't want to use the disk-backed message buffer, don't include the diskBackedMessageBufferSettings
property in your Broker CRD.
Ephemeral volume
Ephemeral volume is the preferred option for your message buffer.
For ephemeral volume, follow the advice in the Considerations for storage providers section.
The value of the ephemeralVolumeClaimSpec property is used as the ephemeral.volumeClaimTemplate.spec property of the volume in the StatefulSet specs of the backend chains.
For example, to use an ephemeral volume with a capacity of 1 gigabyte, specify the following parameters in your Broker CRD:
diskBackedMessageBufferSettings:
maxSize: "1G"
ephemeralVolumeClaimSpec:
storageClassName: "foo"
accessModes:
- "ReadWriteOnce"
Persistent volume
Persistent volume is the next preferred option for your message buffer after ephemeral volume.
For persistent volume, follow the advice in Considerations for storage providers section.
The value of the persistentVolumeClaimSpec property is used as the volumeClaimTemplates.spec property of the StatefulSet specs of the backend chains.
For example, to use a persistent volume with a capacity of 1 gigabyte, specify the following parameters in your Broker CRD:
diskBackedMessageBufferSettings:
maxSize: "1G"
persistentVolumeClaimSpec:
storageClassName: "foo"
accessModes:
- "ReadWriteOnce"
emptyDir volume
Use an emptyDir volume. An emptyDir volume is the next preferred option after persistent volume.
Only use emptyDir volume when using a cluster with filesystem quotas. For more information, see details in the Filesystem project quota tab. If the feature isn't enabled, the cluster does periodic scanning that doesn't enforce any limit and allows the host node to fill disk space and mark the whole host node as unhealthy.
For example, to use an emptyDir volume with a capacity of 1 gigabyte, specify the following parameters in your Broker CRD:
diskBackedMessageBufferSettings:
maxSize: "1G"
Considerations for storage providers
Consider the behavior of your chosen storage provider. For example, when using providers like rancher.io/local-path
. If the provider doesn't support limits, filling up the volume consumes the node's disk space. This could lead to Kubernetes marking the node and all associated pods as unhealthy. It's crucial to understand how your storage provider behaves in such scenarios.
Persistence
It's important to understand that the diskBackedMessageBufferSettings feature isn't synonymous with persistence. In this context, persistence refers to data that survives across pod restarts. However, this feature provides temporary storage space for data to be saved to disk, preventing memory overflows and data loss during pod restarts.