Login Logout

Howto DRBD

DRBD (Distributed Replicated Block Device) est un outil libre pour répliquer des blocs (disques, partitions, volumes LVM…) entre deux serveurs Linux via une connexion réseau. On peut voir cela comme un « RAID1 over TCP/IP ». Nous l’utilisons principalement comme stockage pour de la virtualisation avec KVM, cela permet notamment de réaliser des migrations à chaud de machines virtuelles entre deux hyperviseurs sans dépendre d’un équipement externe de type SAN.

La version 8.4 est intégrée dans le noyau Linux et dans Debian par défaut.

LINBIT (l’entreprise qui développe DRBD) propose aussi la version 9.0 qui permet notamment de faire facilement du DRBD entre trois serveurs Linux, ou encore d’être utilisé par Proxmox par l’intermédiaire de LINSTOR.

Installation

DRBD 8.4

# apt install drbd-utils
# drbdadm -V
DRBDADM_BUILDTAG=GIT-hash:\ 409097fe02187f83790b88ac3e0d94f3c167adab\ reproducible\ build\,\ 2023-01-09\ 14:51:18
DRBDADM_API_VERSION=1
DRBD_KERNEL_VERSION_CODE=0x08040b
DRBDADM_VERSION_CODE=0x091600
DRBDADM_VERSION=9.22.0

# modinfo drbd
filename:       /lib/modules/6.1.0-17-amd64/kernel/drivers/block/drbd/drbd.ko
alias:          block-major-147-*
license:        GPL
version:        8.4.11
description:    drbd - Distributed Replicated Block Device v8.4.11
author:         Philipp Reisner <phil@linbit.com>, Lars Ellenberg <lars@linbit.com>
srcversion:     488C1124B879DCE7CD031DA
depends:        lru_cache,libcrc32c
retpoline:      Y
intree:         Y
name:           drbd
vermagic:       6.1.0-17-amd64 SMP preempt mod_unload modversions 
sig_id:         PKCS#7
signer:         Debian Secure Boot CA
sig_key:        32:A0:28:7F:84:1A:03:6F:A3:93:C1:E0:65:C4:3A:E6:B2:42:26:43
sig_hashalgo:   sha256
signature:      0C:85:38:83:85:36:BA:7B:25:BC:00:8A:1A:B6:E5:2F:03:BE:1D:48:
        A7:C2:B1:AF:D3:94:6F:AC:28:9A:2F:F4:16:91:A3:6C:F9:67:E3:AF:
        3E:70:4F:37:2D:A3:FA:9F:3F:2A:53:DB:87:0B:76:69:E2:9D:F5:F4:
        9E:6C:DA:53:C4:79:4B:7E:02:F3:49:6C:A5:72:B3:AC:7C:5A:72:DB:
        36:92:5E:A9:4F:60:10:FD:7C:A6:88:BB:E4:AD:0E:F7:27:B1:AB:69:
        76:F7:53:BC:5C:97:DF:27:C5:97:5E:B6:6F:DD:36:20:83:25:53:BB:
        1C:EF:E6:4B:F0:EC:D2:17:8F:43:E6:13:8A:F6:A6:E6:AA:14:B8:A3:
        B6:6A:B2:2F:2A:61:77:81:81:CB:23:9E:B0:90:26:64:3E:45:A1:07:
        68:2D:E5:2F:B1:96:D2:9E:20:47:14:1A:0E:49:40:56:68:D5:F7:B5:
        89:CA:FA:95:9E:9D:36:58:89:88:11:6C:C7:CA:A3:E1:CE:3C:18:22:
        BF:41:DD:1B:0A:5D:FC:EA:AA:83:B5:32:01:C1:00:B2:09:F2:83:55:
        94:8F:FA:E8:22:99:2C:84:D6:B7:84:FC:03:6C:E5:79:96:C0:6E:84:
        FD:2C:76:67:83:87:F2:92:2E:E5:DD:A2:1D:BA:53:47
parm:           allow_oos:DONT USE! (bool)
parm:           disable_sendpage:bool
parm:           proc_details:int
parm:           minor_count:Approximate number of drbd devices (1-255) (uint)
parm:           usermode_helper:string

DRBD 9.0

LINBIT fournit un dépôt. Ce qui est étrange c’est que les modules pour DRBD 9 sont dans la suite Proxmox.

On ajoute les clés de LINBIT :

$ wget https://packages.linbit.com/public/linbit-keyring.deb
# dpkg -i « linbit-keyring.deb »

Et voici les sources pour Debian 12 ou Proxmox 8 :

# vim /etc/apt/sources.list.d/drbd.sources

Types: deb
URIs: https://packages.linbit.com/public
Enabled: yes
Suites: proxmox-8
Components: drbd-9
Signed-by: /etc/apt/trusted.gpg.d/linbit-keyring.gpg

et les sources pour Debian 11 ou Proxmox 7 :

# vim /etc/apt/sources.list.d/drbd.sources

Types: deb
URIs: https://packages.linbit.com/public
Enabled: yes
Suites: proxmox-7
Components: drbd-9
Signed-by: /etc/apt/trusted.gpg.d/linbit-keyring.gpg

Et enfin on installe :

# apt install drbd-dkms drbd-utils
# drbdadm -V
DRBDADM_BUILDTAG=GIT-hash:\ ba2ce9037989b6141222c7901d1219cf852949f1\ build\ by\ @buildsystem\,\ 2024-05-06\ 07:39:36
DRBDADM_API_VERSION=2
DRBD_KERNEL_VERSION_CODE=0x09020b
DRBD_KERNEL_VERSION=9.2.11
DRBDADM_VERSION_CODE=0x091c00
DRBDADM_VERSION=9.28.0

~# modinfo drbd
filename:       /lib/modules/5.10.0-32-amd64/updates/dkms/drbd.ko
alias:          block-major-147-*
license:        GPL
version:        9.2.11
description:    drbd - Distributed Replicated Block Device v9.2.11
author:         Philipp Reisner <phil@linbit.com>, Lars Ellenberg <lars@linbit.com>
srcversion:     954B7260FDB1F57D723507F
depends:        lru_cache,libcrc32c
retpoline:      Y
name:           drbd
vermagic:       5.10.0-32-amd64 SMP mod_unload modversions 
parm:           enable_faults:int
parm:           fault_rate:int
parm:           fault_count:int
parm:           fault_devs:int
parm:           disable_sendpage:bool
parm:           allow_oos:DONT USE! (bool)
parm:           minor_count:Approximate number of drbd devices (1U-255U) (uint)
parm:           usermode_helper:string
parm:           protocol_version_min:drbd_protocol_version
parm:           strict_names:restrict resource and connection names to ascii alnum and a subset of punct (drbd_strict_names)

Il faut alors charger le nouveau module et redémarrer. On peut vérifier que c’est bien pris en compte via /proc/drbd.

Utilisation basique

Sur une installation DRBD on définit :

  • des ressources : chaque ressource DRBD a plusieurs paramètres, notamment le second serveur vers qui envoyer/recevoir la réplication
  • des volumes : chaque ressource DRBD peut avoir un ou plusieurs volumes, chaque volume est accessible via un périphérique unique nommé /dev/drbdXX

La configuration des ressources DRBD est dans le répertoire /etc/drbd.d/ ; voici un exemple simple d’une ressource foo avec un volume /dev/drbd42 définie dans un fichier /etc/drbd.d/foo.res entre deux serveurs nommés tic et tac (cet exemple sera repris par la suite) :

resource "foo" {
    volume 0 {
        device minor 42;
        disk /dev/sdz1;
        meta-disk internal;
    }
    on tic {
        address 192.0.2.1:7014;
    }
    on tac {
        address 192.0.2.2:7014;
    }
}

Pour voir les volumes configurés et leur statut :

$ cat /proc/drbd
version: 8.4.7 (api:1/proto:86-101)
srcversion: 0904DF2CCF7283ACE07D07A 

42: cs:WFConnection ro:Secondary/Unknown ds:Inconsistent/DUnknown C r----s
    ns:0 nr:0 dw:0 dr:0 al:8 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:1048508

# drbd-overview
42:foo/0  WFConnection Secondary/Unknown Inconsistent/DUnknown 

Attention : Depuis Debian 11 (Bullseye), la commande drbd-overview n’est plus disponible. On peut utiliser drbdadm status [ressource] ou drbdmon à la place.

Il existe aussi drbdmon(8) qui permet d’avoir un affichage en temps réel (façon htop(8)) de l’état des ressources DRBD.

Pour lister la configuration et vérifier la syntaxe :

# drbdadm dump

drbdadm est l’outil principal pour DRBD, voici quelques commandes utilisables sur une ressource :

# drbdadm dump
# drbdadm create-md [ressource]
# drbdadm attach/detach [ressource]
# drbdadm connect/disconnect [ressource]
# drbdadm adjust/adjust-with-progress [ressource]
# drbdadm primary/secondary [ressource]

On peut également piloter un volume d’une ressource en indiquant la syntaxe [ressource]/[n° de volume], par exemple :

# drbdadm secondary foo/0

drbdadm pilote principalement les commandes bas niveau drbdsetup et drbdmeta. Son mode « dry-run » est très utile car il va lister les commandes bas niveau effectuées (sans les appliquer). Par exemple pour voir tous les changements de configuration non appliqués :

# drbdadm -d adjust all

Création de ressources/volumes

ressource avec un seul volume

Il faut créer /etc/drbd.d/foo.res sur les deux serveurs concernés :

resource "foo" {
    net {
        #allow-two-primaries;
    }
    volume 0 {
        device minor 42;
        disk /dev/sdz1;
        meta-disk internal;
    }
    on tic {
        address 192.0.2.1:7014;
    }
    on tac {
        address 192.0.2.2:7014;
    }
}

Note : les hostnames et adresses IP doivent être corrects car DRBD vérifie qu’ils sont effectivement configurés en local !

On vérifie la syntaxe via :

# drbdadm dump foo

 # resource foo on tic: not ignored, not stacked
 # defined at /etc/drbd.d/foo.res:1
 […]

On initialise les metadata sur les disques (attention, cela écrit des données à la fin des disk) sur chaque serveur :

tic# drbdadm create-md foo
tac# drbdadm create-md foo

initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.

On utilise la commande drbdadm adjust en mode dry-run sur chaque serveur pour vérifier les actions :

tic# drbdadm -d adjust foo
tac# drbdadm -d adjust foo

drbdsetup-84 new-resource foo 
drbdsetup-84 new-minor foo 42 0 
drbdmeta 42 v08 /dev/sdz1 internal apply-al 
drbdsetup-84 attach 42 /dev/sdz1 /dev/sdz1 internal 
drbdsetup-84 connect foo ipv4:192.0.2.1:7014 ipv4:192.0.2.2:7014

Puis on applique cette nouvelle configuration :

tic# drbdadm adjust foo
tac# drbdadm adjust foo

À ce stade, vous devez avoir une ressource Connected avec des données Inconsistent :

# drbd-overview
42:foo/0  Connected Secondary/Secondary Inconsistent/Inconsistent 

Il reste à forcer la synchronisation d’un côté :

tic# drbdadm -- --overwrite-data-of-peer primary foo

Et observer cette première synchronisation puis l’état UpToDate de chaque côté :

# drbd-overview
42:foo/0  SyncSource Primary/Secondary UpToDate/Inconsistent 
        [===>................] sync'ed: 22.3% (818364/1048508)K

# drbd-overview 
42:foo/0  Connected Primary/Secondary UpToDate/UpToDate 

Si l’on veut être en Primary/Primary il faut avoir configuré allow-two-primaries; puis :

tac# drbdadm primary foo

# drbd-overview 
42:foo/0  Connected Primary/Primary UpToDate/UpToDate

ressource avec plusieurs volumes

On peut avoir plusieurs volumes pour une même ressource. Cela simplifie la configuration (un seul fichier, un seul port TCP) et la gestion (drbdadm s’applique alors pour tous les volumes d’une même ressource).

Voici un exemple de fichier /etc/drbd.d/foo.res associé à un volume pour /dev/drbd43 et un volume pour /dev/drbd44 :

resource "foo" {
    net {
        #allow-two-primaries;
    }
    volume 0 {
        device minor 43;
        disk /dev/sdz1;
        meta-disk internal;
    }
    volume 1 {
        device minor 44;
        disk /dev/sdz2;
        meta-disk internal;
    }
    on tic {
        address 192.0.2.1:7014;
    }
    on tac {
        address 192.0.2.2:7014;
    }
}

Note : attention, les device minor doivent être différents pour chaque volume DRBD sur l’ensemble du serveur car ils vont correspondre à un périphérique unique /dev/drbd<device minor>

Les étapes sont ensuite similaires à une ressource avec un seul volume (voir détails ci-dessus). En résumé :

tic# drbdadm create-md foo
tac# drbdadm create-md foo

tic# drbdadm adjust foo
tac# drbdadm adjust foo

tic# drbdadm -- --overwrite-data-of-peer primary foo

tac# drbdadm primary foo

# drbd-overview 
43:foo/0  Connected Primary/Primary UpToDate/UpToDate
44:foo/0  Connected Primary/Primary UpToDate/UpToDate

ajouter un volume à une ressource existante

Pour ajouter un nouveau volume à une ressource avec des volumes déjà en production, on utilisera directement les commandes bas niveau drbdsetup et drbdmeta pour ne pas perturber les autres volumes.

Voici l’exemple du fichier /etc/drbd.d/foo.res ci-dessus avec l’ajout d’un 3ème volume /dev/drbd45 :

resource "foo" {
    net {
        #allow-two-primaries;
    }
    volume 0 {
        device minor 43;
        disk /dev/sdz1;
        meta-disk internal;
    }
    volume 1 {
        device minor 44;
        disk /dev/sdz2;
        meta-disk internal;
    }
    volume 2 {
        device minor 45;
        disk /dev/sdz3;
        meta-disk internal;
    }
    on tic {
        address 192.0.2.1:7014;
    }
    on tac {
        address 192.0.2.2:7014;
    }
}

On crée ensuite les metadatas uniquement pour ce nouveau volume /dev/drbd45 :

tic# drbdmeta 45 v08 /dev/sdz3 internal create-md
tac# drbdmeta 45 v08 /dev/sdz3 internal create-md

Puis on applique cette nouvelle configuration (en observant avant en mode dry-run) :

tic# drbdadm -d adjust foo
tac# drbdadm -d adjust foo

tic# drbdadm adjust foo
tac# drbdadm adjust foo

Et enfin, on force la synchronisation de ce nouveau volume /dev/drbd45 :

tic# drbdsetup primary 45 --overwrite-data-of-peer 

Mise en place de 3 nœuds avec DRBD 9.0

Voici un exemple d’une ressource nommée “foo” :

resource "foo" {
    volume 0 {
        device minor 42;
        disk /dev/sdz1;
        meta-disk internal;
    }
    on tic {
        address 192.0.2.1:7014;
    }
    on tac {
        address 192.0.2.2:7014;
    }
}

Pour chaque nœud, ajoutez un node-id :

    on tic {
        address 192.0.2.1:7014;
        node-id 0;
    }
    on tac {
        address 192.0.2.2:7014;
        node-id 1;
    }
    on toc {
        address 192.0.2.3:7014;
        node-id 2;
    }

Afin d’énumérer l’ordre de connection de tous les nœuds participants, ajoutez la directive :

connection-mesh {
  hosts tic tac toc;
}

Configuration

https://www.drbd.org/en/doc/users-guide-84/re-drbdconf

La configuration générale (directives global et common) est dans le fichier /etc/drbd.d/global_common.conf (inclus par /etc/drbd.conf), les ressources sont dans des fichiers /etc/drbd.d/*.res (directives resource).

/etc/drbd.conf
├── /etc/drbd.d/global_common.conf
└── /etc/drbd.d/*.res

authentification

Afin de sécuriser un peu les échanges DRBD entre deux serveurs, on peut configurer une authentification dans la section net{} (que l’on peut mettre dans common ou dans chaque directive resource):

net {
    cram-hmac-alg "sha1";
    shared-secret "PASSWORD";
}

protocoles A/B/C et allow-two-primaries

DRBD dispose de 3 protocoles de réplication/synchronisation : A, B et C.

  • A : réplication asynchrone
  • B : réplication semi-asynchrone
  • C : réplicaton synchrone (c’est le protocole utilisé par défaut), seul ce mode permet l’option allow-two-primaries;

On peut configurer le protocole dans la section net{} (que l’on peut mettre dans common ou dans chaque directive resource):

net {
    protocol A;
}

net {
    protocol B;
}

net {
    protocol C;
    allow-two-primaries;
}

vitesse de re-synchronisation

https://www.drbd.org/en/doc/users-guide-84/s-configure-sync-rate

La re-synchronisation est l’étape d’échange des données quand un volume n’est pas/plus en UpToDate/UpToDate (par exemple à la création d’un nouveau volume). Par défaut, la vitesse de re-synchronisation est dynamique et limitée à 100Mo/s (soit 800Mb/s). Ceci est valable depuis DRBD 8.4 même si la documentation principale n’est pas tout à fait à jour. Les paramètres par défaut sont c-plan-ahead 20; c-fill-target 50k; c-min-rate 250k; c-max-rate 100M;.

Si besoin, on peut fixer temporairement cette vitesse (pour la limiter ou pour l’augmenter) en définissant en Mo/s sur le serveur qui reçoit les données. Par exemple pour forcer à 200 Mo/s :

# drbdadm disk-options --c-plan-ahead=0 --resync-rate=200M <ressource>

Pour reprendre les valeurs des fichiers de configuration :

# drbdadm adjust <ressource>

Si l’on veut modifier ces paramètres de façon définitive, on utilisera la section disk{} (que l’on peut mettre dans common ou dans chaque directive resource) :

disk {
    resync-rate 200M;
}

Administration

supprimer une ressource

On peut supprimer une ressource via drbdadm down (qui fait un disconnect puis detach) :

# drbdadm down <ressource>

On peut ensuite supprimer le fichier de conf associé et s’assurer que c’est bien pris en compte :

# rm /etc/drbd.d/<ressource>.res
# drbdadm dump <ressource>

supprimer un volume d’une ressource

Dans le fichier /etc/drbd.d/foo.res on supprime la section suivante correspondant au volume /dev/drbd45 :

volume 2 {
    device minor 45;
    disk /dev/sdz3;
    meta-disk internal;
}

On utilise ensuite drbdsetup sur chaque serveur avec le device minor correspondant au volume à supprimer :

tic# drbdsetup secondary 45
tic# drbdsetup detach 45
tic# drbdsetup del-minor 45

tac# drbdsetup secondary 45
tac# drbdsetup detach 45
tac# drbdsetup del-minor 45

Puis on applique cette nouvelle configuration (en observant avant en mode dry-run) :

tic# drbdadm -d adjust foo
tac# drbdadm -d adjust foo

tic# drbdadm adjust foo
tac# drbdadm adjust foo

passer une ressource en primary/secondary

Pour passer une ressource en primary ou secondary :

# drbdadm primary <ressource>
# drbdadm secondary <ressource>

Note : pour passer en primary il faut s’assurer d’utiliser le protocole C et d’avoir configuré allow-two-primaries;

Pour passer toutes les ressources en primary ou secondary :

# drbdadm primary all
# drbdadm secondary all

invalider une ressource

Si l’on considère qu’une ressource locale est out-of-sync on va l’invalider, ce qui provoque une resynchronisation immédiate depuis le serveur distant :

# drbdadm invalidate <ressource>

Note : on peut aussi utiliser drbdadm invalidate-remote pour invalider une ressource sur le serveur distant

déconnecter/connecter une ressource

Pour des raisons de maintenance, on peut déconnecter une ressource. Attention, il faudra alors éviter un split-brain (notamment ne pas écrire sur les deux serveurs) :

# drbdadm disconnect <ressource>
# drbdadm connect <ressource>

Note : pour toutes les ressources on pourra utiliser drbdadm disconnect all

Resize une ressource

Doc officielle : http://docs.linbit.com/doc/users-guide-84/s-resizing/

À chaud, après avoir étendu le block device associé au volume drbd (par exemple avec LVM).

# drbdadm resize <resource>

Changer le serveur secondaire

Dans le cas où on a besoin de changer la réplication de host1 → host2 à host1 → host3. Cette procédure se fait à chaud.

  • sur le nouveau secondaire, s’assurer de recréer le même block device (exactement de même taille) puis configurer la ressource DRBD comme pour une première configuration
  • sur les serveurs primaire et secondaire actuels, déconnecter la ressource :
# drbdadm detach <ressource>
# drbdadm disconnect <ressource>
  • sur le primaire, mettre à jour les informations de connexion du secondaire dans le fichier de ressource puis appliquer les changements et lancer la synchronisation vers le nouveau secondaire :
# drbdadm adjust all
# drbdadm attach <ressource>
# drbdadm -- --overwrite-data-of-peer primary <ressources>
  • sur l’ancien secondaire, le fichier de ressource peut être supprimé.

DRBD et systemd

Bien qu’il n’y ait pas de démon pour DRBD, il y a une unité systemd, mais son utilisation est déconseillée :

  • systemctl reload drbd fait un drbdadm adjust all : autant utiliser la commande soi-même (en la testant en dry-run avant)
  • systemctl start drbd fait tout d’abord un drbdadm adjust-with-progress all : si vous n’avez aucune ressource DRBD, cela échoue avec no resources defined! ; il fait ensuite drbdadm wait-connect all qui sera bloqué infiniment si vos serveurs secondaires ne sont pas encore opérationnels ; enfin, il tente de passer les ressources en Primary ce qu’il est plus prudent de faire manuellement
  • systemctl stop drbd est dangereux, il stoppe toutes les ressources en faisant drbdadm down all

DRBD et les filesystem

DRBD réalise une réplication au niveau bloc, il ne tient donc absolument pas compte du filesystem :

  • si l’on utilise un filesystem classique (ext4, btrfs etc.) il faut faire attention à ne jamais monter le filesystem à deux endroits à la fois
  • si l’on veut lire/écrire les données d’une ressource DRBD depuis les deux serveurs, il faut utiliser un filesystem réseau comme OCFS2 ou GFS2

Plomberie

https://www.drbd.org/en/doc/users-guide-84/p-learn

DRBD est un block device qui se met en proxy devant un périphérique de stockage pour intercepter les requêtes en écriture et les répliquer sur un périphérique distant via un lien réseau.

Architecture de DRBD

DRBD a besoin de metadatas : il les écrit en général à la fin du disque concerné (option meta-disk internal)… la taille du block device final est donc un peu plus petite que le disque concerné. Il peut aussi gérer ses metadatas à un autre emplacement, ce qui peut notamment servir à utiliser DRBD avec un disque sans le modifier.

Les metadatas DRBD contiennent :

  • la taille du volume DRBD
  • des Generation Identifiers (GI)
  • un Activity Log (AL) qui liste les blocs récemment écrits au cas où
  • Un quick-sync bitmap qui est une sorte de hash du volume DRBD pour optimiser la re-synchronisation

Les Generation Identifiers (GI) identifient le statut d’un volume DRBD. Concrètement il s’agit de plusieurs UUID auxquels on peut accéder via :

# drbdadm show-gi foo

       +--<  Current data generation UUID  >-
       |               +--<  Bitmap's base data generation UUID  >-
       |               |                 +--<  younger history UUID  >-
       |               |                 |         +-<  older history  >-
       V               V                 V         V
0283D46356ABF426:0000000000000000:E55525BF67DFF687:E55425BF67DFF687:1:1:0:1:0:0:0
                                                                    ^ ^ ^ ^ ^ ^ ^
                                      -<  Data consistency flag  >--+ | | | | | |
                             -<  Data was/is currently up-to-date  >--+ | | | | |
                                  -<  Node was/is currently primary  >--+ | | | |
                                  -<  Node was/is currently connected  >--+ | | |
         -<  Node was in the progress of setting all bits in the bitmap  >--+ | |
                        -<  The peer's disk was out-dated or inconsistent  >--+ |
      -<  This node was a crashed primary, and has not seen its peer since   >--+

flags: Secondary, Connected, UpToDate
meta-data: need apply-al

À propos des protocoles

Il est important de bien comprendre les 3 protocoles de réplication/synchronisation :

A : Réplication asynchrone. Les écritures sur le disque local du nœud primaire sont considérées complètes dès que le disque local a fini. Les paquets de réplication sont placés dans le buffer TCP.

B : Réplication synchronisée en mémoire. Les écritures sur le disque local du nœud primaire sont considérées complètes dès que le disque local a fini et que les paquets de réplication sont reçus sur le second nœud.

C : Réplication synchronisée sur les disques. Les écritures sur le disque local du nœud primaire sont considérées complètes dès que le disque local a fini et sur le disque distant aussi.

Le protocole C est donc le plus sécurisé mais ayant le plus d’impact sur les performances, le protocole A a les meilleures performances (comparables aux performances des disques locaux… si les buffers de réplication ne sont pas saturés) et le protocole B est un compromis entre les deux : il n’est ni sécurisé ni performant…

Bien comprendre /proc/drbd

http://www.octetmalin.net/linux/tutoriels/drbd-afficher-et-comprendre-les-differents-etats-des-disques.php

  • cs : Connection State (Connected/WFConnection/Unconnected/StandAlone/PausedSync/etc.)
  • ro : Resources roles (Primary/Secondary/Unknow)
  • ds : Disk States (UpToDate/Inconsistent/DUnknown/etc.)
  • A/B/C : Replication Protocol
  • r----- : I/O Flags [r/s][-/a][-/p][-/u][-/d/b/n/a][-/s]
  • ns nr dw dr al bm log pe ua ap ep wo oos : Performance indicators notamment ns/nr (network send/receive), dw/dr (disk write/read), oos (out of sync)

Exemples :

42: cs:WFConnection ro:Primary/Unknown ds:UpToDate/DUnknown C r-----

=> Le nœud attend une reconnexion avec le second serveur pour lui renvoyer les données (re-synchronisation).

42: cs:StandAlone ro:Primary/Unknown ds:UpToDate/DUnknown   r-----

=> Il s’agit d’un split-brain, le nœud est en standalone, et n’est plus synchronisé avec le second serveur.

42: cs:Connected ro:Primary/Primary ds:UpToDate/UpToDate C r-----

=> Les serveurs sont bien synchronisés.

42: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----                               
   ns:782997 nr:8388524 dw:10158853 dr:684557 al:456 bm:562 lo:0 pe:5 ua:64 ap:0 ep:1 wo:f oos:7780060
       [>…] sync'ed:  7.3% (7596/8188)Mfinish: 0:04:29 speed: 28,800 (28,964) K/sec

=> Une re-synchronisation est en cours vers le second serveur.

42: cs:SyncSource ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
   ns:73484284 nr:0 dw:64998220 dr:28984421 al:10100 bm:1287 lo:38 pe:20001 ua:0 ap:20001 ep:1 wo:d oos:0

=> Les serveurs sont bien synchronisés (en protocole C) mais un échange intensif de données est en cours, on le voit car les indicateurs pe: (pending) et ap: (application pending) sont à 20001, qui est le max-buffers/max-epoch-size dans ce cas.

Optimisations

disque

DRBD s’assure que les données sont écrites, et notamment que les données sont effectivement écrites sur le disque. Si l’on veut davantage de performance, on peut désactiver ces actions. On conseille notamment de le faire si l’on utilise une carte RAID hardware équipée d’une batterie :

disk {
    disk-barrier no;
    disk-flushes no;
    md-flushes no;
}

On peut synchroniser moins souvent les metadatas :

disk {
    al-extents 6433;
}

On peut aussi envisager de modifier le scheduler des disques concernés par DRBD de cfq à deadline et modifier certaines valeurs iosched/*.

réseau

Si possible, on peut activer les Jumbo Frames sur interfaces concernées par DRBD et tous les équipements intermédiaires :

# ifconfig eth4 mtu 9000

On peut augmenter les buffers de chaque volume :

net {
    max-buffers 8000;
    max-epoch-size 8000;
}

Choix du protocole

Le protocole C utilisé par défaut est le plus sécurisé, mais il implique qu’une donnée est considérée comme écrite si elle l’a été également sur le second serveur. Pour éviter cela on peut utiliser le protocole A ou B tout en gardant en tête que c’est risqué. Le plus performant (et le plus risqué) est protocol A;

Monitoring

Munin

Il existe un plugin Munin pour avoir des graphes disque/réseau pour chaque volume DRBD :

$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/drbd/drbd

Le plugin drbd nécessite a priori de tourner en root, /etc/munin/plugin-conf.d/munin-node :

[drbd]
user root

Nagios

On peut surveiller l’état des volumes DRBD via Nagios via https://exchange.nagios.org/directory/Plugins/Operating-Systems/Linux/check_drbd/details

/usr/local/lib/nagios/plugins/check_drbd -d All -c StandAlone

FAQ

Récupérer d’un split-brain

https://www.drbd.org/en/doc/users-guide-84/s-resolve-split-brain

Un split-brain signifie que des écritures ont été réalisées sur deux volumes primaires et désynchronisés, le seul moyen est de choisir manuellement un volume à réinitialiser !

Sur le serveur en Standalone qu’on veut réinitialiser :

# drbdadm secondary <ressource>
# drbdadm invalidate <ressource>
# drbdadm disconnect <ressource>
# drbdadm -- --discard-my-data connect <ressource>

Sur le serveur primaire où sont les données choisies comme valides :

# drbdadm connect <ressource>

Unrelated data, aborting

block drbd0: Unrelated data, aborting

Si l’on obtient ce message, c’est probablement que les metadatas ont été perdues sur un volume. Il faut alors les recréer…

Vérifier la configuration avec drbdadm verify ?

Attention drbdadm verify ne vérifie pas la configuration mais une vérification à chaud des volumes… à ne pas lancer à la légère en production !

Erreur Failure: (127) Device minor not allocated

Si l’on obtient une erreur du type :

42: Failure: (127) Device minor not allocated
additional info from kernel:
unknown minor
Command 'drbdsetup-84 verify 42' terminated with exit code 10

il faut créer le périphérique avec drbdsetup new-minor …ou plus simple avec drbdadm adjust.

Erreur Diskless

Si l’on obtient un état « Diskless » cela peut vouloir dire que la ressource n’est pas ou plus attachée.

Note : Une ressource peut être automatiquement détachée suite à des erreurs d’I/O.

42: cs:WFConnection ro:Primary/Unknown ds:Diskless/DUnknown C r-----
    ns:0 nr:932 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

On corrigera avec un drbdadm attach de la ressource en question.

Cela peut aussi être le cas avec un VG LVM qui serait activé sur un hyperviseur par exemple. On pourra le corriger avec un :

# vgchange -an /dev/<vgname>

Pour éviter que le noyau active le VG voir : https://wiki.evolix.org/HowtoLVM#filter-la-d%C3%A9tection-des-vg

Peut-on avoir plusieurs serveurs ?

Une ressource DRBD doit être définie entre deux serveurs, mais rien n’enpêche d’avoir d’autres ressources liées à différents serveurs.

Si l’on veut répliquer une ressource avec un troisième serveur, une solution est d’empiler deux réplications DRBD

États différents pour les volumes d’une ressource

Les volumes d’une même ressource sont-ils forcément dans le même état primary/secondary ?

Contrairement à ce que l’on pourrait penser, on peut très bien ajuster des volumes d’une même ressource dans des états différents :

tic# drbdsetup primary 43
tic# drbdsetup secondary 44
tac# drbdsetup secondary 43
tac# drbdsetup primary 44

# drbd-overview 
43:foo/0  Connected Primary/Secondary UpToDate/UpToDate 
44:foo/1  Connected Secondary/Primary UpToDate/UpToDate 

Note : cela nécessite d’utiliser le protocole C et d’avoir configuré allow-two-primaries;

Détruire les metadatas

Pour détruire les metadatas des volumes d’une ressource (attention, c’est évidemment dangereux) :

# drbdadm wipe-md <ressource>
Do you really want to wipe out the DRBD meta data?
[need to type 'yes' to confirm] yes

Wiping meta data...
DRBD meta data block successfully wiped out.

Migration rsync-like d’un disque existant avec DRBD

On peut migrer les données d’un disque existant en créant un volume DRBD avec des metadatas stockées en externe. Par exemple, Gitlab a migré 9To de données en quelques jours.

Voici la configuration d’un volume avec les metadatas en externe :

volume 0 {
    device minor 42;
    disk /dev/sdz1;
    meta-disk /dev/sdx1;
}

Note : meta-disk doit indiquer un périphérique d’une taille suffisante, on peut utiliser /dev/loop*

On démonte le disque, puis comme pour la création d’une ressource avec un seul volume on ajoute la configuration sur chaque serveur, puis on remonte le disque via DRBD (cela doit prendre quelques secondes) :

tic# umount /dev/sdz1
tic# drbdadm create-md foo
tic# drbdadm adjust foo
tic# mount /dev/drbd42 /mnt

On prépare ensuite le second serveur, puis on démarre la réplication depuis le premier serveur :

tac# drbdadm create-md foo
tac# drbdadm adjust foo

tic# drbdadm -- --overwrite-data-of-peer primary foo

La synchronisation va ensuite se faire (et prendre du temps suivant le volume).

Une fois terminé, on pourra choisir son moment pour démounter le disque en production et remounter le volume sans DRBD sur le second serveur (on peut ensuite supprimer tout ce qui est relatif à DRBD) :

tic# umount /dev/drbd42
tic# drbadm secondary foo
tic# drbadm down foo
tic# rm /etc/drbd.d/foo.res

tac# drbadm down foo
tac# mount /dev/sdz1 /mnt
tac# rm /etc/drbd.d/foo.res

Réplication sans synchronisation de données initiales

Une fois les nœuds connectés, au lieu de faire --overwrite-data-of-peer sur l’un des serveurs :

tic# drbdadm -- --clear-bitmap new-current-uuid foo
tic# drbdadm primary foo

Réplication truck-base

Plus fort que l’IPoAC, DRBD décrit la réplication truck-based

Supprimer DRBD 9.0

Vous pouvez vouloir supprimer DRBD pour changer sa version (downgrade ou changement majeur). Pour ce faire:

Arrêter et désactiver les services DRBD

sudo systemctl stop drbd
sudo systemctl disable drbd

Décharger les modules DRBD

sudo rmmod drbd

Si le module DRBD ne peut pas être déchargé, cela peut être dû au fait qu’il est en cours d’utilisation. Assurez-vous qu’aucun service ou processus n’utilise DRBD.

Supprimez le fichier du module DRBD manuellement :

sudo rm /lib/modules/$(uname -r)/kernel/drivers/block/drbd.ko (ou .../block/drbd/drbd.ko)

Mettre à jour les dépendances des modules

sudo depmod -a

Désinstallez les packages DRBD :

sudo apt-get remove --purge drbd-utils drbd8-module-source (drbd-module-source pour DRBD9)

Nettoyer les fichiers de configuration restants

sudo find /etc -name "*drbd*" -exec rm -rf {} \;
sudo find /var -name "*drbd*" -exec rm -rf {} \;

Vérifier la suppression

Vérifiez que le module DRBD a bien été supprimé :

ls /lib/modules/$(uname -r)/kernel/drivers/block/ | grep drbd

Redémarrez pour vous assurer que toutes les modifications sont prises en compte.