Pull to refresh

Comments 67

То, что вы разбираетесь в PostgreSQL, заслуживает уважения.
На презентации Яндекса была шутка о том, что в России есть специалисты по PostgreSQL, и оба они работают в Яндексе :)
К сожалению, не могу похвастаться, что разбираюсь. Только начинаю вникать во все это. Именно поэтому собираюсь посетить конференцию HighLoad++ по проблемам высконагруженных систем, которая пройдет в октябре в Москве. Надеюсь, постгресятников там будет поболее, чем двое:)
Логи на raid0, как-то напрягают. Для логов лучше raid1. Их даже можно забросить на туже дисковую систему, на которой стоит ОС. У меня данные (и индексы) постгрес крутятся на железном рейде (raid6 512м аппаратного кеша, 8 простых 2х терабайтника, место нужно было, поэтому raid6 а не raid10), а логи вынесены на софтовый raid1. И могу сказать, что в моем случае скорость записи логов не является узким местом.
Руководствовался следующими соображениями: если индексы и логи пропадут в случае поломки, ну ладно:) — это не критично для данных. Индексы можно завести вновь. А вот поломка дисков с разделами, где система с постгре и таблицы с данными — это критично, поэтому их на разделы с зеркалированием.
А вот логи и постгре на одном разделе хранить, мне кажется не айс, т.к. диску придется по очереди читать то одно, то другое.
> А вот логи и постгре на одном разделе хранить

Логи и исполняемые файлы системы — на одной дисковой системе (!= раздел) это нормально. Но логи в любом случае надо писать в отдельный раздел.

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

если… логи пропадут в случае поломки… это не критично для данных
Что-то мне подсказывает, что это неверно. Наверное, вот эта статья.
Хочется взять и проверить.
Спасибо большое! Интересно что из вышеперечисленного можно применить к mysql?
Рад был оказаться полезным.
Несмотря на то, что с MySQL знаком намного дольше, чем с PostgreSQL, пока не приходилось сталкиваться с проблемой высокой нагрузки. Могу лишь сказать, что партицирование для нее будет организовать удобнее, т.к. механизм партицирования реализован на уровне БД.
Спасибо за статью, автор! Правда, встречаются слишком очевидные вещи. Те, кто все таки юзает фряху, наверняка сами знают как запустить демон постгреса ;)
Писал как для себя, может поэтому где-то излишние подробности. Не судите строго:)
Да, тюнинг фрюхи смешной. :) Про постгресс немного интереснее. ;)
Тюнинга фряхи как такового нет. Просто поправил пару параметров для постгре. Но раз уж вы об этом заговорили, поделитесь, пожалуйста, своими знаниями.

Коллеги, которые наплюсовали к данному посту, не стесняемся, высказываем свое мнение;)
Вам уже подсказали ниже, пересборка ядра VS sysctl — это как замена фундамента когда надо окна помыть. А если какой-нибудь параметр надо будет еще потюнить? sysctl — не просто так придуман.
Этот пост раньше был написан.
Спасибо за мнение. Мне так даже удобнее — дописать пару строчек в конфиг, чем ядро компилить.
Зачим ядро пересобирать дарагой, а? сись-ка-тэ-эл шайтанама и проблема нема, э?
Зачем sysctl когда можно пофиксить глобально и навсегда?
Вы же, когда стекло в окно вставляете, если оно меньше окна, не скотчем кусочки стекла наклеиваете, а просто покупаете другое, большее стекло.

//я не фряшник
Занес в /etc/sysctl.conf — чем не глобально и навсегда?
Можно вообще в /boot/loader.conf засунуть — глобальнее некуда)
Видимо просто разные философии у нас с вами :_) Оба варианта годны же, думаю.
Я просто считаю, что максимум нужно делать «чем раньше, нем лучше» (в адекватной мере).
Пересобрав ядро из-за такой мелочи, вы лишаетесь возможности обновления ядра через freebsd-update.
Т.е. вместо быстрого обновления вы получаете цирк с конями возню с обновлением сорцов и пересбором ядра.
А если для обновления загрузить дефолтное ядро?
А смысл?

Есть три варианта:
1) Все стандартное — обновление проще простого.
2) Ядро свое, «мир» стандартный — ядро обновляется вручную, «мир» через freebsd-update
3) Все собрано вручную — полностью ручное обновление.

Может конечно быть еще вариант когда ядро стандартное а «мир» нет — но это уже извращение.

В упор не вижу смысла из-за нескольких значений, которые замечательно крутятся через sysctl, наживать себе геморрой в будущем.
При апгрейде на более свежую версию «ручное» обновление бывает безумно интересно :)
Спасибо, учту.

P.S. А если перспектива с обновлением не грозит, тогда какой вариант изменения параметров предпочтете вы?
Я, когда начинал только (с freebsd, кстати, тоже) — фраза "пересобрать ядро" завораживала. Не говоря уже о самом процессе его сборки!

По неопытности пересобирал по поводу и без :)
Во-во:) процесс завораживающий:)
Со временем начинает вызывать отвращение:
«О боги опять это дерьмо не работает, теперь пересобирать все ядро :(»
«О черт опять я 2 часа не буду спать из-за того что freebsd-update тупанул или клиент пересобрал себе ядро (на кой черт-то?)»
«Вот блин надо перекомпилировать ядро с новыми 0-day патчами, 4 часа из жизни вон :(, т.к. мир тоже пересобирать»
Короче, не знаю, когда я обновлял с 4.11 до 6.4 это было вызовом, но у меня видимо характер такой, как я добьюсь меня перестает это завораживать и начинает раздражать. Хотя может я просто задолбался тратить 4 часа на пересборку ядра, или 8 когда что-то пойдет не так?
+1 к systcl
на мой вкус, если что-то можно сделать без компиляции, это нужно делать именно так. Наличие стандартных компонент (которые скомпилировал кто-то другой) сильно облегчает поддержку/обслуживание решения в целом.
А потом при апгрейде ковырять манулов и вспоминать, что творили? :)
Сборка ядра хороша, когда надо пофиксить баг, который коммитер ядра уже 3 года подряд «забывает» добавить (например ata_to) или собрать микроядро по размерам для embedded девайса.
А если это можно поправить в sysctl.conf или loader.conf зачем мучаться и тратить время?
Мне вообще по душе мобильное ядро, когда все что можно и нельзя можно модифицировать в sysctl или loader и желательно на лету. И насколько я вижу разработчикам фряхи это тоже к счастью по душе. Большинство модулей уже можно подключать динамически, а большинство внутренних скрытых переменных модифицируемы через sysctl.conf и loader.conf.
Хозяйке на заметку:
Вместо пересбора ядра, достаточно лишь выкрутить соответствующие sysctl'и:
kern.ipc.sem*
kern.ipc.shm*
Единственный момент — в итоге, если выкручивать всякие значения с азартом или в следствии острой нужды, это может упереться в максимальное кол-во памяти, доступной ядру (vm.kmem_size и vm.kmem_size_max).

При увеличении kmem >= 1Gb на i386 все-таки надо будет пересобрать ядро с увеличенным значением KVA_PAGES, иначе будет паника.
Кстати, советую кодировку для пользователей системы выбрать UTF-8. Меньше будет проблем с PostgreSQL.
work_mem в 1/20 RAM;

Зачем так много? Какой-нибудь неправильный запрос и в своп уйдете.

The normal guidance for work_mem is to consider how much free RAM is around after shared_buffers is allocated (the same OS caching size figure needed to compute effective_cache_size), divide by max_connections, and then take a fraction of that figure; a half of that would be an aggressive work_mem value. In that case, only
if every client had two sorts active all at the same time would the server be likely
to run out of memory, which is an unlikely scenario.
Значение этого параметра обсуждаемо. Думаю, нужно поэкспериментировать.
Используя этот параметр надо понимать для чего выставлять и какой объем, если система использует какой нить ORM то не обязательно делать его большим если же есть «OLAP» выборки… то малое значение запросто увеличит время выполнения в сотни, а то и в тысячи раз по той же причине.

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

fsync — держать включенным или выключенным зависит уже от архитектуры системы, и обширного числа параметров… Хотя с отключенным fsync жизнь есть!
Здесь вообще все спорно, кроме fsync — без него не работает партицирование.
думаю вот это поможет в дальнейшем изучении постгреса
А это и есть книга Алексея Васильева «Работа с Postgresql. Настройка, масштабирование», которая упоминается в моей статье. Также я написал, почему не согласен с некоторыми параметрами.
а, ну упоминаемую книгу я не читал, поэтому не знал, что Вы не согласны с тезисами статьи.
И так с помощью нее я постгрес под 1С затачивал. Смог добиться неплохого ускорения производительности.
Первоначально эти рекомендации и мне принесли неплохое ускорение. Но на больших запросах постгре захлебывался, оперативки под один процесс понадобилось больше, чем 1/8 от всего объема.
не понятно, какой результат всей этой работы? на сколько выросла производительность — 1%? 10%? 100%? 1000%? может достаточно было поставить всё по умолчанию и разницы бы никто не заметил?
Конечно, если подходить к вопросу более педантично, нужно было бы замерять. Но совершенно точно могу сказать, что ускорение производительности очень существенное. Статистика за сутки строится секунд за 5 максимум (и тормозится уже прострением графика, а не выборкой из БД), при том что размер мастер-таблицы перешагнул за 100млн записей. До произведенных действий по разгону скрипт работал минут 20 и выходил по таймауту.
Судя по max_fsm_pages у вас PostgreSQL 8.3 или более ранняя версия. Я бы для новых установок рекомендовал 9.0, текущая версия 9.0.4 достаточно стабильная для использования в production.

Советы, приведенные вами (со ссылкой на книгу) очень неоднозначны, для того, чтобы менять tuple_cost/page_cost в оптимизаторе нужно четко представлять себе, что они меняют, выбор этих параметров сильно зависит от соотношения доступная RAM/размер базы данных и скорость произвольного доступа к устройству хранения данных.

Хороший обзор тюнинга сервера приведен в книжке Грэга Смита (Greg Smith):
www.packtpub.com/postgresql-90-high-performance/book

Статья Грэга в PostgreSQL Wiki:
wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
У меня как раз версия 9.0.4 (в статье это указано). Это просто была цитата из книги.
Спасибо за ссылки, обязательно изучу этот материал. На данный момент скрость работы БД меня вполне устраивает, но как только появится необходимость, буду тюнить дальше. Тогда, возможно, появится вторая часть статьи.
Скажите, а почему бы не генерировать «на год вперед» таблицы, а проверять существование таблицы прямо в триггере и, при необходимости, создавать ее? Имена таблиц у вас в определенном формате, т.к. скрипт по крону, то производительность высокая, вероятно, не нужна и на тормоза инсерта (может, все ваше if'ы сработают быстрее, конечно, не тестил) будет пофиг и можно использовать что-то вроде:
CREATE TABLE measure_data_master(
     measure_time TIMESTAMP NOT NULL DEFAULT NOW(),
     message TEXT
); 


затем триггер:

CREATE OR REPLACE FUNCTION measure_insert_trigger() RETURNS TRIGGER AS $$
DECLARE
    tbl_name TEXT;
    d_start DATE;
    d_stop DATE;
BEGIN
    SELECT INTO tbl_name TO_CHAR(DATE_TRUNC('week', NEW.measure_time), '"measure_data_y"YYYY"m"MM"d"DD');
    IF NOT EXISTS(SELECT * FROM pg_tables where tablename = tbl_name) THEN
        SELECT INTO d_start TO_CHAR(DATE_TRUNC('week', NEW.measure_time), 'YYYY-MM-DD');
        SELECT INTO d_stop TO_CHAR(DATE_TRUNC('week', NEW.measure_time + INTERVAL '6 DAYS'), 'YYYY-MM-DD');
        EXECUTE 'CREATE TABLE '||tbl_name||'(CHECK (measure_time >= '''||d_start||''' AND measure_time < '''||d_stop||''')) INHERITS(measure_data_master);';
        EXECUTE 'CREATE INDEX '||tbl_name||'_key ON '||tbl_name||'(measure_time);';
    END IF;
    EXECUTE 'INSERT INTO '||tbl_name||' VALUES ('''||NEW.measure_time||''','''||NEW.message||''');';
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER insert_measure_trigger BEFORE INSERT ON measure_data_master FOR EACH ROW EXECUTE PROCEDURE measure_insert_trigger(); 


Минусы: падает скорость, особенно если таблицы еще не было; в триггере нужно перечислить поля таблицы (и при изменениях в ней поменять код триггера).

Да, и еще. Чтобы "… серверу БД при запросе придется шерстить не всю большую таблицу, а несколько маленьких, попавших в выбранный временной промежуток..." надо выставить параметр constraint_exclusion = ON.
Отличная идея, спасибо!
Но в моем случае это менее предпочтительно, т.к. скрипт инсертит за каждый свой запуск довольно много строк (и предполагается увеличение), так что придется делать так, как я описал в статье. Ну, для полной автоматизации, можно также скрипт, который таблицы создает, в крон засунуть:)

По constraint_exclusion = ON вы правы. У меня так и есть, но вот забыл об этом упомянуть. Сейчас подредактирую.
Было бы интересно, если бы вы привели результаты сравнения (учитывая ваши немалые объемы данных) способа, подобного моему, и вашего. Просто ради интереса :) Я сам буду рад встать на путь истинный.
Ну, вроде б мой побыстрее должен быть. Вопрос только в том, существенно или нет. Релиз на носу, экспериментировать немного боязно. Я проверю ваш способ при первой возможности.
Ну, если выдастся вариант, вы апдейтните топик, а я уж в избранном послежу. Спасибо, удачного вам релиза! :)
> max_connection = 256;
а вы уверены что это хотябы рядом стояло с оптимизацией???

возьмите табличку на 100 000 000 записей или более, чтоб она весила больше Shared Memory раза в 2-3. и сделайте параллельно 256 выборок по индексу с фильтром и лимитом в сотню строк… т.е. обеспечте выборку со всех частей таблицы(в реальной жизни это почти всегда так)

как вы думаете, как скоро вы получите результат?
Прежде чем писать столь эмоциональные посты, рекомендую вникнуть в контекст, а не вырывать цитаты из цельного текста.
я со всем согласен, везде все параметры рассчитаны в зависимости от объёма памяти и др. аттрибутов, кроме max_connection… у вас max_connection зависит от кол-ва кроновых заданий, а нет от числа процессоров, скоростных характеристик дисковой подсистемы и т.д.
Да, это так, пришлось исходить из конкретных условий конкретной задачи. Если вы мне поможете скорректировать параметры постгре под мою задачу, буду благодарен.
V — объём базы
S — объём разделяемой памяти
K — средний объём данных на запрос

m — % базы в памяти (S*100)/V
d — % базы на диске V — m

R — средний объём данных считанных с диска на запрос (K*d)/100

— при R близком к 0 можно ставить max_connection = 256, но если в запросах нет длительных сортировок и агрегаций, либо число процессоров близко к max_connection
— при R 2кб и более нужно искать золотую середину. как правило чем меньше параллельных запросов, тем быстрее. всё зависит от кол-ва дисков
У меня имеется три вида запросов:
1) много мелких типа INSERT (то, что делает скрипт в кроне)
2) средний типа SELECT (порядок 10 в 4 степени строк, строки по 8 полей), происходит редко, когда пользователь смотрит статистику
3) большой типа SELECT (порядок 10 в 5 степени строк, строки по 8 полей), происходит еще реже, когда пользователь смотрит статистику
Как при таком раскладе искать золотую середину?
В случае insert и update это 100% дисковая операция, поэтому множество параллельных даже мало пишущих запросов начнут драться за головку диска
Да, еще забыл добавить, что меньше 256 соединений скрипту просто не хватает. Как следствие возникают «дыры» в статистике, и разрастается лог.
для этого есть pgbouncer или др. пулер
Классная статья.
НО почему так не любим родной язык? Какой оунер?
owner — владелец, хозяин.
Спасибо.
Родной язык очень даже люблю:) Это скорее влияние профессии — когда технические термины не переводишь в разговорной речи, и со временем начинаешь воспринимать их уже как часть если не речи, то сленга.
CREATE TABLE measure_data_y2011m06d06 (CHECK(measure_time = DATE '2011-06-06' AND measure_time DATE '2011-06-13')
) INHERITS (measure_data_master);

CHECK(measure_time = DATE '2011-06-06' AND measure_time DATE '2011-06-13')

Мне кажется или тут закралась ошибка?
Совершенно верно. Видимо, парсер съел знаки < и >.
В первом случае >=, а во втором <.
Sign up to leave a comment.

Articles