#postgresql #go #sql-update
#postgresql #Вперед #sql-обновление
Вопрос:
ПРОБЛЕМА
Я работаю с PostgreSQL v10 golang и сталкиваюсь с тем, что я считаю очень распространенной проблемой SQL:
- У меня есть таблица «счетчики», в которой есть
current_value
иmax_value
целочисленные столбцы. - Строго говоря, один раз
current_value >= max_value
я хотел бы отклонить запрос. - У меня есть несколько модулей Kubernetes, которые при каждом вызове API могут увеличивать
current_value
количество одной и той же строки (в худшем случае) в таблице «счетчики» на 1 (можно рассматривать как одновременные обновления одной и той же базы данных с распределенных хостов).
В моей текущей и наивной реализации несколько ОБНОВЛЕНИЙ для одной и той же строки естественным образом блокируют друг друга (уровень изоляции «зафиксирован для чтения», если это имеет значение). В худшем случае у меня более 10 запросов в секунду, которые обновляют одну и ту же строку. Это создает бутылочное горлышко и снижает производительность, чего я не могу себе позволить.
ВОЗМОЖНОЕ РЕШЕНИЕ
Я придумал несколько идей для решения этой проблемы, но все они приносят в жертву целостность или производительность. Единственный, который поддерживает оба, звучит не очень чисто для этой, казалось бы, распространенной проблемы:
Пока счетчик current_value
находится на относительно безопасном расстоянии от max_value
(дельта > 100), отправляйте запрос на обновление на канал, который будет сбрасываться каждую секунду или около того работником, который будет агрегировать обновления и запрашивать их сразу. В противном случае (дельта <= 100) выполните обновление в контексте транзакции (и устраните узкое место, но в меньшинстве случаев). Это ускорит запросы на обновление до тех пор, пока предел почти не будет достигнут, эффективно устраняя узкое место.
Вероятно, это сработало бы для решения моей проблемы. Однако я не могу не думать, что есть лучшие способы решения этой проблемы.
Я не нашел отличного решения в Интернете, и хотя мой эвристический метод сработал бы, он кажется нечистым и ему не хватает целостности.
Креативные решения очень приветствуются!
Редактировать:
Благодаря совету @laurenz-albe я попытался сократить продолжительность между ОБНОВЛЕНИЕМ, при котором строка блокируется, и фиксацией транзакции. Похоже, что нажатие всех ОБНОВЛЕНИЙ до конца транзакции сделало свое дело. Теперь я могу обрабатывать более 100 запросов в секунду и поддерживать целостность!
Ответ №1:
10 одновременных обновлений в секунду — это смехотворно мало. Просто убедитесь, что транзакции как можно короче, и это не будет проблемой.
Вашей самой большой проблемой будет VACUUM
, поскольку большое количество обновлений — это наихудшая возможная рабочая нагрузка для PostgreSQL. Убедитесь, что вы создали таблицу с fillfactor
числом 70 или около того, и она current_value
не проиндексирована, чтобы получать ГОРЯЧИЕ обновления.
Комментарии:
1. Вы правы. Проблема заключается в большой продолжительности моих транзакций, поскольку каждая транзакция длится в течение всего срока действия запроса. Я попытаюсь создать дополнительную транзакцию, только для этого обновления, и попытаюсь придумать способ отменить обновление в случае сбоя основной транзакции (запроса).
2. Доведение ОБНОВЛЕНИЯ до самого конца транзакции сделало свое дело. Теперь я могу обрабатывать более 100 запросов в секунду. Спасибо.