Технические заметки одного Евтуховича

Рассказ о серых трудовых буднях инженера программных систем

БД — большой кэш

| Комментарии

В прошлый раз я обещал написать о том, что в проектах с более менее серьезной нагрузкой БД либо помещается в память, либо не работает. Ситуация в современном мире меняется в связи с появлением SSD дисков, но пока что они стоят достаточно дорого, по сравнению со старыми добрыми вращающимися дисками. Чтобы «потрогать» это руками, проделаем несложный тест.

Я завел новую машину с Ubuntu 12.04, на облачном хостинге Amazon размера t1.micro. После этого необходимо поставить 2 пакета: postgresql-contrib-9.1 и ruby.

PostgreSQL contrib содержит, помимо всего прочего, программу pgbench, специально предназначенную для нагрузочного тестирования PostgreSQL.

В postgresql.conf параметр shared_buffers был выставлен в 64MB.

Далее был написан скрипт на ruby, который проводил тестирование:

File.open('res.txt', 'w') do |f|
    (1..50).each do |s|
        # -i означает, что мы создаем чистую БД
        # -s - это scale factor, определяет размер БД
        `/usr/lib/postgresql/9.1/bin/pgbench -i -s #{s}`

        # -S - тесты для запросов только на чтение
        # -T 20 - тест длится 20 секунд
        # -c 40 - 40 клиентов
        # -j 4 - 4 потока
        res = `/usr/lib/postgresql/9.1/bin/pgbench -c 40 -j 4 -S -T 20`
        puts res
        f.write res
    end
end

Более подробно про pgbench можно почитать в официальной документации.

На машинках t1.micro free -m выдает следующее: total used free shared buffers cached Mem: 590 583 6 0 1 428

Именно этим обусловлен такой выбор границ scale factor. Про scale factor = 50 размер БД приблизительно 750Мб, то есть больше количества доступной памяти, а граница shared_buffers пересекается при значениях scale factor 4-5.

Давайте же посмотрим на график.

tps graph

Данные получились не очень красивыми, но в целом — понятными. Виден провал в районе scale factor 5, а следующий провал в районе scale factor 45. Собственно, две явные ступеньки — выпадание из shared buffers и из дискового кэша.

Параметр shared_buffers отвечает за то, сколько памяти будет использовано PostgreSQL для общего кэша, доступного всем процессам БД. Если какие-то данные попадают в shared buffers, то доступ к ним осуществляется быстрее всего. Более того, все изменения shared buffers происходят с правильными блокировками, поэтому данные там всегда актуальны. По большому счету именно этот большой кэш позволяет БД быстро работать. Более того, в PostgreSQL используется специальный алгоритм, который помогает наиболее часто используемым данным попадать и оставаться в этом кэше.

Следующий уровень — это дисковый кэш операционной системы. Вся свободная память ОС linux используется как дисковый кэш. Конечно, доступ к данным, которые лежат в дисковом кэше будет осуществляться медленнее, чем к тем, что лежат в shared buffers. Но все же это будет происходить достаточно быстро.

Если же данные не были обнаружены в дисковом кэше, то ОС полезет за ними на диск. И это очень-очень долго (конечно, не ясно, что за диски внутри Amazon, но это точно не SSD). Обычный диск может выдать 100-200 случайных операций в секунду (посмотрите калькулятор IOPS), и если количество запросов значительно превышает возможности дисковой подсистемы, то такой режим работы БД обычно называют «у нас легла БД».

Диски являются самым дорогим ресурсом для БД, поэтому их надо экономить и тратить их ресурсы в основном только на запись. Все актуальные данные должны попадать в кэш БД или кэш ОС. Именно поэтому всегда рекомендуют держать для отчетов отдельный сервер БД. Обычно данные, которые нужны для отчетов, не используются на web-сайте. И как только запускается аналитический отчет, он вымывает данные из кэша ОС и БД, и сайт буквально ложится, что мы наблюдали неоднократно у наших клиентов. Конечно, такое происходит только в том случае, если размер БД значительно превышает размер оперативной памяти на сервере.

PS Для любителей PostgreSQL хорошо известный в Ruby-мире Питер Купер выпускает рассылку PostgreSQL Weekly.

Комментарии