1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
---
title: "High Availability (HA)"
layout: default
---
[configure]: ./configure.markdown
[pe-configure]: https://puppet.com/docs/pe/latest/config_puppetdb.html
[logging]: ./logging.markdown
[metrics]: ./api/metrics/v2/jolokia.markdown
# Configuring PuppetDB for High Availability
In Puppet Enterprise 2016.5 and later, PuppetDB may be configured for high
availability in order to withstand network partitions or system failure.
PuppetDB is automatically configured for high availability as part of an HA
deployment of Puppet Enterprise. For more information about high availability in
Puppet Enterprise, see [High availability overview](https://puppet.com/docs/pe/latest/dr_overview.html).
## HA Overview
PuppetDB HA has two parts: first, Puppet Server is configured to send commands
and queries to multiple PuppetDB servers. Second, those servers are configured
to periodically reconcile their differences, transferring any records which they
are missing. This process is pull-based and runs on a configurable interval.
PuppetDB replication is in principle a multi-leader system. You can issue
commands to any server, and they can be reconciled with any other server without
conflicts. But, in order to minimize confusion when using exported resources, we
recommend that only one node be conventionally treated as
primary. [See below](#exportedResources) for further discussion.
PuppetDB HA is available in Puppet Enterprise 2016.5 and later.
Manual Installation and Configuration
----
1. Provision two PuppetDB nodes. Designate one of these as your _primary_
PuppetDB, and the other as the _replica_. Be sure that each PuppetDB is using
its own PostgreSQL cluster, because HA doesn't buy you anything if you have
single database. In this guide, we will give them the hostnames
`primary-puppetdb.mycorp.net` and `replica-puppetdb.mycorp.net`.
2. Configure each PuppetDB to pull from the other. This guide will use
HOCON-style configuration. See the
[PE Configuration Documentation][pe-configure] for further details.
a. Configure primary-puppetdb to pull from replica-puppetdb by placing this in its
config file:
[sync]
server_urls = https://replica-puppetdb.mycorp.net:8081
intervals = 2m
b. Configure replica-puppetdb to pull from primary-puppetdb:
[sync]
server_urls = https://primary-puppetdb.mycorp.net:8081
intervals = 2m
3. Configure the Puppet Server to point to both of your PuppetDB instances. In
your puppetdb.conf, use this as your server configuration (in the 'main' section):
server_urls = https://primary-puppetdb.mycorp.net:8081,https://replica-puppetdb.mycorp.net:8081
sticky_read_failover = true
command_broadcast = true
It is important that your primary PuppetDB appear first in this list, so it
will always be tried first when submitting new data from the Puppet Server.
4. Restart your PuppetDBs and your Puppet Server.
Deployment tips
----
- Each PuppetDB server should be configured to use a separate PostgreSQL
instance.
- If you are using multiple compile Server, be sure that their clocks are in
sync (using NTP, for example). PuppetDB relies on timestamps for discerning
which data is newer for any given node, so the clocks on your compile servers
need to be within `runinterval` of each other.
- The timeout for HTTP connections made by Puppet Server, including those to
PuppetDB, can be configured using the
`http-client.connect-timeout-milliseconds` key. This defaults to 120 seconds,
which is a good value for communications with single services. But for
PuppetDB HA to work well, you should use a considerably smaller timeout. The
exact value will depend on your infrastructure, but 10 seconds is a good place
to start. A catalog compilation can require as many as 4 timeouts, so be sure
that you choose a value that is less that 25% of the timeout configured on any
upstream load balancers. See the
[Puppet Server configuration documentation](https://puppet.com/docs/puppet/latest/server/config_file_puppetserver.html)
for details.
## FAQ
Q: *Why not just use PostgreSQL streaming replication?*
A: The principal goal of PuppetDB's HA solution is to ensure that Puppet runs
can succeed despite server outages and intermittent network connections. The
replica must be writable for this, and PostgreSQL streaming replication only
provides a read-only replica. If you need such a replica for performance
reasons, then streaming replication works very well.
There are other replication solutions available for PostgreSQL that do provide
write availability. Some of these use a leader election system to choose which
database is writable. This can work, but it tends to be difficult to deploy and
operate.
Others accept writes to all databases, recording conflicts for later resolution
by the application. For PuppetDB, handling such conflicts at the database level
would be very complex. Conversely, at the application level we can treat the
entities as they are treated through the rest of the Puppet stack (e.g. a whole
catalog vs. the many database rows required to store its resources). This
facilitates simple, deterministic conflict resolution.
Q: <a name="exportedResources"></a>*What's the deal with exported resources?*
A: Exported resources are a great feature, but you need to be careful when using
them. In particular: because PuppetDB is *eventually* consistent, changes to
exported resources will *eventually* be visible on other nodes (not
immediately). This is true in any PuppetDB installation, but there is an added
subtlety which you should be aware of when using an HA configuration:
In failover scenarios, exported resources may appear to go back in time. This
can happen if commands have been written to your primary PuppetDB but haven't yet
been copied to the replica. If the primary PuppetDB becomes unreachable
in this state, exported resource queries will be redirected to the replica,
which does not yet have the latest data.
This problem is significantly mitigated by using the command_broadcast flag in
puppetdb.conf, as recommended above. By pushing all data to the replica PuppetDB
when doing the initial write, the replica should nearly always be up to date,
but some failure cases still exist (for instance, intermittent connectivity to a
replica followed by immediately losing the primary). Because of this, we don't
recommend using PuppetDB HA in conjunction with exported resources for sensitive
applications where the data is changing often. For typical applications, such as
adding newly provisioned nodes to a load balancer's pool or registering them
with a monitoring system, small state regressions will have very low impact.
Q: *What durability guarantees does PuppetDB HA offer?*
A: In the recommended configuration described above, there are corner cases
which allow data loss. If you want to be absolutely certain that all data is
stored on at least 2 (or more) PuppetDB servers, you can put this in your
puppetdb.conf:
min_successful_submissions = 2
With this configuration, a Puppet run will fail if any data cannot be written to
at least two PuppetDB servers. This may be useful if you have three PuppetDB
servers, for example.
## Operations
PuppetDB provides several facilities to help you monitor the state of
replication:
## Structured Logging
HA-related events are written to a log named ":sync". You can configure the
handling of these events to fit your requirements.
If you have configured structured logging as described in the
[Logging Configuration Guide][logging], you will see additional attributes on each JSON log message.
### Common fields
* `phase`: The sync is divided into nested phases: `"sync"`, `"entity"`, `"record"`, and
`"deactivate"`. These are described in more detail below.
* `event`: All sync log messages have an event field, indicating its position
within the phase. This is one of `"start"`, `"finished"`, or `"error"`.
* `ok`:
* `finished` messages have the JSON boolean value `true`.
* `error` messages have the JSON boolean value `false`.
* `elapsed`: `finished` and `error` messages have an `elapsed` field whose value
is the time span since the corresponding start event in milliseconds
(formatted as a JSON number).
### Sync phase
`sync` events have the following fields:
* remote: The URL on the remote system from which data is being pulled.
### Entity phase
`entity` events surround the syncing for each type of record, i.e. catalogs,
facts, or reports.
* `entity`: The entity being processed. One of `"catalogs"`, `"facts"`,
`"reports"`, or `"nodes"`. Nodes is used only to sync node deactivation
status.
* remote: As above
* `transferred`: For the `finished` message, the number of records that were
transferred (pulled) and enqueued for processing.
* `failed`: For the `finished` message, the number of records that could not be
transferred.
### Record phase
`record` events surround the transfer of each record, for the `catalogs`,
`facts`, and `reports` entities. They are logged at debug level, unless there is
a problem.
* query: The query issued to the remote PuppetDB server to retrieve this record
* certname: The certname of the node with which this record is associated
* hash (reports only): The hash of the report being transferred
* entity: As above
* remote: As above
### Deactivate phase
`deactivate` events surround the process of issuing a local `deactivate node`
command for a particular node.
* certname: The certname of the node being deactivated
## Metrics
Some additional metrics are provided to help monitor the state of your HA setup.
For basic information on metrics in PuppetDB, see
[the main metrics documentation][metrics].
These metrics are all available via the metrics v2 endpoint. For example, you
can fetch the data using cURL like this:
```sh
curl https://localhost:8081/metrics/v2/read/puppetlabs.puppetdb.ha:name\=sync-has-worked-once \
--cert path/to/localhost.pem \
--key path/to/localhost.key \
--cacert path/to/ca.pem
```
The following metrics are all located in the `puppetlabs.puppetdb.ha` namespace.
* `last-sync-succeeded` (boolean): Did the last sync succeed?
* `sync-has-worked-once`(boolean): Has the sync worked at all since starting this process?
* `sync-has-failed-after-working`(boolean): Has the sync stopped working after
working previously? This may be useful for ignoring errors that occur when many
machines in the same cluster are starting at the same time.
* `last-successful-sync-time` (timestamp): The wall-clock time, on the PuppetDB
server, of when the last successful sync finished.
* `last-failed-sync-time` (timestamp): The wall-clock time, on the PuppetDB
server, of when the last failed sync finished.
* `seconds-since-last-successful-sync` (integer): The amount of time that
elapsed since the last time a sync succeeded.
* `seconds-since-last-failed-sync` (integer): The amount of time that elapsed
since the last time a sync failed.
* `failed-request-counter` (integer): The number of sync-related http requests
that have failed. Even if syncs are not failing, this may increase when
individual requests fail and are retried. Unexpected increases in this counter
should be investigated.
The following metrics expose timing statistics for various phases of the sync.
See the Structured Logging section for a detailed explanation of each phase.
* `sync-duration`
* `catalogs-sync-duration`
* `reports-sync-duration`
* `factsets-sync-duration`
* `nodes-sync-duration`
* `record-transfer-duration`
|