Przejdź do treści
Administracja·~31 min czytania

Multipath w Linuksie: jeden dysk iSCSI przez dwie ścieżki, awaria i powrót ścieżki

Dlaczego macierz podłączona dwoma kablami pokazuje się jako dwa dyski, jak sprawić, żeby znów był jeden, i co naprawdę dzieje się z zapisem, gdy ścieżka padnie.

Autor: Zespół LinuxLab

Wszędzie tam, gdzie dane leżą na macierzy, a nie w serwerze, pojawia się to samo pytanie: co się stanie, gdy padnie kabel, przełącznik albo kontroler. Odpowiedzią jest podłączenie macierzy więcej niż jedną drogą - i mechanizm, który potrafi te drogi ze sobą powiązać. W Linuksie odpowiada za to multipath.

Ten artykuł dokumentuje historyczny test z 11 września 2026: dwa portale iSCSI na jednej maszynie wirtualnej, klient widzący jeden wolumin jako dwa urządzenia i mapa multipath, która je scala. Następnie odcięto jeden portal podczas zapisu, a potem oba. Wydruki są zapisem tamtego testu, nie bieżącym stanem infrastruktury: 18 września 2026 host bm-lab-01 i sześć VM labu nie miały nasłuchu TCP/3260 ani map multipath. Na części obrazów Ubuntu działał multipathd, ale bez map.

Spis treści

  1. Czym jest multipath w Linuksie i po co łączyć serwer z macierzą kilkoma ścieżkami
  2. Stanowisko testowe iSCSI z dwiema ścieżkami i wyniki w skrócie
  3. Budowa stanowiska: macierz iSCSI na Debianie 13 z targetcli
  4. Budowa stanowiska: klient z open-iscsi i multipath-tools
  5. Na jakich portach działa iSCSI, a na jakich multipath
  6. Jeden dysk iSCSI widoczny jako dwa urządzenia sda i sdb
  7. Skąd się biorą urządzenia sda i sdb przy dwóch sesjach iSCSI
  8. Po czym poznać, że sda i sdb to ten sam dysk: identyfikator nadany przez macierz
  9. Uruchomienie multipath krok po kroku i pułapka braku map
  10. Jak czytać multipath -ll
  11. Test awarii jednej ścieżki: co widzą system plików i aplikacja
  12. Powrót ścieżki po awarii bez ingerencji administratora
  13. Co się dzieje, gdy padną wszystkie ścieżki: queue_if_no_path
  14. Polityki wyboru ścieżki w multipath: round-robin, queue-length i service-time
  15. Czego multipath nie robi: nie zastępuje kopii zapasowej ani nadmiarowości danych
  16. Checklista uruchomienia i diagnostyki multipath z iSCSI
  17. Podsumowanie: cztery zachowania multipath, które zaskakują za pierwszym razem

Czym jest multipath w Linuksie i po co łączyć serwer z macierzą kilkoma ścieżkami

Wyobraź sobie serwer i macierz dyskową połączone dwoma niezależnymi drogami - dwoma kartami, dwoma przełącznikami, dwoma kontrolerami po stronie macierzy. Robi się tak z jednego powodu: żeby awaria dowolnego elementu po drodze nie odcięła serwera od danych.

Problem w tym, że system operacyjny nie wie o zamyśle. Każdą drogę wykrywa osobno i dla każdej tworzy osobne urządzenie blokowe. Dwa kable do jednego dysku dają dwa dyski w systemie - i gdyby zamontować oba naraz, system plików zostałby uszkodzony, bo dwa niezależne wejścia zapisywałyby te same bloki.

Multipath rozwiązuje dokładnie ten problem. Rozpoznaje, że kilka urządzeń to w rzeczywistości jeden dysk, i tworzy nad nimi jedno urządzenie zbiorcze. To urządzenie zbiorcze wraz z listą prowadzących do niego dróg nazywa się mapą wielościeżkową - i tym słowem, w skrócie "mapa", będziemy się dalej posługiwać, bo tak nazywają je same narzędzia. Od tej chwili system operacyjny widzi jeden dysk, a multipath decyduje, którą drogą przesłać każdą operację - i przełącza się na sprawną, gdy jedna przestaje odpowiadać.

Mechanizm działa w device-mapper, czyli w tej samej warstwie jądra, która obsługuje szyfrowanie dysków i menedżera woluminów. Obsługują go dwa elementy: usługa multipathd, która na bieżąco pilnuje stanu ścieżek, oraz polecenie multipath do oglądania i zmiany konfiguracji.

Multipath to nie jest kopia danych. Dane leżą w jednym miejscu - na macierzy. Zwielokrotnione są wyłącznie drogi do nich. Jeżeli awarii ulegnie sama macierz albo dysk w niej, multipath nie pomoże w niczym; od tego są kopie zapasowe i mechanizmy nadmiarowości po stronie macierzy. Multipath chroni przed awarią połączenia, nie przed utratą danych.

Stanowisko testowe iSCSI z dwiema ścieżkami i wyniki w skrócie

Zanim przejdziemy do szczegółów: z czego złożone jest stanowisko testowe i co na nim wyszło. Kto woli od razu zobaczyć polecenia, może tę sekcję pominąć - dalej wszystko jest rozpisane krok po kroku.

Historyczne stanowisko składało się z dwóch maszyn wirtualnych w jednej sieci. Pierwsza udawała macierz: udostępniała dysk przez iSCSI (od angielskiego Internet Small Computer System Interface), czyli protokół podający urządzenie blokowe po sieci. Druga była klientem. Dwa portale pod dwoma adresami na tej samej karcie sieciowej VM utworzyły dwie sesje iSCSI. Taki układ pozwala sprawdzić utratę portalu, ale nie niezależność kart, przełączników ani kontrolerów.

Z czego zbudowaliśmy stanowisko testowe

To nie są pomiary, tylko konfiguracja użyta w historycznym teście:

ElementKonfiguracja
MacierzDebian 13, targetcli-fb 1:2.1.53-1.3, adresy 192.168.123.226 i 192.168.123.240
KlientDebian 12, open-iscsi 2.1.8-1, multipath-tools 0.9.4-3+deb12u2, adres 192.168.123.220
Woluminplik /srv/iscsi/lun0.img o wielkości 256 MB
Drogidwa wejścia do tego samego magazynu, pod dwoma adresami

Co pokazało stanowisko testowe

Tu z kolei jest wyłącznie to, co stanowisko pokazało - każdy wiersz ma swój wydruk w dalszej części artykułu. Pomiary wykonaliśmy 11 września 2026:

SprawdzenieWynik
Ile urządzeń widzi klientdwa, sda i sdb, oba 256 MB, ten sam producent i model
Czy identyfikatory obu urządzeń są zgodnetak, identyczne: 360014058dd8a6a3ef4943f4876db1b69
Czy multipath sam połączył je w jednonie - powstrzymało go domyślne ustawienie find_multipaths strict
Co powstało po skonfigurowaniujedno urządzenie mpatha (dm-0), dwie ścieżki active ready
Co się dzieje przy awarii jednej ścieżkiodczyt, zapis i sync działały bez przerwy; ścieżka oznaczona failed faulty
Jak szybko ścieżka wraca po naprawieautomatycznie, 8-10 sekund od przywrócenia łączności
Co się dzieje, gdy padną wszystkie ścieżkizapis zablokowany, nie przerwany błędem; po powrocie dokończył się

Czego na stanowisku nie sprawdzaliśmy

Nie sprawdzaliśmy prawdziwego sprzętu z dwoma kontrolerami, awarii niezależnej karty sieciowej lub przełącznika, zachowania przy więcej niż dwóch ścieżkach ani pracy z macierzami wymagającymi własnych ustawień producenta. Oba portale korzystały z jednej karty VM, więc test nie potwierdza odporności na awarię wspólnego elementu. Mechanizm jest ten sam, ale liczby i czasy na prawdziwym sprzęcie będą inne.

Budowa stanowiska: macierz iSCSI na Debianie 13 z targetcli

Zanim na kliencie pojawią się sda i sdb, ktoś musi je udostępnić. Tę rolę pełni tu Debian 13 z pakietem targetcli-fb - narzędziem do konfigurowania wbudowanego w jądro Linuksa celu iSCSI (w terminologii protokołu: target).

W prawdziwym środowisku w tym miejscu stoi macierz dyskowa i tych poleceń się nie wykonuje - konfiguruje się ją własnym interfejsem producenta. Ta sekcja istnieje po to, żeby całość dało się odtworzyć bez macierzy, na dwóch maszynach wirtualnych.

Zanim przejdziemy do poleceń, pięć słów, które będą się przewijać przez cały artykuł. Warto je znać, bo narzędzia posługują się nimi bez tłumaczenia:

  • Cel (w narzędziach: target) - strona, która udostępnia dysk. U nas Debian 13; w firmie byłaby to macierz.
  • Inicjator (initiator) - strona, która się podłącza i korzysta z dysku, czyli klient. U nas Debian 12.
  • Portal - logiczny punkt dostępu: adres i numer portu, pod którymi cel jest osiągalny. Dwa portale mogą utworzyć dwie sesje, lecz same nie dowodzą niezależnej ścieżki awarii.
  • LUN (od angielskiego Logical Unit Number) - numer, pod którym cel wystawia konkretny wolumin. Jeden cel może udostępniać wiele woluminów, każdy pod swoim numerem.
  • Backstore - to, co po stronie celu faktycznie przechowuje dane: prawdziwy dysk, wolumin logiczny albo, jak u nas, zwykły plik.
$ sudo apt-get install -y targetcli-fb

Krok 1: plik, który udaje dysk. Nie jest potrzebny osobny wolumin - wystarczy zwykły plik. Polecenie truncate tworzy go natychmiast, bez zapisywania 256 MB zer:

$ sudo mkdir -p /srv/iscsi
$ sudo truncate -s 256M /srv/iscsi/lun0.img

Krok 2: backstore - wskazujemy celowi, że to właśnie ten plik ma odtąd udawać dysk i przechowywać dane:

$ sudo targetcli /backstores/fileio create name=dysk0 file_or_dev=/srv/iscsi/lun0.img size=256M
/srv/iscsi/lun0.img exists, using its size (268435456 bytes) instead
Created fileio dysk0 with size 268435456

Krok 3: cel (target) i jego nazwa. Nazwa w protokole iSCSI ma ustalony format zwany IQN (od angielskiego iSCSI Qualified Name): człon iqn., rok i miesiąc, odwrócona nazwa domeny, dwukropek i dowolna nazwa własna. Domena ma być taka, którą naprawdę się włada - to jedyny sposób, żeby nazwy były niepowtarzalne na świecie:

$ sudo targetcli /iscsi create iqn.2026-09.pl.linuxlab.lab:magazyn0
Created target iqn.2026-09.pl.linuxlab.lab:magazyn0.
Created TPG 1.
Global pref auto_add_default_portal=true
Created default portal listening on all IPs (0.0.0.0), port 3260.

W ścieżkach poleceń zaraz pojawi się człon tpg1. To skrót od angielskiego Target Portal Group, czyli grupy wejść obsługujących ten sam cel. Przy zwykłej konfiguracji grupa jest jedna i nosi numer 1 - wystarczy wiedzieć, że to stały element ścieżki, a nie coś, co trzeba osobno tworzyć.

Krok 4: LUN - podpięcie magazynu (w targetcli: backstore) pod cel, czyli nadanie woluminowi numeru, pod którym zobaczy go klient:

$ sudo targetcli /iscsi/iqn.2026-09.pl.linuxlab.lab:magazyn0/tpg1/luns create /backstores/fileio/dysk0
Created LUN 0.

Krok 5: dwa portale testowe. Maszyna dostaje drugi adres na tej samej karcie. Pozwala to odtworzyć utratę jednego portalu iSCSI, ale nie jest odpowiednikiem drugiego kontrolera: oba portale nadal zależą od tej samej karty VM, sieci i hosta.

$ sudo ip addr add 192.168.123.240/24 dev enp1s0

Adres dodany poleceniem ip addr add nie przetrwa restartu. Na stanowisku testowym to zaleta - wystarczy ponowne uruchomienie, żeby wrócić do stanu wyjściowego. Do trwałej konfiguracji służy plik /etc/network/interfaces albo systemd-networkd, zależnie od tego, co zarządza siecią w danym systemie.

W zapisanej konfiguracji z ustawieniem auto_add_default_portal=true krok 3 utworzył jeden nasłuch na wszystkich adresach (0.0.0.0, w targetcli nazywany wildcard). Nie definiuje on dwóch jawnych rekordów portali. Do tego testu najpierw sprawdziliśmy wynik przez targetcli ls, a potem usunęliśmy ten nasłuch i utworzyliśmy dwa portale, każdy przypisany do konkretnego adresu:

$ T=iqn.2026-09.pl.linuxlab.lab:magazyn0
$ sudo targetcli /iscsi/$T/tpg1/portals delete 0.0.0.0 3260
Deleted network portal 0.0.0.0:3260

$ sudo targetcli /iscsi/$T/tpg1/portals create 192.168.123.226 3260
Created network portal 192.168.123.226:3260.

$ sudo targetcli /iscsi/$T/tpg1/portals create 192.168.123.240 3260
Created network portal 192.168.123.240:3260.

Krok 6: kto ma prawo się podłączyć. Cel nie wpuszcza kogokolwiek - listę uprawnionych tworzą wpisy ACL (od angielskiego Access Control List), a klienta identyfikuje jego własny IQN. Skąd go wziąć, pokazujemy w następnej sekcji; tutaj jest już podstawiony:

$ sudo targetcli /iscsi/$T/tpg1/acls create iqn.1993-08.org.debian:01:51cf2a72f4a
Created Node ACL for iqn.1993-08.org.debian:01:51cf2a72f4a
Created mapped LUN 0.

Zwróćmy uwagę na drugą linię: wraz z wpisem ACL powstało przypisanie LUN-u do tego konkretnego klienta. Bez tego klient owszem nawiązałby sesję z celem, ale nie zobaczyłby żadnego dysku - to częsta przyczyna pustego lsblk mimo komunikatu o powodzeniu.

Krok 7: zapis konfiguracji. Bez tego wszystko powyżej zniknie po restarcie, bo konfiguracja celu żyje w jądrze:

$ sudo targetcli saveconfig
Last 10 configs saved in /etc/rtslib-fb-target/backup/.
Configuration saved to /etc/rtslib-fb-target/saveconfig.json

Całość można teraz obejrzeć jednym poleceniem. Ten wydruk warto przeczytać uważnie, bo widać na nim wszystkie elementy naraz:

$ sudo targetcli ls
o- / ......................................................... [...]
  o- backstores .............................................. [...]
  | o- fileio ................................. [Storage Objects: 1]
  | | o- dysk0 ...... [/srv/iscsi/lun0.img (256.0MiB) write-back activated]
  | |   o- alua ................................... [ALUA Groups: 1]
  | |     o- default_tg_pt_gp ....... [ALUA state: Active/optimized]
  o- iscsi ............................................ [Targets: 1]
  | o- iqn.2026-09.pl.linuxlab.lab:magazyn0 .............. [TPGs: 1]
  |   o- tpg1 ............................... [no-gen-acls, no-auth]
  |     o- acls .......................................... [ACLs: 1]
  |     | o- iqn.1993-08.org.debian:01:51cf2a72f4a . [Mapped LUNs: 1]
  |     |   o- mapped_lun0 ............ [lun0 fileio/dysk0 (rw)]
  |     o- luns .......................................... [LUNs: 1]
  |     | o- lun0 ... [fileio/dysk0 (/srv/iscsi/lun0.img) (default_tg_pt_gp)]
  |     o- portals .................................... [Portals: 2]
  |       o- 192.168.123.226:3260 ......................... [OK]
  |       o- 192.168.123.240:3260 ......................... [OK]

Dwa wiersze są tu ważne dla dalszej części artykułu. Portals: 2 oznacza dwa jawne logiczne punkty dostępu; w tym labie pozwoliły utworzyć dwie sesje, ale nie były niezależnymi drogami sprzętowymi. A wpis ALUA state: Active/optimized dotyczy mechanizmu ALUA (od angielskiego Asymmetric Logical Unit Access) - sposobu, w jaki macierz informuje klienta, które ścieżki do danego woluminu są dla niej preferowane, a które zapasowe. Cel ogłasza tę informację z własnej inicjatywy, a multipath ją podchwytuje; zobaczymy ją potem na kliencie jako hwhandler='1 alua'.

Budowa stanowiska: klient z open-iscsi i multipath-tools

Na kliencie potrzebne są dwa pakiety: open-iscsi do samego protokołu i multipath-tools do scalania ścieżek.

$ sudo apt-get install -y open-iscsi multipath-tools

Instalacja open-iscsi nadaje maszynie własny IQN - to ten identyfikator, który wpisaliśmy na macierzy w kroku 6:

$ cat /etc/iscsi/initiatorname.iscsi
## DO NOT EDIT OR REMOVE THIS FILE!
## If you remove this file, the iSCSI daemon will not start.
InitiatorName=iqn.1993-08.org.debian:01:51cf2a72f4a

Teraz wykrywamy cele. W tym czystym historycznym labie zapytanie jednego adresu zwróciło oba jawne portale. Wynik discovery zawsze trzeba jednak traktować jako źródło prawdy dla danego celu:

$ sudo iscsiadm -m discovery -t sendtargets -p 192.168.123.226
192.168.123.226:3260,1 iqn.2026-09.pl.linuxlab.lab:magazyn0
192.168.123.240:3260,1 iqn.2026-09.pl.linuxlab.lab:magazyn0

Jedno pytanie, dwie odpowiedzi - dwa portale, do których można utworzyć osobne sesje. Zapytanie drugiego adresu dało ten sam wynik. Gdyby lista zawierała tylko jeden wiersz, w tym stanowisku multipath nie miałby czego scalać; przyczyny należałoby szukać w konfiguracji portali na macierzy.

Kolejny krok narzędzia nazywają logowaniem - i to jest określenie mylące, więc warto je od razu wyjaśnić. Nie chodzi o podanie nazwy użytkownika ani hasła. W protokole iSCSI "logowanie" to nazwa etapu, na którym klient nawiązuje sesję: otwiera połączenie do wskazanego adresu i uzgadnia z celem parametry dalszej pracy. Dopiero po tym cel pokazuje mu swoje woluminy.

Hasło może się na tym etapie pojawić - służy do tego mechanizm CHAP (od angielskiego Challenge-Handshake Authentication Protocol) - ale domyślnie go nie ma i w tym teście go nie włączaliśmy. CHAP uwierzytelnia klienta względem celu, a w wariancie wzajemnym także cel względem klienta; nie szyfruje ruchu iSCSI. W wydruku targetcli ls z poprzedniej sekcji przy tpg1 stoi no-auth, czyli uwierzytelnianie było wyłączone. Dostępu pilnowała wyłącznie lista ACL z kroku 6, czyli sprawdzenie, czy klient przedstawia się znanym IQN.

Na czystym kliencie historyczne polecenie bez dodatkowych argumentów zalogowało się do obu rekordów node. Na systemie z istniejącą bazą node-records trzeba wskazać cel i portal jawnie:

$ T=iqn.2026-09.pl.linuxlab.lab:magazyn0
$ for portal in 192.168.123.226:3260 192.168.123.240:3260; do
>   sudo iscsiadm -m node -T "$T" -p "$portal" --login
> done
Logging in to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.240,3260]
Logging in to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.226,3260]
Login to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.240,3260] successful.
Login to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.226,3260] successful.

Powstały dwie sesje - po jednej do każdego portalu:

$ sudo iscsiadm -m session
tcp: [3] 192.168.123.240:3260,1 iqn.2026-09.pl.linuxlab.lab:magazyn0 (non-flash)
tcp: [4] 192.168.123.226:3260,1 iqn.2026-09.pl.linuxlab.lab:magazyn0 (non-flash)

Po restarcie sesje nie wrócą same. Domyślnie węzeł ma node.startup = manual, co można sprawdzić poleceniem iscsiadm -m node -T <IQN> -p <adres> -o show. Żeby klient logował się przy starcie systemu, trzeba to zmienić na automatic - i dopiero wtedy ma sens wpisywanie woluminu do /etc/fstab.

Na jakich portach działa iSCSI, a na jakich multipath

Warto wiedzieć dokładnie, co się z czym łączy - choćby po to, żeby ustawić zaporę i nie szukać potem godzinami, dlaczego jedna ścieżka nie wstaje.

iSCSI używa portu TCP 3260. Ma on nawet własną nazwę w systemowym spisie usług:

$ grep '^iscsi' /etc/services
iscsi-target	3260/tcp

Po stronie macierzy każdy portal to osobny nasłuch na swoim adresie. Dwa wiersze pokazują dwa logiczne punkty dostępu, nie niezależne ścieżki sprzętowe:

$ sudo ss -ltnp | grep 3260
LISTEN 0 256  192.168.123.226:3260  0.0.0.0:*
LISTEN 0 256  192.168.123.240:3260  0.0.0.0:*

Po stronie klienta jest odwrotnie - nic nie nasłuchuje. Usługa iscsid wyłącznie nawiązuje połączenia wychodzące, po jednym do każdego portalu:

$ sudo ss -tnp | grep 3260
ESTAB 0 0  192.168.123.220:45796  192.168.123.226:3260  users:(("iscsid",pid=216704,fd=7))
ESTAB 0 0  192.168.123.220:53854  192.168.123.240:3260  users:(("iscsid",pid=216704,fd=8))

Te dwa połączenia pokazują dwie odrębne sesje TCP do tego samego woluminu. W tym labie nie były jednak niezależnymi torami sprzętowymi, bo oba portale korzystały z tej samej karty VM. Kiedy w dalszej części artykułu odetniemy jeden portal, zniknie dokładnie jeden z tych wierszy.

A jakiego portu używa sam multipath? Nie zajmuje żadnego portu sieciowego. Działa wyłącznie lokalnie, a z narzędziami wiersza poleceń rozmawia przez gniazdo domenowe systemu Unix:

$ sudo ss -lxp | grep multipath
u_str LISTEN 0 10  @/org/kernel/linux/storage/multipathd  users:(("multipathd",pid=216864,fd=5))

Wynika z tego prosta reguła dla zapory:

  • Na macierzy otworzyć port 3260/tcp - i to najlepiej wyłącznie dla adresów klientów, którzy mają prawo się łączyć.
  • Na kliencie nie trzeba otwierać portu nasłuchującego. Jeżeli zapora blokuje ruch wychodzący, dopuść TCP/3260 do portali celu oraz odpowiedzi na nawiązane połączenia.
  • Dla multipath nie trzeba otwierać niczego w ogóle - to mechanizm lokalny.

Warto też pamiętać, że sam protokół iSCSI domyślnie nie szyfruje przesyłanych danych. CHAP uwierzytelnia klienta, a w wariancie wzajemnym także cel, lecz nie zapewnia poufności. Dla danych przesyłanych przez niezaufaną sieć potrzebna jest segmentacja sieci i/lub IPsec; żadne z tych zabezpieczeń nie było elementem opisanego testu.

Jeden dysk iSCSI widoczny jako dwa urządzenia sda i sdb

Wracamy do klienta. Zanim nawiązał sesje z macierzą, widać było tylko jego własne dyski wirtualne:

$ lsblk -d -o NAME,SIZE,TYPE,VENDOR,MODEL
NAME  SIZE TYPE VENDOR   MODEL
vda    10G disk 0x1af4
vdb   366K disk 0x1af4

Po nawiązaniu sesji z obydwoma adresami pojawia się problem, dla którego istnieje multipath:

$ lsblk -d -o NAME,SIZE,TYPE,VENDOR,MODEL
NAME  SIZE TYPE VENDOR   MODEL
sda   256M disk LIO-ORG  dysk0
sdb   256M disk LIO-ORG  dysk0
vda    10G disk 0x1af4
vdb   366K disk 0x1af4

Widać dwa dyski po 256 MB tego samego producenta i modelu. To nie są dwa magazyny - to jeden, pokazany dwa razy, bo prowadzą do niego dwie sesje. Gdyby ktoś teraz utworzył system plików na sda, a potem zamontował sdb i też zaczął pisać, dane zostałyby uszkodzone, bo obie nazwy prowadzą do tych samych bloków.

Warto zauważyć, że LIO-ORG w kolumnie producenta to nie jest żadna firma. Tak przedstawia się implementacja celu iSCSI wbudowana w jądro Linuksa, nazywana LIO - czyli u nas po prostu druga maszyna wirtualna. Prawdziwa macierz pokaże w tym miejscu swojego producenta i model, ale mechanizm jest identyczny.

Skąd się biorą urządzenia sda i sdb przy dwóch sesjach iSCSI

To jest pytanie, które warto zadać, bo odpowiedź tłumaczy całą resztę. Żadne polecenie ich nie tworzy. Nie ma kroku, w którym administrator wywołuje mknod albo cokolwiek innego - urządzenia pojawiają się same, jako skutek zalogowania do portalu, i znikają, gdy się wylogować.

Zacznijmy od stanu wyjściowego. Klient nie ma ani jednego urządzenia SCSI - to skrót od angielskiego Small Computer System Interface, standardu, którym system porozumiewa się z dyskami; iSCSI to po prostu ten sam zestaw poleceń przesyłany po sieci:

$ ls /sys/class/scsi_host/
(pusto)

$ ls /dev/sd*
ls: cannot access '/dev/sd*': No such file or directory

Teraz nawiązujemy sesję z jednym tylko adresem macierzy - czyli otwieramy jedną z dwóch dróg. Służy do tego to samo polecenie co wyżej, ale ze wskazaniem konkretnego celu i adresu:

$ sudo iscsiadm -m node -T iqn.2026-09.pl.linuxlab.lab:magazyn0 -p 192.168.123.226 --login
Login to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.226,3260] successful.

$ ls /sys/class/scsi_host/
host0

$ ls /dev/sd*
/dev/sda

Jedna sesja - i pojawił się jeden host SCSI oraz jedno urządzenie. "Host SCSI" to w nazewnictwie jądra tyle, co jeden kanał, przez który system rozmawia z dyskami - odpowiednik pojedynczego kontrolera dyskowego. Przy dyskach wpinanych w płytę główną host odpowiada fizycznemu kontrolerowi; przy iSCSI powstaje jeden host na każdą sesję sieciową.

Otwieramy teraz drugą drogę, czyli sesję z drugim adresem:

$ sudo iscsiadm -m node -T iqn.2026-09.pl.linuxlab.lab:magazyn0 -p 192.168.123.240 --login
Login to [iface: default, target: iqn.2026-09...:magazyn0, portal: 192.168.123.240,3260] successful.

$ ls /sys/class/scsi_host/
host0
host1

$ ls /dev/sd*
/dev/sda
/dev/sdb

Druga sesja dała drugi host SCSI i drugie urządzenie. Zależność jest dokładnie taka: jedna sesja iSCSI = jeden host SCSI = jedno urządzenie blokowe na każdy udostępniony wolumin. Potwierdza to szczegółowy widok sesji, gdzie widać całe powiązanie naraz:

$ sudo iscsiadm -m session -P 3 | grep -E 'Current Portal:|Host Number:|Attached scsi disk'
Current Portal: 192.168.123.226:3260,1
	Host Number: 0	State: running
	Attached scsi disk sda		State: running
Current Portal: 192.168.123.240:3260,1
	Host Number: 1	State: running
	Attached scsi disk sdb		State: running

Każdy wiersz opisuje jedną drogę: portal, numer hosta i nazwę urządzenia. Stąd biorą się też adresy SCSI widoczne w multipath -ll. Zapis 0:0:0:0 i 1:0:0:0 to cztery liczby: host, kanał, cel i numer LUN. Różni się tylko pierwsza, bo hosty są dwa; wolumin jest ten sam, więc LUN w obu przypadkach wynosi 0.

Najczytelniej widać to w dowiązaniach tworzonych przez udev - usługę, która pilnuje zawartości katalogu /dev i dla każdego wykrytego urządzenia zakłada dodatkowe nazwy opisowe. W samej nazwie jest adres, pod którym poszło połączenie, nazwa celu i numer LUN-u:

$ ls -l /dev/disk/by-path/ | grep iscsi
ip-192.168.123.226:3260-iscsi-iqn.2026-09.pl.linuxlab.lab:magazyn0-lun-0 -> ../../sda
ip-192.168.123.240:3260-iscsi-iqn.2026-09.pl.linuxlab.lab:magazyn0-lun-0 -> ../../sdb

Ten sam cel i ten sam lun-0 przez dwa różne adresy dały dwa urządzenia. Cała dwuznaczność, którą naprawia multipath, mieści się w tej jednej różnicy.

Działa to symetrycznie. Zamknięcie jednej sesji usuwa jej host i jej urządzenie:

$ sudo iscsiadm -m node -T iqn...:magazyn0 -p 192.168.123.240 --logout
$ ls /sys/class/scsi_host/
host0
$ ls /dev/sd*
/dev/sda

Kto tworzy pliki urządzeń w katalogu /dev

Skoro pliku nie tworzy administrator, to kto? Katalog /dev nie jest zwykłym katalogiem na dysku - to system plików zarządzany przez jądro:

$ mount | grep ' /dev type'
udev on /dev type devtmpfs (rw,nosuid,relatime,size=979748k,...)

Kolejność zdarzeń jest więc taka: sesja iSCSI rejestruje w jądrze host SCSI; jądro pyta cel o listę LUN-ów; dla każdego znalezionego woluminu powstaje urządzenie SCSI; przejmuje je sterownik sd (od SCSI disk) i nadaje mu pierwszą wolną nazwę z serii sda, sdb, sdc; na końcu devtmpfs tworzy plik w /dev, a udev dokłada dowiązania w /dev/disk/. Sterownik można sprawdzić wprost:

$ basename $(readlink -f /sys/block/sda/device/driver)
sd

Z tego bierze się też para liczb, którą zobaczymy później w wyniku multipath -ll jako sda 8:0 i sdb 8:16. Pierwsza z nich, numer główny, wskazuje jądru sterownik obsługujący urządzenie - i numer 8 należy właśnie do sterownika sd:

$ grep -E '^ *8 ' /proc/devices
  8 sd

Dlaczego mknod tu nie pomoże. Polecenie mknod tworzy wpis wskazujący na parę numerów, a nie urządzenie. Jeżeli za tymi numerami nic nie stoi, wpis jest pusty w środku:

$ sudo mknod /tmp/niby-sdz b 8 240
$ ls -l /tmp/niby-sdz
brw-r--r-- 1 root root 8, 240 /tmp/niby-sdz

$ sudo dd if=/tmp/niby-sdz of=/dev/null bs=512 count=1
dd: failed to open '/tmp/niby-sdz': No such device or address

Plik jest, prawa się zgadzają, numery też - a odczytu nie ma, bo nie ma urządzenia. Dysk tworzy sterownik w jądrze, nie wpis w katalogu.

Z tego wynika jeszcze jedna rzecz, ważna dla całego artykułu. Nazwy sda i sdb to kolejność przydzielania, a nie tożsamość. Przy następnym uruchomieniu sesje mogą wstać w innej kolejności i ten sam wolumin dostanie inną literę. Dlatego multipath nie może opierać się na nazwach - i dlatego w następnej sekcji szukamy czegoś, co należy do samego woluminu.

Po czym poznać, że sda i sdb to ten sam dysk: identyfikator nadany przez macierz

Nie trzeba tego zgadywać z rozmiaru i modelu. Każde urządzenie blokowe ma identyfikator nadany przez macierz - w świecie multipath nazywany WWID, od angielskiego World Wide Identifier. Jest unikalny dla konkretnego woluminu i taki sam niezależnie od drogi, którą się do niego dotrze:

$ sudo /lib/udev/scsi_id -g -u -d /dev/sda
360014058dd8a6a3ef4943f4876db1b69

$ sudo /lib/udev/scsi_id -g -u -d /dev/sdb
360014058dd8a6a3ef4943f4876db1b69

Identyczny ciąg znaków na obu urządzeniach to dowód, że mamy do czynienia z jednym woluminem. To jest cała podstawa działania multipath - mechanizm nie zgaduje po nazwach ani rozmiarach, tylko grupuje urządzenia według tego identyfikatora.

Identyfikator jest przypisany do woluminu, nie do maszyny. Gdyby na macierzy usunąć backstore i utworzyć go od nowa, powstałby nowy wolumin z nowym identyfikatorem - a wcześniejszy wpis w konfiguracji multipath przestałby do czegokolwiek pasować.

Praktyczna konsekwencja: jeżeli macierz z jakiegoś powodu podaje różne identyfikatory różnymi drogami, multipath nie połączy ścieżek. Dlatego przy problemach to jest pierwsza rzecz do sprawdzenia - zanim zacznie się grzebać w konfiguracji.

Uruchomienie multipath krok po kroku i pułapka braku map

Tu czeka niespodzianka, która potrafi zabrać sporo czasu. Po instalacji pakietu usługa multipathd działa, urządzenia są widoczne, identyfikatory się zgadzają - a mapy nie ma:

$ systemctl is-active multipathd
active

$ sudo multipath -ll
(nic)

Przyczyna siedzi w domyślnym ustawieniu:

$ sudo multipathd show config | grep find_multipaths
	find_multipaths "strict"

W trybie strict multipath obsługuje wyłącznie urządzenia wpisane wcześniej na listę. Nowego dysku nie doda z własnej inicjatywy, nawet gdy widzi do niego dwie drogi. Jest to zachowanie celowe - chroni przed przypadkowym przejęciem dysku systemowego - ale dla kogoś, kto uruchamia multipath pierwszy raz, wygląda jak awaria.

Uruchomienie sprowadza się do trzech kroków. Najpierw plik konfiguracyjny, którego po instalacji w ogóle nie ma:

# /etc/multipath.conf
defaults {
    user_friendly_names     yes
    find_multipaths         yes
}

blacklist {
    devnode "^(ram|zram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
    devnode "^(vd|xvd)[a-z]"
}

Ustawienie user_friendly_names sprawia, że urządzenie dostanie czytelną nazwę mpatha zamiast długiego identyfikatora. Lista wykluczeń jest równie ważna: wpisujemy tam urządzenia, których multipath nie ma ruszać - w naszym przypadku dyski wirtualne maszyny, czyli te, na których stoi system.

Drugi krok to wskazanie konkretnego dysku po jego identyfikatorze:

$ sudo multipath -a 360014058dd8a6a3ef4943f4876db1b69
wwid '360014058dd8a6a3ef4943f4876db1b69' added

Trzecim krokiem jest ponowne uruchomienie usługi:

$ sudo systemctl restart multipathd
$ sudo multipath -r

Od tej chwili mapa istnieje. Potwierdza ją multipath -ll, którego wynik rozbieramy na czynniki w następnej sekcji, oraz nowe urządzenie w katalogu /dev/mapper/:

$ ls -1 /dev/mapper/
control
mpatha

Oba urządzenia sda i sdb są teraz podporządkowane jednemu urządzeniu mpatha. Od tej pory pracujemy wyłącznie na /dev/mapper/mpatha - a sda i sdb zostawiamy w spokoju. Dobrym odruchem jest sprawdzenie tego w lsblk: obie ścieżki powinny być tam pokazane jako gałęzie pod wspólnym wpisem typu mpath.

Kolejność ma znaczenie. System plików zakładamy dopiero na /dev/mapper/mpatha, nigdy wcześniej na sda. Jeżeli ktoś sformatuje pojedynczą ścieżkę, a potem doda ją do mapy, multipath owszem zadziała - ale przez chwilę istniały dwie niezależne drogi zapisu do tych samych bloków, i to jest dokładnie ta sytuacja, przed którą multipath ma chronić.

Jak czytać wynik multipath -ll

To jest polecenie, które będziemy wpisywać najczęściej. Wygląda gęsto, ale każda linia znaczy coś konkretnego:

$ sudo multipath -ll
mpatha (360014058dd8a6a3ef4943f4876db1b69) dm-0 LIO-ORG,dysk0
size=256M features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 0:0:0:0 sda 8:0  active ready running
  `- 1:0:0:0 sdb 8:16 active ready running

Omawiamy go linia po linii:

  • Linia pierwsza - nazwa mapy (mpatha), w nawiasie identyfikator woluminu, dalej urządzenie device-mappera (dm-0), producent i model.
  • size=256M - rozmiar woluminu. Tyle, ile ma pojedyncza ścieżka, nie suma - bo to jeden dysk.
  • features='1 queue_if_no_path' - najważniejsze ustawienie w całym wyniku. Mówi, co się stanie, gdy padną wszystkie ścieżki. Opisujemy to w osobnej sekcji niżej.
  • hwhandler='1 alua' - moduł obsługi sprzętu. ALUA (od angielskiego Asymmetric Logical Unit Access) to standardowy sposób, w jaki macierz informuje system, które ścieżki są dla danego woluminu preferowane.
  • wp=rw - wolumin jest do odczytu i zapisu.
  • policy='service-time 0' - reguła wyboru ścieżki dla kolejnej operacji.
  • prio=50 status=active - priorytet i stan grupy ścieżek. Multipath nie traktuje ścieżek pojedynczo, tylko dzieli je na grupy i wybiera jedną grupę do pracy; u nas grupa jest jedna i obejmuje obie ścieżki. Do czego to służy przy prawdziwych macierzach, wracamy w sekcji o politykach.
  • Dwie ostatnie linie to ścieżki. Każda ma adres SCSI (0:0:0:0), nazwę urządzenia, parę liczb w rodzaju 8:0, a na końcu trzy słowa stanu. Te dwie liczby to numer główny i poboczny, omówione wcześniej przy powstawaniu urządzeń: pierwszy mówi jądru, który sterownik obsługuje urządzenie (8 to sd), drugi które to urządzenie spośród obsługiwanych przez ten sterownik.

Te trzy słowa czyta się przy awarii w pierwszej kolejności. Ich znaczenie wyjaśnia tabela:

PozycjaWartośćZnaczenie
1 - stan w mapieactivemultipath kieruje tędy operacje
failedmultipath tędy nie kieruje niczego
2 - stan sprawdzeniareadyostatnie sprawdzenie ścieżki się powiodło
faultyostatnie sprawdzenie się nie powiodło
3 - stan urządzeniarunningurządzenie SCSI odpowiada

Warto zapamiętać, że dwa pierwsze słowa zmieniają się niezależnie i w innym tempie. Ścieżka może być już failed, ale jeszcze ready - to znaczy, że łączność wróciła, a multipath jeszcze jej nie przywrócił do użycia. Zobaczymy ten stan za chwilę, w teście powrotu.

Test awarii jednej ścieżki: co widzą system plików i aplikacja

Teraz przechodzimy do najciekawszej części. Zakładamy system plików i montujemy - wyłącznie przez mapę:

$ sudo mkfs.ext4 -q -L MPTEST /dev/mapper/mpatha
$ sudo mkdir -p /mnt/mp
$ sudo mount /dev/mapper/mpatha /mnt/mp
$ df -h /mnt/mp
Filesystem          Size  Used Avail Use% Mounted on
/dev/mapper/mpatha  230M   14K  214M   1% /mnt/mp

Zapisujemy plik kontrolny i liczymy jego sumę kontrolną, żeby później mieć co porównać. Potem w trakcie pracy zabieramy macierzy jeden z adresów. To test utraty jednego portalu iSCSI; ponieważ oba portale działały przez tę samą kartę VM, nie jest to test wyciągnięcia niezależnego kabla ani awarii przełącznika lub kontrolera.

Tak wyglądał wynik zmierzony na działającym stanowisku:

Operacja w czasie awariiWynik
odczyt pliku zapisanego wcześniejpowiódł się, suma kontrolna zgodna
zapis nowego plikupowiódł się
sync (wymuszenie zapisu na dysk)powiódł się
system plikówpozostał zamontowany, bez błędów

Aplikacja nie zauważyła awarii. To jest cały sens multipath i właśnie to chcieliśmy potwierdzić pomiarem, a nie założyć.

W tym samym czasie mapa wyglądała tak:

mpatha (360014058dd8a6a3ef4943f4876db1b69) dm-0 LIO-ORG,dysk0
size=256M features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 0:0:0:0 sda 8:0  failed faulty running
  `- 1:0:0:0 sdb 8:16 active ready  running

Ścieżka sda ma failed faulty - multipath nie kieruje już tędy niczego, bo sprawdzenie się nie powiodło. Druga przejęła cały ruch. W dzienniku systemowym widać to wprost:

$ journalctl -u multipathd -n 20 --no-pager
multipathd[..]: sda: mark as failed
multipathd[..]: mpatha: remaining active paths: 1

Linia remaining active paths: 1 to jest dokładnie ta informacja, której szuka się w dzienniku przy zgłoszeniu "coś jest nie tak z macierzą". Jeżeli spadła do 1, system działa, ale utracił nadmiarowość - kolejna awaria zatrzyma pracę. To jest moment na reakcję, a nie moment na spokój.

Stąd wniosek dla monitoringu: samo sprawdzanie, czy system plików jest zamontowany i czy działa zapis, nie wykryje utraty ścieżki - bo zapis działa dalej. Monitorować trzeba liczbę czynnych ścieżek. Najprościej zrobić to, licząc w wyniku multipath -ll linie ze słowem active albo obserwując komunikaty multipathd w dzienniku.

Powrót ścieżki po awarii bez ingerencji administratora

Przywracamy macierzy zabrany adres i nie robimy nic więcej - żadnego ponownego logowania, żadnego przeładowania usługi.

Ścieżka wróciła sama - w dwóch przebiegach zajęło to 8 i 10 sekund. Po drodze mapa przeszła przez stan pośredni, o którym była mowa wyżej:

  |- 0:0:0:0 sda 8:0  failed ready running

Czyli: sprawdzenie już się powiodło (ready), ale multipath jeszcze nie wznowił kierowania tędy operacji (failed). Chwilę później wynik wyglądał tak:

  |- 0:0:0:0 sda 8:0  active ready running
  `- 1:0:0:0 sdb 8:16 active ready running

Obie ścieżki są czynne, a nadmiarowość została odzyskana. Bez ingerencji administratora - to zasługa usługi multipathd, która w tle regularnie odpytuje każdą ścieżkę i sama decyduje o przywróceniu.

Widząc stan pośredni failed ready nie należy się niecierpliwić ani nic naprawiać ręcznie. Odczekanie kilkunastu sekund i ponowne multipath -ll zwykle wystarcza.

Co się dzieje, gdy padną wszystkie ścieżki: queue_if_no_path

Awaria jednej ścieżki to sytuacja, którą multipath obsługuje niewidocznie. Znacznie ciekawsze jest pytanie, co się dzieje, gdy przestaną odpowiadać wszystkie. Odpowiedź zależy od ustawienia, które widzieliśmy w pierwszym wierszu wyniku: features='1 queue_if_no_path'.

Nazwa mówi dosłownie: "kolejkuj, gdy nie ma ścieżki". Zamiast zwrócić aplikacji błąd wejścia-wyjścia, multipath wstrzymuje operacje i czeka, aż jakakolwiek ścieżka wróci.

Sprawdziliśmy to, odcinając regułą zapory port 3260 na macierzy - czyli obie drogi naraz. Mapa wygląda wtedy tak:

$ sudo multipath -ll
mpatha (360014058dd8a6a3ef4943f4876db1b69) dm-0 LIO-ORG,dysk0
size=256M features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=0 status=active
  |- 0:0:0:0 sda 8:0  failed faulty running
  `- 1:0:0:0 sdb 8:16 failed faulty running

Obie ścieżki failed faulty, a priorytet grupy spadł do prio=0. Wyniki operacji zebraliśmy w tabeli:

Operacja przy wszystkich ścieżkach niedostępnychWynik
odczyt pliku, który był już w pamięci podręcznejpowiódł się natychmiast - dane nie musiały iść po sieci
zapis z pominięciem pamięci podręcznej (dd oflag=direct)zawisł - nie zakończył się błędem, tylko czekał
po przywróceniu łącznościzawieszony zapis dokończył się sam, bez błędu i bez powtarzania
pliki kontrolne po całym teścieobie sumy kontrolne zgodne, dane nienaruszone

To jest zachowanie, które trzeba rozumieć zanim wystąpi, bo objawia się inaczej, niż podpowiada intuicja. Serwer nie zgłasza błędu dysku. Nie ma wpisu "input/output error" w dzienniku aplikacji. Zamiast tego procesy, które chcą pisać, po prostu przestają się kończyć - zawieszają się w stanie nieprzerywalnego oczekiwania (w ps kolumna stanu pokazuje D). Takiego procesu nie da się zabić nawet sygnałem KILL, bo czeka w jądrze. Tak to wygląda zmierzone:

$ ps -o pid,stat,wchan:20,cmd -C dd --no-headers
 217251 D+   iomap_dio_rw         dd if=/dev/urandom of=/mnt/mp/blokada.bin bs=1M count=8 oflag=direct

Kolumna STAT pokazuje D, a kolumna WCHAN mówi, w którym miejscu jądra proces czeka. Po przywróceniu łączności zapis dokończył się sam, bez żadnej ingerencji:

8+0 records in
8+0 records out
8388608 bytes (8,4 MB, 8,0 MiB) copied, 53,9249 s, 156 kB/s

Warto zwrócić uwagę na te liczby, bo łatwo je źle odczytać. 156 kB/s to nie jest wydajność dysku - to średnia z całego czasu, w którym proces przez większość sekund nie robił nic, tylko czekał w kolejce. Sam zapis 8 MB zajął ułamek sekundy; pozostałe pięćdziesiąt kilka to czas odcięcia. Dokładnie tak samo zachowa się aplikacja: nie zobaczy błędu, tylko operację, która trwała absurdalnie długo.

Objaw z życia: baza danych przestaje odpowiadać, obciążenie procesora spada niemal do zera, a średnie obciążenie systemu rośnie do kilkudziesięciu. To nie jest przeciążenie - to kolejka procesów czekających na dysk, którego nie ma. Pierwszym poleceniem w takiej sytuacji jest multipath -ll, a nie restart usługi.

Czy to zachowanie jest dobre? To zależy od zastosowania i jest to świadoma decyzja do podjęcia, a nie ustawienie do zostawienia domyślnie:

  • Kolejkowanie ma sens, gdy przerwa jest krótka i przewidywalna - przełączenie kontrolera macierzy, restart przełącznika, aktualizacja oprogramowania macierzy. Aplikacja przeczeka i będzie pracować dalej, bez utraty danych i bez ręcznego wznawiania.
  • Kolejkowanie szkodzi, gdy macierz nie wróci szybko. System zawiesza się w sposób trudny do naprawienia - nie da się nawet czysto odmontować systemu plików, a wyłączenie serwera potrafi utknąć.

Alternatywą jest ustawienie no_path_retry na liczbę prób zamiast na kolejkowanie bez końca. Po wyczerpaniu prób multipath może zwrócić błędy operacji wejścia-wyjścia. Nie gwarantuje to przejścia systemu plików w tryb tylko do odczytu: wynik zależy między innymi od systemu plików, opcji montowania, aktualnie oczekujących operacji i zachowania aplikacji. Opisany test obejmował tylko queue_if_no_path; wariant z no_path_retry trzeba sprawdzić na własnym stosie przed użyciem produkcyjnym. Szczegóły obu ustawień opisuje strona podręcznika multipath.conf(5).

Polityki wyboru ścieżki w multipath: round-robin, queue-length i service-time

Gdy działają obie ścieżki, multipath musi zdecydować, którą wysłać kolejną operację. Reguła nazywa się polityką wyboru ścieżki i w naszym pomiarze była to service-time 0.

Jądro Debiana 12 udostępnia trzy takie reguły - sprawdzone na liście modułów jądra:

NazwaModuł jądraJak wybiera
round-robindm-round-robinpo kolei, na zmianę. Najprostsza; nie patrzy na to, czy ścieżka jest obciążona.
queue-lengthdm-queue-lengthtę, która ma w tej chwili mniej operacji w kolejce.
service-timedm-service-timetę, która według szacunku obsłuży operację najszybciej - bierze pod uwagę wielkość kolejki i przepustowość ścieżki.

W praktyce domyślnej wartości nie zmienia się bez powodu. service-time radzi sobie dobrze także wtedy, gdy ścieżki nie są równorzędne - na przykład jedna prowadzi przez wolniejsze łącze. Zmiana polityki to sensowny krok dopiero wtedy, gdy producent macierzy zaleca konkretną wartość albo gdy pomiar pokazuje nierówne wykorzystanie ścieżek.

Warto natomiast wiedzieć, że polityka działa wewnątrz grupy ścieżek. Macierze z ALUA dzielą ścieżki na grupy o różnym priorytecie (widoczne jako prio=) i multipath najpierw wybiera grupę o najwyższym priorytecie, a dopiero w jej obrębie stosuje politykę. Dlatego na prawdziwej macierzy można zobaczyć ścieżki w stanie enabled zamiast active - to grupa zapasowa, gotowa, ale nieużywana, dopóki działa grupa preferowana.

Czego multipath nie robi: nie zastępuje kopii zapasowej ani nadmiarowości danych

Zebrane w jednym miejscu, bo każde z tych nieporozumień prowadzi do realnych kłopotów:

  • Nie jest kopią zapasową ani nadmiarowością danych. Dane są w jednym miejscu - na macierzy. Kasowanie pliku, uszkodzenie systemu plików, awaria macierzy: multipath nie pomaga w żadnym z tych przypadków.
  • Nie zwiększa pojemności. Dwie ścieżki do woluminu 256 MB dają wolumin 256 MB, a nie 512 MB. Od łączenia dysków w większą całość jest menedżer woluminów logicznych (LVM, od angielskiego Logical Volume Manager) albo RAID.
  • Nie zawsze zwiększa wydajność. Owszem, operacje rozkładają się na dwie drogi, ale wąskim gardłem najczęściej jest macierz albo dysk w niej, a nie łącze. Multipath buduje się dla dostępności; wzrost przepustowości to skutek uboczny, na który nie należy liczyć z góry.
  • Nie chroni przed własnym błędem konfiguracji. Jeżeli ktoś zamontuje sda obok /dev/mapper/mpatha, multipath tego nie zablokuje - a system plików zostanie uszkodzony. Stąd lista wykluczeń w konfiguracji i zasada, żeby pracować wyłącznie przez /dev/mapper/.
  • Nie uruchomi się sam na nowym dysku przy domyślnym ustawieniu find_multipaths strict w Debianie. To nie jest awaria, tylko celowe zachowanie - opisane wyżej.

Osobna sprawa, o której łatwo zapomnieć: nazwy typu mpatha nie są gwarantowane na stałe przy zmianach sprzętu. W plikach /etc/fstab i w konfiguracji menedżera woluminów bezpieczniej jest używać etykiety systemu plików albo jego identyfikatora UUID (od angielskiego Universally Unique Identifier) niż nazwy urządzenia. Alternatywnie można w /etc/multipath.conf przypisać woluminowi własną, opisową nazwę na podstawie jego identyfikatora - i wtedy nazwa jest stabilna, bo wynika z konfiguracji, a nie z kolejności wykrywania.

Checklista uruchomienia i diagnostyki multipath z iSCSI

Kolejność, która wynika z powyższego przebiegu.

Strona macierzy - tylko dla stanowiska testowego; prawdziwą macierz konfiguruje się jej własnym interfejsem:

# Wolumin udajacy dysk
sudo truncate -s 256M /srv/iscsi/lun0.img

# Backstore, cel, LUN
sudo targetcli /backstores/fileio create name=dysk0 file_or_dev=/srv/iscsi/lun0.img
T=iqn.ROK-MC.odwrocona.domena:nazwa
sudo targetcli /iscsi create "$T"
sudo targetcli /iscsi/$T/tpg1/luns create /backstores/fileio/dysk0

# Po sprawdzeniu targetcli ls: dwa jawne portale testowe zamiast wildcardowego 0.0.0.0
sudo targetcli /iscsi/$T/tpg1/portals delete 0.0.0.0 3260
sudo targetcli /iscsi/$T/tpg1/portals create ADRES_1 3260
sudo targetcli /iscsi/$T/tpg1/portals create ADRES_2 3260

# Kto ma prawo sie podlaczyc (IQN klienta) + zapis konfiguracji
sudo targetcli /iscsi/$T/tpg1/acls create IQN_KLIENTA
sudo targetcli saveconfig

# Kontrola: maja byc dwa nasluchy
sudo ss -ltnp | grep 3260

Strona klienta - uruchomienie:

# 0. Podlaczenie do macierzy (jesli to iSCSI): discovery pokazuje
#    aktualne rekordy portali; sprawdz oczekiwane adresy i cele.
sudo iscsiadm -m discovery -t sendtargets -p ADRES_MACIERZY

# Zaloguj jawnie tylko do obu portali wybranego celu; nie uzywaj
# golej komendy "iscsiadm -m node --login" na nieczystym kliencie.
T=IQN_CELU
for portal in ADRES_1:3260 ADRES_2:3260; do
  sudo iscsiadm -m node -T "$T" -p "$portal" --login
done
sudo iscsiadm -m session          # po jednej sesji na portal

# 1. Czy widać wiele urządzeń o tym samym rozmiarze i modelu?
lsblk -d -o NAME,SIZE,TYPE,VENDOR,MODEL

# 2. Czy identyfikator woluminu jest ten sam? To warunek konieczny.
sudo /lib/udev/scsi_id -g -u -d /dev/sda
sudo /lib/udev/scsi_id -g -u -d /dev/sdb

# 3. Plik konfiguracyjny: nazwy czytelne + wykluczenie dyskow systemowych
sudoedit /etc/multipath.conf

# 4. Dopisanie woluminu po identyfikatorze (konieczne przy find_multipaths strict)
sudo multipath -a <identyfikator>

# 5. Przeladowanie i sprawdzenie
sudo systemctl restart multipathd
sudo multipath -r
sudo multipath -ll

# 6. System plikow TYLKO na mapie, nigdy na pojedynczej sciezce
sudo mkfs.ext4 -L DANE /dev/mapper/mpatha
sudo mount /dev/mapper/mpatha /mnt/dane

Diagnostyka, gdy coś nie działa:

# Mapa w ogole nie powstala - sprawdz tryb find_multipaths
sudo multipathd show config | grep find_multipaths

# Pelna konfiguracja obowiazujaca (domyslna + z pliku)
sudo multipathd show config

# Dlaczego urzadzenie zostalo pominiete - tryb szczegolowy
sudo multipath -v3 -d          # -d = tylko pokaz, nic nie zmieniaj

# Stan sciezek i historia decyzji multipathd
sudo multipath -ll
journalctl -u multipathd -n 50 --no-pager

# Ile sciezek zostalo czynnych - to monitorowac, nie sam montaz
sudo multipath -ll | grep -c 'active ready running'

Uwaga do dwóch poleceń wyżej: multipath -v3 -d jest bezpieczne, bo -d oznacza wyłącznie wypisanie tego, co narzędzie by zrobiło, bez wprowadzania zmian. To najszybszy sposób, żeby zobaczyć, dlaczego konkretne urządzenie nie trafiło do mapy - wynik podaje powód dla każdego pominiętego urządzenia osobno.

Polecenie multipathd show config pokazuje z kolei rzeczywiście obowiązującą konfigurację, czyli wartości domyślne wraz z nadpisaniami z pliku. Przy diagnozowaniu to ono rozstrzyga, a nie zawartość /etc/multipath.conf - bo tam widać tylko to, co ktoś dopisał. Pełny opis obu narzędzi znajduje się w multipathd(8).

Podsumowanie: cztery zachowania multipath, które zaskakują za pierwszym razem

Multipath nie jest skomplikowany, ale ma kilka zachowań, które zaskakują przy pierwszym zetknięciu. Z przeprowadzonego przebiegu wynikają cztery rzeczy warte zapamiętania:

  1. Punktem odniesienia jest identyfikator woluminu, a nie nazwa czy rozmiar urządzenia. Jeżeli identyfikatory się zgadzają, to jest jeden dysk - i to jest pierwsza rzecz do sprawdzenia przy każdym problemie.
  2. W Debianie multipath nie przejmie dysku sam. Domyślne find_multipaths strict wymaga jawnego dopisania woluminu. Brak mapy po instalacji pakietu to zachowanie zgodne z projektem, nie awaria.
  3. Awaria jednej ścieżki jest niewidoczna dla aplikacji - i właśnie dlatego monitoring musi liczyć czynne ścieżki. Sprawdzanie, czy zapis działa, nie wykryje utraty nadmiarowości.
  4. W tym teście dwa portale dały dwie sesje TCP na porcie 3260. To nie dowodzi niezależności sprzętowej: oba portale korzystały z tej samej karty VM. Sam multipath nie zajmuje portu sieciowego; zapora musi obsłużyć ruch iSCSI, w tym egress klienta przy polityce default-deny.
  5. W historycznym teście z queue_if_no_path utrata obu portali zatrzymała zapis zamiast zwrócić błąd. Czy takie zachowanie jest właściwe, zależy od zastosowania. Nie należy z tego wyciągać wniosku o zachowaniu no_path_retry ani konkretnego systemu plików bez własnego testu.

Cały opis powstał na historycznym stanowisku w naszym labie: dwie maszyny wirtualne, dysk plikowy o pojemności 256 MB i drugi adres na tej samej karcie sieciowej. Wystarczyło to, żeby zaobserwować zachowanie portali i mapy multipath, lecz nie redundancję sprzętową. Jak postawić podobne środowisko do własnych, ograniczonych testów, opisujemy w artykule Lab do testów na Terraform i OpenTofu, a kod tego labu jest publicznie dostępny w katalogu terraform/ repozytorium sysgroup/linuxlab (stan z 22 września 2026, commit eba6d62).

Dokumentacja

  • multipath.conf(5) - format pliku konfiguracyjnego, w tym find_multipaths, no_path_retry i listy wykluczeń
  • multipathd(8) - usługa nadzorująca ścieżki i jej tryb interaktywny
  • multipath(8) - polecenie do oglądania i przebudowy map
  • iscsiadm(8) - wykrywanie celów iSCSI i logowanie do nich
  • targetcli(8) - konfiguracja strony macierzy: backstore, cel, LUN, portale i ACL

Macierz, do której prowadzi jedna droga, to jeden punkt awarii

Projektujemy i utrzymujemy dostęp do magazynu danych tak, żeby awaria kabla, przełącznika czy kontrolera nie zatrzymała pracy - razem z monitoringiem, który zauważy utratę nadmiarowości, zanim zabraknie drugiej ścieżki.