Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Имеем таблицу, например с пин-кодами... Имеем веб-сайт откуда это все продается... При этом у каждого посетителя есть возможность приобрести срезу несколько пин-кодов одного типа и номинала. Вопрос: как обеспечить конкурентный доступ к пинам без блокировки таблицы. Очевидно что один пин не может быть дважды. Также если человек заказал 5 пинов, и в таблице есть достаточно пинов ему должно быть отдано 5 пинов. Что имеем? SELECT FOR UPDATE + UPDATE +COMMIT -> приходит первый клиент. выполняет SELECT FOR UPDATE. Приходит второй - повисает на первой же залоченой записи пока второй не выполнит COMMIT. В случае с PG проблема усугубляется тем, что после разблокировки записи PG не перезапускает сканирование таблицы, как это делает ORACLE. Таким образом вместо 5 пинов может отдаться например 3. Плюс, доступ всеравно получается последовательный. Кто решал подобные задачи? Как правильно решить данную проблему. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 12:14 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Почему же повисает. Есть такие волшебные слова, как NOWAIT. Правда, вам они вряд ли понравятся. Тогда клиент не повисает, но генерит ошибку, которую можно поймать. Хотя, почему же не поможет. Как вариант - открываете курсор, бежите по таблице и пытаетесь залочить (по одной) нужное число записей. Те, что валятся на ошибке "уже залочено" просто пропускаете. Это первый вариант. Второй - делайте механизм резервирования. Толком не скажу, зачем это может понадобиться вам. Ну, например, для того, чтобы второму клиенту можно было показать, что на момент, когда он начал выбирать, всего в базе 100 пинов, но 20 из них уже за кем-то зарезервировано. В этом случае, пины, выделяемые пользователю резервируются (т.е. в записи есть флаг - резерв/свободен и время резервирования). Пользователь може ещё долго наслаждаться дизайном вашей веб странички, а потом подтвердить или отказаться от покупки. При этом должно быть оговорено время, на которое резервируется пин. По истечению этого времени специальная процедура снимает флаг резерва. Замороченно, но всё зависит от потребностей. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 12:30 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
авторПочему же повисает. Есть такие волшебные слова, как NOWAIT. Правда, вам они вряд ли понравятся. Тогда клиент не повисает, но генерит ошибку, которую можно поймать. Хотя, почему же не поможет. Как вариант - открываете курсор, бежите по таблице и пытаетесь залочить (по одной) нужное число записей. Те, что валятся на ошибке "уже залочено" просто пропускаете. Это понятно авторЭто первый вариант. Второй - делайте механизм резервирования. Толком не скажу, зачем это может понадобиться вам. Ну, например, для того, чтобы второму клиенту можно было показать, что на момент, когда он начал выбирать, всего в базе 100 пинов, но 20 из них уже за кем-то зарезервировано. В этом случае, пины, выделяемые пользователю резервируются (т.е. в записи есть флаг - резерв/свободен и время резервирования). Пользователь може ещё долго наслаждаться дизайном вашей веб странички, а потом подтвердить или отказаться от покупки. При этом должно быть оговорено время, на которое резервируется пин. По истечению этого времени специальная процедура снимает флаг резерва. Замороченно, но всё зависит от потребностей. А как конкурентно зарезервировать тогда? :) . Если же резервировать каким то образом заранее, до того как прийдет клиент. То может сложится ситуация когда пины в базе есть а вот для конкретного клиента их нет. Вариант с блокировкой таблице рабочий.. Но очевидно, что пока работают 100 клиентов - это будет нормально.. если их будет 1000 то все встанет колом и все будут ждать поочереди своих пинов... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 13:07 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Боюсь, что вы предполагаете использовать оптимистическую стратегию блокировок, тогда как в вашем случае (да и в Вебе вообще) нужно использовать пессимистичскую - т.е. свести время нахождения записей в блокированном виде к минимуму. Итак, пришёл пользователь. Сказал, что хочет 5 пинов. Мы их не залочили. Мы их зарезервировали (т.е. быстренько нашли пять нелоченых записей, залочили, обновили у них флаг "резерв" и закоммитились. Ну и запомнили - кому их зарезервировали). Всё. Конкуренция только если этот короткий промежуток времени кто-то ещё будет резервировать записи. Если же сделать так, что пользователь заказал 5 пинов. Мы их залочили и ждём, когда он соизволит подтвердить свой заказ, то всё может встать колом и при 100 пользователях ОДНОВРЕМЕННО заказывающих пины. Да, как вариант первого примера, но без резерва - мы запомнили, что пользователю нужно 5 пинов (но ничего не резервировали), он подтвердил и тогда мы побежали лочить записи, обновлять из как вам нужно - ставить пометку "продано", и тут же коммититься. Опять же это делается одномоментно (т.е. исключительно за время, требуемое для лочки, изменения и коммита), но не за время обдумывания пользователем каких-то своих домашних проблем. В этом случае, если количество пинов ограничено, может случиться так, что пользователь заказав 5 штук так долго думал, прежде чем нажать кнопку подтверждения, что их уже раскупили. Он будет очень удивлён. В этом случае резервирование поможет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 13:32 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
ChameLe0nВариант с блокировкой таблице рабочий..Не надо блокировать всю таблицу. Надо блокировать только нужные записи. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 13:33 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
авторКонкуренция только если этот короткий промежуток времени кто-то ещё будет резервировать записи. Считайте что конкуренция постоянная. Предположим есть только один типа карточки. И 100 клиентов одновременно жмут кнопку - купить 10 пинов. Предположим что время обработки каждого запроса(10 пинов) - 1 с. Как мне отдать все данные клиентам за ~1с. А не за 100 с. авторон подтвердил и тогда мы побежали лочить записи, обновлять из как вам нужно - ставить пометку "продано", и тут же коммититься. Опять же это делается одномоментно Не понял Вашего хода мыслей. Я пример привел с "побежали лочить записи" в первом посте. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 13:58 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
насколько я понял, проблема в том что для "select ... for update" нет способа сказать "игнорируй уже заблокированные на данный момент строки", а перебирать записи постоянно перезапуская транзакцию - не хочется. тогда такая идея - добавить в таблицу пинов колонку g: Код: plaintext при выборке - выбирать из блока "от балды" типа Код: plaintext Код: plaintext -- „Истина — это вовсе не то, что можно убедительно доказать, это то, что делает всё проще и понятнее“ — Антуан де Сент-Экзюпери ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:08 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Ёшнасколько я понял, проблема в том что для "select ... for update" нет способа сказать "игнорируй уже заблокированные на данный момент строки", а перебирать записи постоянно перезапуская транзакцию - не хочется.Зачем постоянно перезапускать транзакцию? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:11 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
кхм... разовью мысль - можно же ещё проще - если выбирать пины не подряд, а случайные :) вероятность того что допустим с хорошим random из 100000 свободных пинов две транзакции выберут один и тот же пин и будут заблокированы - достаточно мала :) имхо. -- „Истина — это вовсе не то, что можно убедительно доказать, это то, что делает всё проще и понятнее“ — Антуан де Сент-Экзюпери ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:13 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
pamir Ёшнасколько я понял, проблема в том что для "select ... for update" нет способа сказать "игнорируй уже заблокированные на данный момент строки", а перебирать записи постоянно перезапуская транзакцию - не хочется.Зачем постоянно перезапускать транзакцию?ну всмысле что "постоянно обрабатывать exception ERROR: could not obtain lock on row in relation" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:15 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Ёш pamir Ёшнасколько я понял, проблема в том что для "select ... for update" нет способа сказать "игнорируй уже заблокированные на данный момент строки", а перебирать записи постоянно перезапуская транзакцию - не хочется.Зачем постоянно перезапускать транзакцию?ну всмысле что "постоянно обрабатывать exception ERROR: could not obtain lock on row in relation"Ааа. Ну так это ж другое совсем. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:18 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
ChameLe0n авторКонкуренция только если этот короткий промежуток времени кто-то ещё будет резервировать записи. Считайте что конкуренция постоянная. Предположим есть только один типа карточки. И 100 клиентов одновременно жмут кнопку - купить 10 пинов. Предположим что время обработки каждого запроса(10 пинов) - 1 с. Как мне отдать все данные клиентам за ~1с. А не за 100 с.Для того чтобы улучшить конкурентный доступ к объектам (таблицам, записям и тд) можно либо уменьшить время блокировки, либо сегментировать доступ к объекту (чтобы у него был не одна блокировка, а несколько независимых). 1) В коротких транзакциях обновлять количество доступных карточек. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Есть большой минус у этого варианта - надо синхронизировать две транзакции через 2PC, либо вручную. 2) ну а чтобы сделать сегментацию блокировок, надо крепко подумать :) Отчасти вариант будет похож на предложенный Ёж'ом :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 15:21 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Ёшкхм... разовью мысль - можно же ещё проще - если выбирать пины не подряд, а случайные :) вероятность того что допустим с хорошим random из 100000 свободных пинов две транзакции выберут один и тот же пин и будут заблокированы - достаточно мала :) имхо. Имеет право на жизнь. Только насколько я понимаю запрос вида Код: plaintext 1. 2. 3. 4. 5. 6. Каждый раз будет тянуть все данные из базы. Если пинов много - будет тяжеловато. Второй момент - это не решит проблему с тем что может вернуться меньше пинов чем запрошено при наличии необходимого количества. Думаю, может перенести логику на сервер приложений. В Java5 появились всякие вкусности на тему конкуретного доступа... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 19:28 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
ChameLe0nДумаю, может перенести логику на сервер приложений. В Java5 появились всякие вкусности на тему конкуретного доступа...При кластеризации возможно большие проблемы синхронизации, да и по большому проблема не решится, а лишь прибавит сложности программы. И, соответственно, затруднит поддержку. ИМХО, это задача, которую лучше всего решать на уровне БД. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 19:37 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
авторТо есть значала резервируем количество карт и быстренько закрываем тразакцию, чтобы не блокировать ресурс. После этого открываем новую транзакцию, где выполняем "медленную" бизнес-логику продажи товара. Вцелом медленной бизнес-логики нет. Я показал как пример, что непонятно как добится приемлемого параллелилизма в конкретном случае и авторТо есть значала резервируем количество карт и быстренько закрываем тразакцию может оказаться очень медленным при 1000 паралельных клиентах ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 19:41 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
ChameLe0n1000 конкурентных запросов на изменение одного ресурса - это очень очень очень круто! Но если предположить такую ситуацию теоретически, то возможно, что пессимистическая блокировка всей таблицы на запись (или блока строк) - это единственное решение, так как любая любая оптимистическая блокировка чревата постоянными эксепшенами (это будет аналогично запуску 1000 приложений на однопроцессорном компьютере, процессор всё время будет занят переключением между задачами, а не выполнением этих задач. В итоге, ни одна задача не будет решена в приемлемое время). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.05.2008, 19:58 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
автор1000 конкурентных запросов на изменение одного ресурса - это очень очень очень круто! Ок, погорячился... но 50 или 100 - вполне реальная цифра.. Еще идеи есть у кого? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.06.2008, 13:42 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Имеем 50-100 килентов которые "сражаются" за ресурс, в данном случае множество еще-не-купленных пинов. На мой взгляд возможны два решения: 1. "взять все и поделить", как предложил Еш . Массив пинов разделяется на N сегментов по какому- либо способу, где N = "concurrency level", i.e. предполагаемое кол-во одновременных клиентов. Каждому клиенту в момент открытия сессии присваивается номер сегмента массива пинов n. Далее вы делаете ваш SELECT FOR UPDATE WHERE segment_num = ... + UPDATE +COMMIT 2. "асинхронно и очередь". т.е. классическая схема продажи чего либо order-invoice-inventory-account-transactions. При наличии не купленных пинов намерение клиента купить X пинов записывается как заказ. Клиент ждет когда его заказ выполнят и выдадут справку-счет где указанны конкретные номера купленных пинов. Выполнением заказов должен заниматся отдельный процесс который работает как по cron или как service/daemon. Такой процесс обрабатывает заказы one-by-one: "BEGIN: считывает заказ, проводит платеж, помечает Х пинов как проданные и номера записывает в иновойс ... изменяет балансы, пишет transaction лог ... етц COMMIT". 3. вариант "2 + 1", то есть вариант 2, только когда имеются несколько процессов которые занимаются исполнением заказов параллельно. Чтобы "заказо-исполнители" не дрались за ресур, его надо разбить на части, например если есть два параллельных процесса, то можно организовать чтоб один работает по четным номерам заказов и отдает пины у которых pin_number <= ( pins_total / 2 ) а другой обрабатывает нечётные заказы и отдаёт пины pin_number > ( pins_total / 2 ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 00:55 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
ChameLe0n автор1000 конкурентных запросов на изменение одного ресурса - это очень очень очень круто! Ок, погорячился... но 50 или 100 - вполне реальная цифра.. Еще идеи есть у кого?имхо быстрее чем вариант Dan Black'а с блокировкой не счётчике - не сделать ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 00:57 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Konstantin~Имеем 50-100 килентов которые "сражаются" за ресурс, в данном случае множество еще-не-купленных пинов. На мой взгляд возможны два решения: 1. "взять все и поделить", как предложил Еш . Массив пинов разделяется на N сегментов по какому- либо способу, где N = "concurrency level", i.e. предполагаемое кол-во одновременных клиентов. Каждому клиенту в момент открытия сессии присваивается номер сегмента массива пинов n. Далее вы делаете ваш SELECT FOR UPDATE WHERE segment_num = ... + UPDATE +COMMIT 2. "асинхронно и очередь". т.е. классическая схема продажи чего либо order-invoice-inventory-account-transactions. При наличии не купленных пинов намерение клиента купить X пинов записывается как заказ. Клиент ждет когда его заказ выполнят и выдадут справку-счет где указанны конкретные номера купленных пинов. Выполнением заказов должен заниматся отдельный процесс который работает как по cron или как service/daemon. Такой процесс обрабатывает заказы one-by-one: "BEGIN: считывает заказ, проводит платеж, помечает Х пинов как проданные и номера записывает в иновойс ... изменяет балансы, пишет transaction лог ... етц COMMIT". 3. вариант "2 + 1", то есть вариант 2, только когда имеются несколько процессов которые занимаются исполнением заказов параллельно. Чтобы "заказо-исполнители" не дрались за ресур, его надо разбить на части, например если есть два параллельных процесса, то можно организовать чтоб один работает по четным номерам заказов и отдает пины у которых pin_number <= ( pins_total / 2 ) а другой обрабатывает нечётные заказы и отдаёт пины pin_number > ( pins_total / 2 ) Спасибо, принято к сведенью ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 09:41 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Кстати, может в других СУБД есть красивое решение? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 09:41 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
IMHO нету т.к. проблема не в бд. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 10:37 |
|
||
|
Конкурентный доступ к таблице
|
|||
|---|---|---|---|
|
#18+
Можно развить вариант 2: Есть таблица заказов, куда валятся заказы и есть демон, который выполняет эти заказы, вне зависимости от того, подтвердил или нет пользователь свой заказ... То есть заказ обрабатывается так: Пользователь сказал "Хочу 5 пинов". Эта "хотелка" записалась в таблицу предварительных заказов. Попала в карзину пользователя и т.д. Тут информацтя попала на компьютер пользователя, где он может выбрать ещё что-то или просто нажать на кнопку выписать. Пораллельно по крону запускается процедура, которая "выполняет" предварительные заказы: Обновляет записи в "хотелке", добавляя их пинами. А в таблицу пинов ставит флаг "зарезервированно". Если пользователь надап "выписать", то идет проверка: выполнена-ли "хотелка". Если она выполнена, то эта "хотелка" переносится/изменяется ее статус до продано. Если она ещё не выполнена, то пользователю говорят что.. так и так... обождите 5 секунд. Если "хотелка" выполнена частично, то это значит что пинов больше нет. О чем радостно сообщают пользователю. Если пины "выписаны", то та-же кроновая процедура доносит эту информацию до таблицы пинов. Аналогично работает функция "я больше не хочу 5 пинов". Вобщем как-то так... Таки образом "хотелки" записываются в отдельную таблицу, которая не растет и зависит напрямую от кол-ва человек. Что позволяет не тормозить пользователя до тех пор когда его "хотелку" выполнят, но в то-же время "хотелку" выполняют не тогда, когда пользователь сказал "выписать", а тогда, когда он усердно изучает нтерфейс(в большинстве случаев). Таким образом после того, как пользователь нажал "выписать" и ушел с сервера его запрос все ещё может обрабатываться (доносится ценная информация о том что пин уже продан, а не зарезервирован), только вот пользователь об этом не узнает. Минусы тут такие: Если будет много отказов (Выбрали 5 пинов, а потом отказались) то может получиться что все пины зарезервированны, хотя от них отказались. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2008, 14:42 |
|
||
|
|

start [/forum/topic.php?fid=53&msg=35350549&tid=2004323]: |
0ms |
get settings: |
7ms |
get forum list: |
17ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
46ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
54ms |
get tp. blocked users: |
1ms |
| others: | 223ms |
| total: | 365ms |

| 0 / 0 |
