Swift/Ring Management
Swift rings are managed by an automated process; you edit a YAML file that describes the hosts in the cluster, and then the swift_ring_manager
process (run by a systemd timer) gradually adjusts the deployed rings to match the state specified in the YAML file. The aim is that the YAML file should be reasonably intuitive; some common tasks are outlined here.
The swift ring manager code is installed on one front-end per Swift cluster (see the ring_manager
entry in swift_clusters
in hiera); the [code repository] is checked out into /srv/deployment/swift_ring_manager
, and the script /usr/local/bin/swift_ring_manager
is templated by puppet to ensure the correct version of python is used. That repository contains a test suite, which contains [an extensive set of example changes].
The configuration file is deployed as /etc/swift/hosts.yaml
by Puppet; so to change the state of the rings, edit the relevant YAML file (found in modules/swift/files/CLUSTERNAME_hosts.yaml
), and put through a CR as usual.
Storage Schemes
Every hosts.yaml
file must define one or more schemes, which specify which devices belong to which rings, and with what weight. You typically won't have to edit these, as WMF tends to buy hardware of consistent specification. Each scheme is a mapping of ring name to the members of that ring, with an additional member "weight" which contains a mapping of ring name to the weight of members of that ring. For example:
schemes: prod: objects: [sdc1, sdd1, sde1] accounts: &ap [sda3, sdb3] containers: *ap ssds: &sp [sda4, sdb4] weight: objects: 4000 accounts: &acw 100 containers: *acw ssds: 300
Here, there is a single scheme "prod". There are three devices (/dev/sdc1
, /dev/sdd1
, /dev/sde1
) which hold objects, with weight 4000. In common with the previous Swift ring management code, the rings are given friendly names ("objects" for the "object" ring, "ssds" for the "object-1" ring, etc.); the mapping of friendly name to ring is defined in the regularize_ring_names
function.
Adding a host
If a host is the same type as other hosts in the cluster, simply add the host to the relevant list in hosts.yaml. So
hosts: prod: - hostname
would become
hosts: prod: - hostname - newhostname
To add newhostname
, a new host with the prod
device scheme. Remember to also add the new node to swift::storagehosts
Removing a host
Simply removing the host entry from hosts.yaml will cause it to be immediately removed from the rings; it is generally better to drain it first (i.e. gradually remove weight from all of its devices). This can be done thus:
hosts: prod: - hostname: - drain
Using failed
instead of drain
will cause all weights to be set to 0 immediately, rather than gradually.
Removing a device
Do this by setting its weight to zero. By default, this will take effect gradually; if you want to do so straight away, specify immediate
as well as weight zero. As a convenience, you can also use drain
for "weight 0" and failed
for "weight 0, immediate". For example:
hosts: prod: - hostname: - sdc1: 0 - sdd1: [0, immediate] - sde1: failed
Here /dev/sdc1
will have weight on it gradually reduced to 0, whereas /dev/sdd1
and /dev/sde1
will both have their weight set to 0 immediately.
Adjusting a device weight
This is essentially the same as the previous operation, but you can specify any weight you like. You may also specify immediate
for a change you want to not be made gradually. For example:
hosts: prod: - hostname: - sdc1: 2000 - sdd1: [3500, immediate]
Here /dev/sdc1
will have its weight gradually changed to 2000, and /dev/sdd1
will have its weight immediately set to 3500.
Rebalancing the rings without making other changes
Sometimes after a lot of changes have completed you may notice that the rings are somewhat unbalanced ("balance" in swift-ring-builder
output is high); you can rebalance the rings by running, on the ring manager host:
sudo /usr/local/bin/swift_ring_manager -o /var/cache/swift_rings --doit --rebalance -v
It's only useful to do this when the rings are otherwise not being changed (as a change to the rings will involve a rebalance anyway).
Invoking swift_ring_manager.py
Typically, you don't need to do this - it should be run automatically on the cluster's ring manager node, which will make changes and distribute the ring files for you. You can run it yourself to see what changes it would make, however - the default operation is to merely say what changes if any would be made. The help message details all the command-line arguments:
usage: swift_ring_manager.py [-h] [--doit] [--immediate-only] [--update-tmp-rings] [-v] [-c CONF_FILE] [--ring-dir RING_DIR] [-o OUT_DIR] [--skip-dispersion-check] [--skip-replication-check] [-s] [--host-file-path HOST_FILE_PATH] [--generate-host-file] Swift Ring Manager optional arguments: -h, --help show this help message and exit --doit Update ring files and deploy --immediate-only Only make changes flagged as immediate --update-tmp-rings Only update temporary copies of ring files -v, --verbose emit more debugging information -c CONF_FILE, --conf-file CONF_FILE path to configuration file --ring-dir RING_DIR directory containing ring builder files -o OUT_DIR, --out-dir OUT_DIR directory to put new rings into --skip-dispersion-check don't check dispersion OK before making changes --skip-replication-check don't check replication OK before making changes -s, --syslog Log to syslog rather than stdout --host-file-path HOST_FILE_PATH fake hosts list file path --generate-host-file generate a hosts file for future testing use