Clustering
Multiple instances ofgnmic
can be run in clustered mode in order to load share the targets connections and protect against failures.
The cluster mode allows gnmic
to scale and be highly available at the same time
To join the cluster, the instances rely on a service discovery system and distributed KV store such as Consul
,
Clustering process#
At startup, all instances belonging to a cluster:
- Enter an election process in order to become the cluster leader.
- Register their API service
gnmic-api
in a configured service discovery system.
Upon becoming the leader:
- The
gnmic
instance starts watching the registeredgnmic-api
services, and maintains a local cache of the active ones. These are essentially the instances restAPI addresses. - The leader then waits for
clustering/leader-wait-timer
to allow the other instances to register their API services as well. This is useful in case an instance is slow to boot, which leaves it out of the initial load sharing process. - The leader then enters a "target watch loop" (
clustering/targets-watch-timer
), at each iteration the leader tries to determine if all configured targets are handled by an instance of the cluster, this is done by checking if there is a lock maintained for each configured target.
The instances which failed to become the leader, continue to try to acquire the leader lock.
Target distribution process#
If the leader detects that a target does not have a lock, it triggers the target distribution process:
- Query all the targets keys from the KV store and calculate each instance load (number of maintained gNMI targets).
- If the target configuration includes
tags
, the leader selects the instance with the most matching tags (in order). If multiple instances have the same matching tags, the one with the lowest load is selected. - If the target doesn't have configured tags, the leader simply select the least loaded instance to handle the target's subscriptions.
- Retrieve the selected instance API address from the local services cache.
- Send both the target configuration as well as a target activation action to the selected instance.
When a cluster instance gets assigned a target (target activation):
- Acquire a key lock for that specific target.
- Once the lock is acquired, create the configured gNMI subscriptions.
- Maintain the target lock for the duration of the gNMI subscription.
The whole target distribution process is repeated for each target missing a lock.
Configuration#
The cluster configuration is as simple as:
# rest api address, format "address:port"
api: ""
# clustering related configuration fields
clustering:
# the cluster name, tells with instances belong to the same cluster
# it is used as part of the leader key lock, and the targets key locks
# if no value is configured, the value from flag --cluster-name is used.
# if the flag has the empty string as value, "default-cluster" is used.
cluster-name: default-cluster
# unique instance name within the cluster,
# used as the value in the target locks,
# used as the value in the leader lock.
# if no value is configured, the value from flag --instance-name is used.
# if the flag has the empty string as value, a value is generated in
# the format `gnmic-$UUID`
instance-name: ""
# service address to be registered in the locker(Consul)
# if not defined, it defaults to the address part of the API address:port
service-address: ""
# gnmic instances API service watch timer
# this is a long timer used by the cluster leader
# in a consul long-blocking query:
# https://www.consul.io/api-docs/features/blocking#implementation-details
services-watch-timer: 60s
# targets-watch-timer, targets watch timer, duration the leader waits
# between consecutive targets distributions
targets-watch-timer: 20s
# target-assignment-timeout, max time a leader waits for an instance to
# lock an assigned target.
# if the timeout is reached the leader unassigns the target and reselects
# a different instance.
target-assignment-timeout: 10s
# leader wait timer, allows to configure a wait time after an instance
# acquires the leader key.
# this wait time goal is to give more chances to other instances to register
# their API services before the target distribution starts
leader-wait-timer: 5s
# ordered list of strings to be added as tags during api service
# registration in addition to `cluster-name=${cluster-name}` and
# `instance-name=${instance-name}`
tags: []
# locker is used to configure the KV store used for
# service registration, service discovery, leader election and targets locks
locker:
# type of locker, only consul is supported currently
type: consul
# address of the locker server
address: localhost:8500
# Consul Data center, defaults to dc1
datacenter:
# Consul username, to be used as part of HTTP basicAuth
username:
# Consul password, to be used as part of HTTP basicAuth
password:
# Consul Token, is used to provide a per-request ACL token which overrides
# the agent's default token
token:
# session-ttl, session time-to-live after which a session is considered
# invalid if not renewed
# upon session invalidation, all services and locks created using this session
# are considered invalid.
session-ttl: 10s
# delay, a time duration (0s to 60s), in the event of a session invalidation
# consul will prevent the lock from being acquired for this duration.
# The purpose is to allow a gnmic instance to stop active subscriptions before
# another one takes over.
delay: 5s
# retry-timer, wait period between retries to acquire a lock
# in the event of client failure, key is already locked or lock lost.
retry-timer: 2s
# renew-period, session renew period, must be lower that session-ttl.
# if the value is greater or equal than session-ttl, is will be set to half
# of session-ttl.
renew-period: 5s
# debug, enable extra logging messages
debug: false
# tls config for the REST API client
tls:
# string, path to the CA certificate file,
# this will be used to verify the certificates of the gNMIc cluster members
# when `skip-verify` is false
ca-file:
# string, client certificate file.
cert-file:
# string, client key file.
key-file:
# boolean, if true, the client will not verify the server
# certificate against the available certificate chain.
skip-verify: false
A gnmic
instance creates gNMI subscriptions only towards targets for which it acquired locks. It is also responsible for maintaining that lock for the duration of the subscription.
Instance affinity#
The target distribution process can be influenced using tags
added to the target configuration.
By default, gnmic
instances register their API service with 2 tags;
cluster-name=${clustering/cluster-name}
instance-name=${clustering/instance-name}
By adding the same tags to a target router1
configuration (below YAML), the cluster leader will "assign" router1
to instance gnmic1
in cluster my-cluster
regardless of the instance load.
targets:
router1:
tags:
- cluster-name=my-cluster
- instance-name=gnmic1
Custom tags can be added to an instance API service registration in order to customize the instance affinity logic.
clustering:
tags:
- my-custom-tag=value1
Instance failure#
In the event of an instance failure, its maintained targets locks expire, which on the next clustering/targets-watch-timer
interval will be detected by the cluster leader.
The leader then performs the same target distribution process for those targets without a lock.
Leader reelection#
If a cluster leader fails, one of the other instances in the cluster eventually acquires the leader lock and becomes the cluster leader.
It then, proceeds with the targets distribution process to assign the unhandled targets to an instance in the cluster.
Scalability#
Using the same above-mentioned clustering mechanism, gnmic
can horizontally scale the number of supported gNMI connections distributed across multiple gnmic
instances.
The collected gNMI data can then be aggregated and made available through any of the running gnmic
instances, regardless of whether that instance collected the data from the target or not.
The data aggregation is done by chaining gnmic
outputs and inputs to build a gNMI data pipeline.
In the diagram below, the gnmic
instances on the left and right side of NATS server can be identical.