Identyfikujemy procesy z aktywnością dyskową w systemie Linux

TL;DR: artykuł opisuje wygodny, szybki i niezawodny sposób określania programów Linux, które zapisują dane na dysku, co pomaga w identyfikacji dużego lub nietypowo wysokiego obciążenia podsystemu dyskowego oraz pozwala ocenić koszty operacyjne systemu plików. Jest to szczególnie istotne w przypadku SSD w PC, EMMC i pamięci Flash w komputerach jednopłytowych.
Podczas pisania artykułu odkryto, że zapis kilku kilobajtów danych na systemie plików BTRFS prowadzi do zapisania 3 megabajtów rzeczywistych danych na dysk.

Wprowadzenie

„O, to bzdura, komórki pamięci w nowoczesnych SSD ulegną awarii po dziesiątkach lat normalnego użytkowania, nie ma się czym martwić, a tym bardziej przenosić swap, maszyny wirtualne i folder profilu przeglądarki na HDD” – typowa odpowiedź na pytanie o niezawodność dysków SSD z gwarantowanymi ≈150 TBW. Jeśli oszacować, ile danych typowe oprogramowanie może zapisować, wydaje się, że 10-20 GB dziennie to już duża liczba, niech będzie maksymalnie 40 GB, ileż można więcej? Przy takich liczbach odpowiedź wydaje się całkiem rozsądna – potrzeba 10 lat, aby osiągnąć gwarantowane wartości dotyczące liczby nadpisania komórek przy 40 GB zapisanych danych codziennie.
Jednak przez 6 lat używałem już trzeciego SSD: w pierwszym zepsuł się kontroler, a drugi zaczął przenosić dane między komórkami kilka razy dziennie, co kończyło się 30-sekundowymi opóźnieniami w obsłudze zapisu.

Po 7 miesiącach użytkowania nowego SSD postanowiłem sprawdzić ilość zapisanych danych, jak podaje sam dysk przez SMART.
19.7 TB.
W ciągu 7 miesięcy wykorzystałem 13% od gwarantowanej ilości zapisanych danych, przy założeniu, że jest on skonfigurowany zgodnie z zaleceniami dotyczącymi wyrównywania partycji i konfiguracji FS, swap używam prawie wcale, dyski maszyn wirtualnych są na HDD!
To nienaturalnie duża liczba, przy takich tempach gwarantowany TBW zostanie przekroczony przed upływem 5-letniej gwarancji dysku. Mój komputer nie może pisać po 93 gigabajty dziennie! Muszę sprawdzić, ile danych jest zapisywanych na dysku w ciągu 10 minut…

Razem:
Zapisów w kolejce: 24 712, 2 237MiB
Zakończone zapisy: 25 507, 2 237MiB
Scalanie zapisów: 58, 5 472KiB

2.2 GiB, o rany!

Określenie ilości zapisanych danych na urządzeniu dyskowym

Jeśli twoje urządzenie obsługuje S.M.A.R.T. (SSD, EMMC, niektóre przemysłowe MicroSD), to na początku warto zapytać o dane z nośnika programami smartctl, skdump lub mmc (z pakietu mmc-utils).

Przykład wyjścia programu smartctl

$ sudo smartctl -a /dev/sdb
smartctl 7.0 2019-03-31 r4903 [x86_64-linux-5.3.11-200.fc30.x86_64] (lokalna wersja)
Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org

=== POCZĄTEK SEKCJI INFORMACYJNEJ ===
Rodzina modelu:     SSD oparte na Samsungu
Model urządzenia:    Samsung SSD 860 EVO mSATA 250GB
Numer seryjny:      S41MNC0KA13477K
Identyfikator WWN urządzenia LU: 5 002538 e700fa64b
Wersja oprogramowania: RVT41B6Q
Pojemność użytkownika:    250 059 350 016 bajtów [250 GB]
Rozmiar sektora:      512 bajtów logicznych/fizycznych
Prędkość obrotowa:    Urządzenie półprzewodnikowe
Format:      mSATA
Urządzenie jest:        W bazie danych smartctl [szczegóły: -P show]
Wersja ATA:   ACS-4 T13/BSR INCITS 529 poprawka 5
Wersja SATA:  SATA 3.1, 6.0 Gb/s (aktualna: 3.0 Gb/s)
Czas lokalny:    Wt Nov 19 01:48:50 2019 MSK
Wsparcie SMART:    Dostępne - urządzenie ma możliwości SMART.
Wsparcie SMART:    Włączone

=== POCZĄTEK SEKCJI ODPOWIEDZI SMART ===
Wynik ogólnej samooceny zdrowia SMART: ZDANY

Ogólne wartości SMART:
Status zbierania danych offline:  (0x00) Aktywność zbierania danych offline
                                        nigdy nie została rozpoczęta.
                                        Automatyczne zbieranie danych offline: Wyłączone.
Status wykonania testu:      (   0) Poprzednia procedura testu samooceny zakończona
                                        bez błędów lub nigdy nie przeprowadzono 
                                        testu samooceny.
Czas potrzebny na zakończenie zbierania danych offline:                (    0) sekund.
Możliwości zbierania danych offline:                    (0x53) SMART wykonuje natychmiastowe zbieranie offline.
                                        Wsparcie dla automatycznego zbierania danych offline włączone/wyłączone.
                                        Wstrzymaj zbieranie offline po nowym
                                        poleceniu.
                                        Brak wsparcia dla skanowania powierzchni offline.
                                        Test samooceny wspierany.
                                        Brak wsparcia dla testu nośnika przekazania.
                                        Wspierany test selektywny.
Możliwości SMART:            (0x0003) Zapisuje dane SMART przed wejściem
                                        w tryb oszczędzania energii.
                                        Wspiera zegar automatycznego zapisu SMART.
Możliwość rejestrowania błędów:        (0x01) Wspierane rejestrowanie błędów.
                                        Wspierane ogólne rejestrowanie.
Zalecany czas odpytywania dla krótkiego testu samooceny:        (   2) minuty.
Zalecany czas odpytywania dla rozszerzonego testu samooceny:        (  85) minuty.
Możliwości SCT:              (0x003d) SCT Status wspierany.
                                        SCT Kontrola odzyskiwania błędów wspierana.
                                        SCT Kontrola funkcji wspierana.
                                        SCT Tabela danych wspierana.

Numer rewizji struktury danych atrybutów SMART: 1
Dane SMART specyficzne dla dostawcy z progami:
ID# NAZWA_ATRYBUTU          FLAGA     WARTOŚĆ NAJLEPSZA NAJWIĘKSZA PROG TYP      AKTUALIZACJA  KIEDY_BŁĄD RAW_WARTOŚĆ
  5 Liczba_zprzeniesionych_sektorów   0x0033   100   100   010    Przed_uszkodzeniem  Zawsze       -       0
  9 Godziny_pracy          0x0032   098   098   000    Stary_wiek   Zawsze       -       5171
 12 Liczba_cykli_urządzenia       0x0032   099   099   000    Stary_wiek   Zawsze       -       459
177 Liczba_wyrównania_zużycia     0x0013   096   096   000    Przed_uszkodzeniem  Zawsze       -       62
179 Liczba_zarezerwowanych_blk_części   0x0013   100   100   010    Przed_uszkodzeniem  Zawsze       -       0
181 Liczba_błędów_programowania  0x0032   100   100   010    Stary_wiek   Zawsze       -       0
182 Liczba_błędów_erase_total  0x0032   100   100   010    Stary_wiek   Zawsze       -       0
183 Runtime_Bad_Block       0x0013   100   100   010    Przed_uszkodzeniem  Zawsze       -       0
187 Liczba_błędów_niepoprawnych 0x0032   100   100   000    Stary_wiek   Zawsze       -       0
190 Temperatura_przepływu_powietrza_Cel 0x0032   058   039   000    Stary_wiek   Zawsze       -       42
195 Współczynnik_błędów_ECC          0x001a   200   200   000    Stary_wiek   Zawsze       -       0
199 Liczba_błędów_CRC         0x003e   100   100   000    Stary_wiek   Zawsze       -       0
235 Liczba_recovery_POR      0x0012   099   099   000    Stary_wiek   Zawsze       -       29
241 Całkowita_liczba_LBAs_zapisanych      0x0032   099   099   000    Stary_wiek   Zawsze       -       38615215765

SMART Wersja Dziennika Błędów: 1
Brak zarejestrowanych błędów

Struktura dziennika testów samooceny SMART numer rewizji 1
Nie zarejestrowano testów samooceny.  [Aby uruchomić testy samooceny, użyj: smartctl -t]

Struktura danych dziennika testów selektywnych SMART numer rewizji 1
 SPAN  MIN_LBA  MAX_LBA  STATUS_TESTU_AKTUALNEGO
    1        0        0  Nie_testowane
    2        0        0  Nie_testowane
    3        0        0  Nie_testowane
    4        0        0  Nie_testowane
    5        0        0  Nie_testowane
Flagi testu selektywnego (0x0):
  Po zeskanowaniu wybranych zakresów, NIE skanuj reszty dysku.
Jeśli test selektywny oczekuje na uruchomienie po włączeniu, wznowi po 0 minutach opóźnienia.

Mój SSD przechowuje liczbę zapisanych danych w parametrze 241 Total_LBAs_Written, w logicznych blokach (LBA), a nie w bajtach. Rozmiar bloku logicznego w moim przypadku to 512 bajtów (można to zobaczyć w wynikach smartctl, w rozmiarze sektora). Aby otrzymać bajty, należy pomnożyć wartość parametru przez 512.

38615215765 × 512 ÷ 1000 ÷ 1000 ÷ 1000 ÷ 1000 = 19,770 TB
38615215765 × 512 ÷ 1024 ÷ 1024 ÷ 1024 ÷ 1024 = 17,981 TiB

Program skdump na moim SSD próbuje interpretować wartość Total_LBAs_Written w sposób własny, przez co wyświetla 1296217.695 TB, co jest oczywiście niepoprawne.

Aby poznać liczbę zapisywanych informacji na poziomie urządzenia, skorzystamy z programu btrace z pakietu blktrace. Pokazuje on zarówno ogólne statystyki za cały czas pracy programu, jak i poszczególne procesy i wątki (w tym jądra), które wykonywały zapis.

Uruchom następującą komendę, aby zebrać informacje przez 10 minut, gdzie /dev/sdb to twój dysk:

# btrace -w 600 -a write /dev/sdb

Typowy wynik komendy

…
  8,16   0     3253    50.085433192     0  C  WS 125424240 + 64 [0]
  8,16   0     3254    50.085550024     0  C  WS 193577744 + 64 [0]
  8,16   0     3255    50.085685165     0  C  WS 197246976 + 64 [0]
  8,16   0     3256    50.085936852     0  C  WS 125736264 + 128 [0]
  8,16   0     3257    50.086060780     0  C  WS 96261752 + 64 [0]
  8,16   0     3258    50.086195031     0  C  WS 94948640 + 64 [0]
  8,16   0     3259    50.086327355     0  C  WS 124656144 + 64 [0]
  8,16   0     3260    50.086843733 15368  C WSM 310218496 + 32 [0]
  8,16   0     3261    50.086975238   753  A WSM 310218368 + 32 <-(8,20) 291339904
  8,16   0     3262    50.086975560   753  Q WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3263    50.086977345   753  G WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3264    50.086978072   753  I WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3265    50.086979159   753  D WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3266    50.087055685     0  C WSM 310218368 + 32 [0]
  8,16   0     3267    50.087060168   753  A WSM 310218592 + 160 <-(8,20) 291340128
  8,16   0     3268    50.087060367   753  Q WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3269    50.087061242   753  G WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3270    50.087061698   753  I WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3271    50.087062361   753  D WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3272    50.087386179     0  C WSM 310218592 + 160 [0]
  8,16   0     3273    50.087436417 15368  A FWS 0 + 0 <-(253,1) 0
  8,16   0     3274    50.087437471 15368  Q FWS [LS Thread]
  8,16   0     3275    50.087440862 15368  G FWS [LS Thread]
  8,16   0     3276    50.088300047     0  C  WS 0 [0]
  8,16   0     3277    50.088470917   753  A WFSM 18882688 + 8 <-(8,20) 4224
  8,16   0     3278    50.088471091   753  Q WFSM 18882688 + 8 [dmcrypt_write/2]
  8,16   0     3279    50.088471688   753  G WFSM 18882688 + 8 [dmcrypt_write/2]
  8,16   0     3280    50.088474334 32254  D WSM 18882688 + 8 [kworker/0:2H]
  8,16   0     3281    50.088515572     0  C WSM 18882688 + 8 [0]
  8,16   0     3282    50.089229069     0  C WSM 18882688 [0]
CPU0 (8,16):
 Liczba odczytów w kolejce:           0,        0KiB  Liczba zapisów w kolejce:         345,   25,932KiB
 Liczba zrealizowanych odczytów:        0,        0KiB  Liczba zrealizowanych zapisów:      331,   25,788KiB
 Liczba odczytów ponownie w kolejce:         0               Liczba zapisów ponownie w kolejce:         0
 Liczba zakończonych odczytów:        0,        0KiB  Liczba zakończonych zapisów:    1,597,  117,112KiB
 Liczba scalonych odczytów:            0,        0KiB  Liczba scalonych zapisów:            1,       16KiB
 Głębokość odczytów:             0               Głębokość zapisów:           177
 Wypięcia IO:             0               Wypięcia timera:           0
CPU1 (8,16):
 Liczba odczytów w kolejce:           0,        0KiB  Liczba zapisów w kolejce:         502,   39,948KiB
 Liczba zrealizowanych odczytów:        0,        0KiB  Liczba zrealizowanych zapisów:      495,   40,076KiB
 Liczba odczytów ponownie w kolejce:         0               Liczba zapisów ponownie w kolejce:         0
 Liczba zakończonych odczytów:        0,        0KiB  Liczba zakończonych zapisów:        0,        0KiB
 Liczba scalonych odczytów:            0,        0KiB  Liczba scalonych zapisów:            0,        0KiB
 Głębokość odczytów:             0               Głębokość zapisów:           177
 Wypięcia IO:             0               Wypięcia timera:           0
CPU2 (8,16):
 Liczba odczytów w kolejce:           0,        0KiB  Liczba zapisów w kolejce:         297,   26,800KiB
 Liczba zrealizowanych odczytów:        0,        0KiB  Liczba zrealizowanych zapisów:      287,   26,800KiB
 Liczba odczytów ponownie w kolejce:         0               Liczba zapisów ponownie w kolejce:         0
 Liczba zakończonych odczytów:        0,        0KiB  Liczba zakończonych zapisów:        0,        0KiB
 Liczba scalonych odczytów:            0,        0KiB  Liczba scalonych zapisów:            0,        0KiB
 Głębokość odczytów:             0               Głębokość zapisów:           177
 Wypięcia IO:             0               Wypięcia timera:           0
CPU3 (8,16):
 Liczba odczytów w kolejce:           0,        0KiB  Liczba zapisów w kolejce:         418,   24,432KiB
 Liczba zrealizowanych odczytów:        0,        0KiB  Liczba zrealizowanych zapisów:      408,   24,448KiB
 Liczba odczytów ponownie w kolejce:         0               Liczba zapisów ponownie w kolejce:         0
 Liczba zakończonych odczytów:        0,        0KiB  Liczba zakończonych zapisów:        0,        0KiB
 Liczba scalonych odczytów:            0,        0KiB  Liczba scalonych zapisów:            2,      272KiB
 Głębokość odczytów:             0               Głębokość zapisów:           177
 Wypięcia IO:             0               Wypięcia timera:           0

Ogółem (8,16):
 Liczba odczytów w kolejce:           0,        0KiB  Liczba zapisów w kolejce:       1,562,  117,112KiB
 Liczba zrealizowanych odczytów:        0,        0KiB  Liczba zrealizowanych zapisów:    1,521,  117,112KiB
 Liczba odczytów ponownie w kolejce:         0               Liczba zapisów ponownie w kolejce:         0
 Liczba zakończonych odczytów:        0,        0KiB  Liczba zakończonych zapisów:    1,597,  117,112KiB
 Liczba scalonych odczytów:            0,        0KiB  Liczba scalonych zapisów:            3,      288KiB
 Wypięcia IO:             0               Wypięcia timera:           0

Przepustowość (R/W): 0KiB/s / 2,338KiB/s
Zdarzenia (8,16): 9,287 wpisów
Pominięcia: 0 do przodu (0 -   0.0%)

btrace umożliwia wizualizację rzeczywistej ilości zapisanych danych, ale z wyniku trudno zrozumieć, które dokładnie programy wykonują zapis.

Określenie programów wykonujących zapis na nośniku

Program iotop pokaże procesy zapisujące na dysk oraz rozmiar zapisanych danych.
Najwygodniejszy wynik zapewniają następujące parametry:

# iotop -obPat

Przykład wyniku programu

02:55:47 Całkowity ODPOŁYWA DISK :       0.00 B/s | Całkowity ZAPIS DISK :      30.65 K/s
02:55:47 Rzeczywisty ODCZYT DISK:       0.00 B/s | Rzeczywisty ZAPIS DISK:       0.00 B/s
    CZAS  PID  PRIO  UŻYTKOWNIK  ODCZYT DISK  ZAPIS DISK  SWAPIN      IO    KOMENDA
b'02:55:47   753 be/4 root          0.00 B      0.00 B  0.00 %  0.04 % [dmcrypt_write/2]'
b'02:55:47   788 be/4 root         72.00 K     18.27 M  0.00 %  0.02 % [btrfs-transacti]'
b'02:55:47 15057 be/4 valdikss    216.00 K    283.05 M  0.00 %  0.01 % firefox'
b'02:55:47  1588 ?dif root          0.00 B      0.00 B  0.00 %  0.00 % Xorg -nolisten tcp -auth /var/run/sddm/{398f030f-9667-4dff-b371-81eaae48dfdf} -background none -noreset -displayfd 18 -seat seat0 vt1'
b'02:55:47 15692 be/4 valdikss    988.00 K      9.41 M  0.00 %  0.00 % python3 /usr/bin/gajim'
b'02:55:47 15730 ?dif valdikss      9.07 M      0.00 B  0.00 %  0.00 % telegram-desktop --'
b'02:55:47  2174 ?dif valdikss   1840.00 K      2.47 M  0.00 %  0.00 % yakuake'
b'02:55:47 19827 be/4 root         16.00 K    896.00 K  0.00 %  0.00 % [kworker/u16:7-events_unbound]'
b'02:55:47 19074 be/4 root         16.00 K    480.00 K  0.00 %  0.00 % [kworker/u16:4-btrfs-endio-write]'
b'02:55:47 19006 be/4 root         16.00 K   1872.00 K  0.00 %  0.00 % [kworker/u16:1-events_unbound]'
b'02:55:47  1429 be/4 root        484.00 K      0.00 B  0.00 %  0.00 % accounts-daemon'
b'02:55:47 15820 be/4 valdikss    312.00 K      0.00 B  0.00 %  0.00 % firefox -contentproc -childID 6 -isForBrowser -prefsLen 7894 -prefMapSize 223880 -parentBuildID 20191022164834 -greomni /usr/lib64/firefox/omni.ja -appomni /usr/lib64/firefox/browser/omni.ja -appdir /usr/lib64/firefox/browser 15057 tab'
b'02:55:47  2125 ?dif valdikss      0.00 B     92.00 K  0.00 %  0.00 % plasmashell'
b'02:55:47  1268 be/3 root          0.00 B      4.00 K  0.00 %  0.00 % auditd'
b'02:55:47  1414 be/4 root          0.00 B      4.00 K  0.00 %  0.00 % sssd_nss --uid 0 --gid 0 --logger=files'
b'02:55:47 15238 be/4 valdikss      0.00 B      4.00 K  0.00 %  0.00 % thunderbird'
b'02:55:47 18605 be/4 root          0.00 B      3.19 M  0.00 %  0.00 % [kworker/u16:0-btrfs-endio-write]'
b'02:55:47 18867 be/4 root          0.00 B     96.00 K  0.00 %  0.00 % [kworker/u16:5-btrfs-endio-meta]'
b'02:55:47 19070 be/4 root          0.00 B    160.00 K  0.00 %  0.00 % [kworker/u16:2-btrfs-freespace-write]'
b'02:55:47 19645 be/4 root          0.00 B      2.17 M  0.00 %  0.00 % [kworker/u16:3-events_unbound]'
b'02:55:47 19982 be/4 root          0.00 B    496.00 K  0.00 %  0.00 % [kworker/u16:6-btrfs-endio-write]'

Zwraca uwagę Firefox, który zapisał 283 megabajty w ciągu kilku minut działania iotop.

Określenie plików, do których następuje zapis

Informacje o procesie, który obciążają dysk — to dobrze, a ścieżki, po których następuje zapis — jeszcze lepiej.

Skorzystamy z programu fatrace, który śledzi zmiany w systemie plików.

# fatrace -f W

Przykład wyniku programu

firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite

Fatrace nie potrafi pokazać ilości zapisanych danych ze względu na dość prostą metodę śledzenia faktu dostępu do plików przez inotify.

Z wyjścia widać, jak Habr zapisuje mój artykuł w local storage przeglądarki, podczas gdy go piszę, a także rozszerzenie Group Speed Dial, które, jak udało się ustalić właśnie dzięki fatrace, czyta swoje dane co 30 sekund. Czyta, a nie zapisuje: CW Przed plikiem mówi, że plik jest otwierany do odczytu i zapisu, a jeśli nie istnieje, jest tworzony (wywołanie openat z flagą O_RDWR|O_CREAT), ale nie stwierdza, że do pliku rzeczywiście została zapisana jakakolwiek informacja.

Na wszelki wypadek, aby to potwierdzić, użyjemy strace z filtrem na wywołania systemowe związane z plikami:

strace -yy -e trace=open,openat,close,write -f -p 15057 2>&1 | grep extension

Wynik komendy

[pid 20352] openat(AT_FDCWD, "/home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 153
[pid 20352] read(153, "SQLite format 3 20 22 @   d 23"..., 100) = 100
[pid 20352] read(153, "SQLite format 3 20 22 @   d 23"..., 4096) = 4096
[pid 20352] openat(AT_FDCWD, "/home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 166
…
[pid 20352] read(54, " r4304364354354364-  4204!4'414" 250 &"..., 4096) = 4096
[pid 20352] read(54, " 136Pt2262504 O24532016:"16.27 r245306>2461t1q370"..., 4096) = 4096
[pid 20352] close(77) = 0
[pid 20352] close(54) = 0

Nie ma żadnych wywołań write(), co wskazuje na brak zapisu do pliku.

Określenie kosztów związanych z systemem plików

Duża różnica w danych iotop i btrace skłoniła mnie do przetestowania systemu plików, zapisując ręcznie dane do pliku i śledząc wskazania btrace.

Jeśli całkowicie wykluczyć zapis na dysk, uruchamiając system w trybie awaryjnym systemd, i ręcznie zapisać kilka bajtów danych w istniejącym pliku, btrace na SSD z btrfs informuje o zapisie 3 megabajty rzeczywiste dane. Świeżo utworzony system plików na pamięci USB o pojemności 8 GB zapisuje przynajmniej 264 KiB przy zapisie jednego bajta.
Dla porównania, zapis dwóch bajtów w pliku na ext4 kończy się zapisem 24 kilobajtów danych na dysk.

W 2017 roku Jayashree Mohan, Rohan Kadekodi i Vijay Chidambaram przeprowadzili badanie wzmacniania zapisu różnych systemów plików, ich wyniki dla btrfs i ext4 przy zapisie 4 KB odpowiadają moim.

Identyfikujemy procesy z aktywnością dyskową w systemie Linux

Wnioski

W wyniku opisanych manipulacji odkryto:

  1. Częsty zapis stanów zadań dla drukarki przez demona drukowania CUPS w /var/pamięć podręczna/cups каждую минуту. Проблема устранена очисткой /var/spool/cups (хотя никаких заданий печати не было);
  2. Fakt odczytu bazy danych co 30 sekund przez rozszerzenie Group Speed Dial dla Firefox;
  3. Okresowy zapis logów przez różne usługi monitorowania wydajności w Fedora, co prowadziło do zapisu kilku megabajtów danych na btrfs: pmcd.service, pmie.service, pmlogger.service;
  4. Ogromna amplifikacja przy zapisie niewielkiej ilości danych przy użyciu btrfs.

Wniosek: nie warto używać btrfs, jeśli programy często zapisują niewielkie ilości danych (kilka kilobajtów), bo to może prowadzić do zapisu megabajtów danych. Jest to szczególnie istotne dla jednopłytkowych komputerów z systemem na MicroSD.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster