Поток с большим количеством обновлений и PostgreSQL - PullRequest
7 голосов
/ 02 ноября 2009

Я новичок в оптимизации PostgreSQL и выборе того, что ему подходит, а что нет. Итак, я хочу знать, когда я пытаюсь использовать PostgreSQL для неподходящей работы, или он подходит для этого, и я должен все настроить правильно.

В любом случае, мне нужна база данных с большим количеством данных, которые часто меняются.

Например, представьте себе интернет-провайдера, у которого много клиентов, у каждого из которых есть сеанс (PPP / VPN / любой другой) с двумя часто описываемыми свойствами с самоописанием bytes_received и bytes_sent. С ними есть таблица, где каждая сессия представлена ​​строкой с уникальным идентификатором:

CREATE TABLE sessions(
    id BIGSERIAL NOT NULL,
    username CHARACTER VARYING(32) NOT NULL,
    some_connection_data BYTEA NOT NULL,
    bytes_received BIGINT NOT NULL,
    bytes_sent BIGINT NOT NULL,
    CONSTRAINT sessions_pkey PRIMARY KEY (id)
)

И в качестве потоков учетных данных эта таблица получает много обновлений, таких как:

-- There are *lots* of such queries!
UPDATE sessions SET bytes_received = bytes_received + 53554,
                    bytes_sent = bytes_sent + 30676
                WHERE id = 42

Когда мы получаем бесконечный поток с довольно большим количеством (например, 1-2 в секунду) обновлений для таблицы с большим количеством (например, несколько тысяч) сеансов, вероятно, благодаря MVCC, это делает PostgreSQL очень занят. Есть ли способы ускорить все, или Postgres просто не совсем подходит для этой задачи, и я бы лучше посчитал это неподходящим для этой работы и поместил эти счетчики в другое хранилище, такое как memcachedb, используя Postgres только для довольно статических данных? Но я буду упускать возможность нечасто запрашивать эти данные, например, чтобы найти загрузчики TOP10, что не очень хорошо.

К сожалению, количество данных не может быть значительно уменьшено. Пример учета провайдера ISP придуман для упрощения объяснения. Настоящая проблема в другой системе, структуру которой как-то сложнее объяснить.

Спасибо за предложения!

Ответы [ 2 ]

14 голосов
/ 02 ноября 2009

База данных действительно не лучший инструмент для сбора множества небольших обновлений, но, поскольку я не знаю ваших требований к запросам и ACID, я не могу порекомендовать что-то еще. Если это приемлемый подход, агрегация обновлений на стороне приложения, предложенная zzzeek, ​​может значительно снизить загрузку обновлений.

Существует аналогичный подход, который может обеспечить вам долговечность и возможность запрашивать более свежие данные при некоторых затратах на производительность. Создайте буферную таблицу, которая может собирать изменения в значения, которые необходимо обновить, и вставьте туда изменения. Через равные промежутки времени транзакция переименовывает таблицу во что-то другое и вместо нее создает новую таблицу. Затем в транзакции объедините все изменения, выполните соответствующие обновления основной таблицы и обрежьте буферную таблицу. Таким образом, если вам нужен непротиворечивый и свежий снимок любых данных, вы можете выбрать их из основной таблицы и объединить все изменения из активных и переименованных буферных таблиц.

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

Чтобы оптимизировать обновление, убедитесь, что PostgreSQL может использовать кортежи только для кучи для хранения обновленных версий строк. Для этого убедитесь, что в часто обновляемых столбцах отсутствуют индексы, и измените fillfactor на значение, меньшее 100% по умолчанию. Вам нужно будет самостоятельно определить подходящий коэффициент заполнения, так как он сильно зависит от деталей рабочей нагрузки и машины, на которой он работает. Коэффициент заполнения должен быть достаточно низким, чтобы почти все обновления помещались на одну и ту же страницу базы данных, прежде чем автоочистка сможет очистить старые невидимые версии. Вы можете настроить параметры автоочистки для компромисса между плотностью базы данных и расходом вакуума. Кроме того, примите во внимание, что любые длинные транзакции, включая статистические запросы, будут удерживать кортежи, которые изменились после запуска транзакции. См. Представление pg_stat_user_tables , чтобы узнать, что настраивать, особенно отношение n_tup_hot_upd к n_tup_upd и n_live_tup к n_dead_tup .

Тяжелое обновление также создаст интенсивную загрузку журнала записи (WAL). Настройка поведения WAL ( документы для настроек ) поможет снизить это. В частности, большее число checkpoint_segments и большее checkpoint_timeout могут значительно снизить нагрузку ввода-вывода, позволяя большему количеству обновлений происходить в памяти. Посмотрите соотношение checkpoints_timed и checkpoints_req в pg_stat_bgwriter, чтобы увидеть, сколько контрольных точек происходит, потому что достигнут любой из этих пределов. Повышение ваших shared_buffers так, чтобы рабочий набор помещался в память, также поможет. Проверьте «buffers_checkpoint» и «buffers_clean + buffers_backend», чтобы узнать, сколько было написано для удовлетворения требований контрольной точки по сравнению с нехваткой памяти.

6 голосов
/ 02 ноября 2009

Вы хотите собирать статистические обновления, когда они попадают в какую-либо очередь в памяти или, наоборот, на шину сообщений, если вы более амбициозны. Процесс получения затем агрегирует эти статистические обновления на периодической основе, которая может быть где угодно, каждые 5 секунд и каждый час, в зависимости от того, что вы хотите. Затем значения bytes_received и bytes_sent обновляются, причем значения, которые могут представлять множество отдельных сообщений «обновления», суммируются вместе. Кроме того, вы должны объединить операторы обновления для нескольких идентификаторов в одну транзакцию, гарантируя, что операторы обновления будут выполняться в том же относительном порядке по отношению к первичному ключу, чтобы предотвратить взаимные блокировки для других транзакций, которые могут делать то же самое.

Таким образом, вы «группируете» действия в более крупные порции, чтобы контролировать, насколько загружена база данных PG, а также сериализуете много одновременных действий в один поток (или несколько, в зависимости от того, сколько потоков / процессов выдает обновления). , Компромисс, который вы настраиваете на основе «периода», заключается в том, сколько свежести и сколько загрузки обновлений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...