Производительность BTRFS по сравнению с LVM + EXT4 с учетом рабочих нагрузок базы данных

Tags: Linux, CoW

Введение

Во многих сборках баз данных резервные копии представляют собой очень большую проблему. Большинство систем резервного копирования требуют эксклюзивной блокировки таблиц и не имеют поддержки для инкрементных резервных копий; они требуют полной резервной копии каждый раз. Когда размер базы данных увеличивается до нескольких терабайт, это становится огромной проблемой. Обычным решением для этого является использование снимков. В облаке это довольно просто, так как облачная платформа может принимать моментальные снимки, сохраняя при этом определенный уровень производительности. В центре обработки данных существует несколько хороших решений. Одним из часто используемых методов является использование LVM в Linux для выполнения моментального снимка на уровне блочного устройства.

Снимки LVM

LVM - это технология Linux, которая позволяет осуществлять расширенные манипуляции с блочными устройствами, включая разделение блочных устройств на многие более мелкие, и объединять более мелкие блочные устройства с более крупными с помощью методов конкатенации или чередования, которые включают избыточное чередование, обычно называемое RAID. В дополнение к этому, технология также поддерживает функцию копирования на запись (CoW), которая позволяет делать снимки. Метод, используемый для реализации этого, состоит в том, чтобы выделить раздел базовых физических томов, на которые копируются исходные данные, перед обновлением основного логического тома.

BTRFS

Согласно wiki: «Btrfs - это современная файловая система Copy-on-Write (CoW) для Linux, нацеленная на внедрение расширенных функций, а также внимание к отказоустойчивости, ремонту и простому администрированию». Это по своей сути файловая система CoW, что означает, что она поддерживает моментальный снимок на уровне файловой системы в дополнение ко многим более продвинутым функциям.

Эксперимент 1: Простой контрольный показатель

Гипотеза

Поскольку и LVM с моментальными снимками, и Btrfs являются CoW, было бы разумно, что решение, предоставляющее функции на более высоком уровне, будет более производительным и обеспечит большую гибкость по сравнению с тем, что на более низком уровне, для которого есть меньше информации для оптимизации. Из-за этого Btrfs должен работать лучше или, по крайней мере, аналогично, и обеспечивать большую гибкость и упрощать управление.

Эксперимент

Эксперимент состоял из специально написанного сценария, который мог бы выделять большой блок данных, приостанавливать, чтобы можно было сделать снимок, а затем случайным образом обновлять разделы большого блока данных. Пользовательский сценарий был выбран потому, что существует несколько тестов, которые позволяют сделать паузу между этапами инициализации и тестирования. На LVM была создана файловая система EXT4, созданная с использованием следующих флагов: -E lazy_itable_init=0,lazy_journal_init=0. Btrfs был создан с использованием параметров по умолчанию. Сценарий производится следующим образом:

import multiprocessing

import datetime

import random

 

EXTENT_SIZE = 4000

EXTENTS = 100000000000 / EXTENT_SIZE

THREADS = 8

FRAGMENT_EXTENTS = 250000

 

def thread_setup(file):

  global urandom

  global output

  urandom = open(‘/dev/urandom’, ‘rb’)

  output = open(file, ‘w+b’)

 

def fill_random(args):

  output.seek(args[‘start’] * EXTENT_SIZE)

  for i in range(args[‘size’]):

      output.write(urandom.read(EXTENT_SIZE))

  output.flush()

 

def fill_random_list(extents):

  for extent in extents:

      output.seek(extent * EXTENT_SIZE)

      output.write(urandom.read(EXTENT_SIZE))

  output.flush()

 

if __name__ == ‘__main__’:

  p = multiprocessing.Pool(THREADS, thread_setup(‘test’))

  args = []

  for i in range(THREADS):

      args.append({‘start’: int((EXTENTS/THREADS)*i), ‘size’: int(EXTENTS/THREADS)})

  start = datetime.datetime.now()

  # Fill a test file

  p.map(fill_random, args, chunksize=1)

  end = datetime.datetime.now()

  print(end – start)

  print(“File made, please make a snapshot now.”)

  input(“Press enter when snapshot made.”)

  # Randomly fragment X pages

  extents = list(range(EXTENTS))

  random.shuffle(extents)

  extents = extents[:FRAGMENT_EXTENTS]

  start = datetime.datetime.now()

  p.map(fill_random_list, extents)

  end = datetime.datetime.now()

  print(end – start)

  # Finally, a big linear seek

  start = datetime.datetime.now()

  with open(‘test’, ‘rb’) as f:

      for i in range(EXTENTS):

          f.read(EXTENT_SIZE)

  end = datetime.datetime.now()

Это было протестировано на выделенном сервере, чтобы удалить столько абстракций, которые могли бы привести к ошибкам измерений, сколько возможно. Он также выполнялся на одном вращающемся диске, что означает, что случайный поиск, вызванный CoW, должен быть усилен по сравнению с SSD. Кроме того, фрагментация была собрана с помощью утилиты filefrag как до теста обновления, так и после.

Результаты

Результаты приведены ниже:

Значение

LVM

BTRFS

Ratio

Время первоначальногосоздания

0:22:09.089155

0:28:43.236595

0.7712749130655504

Время для случайного обновления

0:03:22.869733

0:01:55.728375

1.7529817816935562

Линейное чтение после обновления

0:16:46.113980

0:04:54.382375

3.4177113354697273

Фрагментация перед обновлением

69 экстентов



100 экстентов



0.69

Фрагментация после обновления

70576 экстентов



63848 экстентов найдено

1.1053752662573613

Btrfs занял немного больше времени, чтобы сделать первоначальное создание, что ожидаемо, так как CoW не было на месте в настоящее время для LVM, то есть Btrfs имеет больше накладных расходов. Для основной части гипотезы Btrfs был на 75% быстрее, чем LVM в рабочей нагрузке обновления, что согласуется с гипотезой. Что более удивительно, так это то, что Btrfs был на 342% быстрее, чем LVM на однопоточном линейном считывании после теста обновления. Это можно объяснить тем, что Btrfs имеет более агрессивную политику чтения, чем EXT4 или LVM. Еще одна удивительная находка заключалась в том, что после обновления Btrfs имело на 9,5% меньше фрагментированных экстентов, чем EXT4, что может объяснить часть замедления. Если фрагментация несет исключительную ответственность за замедление, то, используя закон Ахмдаля, операция по фрагментированному экстенду должна быть в среднем на 3600% медленнее, чем по нефрагментированному.

Эксперимент 2: Тест в реальных условиях

С успехом предыдущего эксперимента был сделан более реальный тест.

Гипотеза

Гипотеза заключается в том, что предыдущие результаты будут поддерживаться с использованием более приближенного к реалиям инструмента сравнения.

Эксперимент

Был выбран blogbench в качестве тестовой платформы, поскольку он обеспечивает хорошее сочетание как линейных, так и случайных операций записи и чтения. Было использовано 10 ГБ пространства, которое было равно 136 итерациям. Для теста был использован Blogbench 1.1. Для автоматизации процесса тестирования использовался следующий сценарий:

#!/bin/sh

iterations=30


# Do BTRFS

mkfs.btrfs /dev/sdb

mount /dev/sdb /mnt

cd /root/blogbench-1.1/src

./blogbench -d /mnt -i $iterations | tee ~/btrfs.blogbench.initial

btrfs subvolume snapshot /mnt/ /mnt/snapshot

./blogbench -d /mnt -i $iterations | tee ~/btrfs.blogbench.snapshot

umount /mnt

wipefs -a /dev/sdb


# Do LVM

pvcreate /dev/sdb

vgcreate vg0 /dev/sdb

lvcreate -l 75%FREE -n lv0 vg0

mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vg0/lv0

mount /dev/vg0/lv0 /mnt

cd /root/blogbench-1.1/src

./blogbench -d /mnt -i $iterations | tee ~/lvm.blogbench.initial

lvcreate -l +100%FREE –snapshot -n lv0snap vg0/lv0

./blogbench -d /mnt -i $iterations | tee ~/lvm.blogbench.snapshot

umount /mnt

lvremove -f /dev/vg0/lv0snap

lvremove -f /dev/vg0/lv0

vgremove /dev/vg0

wipefs -a /dev/sdb

Результаты

Результаты приведены ниже:

Значение

LVM

BTRFS

Ratio

Начальный показатель чтения

167695

346567

0.4838746908967097

Начальный показатель записи

1155

1436

0.8043175487465181

Показатель чтения после снимка

88398

233204

0.37905867823879524

Показатель записи после снимка

848

964

0.8796680497925311

В этом тесте Btrfs превзошли LVM в каждом тестировании. Более высокие показатели лучше. Btrfs был на 107% быстрее в начальных показателях чтения и на 24% быстрее в начальных показателях записи. Это также было на 164% быстрее при чтении после снимка и на 17% быстрее при записи после снимка. Это коррелирует с предыдущим экспериментом и гипотезой. Еще одна вещь, которую следует отметить, заключается в том, что после моментального снимка LVM сильно пострадали от проблем с блокировкой, когда для нескольких итераций ничего не произошло, как показано здесь:

[root@btrfs-test ~]# cat lvm.blogbench.snapshot

Frequency = 10 secs

Scratch dir = [/mnt]

Spawning 3 writers…

Spawning 1 rewriters…

Spawning 5 commenters…

Spawning 100 readers…

Benchmarking for 30 iterations.

The test will run during 5 minutes.

Nb blogs   R articles  W articles R pictures    W pictures R comments W comments

     351 255030     17729 222611    19185 174246 354

     519 38783    8539 32165    8203 20519 0

     521 91712     195 75868   225 52156 486

     524 265205        44 219897 61 147229 0

     524   312 0 257            0 264 0

     524     0 0     0 0 0  0

     524     0 0     0 0 0  0

     524     0 0     0 0 0  0

     524     0 0     0 0 0  0

     524     0 1     0 0 0  0

     524     0 0     0 0 0  0

     524     0 49      0 44 0 61

     542 204263       869 170643 1062 113274 2803

     576 263147      1805 218163   1715 142694 1409

     601 223393      1474 186252   1326 120374 0

     630 229142      1252 191061   1876 122406 0

     658 230185      1437 191368   1241 117970 0

     693 294852      2044 240333   1635 144919 488

     737 330354      2093 272406   2153 174214 805

     778 379635      1635 313989   1963 184188 0

     812 302766      1697 248385   1608 151070 0

     814 385820        97 316903 143 184704   0

     814 275654         0 228639 0 132450 0

     814 412152         0 340600 0 195353 0

     814 276715         0 227402 0 131327 0

     842 230882      1243 191560   1226 113133 1314

     848 274873       209 226790  296 126418 257

     848 355217         0 291825 0 168253 0

     848 237893         0 196491 0 110130 0

     848 396703         0 323357 0 179002 0

 

Final score for writes:           848

Final score for reads :         88398

 

Размышления и окончательные примечания

Оба этих теста показывают, что Btrfs превосходит LVM с точки зрения производительности при наличии снимков. Причина этого на самом деле довольно интуитивна и связана с методом внедрения CoW в системах. Причина этого на самом деле довольно интуитивна и связана с методом внедрения CoW в системах. В LVM CoW достигается путем первого копирования блока с основного логического тома на логический том моментального снимка, а затем обновления основного логического тома. Для этой операции требуется одно чтение и две записи для обновления одного блока! Btrfs делает это лучше, используя структуру данных, структурированную в логах для записи, что означает, что для обновления требуется только одна линейная запись. Это объясняет, почему первоначальное время создания в Эксперименте 1 было в целом так похоже: накладные расходы были не в CoW, а в контрольной сумме данных и других функциях. Это также объясняет, почему Btrfs был намного быстрее, чем LVM в режиме CoW. Использование системы CoW, когда это не обязательно, приводит к серьезной деградации производительности, особенно при работе с базами данных. Но если вы все равно будете внедрять CoW, то будет разумно использовать систему CoW, которая работает на уровне файловой системы или выше. Примером более высокой, чем файловая форма CoW, будет та, которая использует CoW в механизме базы данных для создания снимков. Некий тип имеющей имя постоянной транзакции, на которую можно ссылаться.

No Comments

Add a Comment