Buldozer
Новичок
Помогите решить задачу.
Есть задача, реализовать некий шейпер, который бы ограничил кол-во конектов к одному сайту.
итого есть две таблицы:
в первой хранится инфомация для обработки, вторая реализует этот самый шейпер.
алгоритм такой:
*задумка шейпера - что если запись и сайт будут помечаны как используемые, то эта запись и записи принадлежащие этому сайту не будут выбираться больше указанного лимита.
*проблема шейпера - что между селектом и апдэйтом/инсертом(который помечает, записи как используемые) параллельно выполняемые копии скрипта успевают сделать еще несколько селектов и в результате ограничение не соблюдается, и более того одна и та же запись обрабатывается в несколько потоков.
*решено было использованием блокировки - т.е. с пункта 1 по 2 таблицы блокируются и соответственно ограничение теперь соблюдается, но…
*новая проблема - база практически висит из-за постоянных блокировок, сменил тип таблицы на memory, но это не очень помогло.
Как вариант: использовать блокировку физического файла… но скрипты могут запускаться с разных серверов =>… не получится.
Еще вариант: с использованием некой служебной таблицы, которая состоит из одной единственной ячейки, которая может содержать или 1 или 0. 1 – значит, что сейчас производится операция выборки данных для шейпера, и данные выбирать нельзя; 0 – значит, что операции выборки сейчас не производится и следовательно можно выбирать…
здесь смущает первый пункт… придется постоянно опрашивать таблицу, в то время, как на данный момент, скрипт просто посылает запрос и ждет когда его мускуль обслужит.
Есть задача, реализовать некий шейпер, который бы ограничил кол-во конектов к одному сайту.
итого есть две таблицы:
PHP:
mysql> describe spider_check_query;
+----------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+-------+
| page_id | int(10) unsigned | NO | PRI | | |
| page_url | char(255) | NO | | | |
| site_id | int(10) unsigned | NO | MUL | | |
| site_url | char(255) | NO | | | |
| link | char(255) | NO | | | |
| initiated_date | int(10) unsigned | NO | MUL | 0 | |
| status | tinyint(3) unsigned | NO | MUL | 0 | |
| result | tinyint(3) unsigned | NO | MUL | 0 | |
+----------------+---------------------+------+-----+---------+-------+
mysql> describe spider_checker_limiter;
+---------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| site_id | int(10) unsigned | NO | PRI | | |
| count | int(11) | NO | | | |
+---------+------------------+------+-----+---------+-------+
алгоритм такой:
PHP:
1. делаем выборку из таблиц исключая те записи, которые принадлежат сайтам привысившим лимит соединений(т.е. select page_id, page_url, site_id, site_url, link from spider_check_query where status = 0 and site_id not in (select site_id from spider_checker_limiter where count >= 2) limit 1)
2. повышаем счетчик соединений для данного сайта("INSERT INTO spider_checker_limiter values('$site_id', '1') ON DUPLICATE KEY UPDATE count = count + 1"), что бы соблюсти необходимый лимит + помечаем запись как обрабатываемую("mysql_query("update spider_check_query set status = 1, initiated_date = $timestamp where page_id = $page_id");
")
3. обрабатываем данные.
4. по завершению работы минусуем счетчик соединений для сайта, и помечаем запись как обработанную.
*проблема шейпера - что между селектом и апдэйтом/инсертом(который помечает, записи как используемые) параллельно выполняемые копии скрипта успевают сделать еще несколько селектов и в результате ограничение не соблюдается, и более того одна и та же запись обрабатывается в несколько потоков.
*решено было использованием блокировки - т.е. с пункта 1 по 2 таблицы блокируются и соответственно ограничение теперь соблюдается, но…
*новая проблема - база практически висит из-за постоянных блокировок, сменил тип таблицы на memory, но это не очень помогло.
Как вариант: использовать блокировку физического файла… но скрипты могут запускаться с разных серверов =>… не получится.
Еще вариант: с использованием некой служебной таблицы, которая состоит из одной единственной ячейки, которая может содержать или 1 или 0. 1 – значит, что сейчас производится операция выборки данных для шейпера, и данные выбирать нельзя; 0 – значит, что операции выборки сейчас не производится и следовательно можно выбирать…
PHP:
1. ожидаем как только флаг будет = 0
2. как только флаг = 0, лочим таблицу и выставляем флаг 1
3. делаем unlock(что бы иметь возможность работать с другими таблицами)
4. делаем выборку согласно ограничениям
5. выставляем флаг 0
6. обрабатываем данные