From c7166ba58be48d836aae0d38152f2cab7b8edff7 Mon Sep 17 00:00:00 2001 From: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com> Date: Tue, 26 Mar 2019 13:44:20 -0500 Subject: [PATCH] [docs] Semaphore (#5524) * Updating and adding headings. * Update website/source/docs/guides/semaphore.html.md Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com> * Update website/source/docs/guides/semaphore.html.md Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com> --- website/source/docs/guides/semaphore.html.md | 82 ++++++++++---------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/website/source/docs/guides/semaphore.html.md b/website/source/docs/guides/semaphore.html.md index 4ff177e755..178a629540 100644 --- a/website/source/docs/guides/semaphore.html.md +++ b/website/source/docs/guides/semaphore.html.md @@ -8,47 +8,44 @@ description: |- # Semaphore -This guide demonstrates how to implement a distributed semaphore using the Consul -KV store. This is useful when you want to coordinate many services while -restricting access to certain resources. +A distributed semaphore can be useful when you want to coordinate many services, while +restricting access to certain resources. In this guide we will focus on using Consul's support for +sessions and Consul KV to build a distributed +semaphore. Note, there are a number of ways that a semaphore can be built, we will not cover all the possible methods in this guide. + +To complete this guide successfully, you should have familiarity with +[Consul KV](/docs/agent/kv.html) and Consul [sessions](/docs/internals/sessions.html). ~> If you only need mutual exclusion or leader election, [this guide](/docs/guides/leader-election.html) provides a simpler algorithm that can be used instead. -There are a number of ways that a semaphore can be built, so our goal is not to -cover all the possible methods. Instead, we will focus on using Consul's support for -[sessions](/docs/internals/sessions.html). Sessions allow us to build a system that -can gracefully handle failures. --> **Note:** JSON output in this guide has been pretty-printed for easier reading. Actual values returned from the API will not be formatted. - -## Contending Nodes +## Contending Nodes in the Semaphore Let's imagine we have a set of nodes who are attempting to acquire a slot in the -semaphore. All nodes that are participating should agree on three decisions: the -prefix in the KV store used to coordinate, a single key to use as a lock, -and a limit on the number of slot holders. +semaphore. All nodes that are participating should agree on three decisions -For the prefix we will be using for coordination, a good pattern is simply: +- the prefix in the KV store used to coordinate. +- a single key to use as a lock. +- a limit on the number of slot holders. -```text -service/ -``` +### Session -We'll abbreviate this pattern as simply `` for the rest of this guide. +The first step is for each contending node to create a session. Sessions allow us to build a system that +can gracefully handle failures. -The first step is for each contender to create a session. This is done using the -[Session HTTP API](/api/session.html#session_create): +This is done using the +[Session HTTP API](/api/session.html#session_create). -```text +```sh curl -X PUT -d '{"Name": "db-semaphore"}' \ http://localhost:8500/v1/session/create ``` -This will return a JSON object contain the session ID: +This will return a JSON object contain the session ID. -```text +```json { "ID": "4ca8e74b-6350-7587-addf-a18084928f3c" } @@ -56,14 +53,15 @@ This will return a JSON object contain the session ID: -> **Note:** Sessions by default only make use of the gossip failure detector. That 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 at session creation if desired. +### KV Entry for Node Locks + Next, we create a lock contender entry. Each contender creates a kv entry that is tied to a session. This is done so that if a contender is holding a slot and fails, its session is detached from the key, which can then be detected by the other contenders. Create the contender key by doing an `acquire` on `/` via `PUT`. -This is something like: -```text +```sh curl -X PUT -d http://localhost:8500/v1/kv//?acquire= ``` @@ -77,22 +75,22 @@ The call will either return `true` or `false`. If `true`, the contender entry ha created. If `false`, the contender node was not created; it's likely that this indicates a session invalidation. +### Single Key for Coordination + The next step is to create a single key to coordinate which holders are currently reserving a slot. A good choice for this lock key is simply `/.lock`. We will refer to this special coordinating key as ``. -This is done with: - -```text +```sh curl -X PUT -d http://localhost:8500/v1/kv/?cas=0 - ``` +``` Since the lock is being created, a `cas` index of 0 is used so that the key is only put if it does not exist. -`body` should contain both the intended slot limit for the semaphore and the session ids -of the current holders (initially only of the creator). A simple JSON body like the following works: +The `body` of the request should contain both the intended slot limit for the semaphore and the session ids +of the current holders (initially only of the creator). A simple JSON body like the following works. -```text +```json { "Limit": 2, "Holders": [ @@ -101,16 +99,18 @@ of the current holders (initially only of the creator). A simple JSON body like } ``` -The current state of the semaphore is read by doing a `GET` on the entire ``: +## Semaphore Management -```text +The current state of the semaphore is read by doing a `GET` on the entire ``. + +```sh curl http://localhost:8500/v1/kv/?recurse - ``` +``` Within the list of the entries, we should find two keys: the `` and the contender key ‘/’. -```text +```json [ { "LockIndex": 0, @@ -149,9 +149,9 @@ This performs an optimistic update. This is done with: -```text +```sh curl -X PUT -d http://localhost:8500/v1/kv/?cas= - ``` +``` `lock-modify-index` is the latest `ModifyIndex` value known for ``, 901 in this example. If this request succeeds with `true`, the contender now holds a slot in the semaphore. @@ -161,7 +161,7 @@ To re-attempt the acquisition, we watch for changes on ``. This is becau may be released, a node may fail, etc. Watching for changes is done via a blocking query against `/kv/?recurse`. -Slot holders **must** continously watch for changes to `` since their slot can be +Slot holders **must** continuously watch for changes to `` since their slot can be released by an operator or automatically released due to a false positive in the failure detector. On changes to `` the lock’s `Holders` list must be re-checked to ensure the slot is still held. Additionally, if the watch fails to connect the slot should be considered lost. @@ -172,3 +172,7 @@ that a slot is held before (and during) execution of some critical operation. Lastly, if a slot holder ever wishes to release its slot voluntarily, it should be done by doing a Check-And-Set operation against `` to remove its session from the `Holders` object. Once that is done, both its contender key `/` and session should be deleted. + +## Summary + +In this guide we created a distributed semaphore using Consul KV and Consul sessions. We also learned how to manage the newly created semaphore.