Статьи

Какова ваша контрольная группа?

Одной из областей, где мы считаем, что Voron можно улучшить, является политика использования свободного пространства. В частности, более рациональное использование свободного пространства может привести к повышению производительности, так как нам не нужно будет так много искать.

Я потратил некоторое время, работая над этим, и получил кое-что, что, по крайней мере на бумаге, выглядит намного лучше, с точки зрения производительности. Но … фактические тесты показали незначительное улучшение, а в некоторых случаях реальную деградацию! Это был момент, когда я понял, что на самом деле мне нужен какой-то контроль, чтобы увидеть, какой сценарий будет для нас абсолютно оптимальным. Так что я написал нулевую политику свободного пространства. Без свободного места Ворон всегда будет идти до конца файла, предоставляя нам лучший сценарий последовательной записи.

Это дает нам следующее поведение:

Flush      1 with   2 pages -   8 kb writes and   1 seeks (  2 leaves,   0 branches,   0 overflows)
Flush      2 with   8 pages -  32 kb writes and   1 seeks (  7 leaves,   1 branches,   0 overflows)
Flush      3 with  10 pages -  40 kb writes and   1 seeks (  9 leaves,   1 branches,   0 overflows)
Flush     27 with  74 pages - 296 kb writes and   1 seeks ( 72 leaves,   2 branches,   0 overflows)
Flush     28 with  74 pages - 296 kb writes and   1 seeks ( 72 leaves,   2 branches,   0 overflows)
Flush     29 with  72 pages - 288 kb writes and   1 seeks ( 70 leaves,   2 branches,   0 overflows)
Flush  1,153 with 155 pages - 620 kb writes and   1 seeks (102 leaves,  53 branches,   0 overflows)
Flush  1,154 with 157 pages - 628 kb writes and   1 seeks (104 leaves,  53 branches,   0 overflows)
Flush  1,155 with 165 pages - 660 kb writes and   1 seeks (108 leaves,  57 branches,   0 overflows)
Flush  4,441 with 191 pages - 764 kb writes and   1 seeks (104 leaves,  87 branches,   0 overflows)
Flush  4,442 with 196 pages - 784 kb writes and   1 seeks (107 leaves,  89 branches,   0 overflows)
Flush  4,443 with 198 pages - 792 kb writes and   1 seeks (108 leaves,  90 branches,   0 overflows)
Flush  7,707 with 200 pages - 800 kb writes and   1 seeks (106 leaves,  94 branches,   0 overflows)
Flush  7,708 with 204 pages - 816 kb writes and   1 seeks (106 leaves,  98 branches,   0 overflows)
Flush  7,709 with 211 pages - 844 kb writes and   1 seeks (113 leaves,  98 branches,   0 overflows)
Flush  9,069 with 209 pages - 836 kb writes and   1 seeks (107 leaves, 102 branches,   0 overflows)
Flush  9,070 with 205 pages - 820 kb writes and   1 seeks (106 leaves,  99 branches,   0 overflows)
Flush  9,071 with 208 pages - 832 kb writes and   1 seeks (108 leaves, 100 branches,   0 overflows)

И с этим, 10000 транзакций с 100 случайными значениями каждая:

fill rnd buff separate tx          :    106,383 ms      9,400 ops / sec

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

образ

образ

Другими словами, почти все время было потрачено на вызов FlushViewOfFile. Однако я думаю, что мы уже достаточно оптимизировали это, не так ли? Глядя на вызовы, кажется, что у нас есть только один FlushViewOfFile на транзакцию в этом сценарии.

Фактически, глядя на реальное поведение системы, мы можем увидеть:

образ

Так что ищем, у нас все хорошо. Однако я не могу понять, почему мы видим эти вызовы ReadFile. Глядя на данные, кажется, что мы сталкиваемся с этим всякий раз, когда получаем доступ к текущей части файла, так что это подсистема mmap, делающая страницы содержимого файла в памяти, прежде чем мы начнем делать это. Это на самом деле очень здорово, что он способен страница 1 МБ за раз.

Далее, давайте посмотрим, что еще мы можем сделать здесь. Я провел тест 500 TX на жестком диске, и он дал мне следующий результат:

fill rnd sync separate tx          :     25,540 ms      1,958 ops / sec

Но обратите внимание, что каждая запись имеет две записи. Один в конце файла и один в начале файла (что является фактическим последним актом фиксации). Что случилось, если мы просто удалили эту часть?

Это дало мне совсем другое число:

fill rnd sync separate tx          :     21,764 ms      2,297 ops / sec

Так что поиск и запись одной страницы стоили нам 17% нашей производительности. Вот подробности запуска этого теста:

образ

Теперь это бессмысленный тест, добавленный только для проверки относительных затрат. Мы должны сделать запись заголовка, иначе мы не можем сделать реальные транзакции.

Ради интереса, я запустил то же самое, используя последовательные записи, что дало мне 3619 операций в секунду. Поскольку в обоих случаях мы на самом деле делаем последовательные записи, основным отличием было то, сколько мы на самом деле написали. Это вид записи последовательно:

образ

Как видите, нам нужно всего лишь записать от 8 до 10 страниц за транзакцию, а в случайном случае — от 110 до 130. И это, очевидно, имеет много последствий.

Все это научило меня чему-то очень важному. В конце концов, актуальная политика свободного пространства имеет значение, но не так много. Поэтому мне нужно выбрать что-то хорошее, но это все.