blob: 3c8132764c07a3bc8143807b157d8881c163aaf8 [file] [view]
<!---
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Permanent failure handling of masters for Kudu 1.0
## Background
Kudu's 1.0 release includes various improvements to multi-master support so that
it can be used in production safely. The original release plan emphasized using
multiple masters for high availability in the event of transient failures, but
unfortunately didn't talk much (if at all) about permanent failures. This
document compares transient and permanent failures, and provides a design for
addressing the latter.
### Transient failures
Kudu's handling of transient master failures is best illustrated with an
example. Assume we have a healthy Raft configuration consisting of three
masters. If one master suffers a transient failure and is offline for a short
time before returning, there's no harm. If the failed node was a follower, the
leader can still replicate to a majority of nodes. If the leader itself failed,
a majority of nodes can still elect a new leader. No new machinery is needed to
support this; all of the code has been written and tested with the caveat that
there are some bugs that we have been squashing over the past few months.
### Permanent failures
What's missing, however, is handling for permanent failures. If a node dies and
is not coming back, we need to replace it with a healthy one ASAP. If we don't,
a second failure (transient or otherwise) will lead to a loss of availability.
## Design proposal for handling permanent failures
In practice, the most straight-forward approach to handling any permanent
failure is to extend Raft configuration change support to the master; currently
it’s only possible to do it in the tserver. However, this just isn't possible
given time constraints. Therefore, we will use a DNS-dependent alternative.
Here is the algorithm:
1. Base state:
1. There's a healthy Raft configuration of three nodes: **A**, **B**, and
**C**.
2. **A** is the leader.
3. The value of **--master_addresses** (the master-only gflag describing the
locations of the entire master Raft configuration) is {**A**, **B**,
**C**} on each node.
4. Each of **A**, **B**, and **C** are DNS cnames.
5. The value of **--tserver_master_address** (the tserver-only gflag
describing the locations of the masters) on each tserver is {**A**, **B**,
**C**}
2. **C** dies, permanently. If **A** dies, the directions below are the same,
except replace **A** with whichever node was elected the new leader.
3. Make sure **C** is completely dead and cannot come back to life. If possible,
destroy its on-disk master state.
4. Find a replacement machine **D**.
5. Modify DNS records such that **D** assumes **C**'s cname.
6. Invoke new command line tool on **D** that uses remote bootstrap to copy
master state from **A** to **D**.
7. Start a new master on **D**. It should use the same value of
**--master_addresses** as used by the other masters.
In order to implement this design, we'll need to make the following changes:
1. Make remote bootstrap available for masters (currently it's tserver-only).
2. Implement new remote bootstrap "client" command line tool.
## Migration from single-master deployments
While not exactly related to failure handling, the remote bootstrap
modifications described above can be used to ease migration from a single master
deployment to a multi-master one. Since migration is a rare and singular event
in the lifetime of a cluster, it is assumed that a temporary loss of
availability during the migration is acceptable.
Here is the algorithm:
1. There exists a healthy single-node master deployment called **A**.
2. Find new master machines, creating DNS cnames for all of them. Create a DNS
cname for **A** too, if it's not already a cname. Note: the total number of
masters must be odd. To figure out how many masters there should be, consider
that **N** failures can be tolerated by a deployment of **2N+1** masters.
3. Stop the master running on **A**.
4. Invoke new command line tool to format a filesystem on each new master node.
5. Invoke new command line tool to print the filesystem uuid on each master node
and on existing master node **A**. Record these UUIDs.
6. Invoke new command line tool on **A** to rewrite the on-disk consensus
metadata (cmeta) file describing the Raft configuration. Provide the uuid and
cname for each new master node as well as for **A**.
7. Start the master running on **A**.
8. Invoke remote bootstrap "client" tool from above on each new node to copy
**A**'s master state onto new node. These invocations can be done in parallel
to speed up the process, though in practice master state is quite small.
9. Start the master on each new node.
In order to implement this design, we'll need the following additional changes:
1. Implement new command line tool to format filesystems.
2. Implement new command line tool to print filesystem uuids.
3. Implement new command line tool to rewrite cmeta files.