172 похожих чатов

Добрый день. Есть приложение на джаве, оно, значит, ходит

в постгрес:
Хороводит запросами hibernate, а менеджит соединения spring (включён автокоммит)
Все в шифте
На один под пул из 5 коннектов

В какой-то момент пользователь, что-то удаляет
Летит транзакция (в которой дохрена запросов), приложение видит, что запрос выполнился, а в базе запрос повисает в idle in transaction и ждет коммит
Пользователь если обновляет страничку 1 из 5 раз видит, что данные удалены
Запрос висит, пока его не грохнет балансер или база ну и транзакция откатывается

Это происходит примерно в 30 % случаев

Что попробовали:
- Отключить автокоммит, включить принудительный коммит
- ограничить на под один коннект
- ходить в обход балансера
- ходить в обход пгбаунсера через балансер
- ходить на мастер в обход балансера и пгбаунсера

Куда ещё глянуть можно? Может кто подсказать?

Конфигурация постгреса: балансировщик перенаправляет на пгбаунсер, а самим кластером управляет patroni

17 ответов

15 просмотров

> Летит транзакция (в которой дохрена запросов), приложение видит, что запрос выполнился, а в базе запрос повисает в idle in transaction и ждет коммит Вот это — 100% ошибка в приложении (т.е. её нужно исправить, хороших обходных путей просто нет). > Пользователь если обновляет страничку 1 из 5 раз видит, что данные удалены А вот это уже из области "не может быть". Т.е. PostgreSQL не будет "видеть", что данные удалены, если удалявшая их транзакция не завершилась (или откатилась). Может быть, это какое-то кеширование?

SagitoS- Автор вопроса
Yaroslav Schekin
> Летит транзакция (в которой дохрена запросов), п...

по первому пункту, я не спорю, но разработчики мне не верят, грешат на инфру по второму, не могу подтвердить или опровергнуть, это слова пользователей

Yaroslav Schekin
> Летит транзакция (в которой дохрена запросов), п...

Если приложение выберет из пула тот самый коннект который idle in transaction то может

SagitoS- Автор вопроса
Yaroslav Schekin
> Летит транзакция (в которой дохрена запросов), п...

ну и по второму пункту, локально в рамках коннекта они же обновились, но до коммита не обновились в базе, на сколько я понимаю

Я бы ожидал,что проблема в связке pgpool - pgbouncer. Кто-то из них похоже "рвёт" транзакцию.Какой уровень стоит в pgbouncer: statement или session? Но если пробовали работать с постгресом напрямую и проблема всё равно воспроизводится,то тогда скорее всего она на стороне приложения. Возможно hybernate "помог". Попробоуйте включит на сервере логгирование всех statement-ов. Тогда увидите - что дошло,а что нет.

Поскольку упомянута java и spring-pool, то стоит наверно предположить что connection берётся из пула на каждый запрос, а не хранится в user session. В связи с этим после выполнения запроса, вызывается connection.close() который и возвращает коннект обратно в пул. Но при этом не был вызван commit. В таком случаи конечно это ошибка приложения ибо connection.close() был вызван без предварительного вызова commit-а, раз транзакция осталась idle in transaction. Если же connection берётся из пула и хранится в user session, то это вообще грубо говоря бардак ибо lifecycle user session-а может прерваться в любой момент, что приведёт к подвисшим транзакциям условно навсегда и idle бекендам.

Konstantin Knizhnik
Я бы ожидал,что проблема в связке pgpool - pgbounc...

+1 к тому чтобы проверить что pool_mode != "statement" на pgbouncer-е. :)

SagitoS
ну и по второму пункту, локально в рамках коннекта...

> по первому пункту, я не спорю, но разработчики мне не верят, грешат на инфру Хмм... можно логи записать и посмотреть, но для "инфры" это была бы очень грубая ошибка (это вариант, когда connection pooler отдаёт соединения кому-то ещё посреди незавершённой транзакции). > но до коммита не обновились в базе, на сколько я понимаю Да, но тогда они были бы видны либо всегда (в той же сессии), либо никогда (в других).

SagitoS- Автор вопроса

может с выводом из pg_stat_activity еще идеи появятся у кого-то SELECT pid, query_start, age(clock_timestamp(), query_start), usename, state, query FROM pg_stat_activity WHERE query NOT ILIKE '%pg_stat_activity%' and state = 'idle in transaction' ORDER BY query_start desc; 24896,2021-08-16 08:44:53.704133,0 years 0 mons 0 days 0 hours 0 mins 12.553178 secs,имя юзера,idle in transaction,COMMIT насколько я понимаю, коммит прилетает в базу, но транзакция его не исполняет получается последний запрос COMMIT

Yaroslav Schekin
> по первому пункту, я не спорю, но разработчики м...

Большинство pool'ов возвращают connection в pool по connection.close() со стороны приложения. Сложно сказать что при этом неявно делается с транзакцией

Sergey Gr
Большинство pool'ов возвращают connection в pool п...

Ну так должны либо откатывать, либо не возвращать. Иначе это не pooler, а русская рулетка. ;)

Недавно разбирался с "брошенными" транзакциями в wildfly (у него там библиотека с пулером имеет какое-то труднопроизносимое название), весь код, который работает с БД, гарантированно выполняет commit/rollback и выставляет autocommit в true непосредственно перед закрытием. Оказалось, что там внутри смена autocommit передаётся в драйвер не сразу, а после первой значащей команды. Зачем это сделано, не знаю, мб. для поддержки каких-то ee-фишек. Из-за этого даже была бага с фоновой валидацией, её сперва пофиксили нормально (отдачей состояния автокоммита драйверу при возврате подключения в пул), но фикс откатили разработчики из-за возникновения дефекта в каком-то другом проекте. Я им писал, что текущее поведение кривое, они признали проблему и написали, что ищут решение. Воспроизводилось это довольно просто: меняем autocommit на false, затем выполняем rollback, меняем autocommit на true и возвращаем подключение в пул.

SagitoS- Автор вопроса
Radist
Недавно разбирался с "брошенными" транзакциями в w...

спасибо попробуем посмотреть в эту сторону

Похожие вопросы

Обсуждают сегодня

Всем привет, написал код ниже, но он выдает сегфолт, в чем причина? #include <stdio.h> #include <stdlib.h> #include <string.h> struct product { char *name; float price; };...
buzz базз
75
Хотел бы спросить у знающих, правильную ли я выбрал книгу для начала изучения ассемблера Юрова В.И ? Или есть более лучшие книги для начала обучения?
Botsman
31
падает джоба хотя уже была собрана на соседнем namespace, куда капать? │ │ Copying blob sha256:2fa066caddb8f09a71082b03aa43046f79346a01d9c89e06a1f508bb1207dba5 427 │ │ Copyin...
Andrei St
6
$params = [ 'formid' => 'feedbackForm', 'formTpl' => '@CODE: <form class="form-validate" data-id="ajax_form"> <fieldset class="margin-bottom-md"> ...
Pathologic
1
Всем привет, подскажите/посоветуйте пожалуйста. Фаердак компоненты, имею одно место где бизнес хочет видеть при открытии формы список всех клиентов, это порядка 30к. Мои дово...
Sasha Sch
8
Здравствуйте. Задача состоит в том, чтобы сделать real-time чат в мобильном приложении. После передачи сообщения пользователем через веб-сокеты, для основного и долговременног...
🐾
5
А как лучше конвертировать физический адрес в виртуальный при маппинге? В случае ядра у меня, например, direct mapping, первые 768МБ я как есть мапплю в higher half, а остальн...
Evg Resh
8
Книга Юрова В.И пойдёт для обучения?
Botsman
24
Всем привет! А в werf есть возможность скипать проверку сертификата кластера? Я пытаюсь сделать werf converge из GitHub actions, но кластер на локалке с docker-desktop выходит...
Roman Ermakov
2
Всем доброго дня, ребят подскажите пожалуйста, если в курсе по ассемблеру используется MASM32, могу ли я использовать FASM? В чем явная разница и будет ли у меня все работать?
Botsman
17
Карта сайта