Форум SAPE.RU

Форум SAPE.RU (http://forum.sape.ru/index.php)
-   Разработка и сопровождение сайтов (http://forum.sape.ru/forumdisplay.php?f=29)
-   -   Одновременное множественное обращение к строке- помогите решить (MySql4.1) (http://forum.sape.ru/showthread.php?t=35437)

Йода 31.07.2009 23:24

Одновременное множественное обращение к строке- помогите решить (MySql4.1)
 
Камрады! Кто шарит- подмогните.
Есть базка. Вней таблички, в табличках, естессн, строки.
Строки надо брать софтинкой, обрабатывать и по результату обработки ставить в этой строке тот или иной флаг (апдейтить, короче); Строка имеет признак того, что она обработанная или необработанная- флажочег, опятьже.. Софтинка берет необработанные и после действа помечает их как обработанные..
Обработка это- процесс ресурсоёмкий, посему экземпляров обработчика (запущенных софтинок) должно быть много. Например 5. Или 100.

Табличка большая- на мильён строк (тоесть это в идеале, если не в идеале- то если не получится работать с большой, буду както чистить, чтоп была маленькая).

Кроме обработчиков, которые обращаются к табличке, есть еще источники, которые в эту табличку строки заносят (создают новые);

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

Лочить таблицу очень не хочется. Это не путь самурая. Хочется как нить хитровыпендрицца :)

Всю голову сломал, ничё путного не придумал.
Поможите, люди добрые!

:)

Vile7xD 01.08.2009 01:11

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

Йода 01.08.2009 01:18

Цитата:

Сообщение от Vile7xD (Сообщение 521115)
каждому обработчику присвоить кратность, брать кол-во строк из таблицы делить на число обработчиков, и пусть каждый в своей зоне шарахается. как-то так.

Спасибо что написали :)
Насчет кратности- количество строк постоянно меняется. Оно увеличивается или уменьшается. Причем не обязательно с краев таблички. Поэтому хочется придумать алгоритм "залочивания" строки за обработчиком.

Vile7xD 01.08.2009 01:23

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

Йода 01.08.2009 01:34

Цитата:

Сообщение от Vile7xD (Сообщение 521129)
ну тогда можно прямо так и указать, к какому обработчику эта строка относится, тогда совсем без лока будет, а при добавлении строки ставить индекс обработчика по кругу. Не передерутся.

Ага. Была такая мысль.
Но:
1. Обработчики разноскоростные с одной стороны и обработка одной строки идет не стандартное количество времени (строки разные)- получится что ктото будет простаивать;
2. Хочется иметь возможность легкого добавления нового обработчика, не завязывая его на регистрацию гдето "на главном компутере"- тоесть поставил новый обработчик, указал ему в конфиге адрес и пароль к базке- и он пошел колбасить..
Или взял, остановил, обработчик и выкинул его. И нигде не нужно их прописывать..

Как считаете? Так можно сделать? Или это слишком жырно? :)

Последний Герой 01.08.2009 01:44

Йода, таблица MyISAM? создайте аналог InnoDB, там встроена построчная блокировка.
или даже в MyISAM можно лишний столбец - флажок (три позиции! 0 незаблокировано, 1 чтение (не записывать), 2 запись (доступ закрыт)) блокировки строки сделать.

Йода 01.08.2009 09:56

Последний Герой, про инно-дб, да. Надо пошукать, что у них там с транзакциями..
А вот насчет
Цитата:

Сообщение от Последний Герой (Сообщение 521148)
в MyISAM можно лишний столбец - флажок (три позиции! 0 незаблокировано, 1 чтение (не записывать), 2 запись (доступ закрыт)) блокировки строки сделать

расскажи подробнее. Тока по шагам. А то у меня получается, что все равно есть возможность двум обработчикам засчитать одну строку своей..
:)

Последний Герой 01.08.2009 13:53

Цитата:

Сообщение от Йода (Сообщение 521207)
Надо пошукать, что у них там с транзакциями..

BEGIN
SELECT ... FROM ... WHERE ... [FOR UPDATE | LOCK IN SHARE MODE]
[COMMIT|ROLLBACK]

FOR UPDATE - блокирует строку на мертво
LOCK IN SHARE MODE - разрешает другим процессам только читать строку
COMMIT - завершить транзакцию с сохранением данных
ROLLBACK - завершить транзакцию с удалением данных (откат)

Цитата:

Сообщение от Йода (Сообщение 521207)
расскажи подробнее. Тока по шагам. А то у меня получается, что все равно есть возможность двум обработчикам засчитать одну строку своей..

реализация транзакций на низком уровне. тока я ошибся там 1 уровень блокировки сойдет и по-другому чуть чуть все будет, вот про это я и расскажу:
1) добавляете столбец числовой и обнуляете его значение для ВСЕХ строк
2) как только какой то поток хочет обратиться к строкам, он записывает в столбец свой айди, с условием, что столбец равен нулю (примерно так UPDATE SET столбец=айди WHERE столбец=0)
3) далее он считывает столбец, если блокировку удалось установить, то в столбце написан его айди (иначе там либо 0 либой айди другого процесса)
4) если блокировки нет, то возвращаемся к шагу 2
5) если блокировка есть, то можно считать, что строки заблокированы и выполнять с ней любые махинации
6) снимаем блокировку, записывая в столбец 0

Alexey 01.08.2009 14:14

Делить таблицу на равные куски плохо т.к. на миллионе параллельных потоков, даже если все операции одинаково ресурсоемки, всегда найдутся процессы, которые сделают их в 3 раза быстрей чем самый медленный. Это обусловлено внешними факторами, неравномерностью распределения процессорного времени и т.д.

Поэтому к концу работы у вас получится что 2 потока "догрызают" последние 10 000 записей, в то время как остальные 98 уже стоят. Т.е. производительность к концу работы будет заметно снижаться.

Простой и эффективный способ есть такой:
1) В таблицу вводим доп поле `handler`.
2) Каждому процессу присваиваем уникальный идентификатор (например, порядковый номер)
3) Делаем
Код:

UPDATE `table` SET
              `handler`=<идентификатор текущего процесса>
WHERE
              `handler` is NULL AND
              `is_processed` = 0
LIMIT 1

Таким образом, процесс как бы резервирует за собой эту строчку.
4) Выбираем эту строчку через
Код:

SELECT .... WHERE `handler`=<идентификатор текущего процесса>
и работаем с ней
5) по завершению ставим записи is_processed = 1


Для оптимизации можно резервировать по 10-30 записей за раз, тогда будет меньше накладных расходов на обращение к БД.

Для легкого добавления обработчика сделайте это поле, например, строковым и пишите туда не число, а типа `mycomputer-1` и т.д. В общем, неймспейсы:)

Совершенно пофигу как и в каком порядка они будут называться. Не забудьте только индекс на это поле поставить.

Последний Герой 01.08.2009 14:19

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


Часовой пояс GMT +3, время: 16:12.

Работает на vBulletin® версия 3.8.7.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
SAPE.RU — система купли-продажи ссылок с главных и внутренних страниц сайтов.