2014-05-20 19:22:16 +00:00
---
2020-04-07 18:55:19 +00:00
layout: docs
page_title: Application Leader Election with Sessions
sidebar_current: docs-guides-leader
description: >-
This guide describes how to build client-side leader election using Consul. If
you are interested in the leader election used internally to Consul, please
refer to the consensus protocol documentation instead.
2014-05-20 19:22:16 +00:00
---
2019-04-17 21:16:15 +00:00
# Application Leader Election with Sessions
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
For some applications, like HDFS, it is necessary to set one instance as
a leader. This ensures the application data is current and stable.
2014-05-20 19:22:16 +00:00
2020-04-06 20:27:35 +00:00
This guide describes how to build client-side leader elections for service
2019-04-17 21:16:15 +00:00
instances, using Consul. Consul's support for
[sessions](/docs/internals/sessions.html) allows you to build a system that can gracefully handle failures.
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
If you
are interested in the leader election used internally by Consul, please refer to the
[consensus protocol](/docs/internals/consensus.html) documentation instead.
2014-12-05 19:09:45 +00:00
2020-04-06 20:27:35 +00:00
## Contending Service Instances
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
Imagine you have a set of MySQL service instances who are attempting to acquire leadership. All service instances that are participating should agree on a given
2015-02-28 05:08:41 +00:00
key to coordinate. A good pattern is simply:
2014-05-20 19:22:16 +00:00
2014-10-19 23:40:10 +00:00
```text
service/<service name>/leader
```
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
This key will be used for all requests to the Consul KV API.
2014-12-05 19:09:45 +00:00
2019-04-17 21:16:15 +00:00
We will use the same, simple pattern for the MySQL services for the remainder of the guide.
2014-12-05 19:09:45 +00:00
```text
2019-04-17 21:16:15 +00:00
service/mysql/leader
```
2020-04-06 20:27:35 +00:00
### Create a Session
2019-04-17 21:16:15 +00:00
The first step is to create a session using the
[Session HTTP API](/api/session.html#session_create).
2020-04-07 23:56:08 +00:00
```shell
2019-04-17 21:16:15 +00:00
$ curl -X PUT -d '{"Name": "mysql-session"}' http://localhost:8500/v1/session/create
```
2014-12-05 19:09:45 +00:00
2015-02-28 05:08:41 +00:00
This will return a JSON object containing the session ID:
2014-12-05 19:09:45 +00:00
2019-04-17 21:16:15 +00:00
```json
2014-12-05 19:09:45 +00:00
{
"ID": "4ca8e74b-6350-7587-addf-a18084928f3c"
}
```
2014-05-20 19:22:16 +00:00
2020-04-06 20:27:35 +00:00
### Acquire a Session
2019-04-17 21:16:15 +00:00
The next step is to acquire a session for a given key from this instance
2017-04-04 16:33:22 +00:00
using the PUT method on a [KV entry](/api/kv.html) with the
2020-04-06 20:27:35 +00:00
`?acquire=<session>` query parameter.
2019-04-17 21:16:15 +00:00
The `<body>` of the PUT should be a
JSON object representing the local instance. This value is opaque to
2015-02-28 05:08:41 +00:00
Consul, but it should contain whatever information clients require to
2014-12-05 19:09:45 +00:00
communicate with your application (e.g., it could be a JSON object
that contains the node's name and the application's port).
2014-05-20 19:22:16 +00:00
2020-04-07 23:56:08 +00:00
```shell
2019-04-17 21:16:15 +00:00
$ curl -X PUT -d <body> http://localhost:8500/v1/kv/service/mysql/leader?acquire=4ca8e74b-6350-7587-addf-a18084928f3c
2020-04-06 20:27:35 +00:00
```
2014-05-20 19:22:16 +00:00
2015-02-28 05:08:41 +00:00
This will either return `true` or `false`. If `true`, the lock has been acquired and
2019-04-17 21:16:15 +00:00
the local service instance is now the leader. If `false` is returned, some other node has acquired
2015-02-28 05:08:41 +00:00
the lock.
2014-05-20 19:22:16 +00:00
2020-04-06 20:27:35 +00:00
### Watch the Session
2019-04-17 21:16:15 +00:00
All instances now remain in an idle waiting state. In this state, they watch for changes
on the key `service/mysql/leader`. This is because the lock may be released or the instance could fail, etc.
2015-02-28 05:08:41 +00:00
The leader must also watch for changes since its lock may be released by an operator
2014-05-20 19:22:16 +00:00
or automatically released due to a false positive in the failure detector.
2016-11-25 16:00:02 +00:00
By default, the session makes use of only the gossip failure detector. That
2015-02-28 05:08:41 +00:00
is, the session is considered held by a node as long as the default Serf health check
has not declared the node unhealthy. Additional checks can be specified if desired.
2019-04-17 21:16:15 +00:00
Watching for changes is done via a blocking query against the key. If they ever
notice that the `Session` field in the response is blank, there is no leader, and then should
2015-02-28 05:08:41 +00:00
retry lock acquisition. Each attempt to acquire the key should be separated by a timed
2014-05-20 19:22:16 +00:00
wait. This is because Consul may be enforcing a [`lock-delay`](/docs/internals/sessions.html).
2019-04-17 21:16:15 +00:00
### Release the Session
2014-05-20 19:22:16 +00:00
If the leader ever wishes to step down voluntarily, this should be done by simply
releasing the lock:
2020-04-07 23:56:08 +00:00
```shell
2019-04-17 21:16:15 +00:00
$ curl -X PUT http://localhost:8500/v1/kv/service/mysql/leader?release=4ca8e74b-6350-7587-addf-a18084928f3c
2014-10-19 23:40:10 +00:00
```
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
## Discover the Leader
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
It is possible to identify the leader of a set of service instances participating in the election process.
2015-02-28 05:08:41 +00:00
2020-04-06 20:27:35 +00:00
As with leader election, all instances that are participating should agree on the key being used to coordinate.
2014-05-20 19:22:16 +00:00
2020-04-06 20:27:35 +00:00
### Retrieve the Key
2014-12-05 19:09:45 +00:00
2019-04-17 21:16:15 +00:00
Instances have a very simple role, they simply read the Consul KV key to discover the current leader. If the key has an associated `Session`, then there is a leader.
2020-04-07 23:56:08 +00:00
```shell
2019-04-17 21:16:15 +00:00
$ curl -X GET http://localhost:8500/v1/kv/service/mysql/leader
2014-12-05 19:09:45 +00:00
[
{
"Session": "4ca8e74b-6350-7587-addf-a18084928f3c",
"Value": "Ym9keQ==",
"Flags": 0,
2019-04-17 21:16:15 +00:00
"Key": "service/mysql/leader",
2014-12-05 19:09:45 +00:00
"LockIndex": 1,
"ModifyIndex": 29,
"CreateIndex": 29
}
]
```
2019-04-17 21:16:15 +00:00
If there is a leader then the value of the key will provide all the
2016-11-25 16:00:02 +00:00
application-dependent information required as a Base64 encoded blob in
the `Value` field.
2015-02-28 05:08:41 +00:00
2019-04-17 21:16:15 +00:00
### Retrieve Session Information
2016-11-25 16:00:02 +00:00
You can query the
2017-04-04 16:33:22 +00:00
[`/v1/session/info`](/api/session.html#session_info)
2019-04-17 21:16:15 +00:00
endpoint to get details about the session
2014-12-05 19:09:45 +00:00
2020-04-07 23:56:08 +00:00
```shell
2019-04-17 21:16:15 +00:00
$ curl -X GET http://localhost:8500/v1/session/info/4ca8e74b-6350-7587-addf-a18084928f3c
2014-12-05 19:09:45 +00:00
[
{
"LockDelay": 1.5e+10,
"Checks": [
"serfHealth"
],
2016-11-25 16:00:02 +00:00
"Node": "consul-primary-bjsiobmvdij6-node-lhe5ihreel7y",
2019-04-17 21:16:15 +00:00
"Name": "mysql-session",
2014-12-05 19:09:45 +00:00
"ID": "4ca8e74b-6350-7587-addf-a18084928f3c",
"CreateIndex": 28
}
]
```
2014-05-20 19:22:16 +00:00
2019-04-17 21:16:15 +00:00
## Summary
In this guide you used a session to initiate manual leader election for a
set of service instances. To fully benefit from this process, instances should also watch the key using a blocking query for any
2016-11-25 16:00:02 +00:00
changes. If the leader steps down or fails, the `Session` associated
with the key will be cleared. When a new leader is elected, the key
value will also be updated.
2018-02-01 20:08:06 +00:00
2019-04-17 21:16:15 +00:00
Using the `acquire` parameter is optional. This means
2018-02-01 20:08:06 +00:00
that if you use leader election to update a key, you must not update the key
without the acquire parameter.