Linux JBD (Journaling Block Device): зачем нам jbd2

article В Linux JBD - это независимый интерфейс журналирования блочных устройств в файловых системах ext3, ext4 и OCFS2 (Oracle Cluster File System). OCFS2 начиная с Linux 2.6.28, а также ext4 используют "форк" JBD известный как JBD2.

В показаниях top|iotop интерфейс журналирования блочных устройств JBD (Journaling Block Device) появляется в виде процесса под именем jbd2 или sda2-8, который проявляет активность по умолчанию с интервалом в 5 сек.:

https://www.kernel.org/doc/Documentation/filesystems/ext4.txt
 
commit=nrsec    (*) Ext4 can be told to sync all its data and metadata
                    every 'nrsec' seconds. The default value is 5 seconds.
                    This means that if you lose your power, you will lose
                    as much as the latest 5 seconds of work (your
                    filesystem will not be damaged though, thanks to the
                    journaling).  This default value (or any low value)
                    will hurt performance, but it's good for data-safety.
                    Setting it to 0 will have the same effect as leaving
                    it at the default (5 seconds).
                    Setting it to very large values will improve
                    performance.

jbd2 (sda2-8) часто обращается к диску для журналирования изменений и из-за того, что процесс jbd2 (sda2-8) постоянно дергает диск, многие предпочитают завышать параметр "commit=nrsec" в опциях монтирования файловой системы надеясь на прирост производительности.

Собственно в описаниях параметра и сказано "Setting it to very large values will improve performance.", что установка очень больших значений позволит повысить производительность, но разумеется в ущерб производительности данных.

Но, не всё так просто, как может показаться на первый взгляд и для того чтобы точно знать какое именно значение "commit=nrsec" поможет увеличить производительность, мы должны чётко себе представлять как в Linux работает JBD (Journaling Block Device) интерфейс журналирования блочных устройств.

Какие данные журналирует JBD/JBD2

Официальная документация гласит:

https://www.kernel.org/doc/Documentation/filesystems/ext4.txt
 
data=journal        All data are committed into the journal prior to being
                    written into the main file system.  Enabling
                    this mode will disable delayed allocation and
                    O_DIRECT support.
 
data=ordered    (*) All data are forced directly out to the main file
                    system prior to its metadata being committed to the
                    journal.
 
data=writeback      Data ordering is not preserved, data may be written
                    into the main file system after its metadata has been
                    committed to the journal.

Что в переводе означает:

  • data=journal - В журнал заносятся все данные про изменения в файловой системе перед записью в главную файловую систему. Включение этого режима отключает "отложенное размещение" и поддержку O_DIRECT.
  • data=ordered - Метаданные заносятся в журнал до записи в главную файловую систему с предварительной группированием метаданных и блоков данных в единое целое называемое транзакцией (transaction).
  • data=writeback - Метаданные, без их группирования, заносятся в журнал после записи в главную файловую систему.

По факту режим data=journal является самым медленным, но существует мнение, что в отдельных тестах при одновременной записи и одновременном чтении, скорость чтения была выше чем при других режимах журналирования, и, что мол этот режим больше всего подходит там где часто выполняются одновременные чтение и запись - опять же, не факт.

Вполне возможно скорость чтения при data=journal будет чуть выше, чем скорость записи, но при условии если результат чтения не зависит от результата записи. Например чтение PHP скрипта, который обращается к БД с целью записи - в таком случае прирост скорости чтения нивелируется понижением скорости записи.

Опытным путём установлено, что для веб-сервера режим data=writeback является самым производительным.

Commit в JBD/JBD2

Как JBD (JBD2) совершает запись в журнал? Журналирование транзакции представляет собой процесс регистрации одного или нескольких атомарных операций файловой системы в журнале на диске. Только после успешного совершения (Commit) транзакции (transaction), операция может считаться полной и гарантируется, что даже в случае краха, эти операции смогут быть восстановлены файловой системой.

Commit выполняется в 8 основных этапов. Основной функцией, которая совершает Commit-ы является journal_commit_transaction(). Когда пришло время добавить данные в журнал, журнал уже находится в рабочем состоянии (T_RUNNING), в момент же совершения записи статус изменяется на T_LOCKED, а все новые потоки данных переходят в режим ожидания до завершения уже начатой транзакции.

В момент завершения транзакции предпринимаются попытки очистить все буферы, принадлежащие зарезервированным спискам (t_reserved_list), а также освободить память, избавившись от буферов сидя на списке контрольных точек (t_checkpoint_list). Интервал Commit-ов регулируется параметром "commit=nrsec".

Информация по Commit в JBD/JBD2 (Journaling Block Device) на kernel.org довольно скудная, а краткое описание приведённое выше является частичным переводом статьи Journalling Block Device (JBD) Linux article, где можно почитать подробнее про Commit в JBD (JBD2)

Как оптимизировать работу Journaling Block Device

Самым популярным способом оптимизации JBD (JBD2) является параметр commit=nrsec, установка которого в очень высокие значения может улучшить производительность - это даже согласно оф. документации. Но это не тот случай, когда "кашу маслом не испортишь"!

Прежде чем шаманить параметрами файловой системы, нужно взять во внимание общее состояние системы, т.е. как минимум знать общий объём физической (оперативной) памяти и скорость доступа к диску.

Например, мы знаем, что между commit-ами JBD/JBD2 хранит данные о изменении ФС в памяти (в буферах, кэше), а значит:

  1. При завышенных значениях параметра commit=nrsec объём данных накапливаемых между длинными commit-ами будет значительно выше, чем между короткими промежутками;
  2. Большие порции данных при длинных commit-ах будут записываться на жесткий диск дольше, вызывая при этом ощутимый интервал I/O Wait если скорость доступа к диску относительно мала;
  3. Затяжной commit отнимет больше памяти, чем короткий.

Следовательно, если у нас слабый диск, мало РАМы, и, мы хотим избежать длительного I/O Wait при "коммитах", то не стоит устанавливать очень большие значения для commit=nrsec.

Хорошим ходом к оптимизации будет понижение I/O приоритета на commit операции:

journal_ioprio=prio The I/O priority (from 0 to 7, where 0 is the
                    highest priority) which should be used for I/O
                    operations submitted by kjournald2 during a
                    commit operation.  This defaults to 3, which is
                    a slightly higher priority than the default I/O
                    priority.

По умолчанию journal_ioprio=3, большее значение понижает приоритет:

iotop -o -d 3
 
Total DISK READ: 549.51 K/s | Total DISK WRITE: 281.53 K/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
  232 be/7 root        0.00 B/s  816.68 B/s  0.00 %  5.93 % [jbd2/sda2-8]
 1858 be/4 mysql     816.68 B/s  235.28 K/s  0.00 %  4.60 % mysqld --~-port=3306
 2126 be/4 dja       138.77 K/s    0.00 B/s  0.00 %  4.34 % php-cgi
 ....

Не лишними также будут и следующие параметры (нет времени на перевод, переводите сами;-):

journal_checksum    Enable checksumming of the journal transactions.
                    This will allow the recovery code in e2fsck and the
                    kernel to detect corruption in the kernel.  It is a
                    compatible change and will be ignored by older kernels.
 
journal_async_commit    Commit block can be written to disk without waiting
                        for descriptor blocks. If enabled older kernels cannot
                        mount the device. This will enable 'journal_checksum'
                        internally.
 
noauto_da_alloc     Many broken applications don't use fsync() when 
                    replacing existing files via patterns such as
                    fd = open("foo.new")/write(fd,..)/close(fd)/
                    rename("foo.new", "foo"), or worse yet,
                    fd = open("foo", O_TRUNC)/write(fd,..)/close(fd).
                    If auto_da_alloc is enabled, ext4 will detect
                    the replace-via-rename and replace-via-truncate
                    patterns and force that any delayed allocation
                    blocks are allocated such that at the next
                    journal commit, in the default data=ordered
                    mode, the data blocks of the new file are forced
                    to disk before the rename() operation is
                    committed.  This provides roughly the same level
                    of guarantees as ext3, and avoids the
                    "zero-length" problem that can happen when a
                    system crashes before the delayed allocation
                    blocks are forced to disk.

Ну, и разумеется смена режима журналирования на writeback, удаление некоторых излишних функций, а также финальная правка /etc/fstab:

 

При использовании твердотельных SSD (solid-state drive) накопителей ещё можно применить "tune2fs -o discard /dev/sda1".

А раз уж мы затронули тему оптимизации, то ещё вскользь упомянём и про такие навязчивые процессы как kswapd0 и pdflush (ещё ака flush-8:0):

 

Ссылки по теме:


Добавить комментарий


Защитный код
Обновить

no-script
[ Подробнее... ]
27 megabytes