Форум сайта python.su
Стоит задача - сделать очередь сообщений в MySQL, которая будет разбираться потоковыми воркерами. Движок, логично, InnoDB.
Вот что пытаюсь сделать - воркеру нужно ждать, пока в очереди что-либо не появится, а затем взять элемент, сменить ему тут же статус и обрабатывать дальше, без возникновения конфликтов с другими воркерами.
Логично, что это надо сделать как-то через транзакции, но MySQLdb, несмотря на заявленную thread-safe-овость, регулярно падает либо с ошибкой “'MySQL server has gone away”, либо “Commands can not sync”.
Посоветуйте, пожалуйста, как организовать код очереди (думал про мьютексы, но нужна максимальная скорость и хотелось бы использовать преимущества InnoDB).
То, что ковыряю сейчас - http://pastie.org/2654033
Офлайн
Может заюзать какой-нибудь специализированный сервер очередей (сообщений). Зачем насиловать базу?
Или сделать самодельное на zmq например.
+ лучше сделать метод при котором сервер будет раздавать сообщения воркерам, чем воркеры будут заваливать сервер “селектами”.
Какой размер очереди будет кстати? Если нет доверия транзакциям, то можно так же сделать оболочку над базой которая будет раздавать сообщения.
> нужна максимальная скорость
какая нагрузка? какие размеры сообщений?
Офлайн
o7412369815963
если бы по заданию можно было заюзать очередь сообщений - я бы так и сделал. Но нужна персистентность. Второй вариант у меня работает через Redis, но такой тоже надо реализовать.
Размер будет максимум около 10-15 тысяч сообщений.
Офлайн
MySQL не причем.
Эти ошибки возникают либо из-за неверных настроек СУБД, либо из-за слабого железа, либо из-за неправильно настроенного железа (дисковая подсистема), либо от плохого алгоритма.
По поводу первой ошибки почитайте http://www.mysql.ru/docs/man/Gone_away.html
По поводу второй - для начала убедитесь, что у вас данные физически ложатся на диск, а не остаются в системном кэше или кэше жесткого диска.
Если тесты вы гоняете на рабочей машине, а не на сервере БД, то скорее всего именно в настройках кэша проблема.
Если с железом все ОК, тогда что-то не то алгоритмом:
http://www.mysql.ru/docs/man/Commands_out_of_sync.html
Офлайн
Lexander
Гоняю на developer-машине. Про ошибку “Commands out of sync” я понял, но вот насчет остального… И еще - стоит ли делать объект очереди синглтоном, чтобы все воркеры ломились к нему, или можно просто передать один и тот же объект всем воркерам? Главная проблема сейчас - чтение из бд. Со вставкой более-менее понятно, а вот чтение сразу тучей воркеров падает. Может быть, как-то отрегулировать частоту запросов из воркеров к базе?
Офлайн
Тучу воркеров нужно ограничить. Сделать пул воркеров. Его размер зависит от настроек СУБД и мощности железа.
Фактически, она уже ограничена настройками СУБД (одна из настроек - макс. кол-во подключений).
Но в этом случае СУБД может выдавать ошибку при попытке подключения воркера сверх допустимого кол-ва.
Или, что гораздо чаще, вновь подключившиеся воркеры просто ждут, когда СУБД освободится и выполнит их запрос.
Ну и такая работа в конце концов всегда упрется в производительность дисковой (или сетевой, если используется NAS) подсистемы.
По хорошему если есть очень большая очередь и ее нужно обрабатывать множеством воркеров, то делают доп. локальную очередь (обычная питоновская очередь).
Очередь в БД обрабатывается пакетами. Размер пакетов должен быть согласован с размером страницы СУБД.
С пакетами работает менеджер очереди (или синглтон, как вы его называете).
Из очереди в БД получают N заданий и воркеры их обрабатывают.
Когда все задания в локальной очереди выполнены, менеджер делает 2 запроса:
- обновляет состояние выполненных заданий
- получает новый пакет заданий
Такой режим позволяет задействовать дисковый кэш максимально.
И даже больше, такой режим соответствует обычному режиму работы дисковой подсистемы - данные записываются и считываются пакетами.
Даже если вам нужно считать 1 запись, все равно машина считает с диска весь пакет, но отдаст только ту запись которую вы запросили.
Эффективность такого подхода можете оценить сами.
ЗЫ
Менеджеров может быть много - по числу машин, на которых запускаются воркеры.
Или по числу ядер/процессоров, если есть возможность обрабатывать задания на разных ядрах/процессорах.
Но и тогда их кол-во ограничено аппаратными возможностями сервера БД.
ЗЫ2
Все вышенаписанное будет совсем по другому, если у вас в качестве хранилища используются носители с произвольным доступом (например, SSD).
Но я таких еще не встречал в промышленных масштабах - дорого :)
Офлайн
LexanderВ том-то и прикол, что я через синглтон пытаюсь использовать всеми воркерами одно и то же подключение. Неужели для каждого делать разное?
Тучу воркеров нужно ограничить. Сделать пул воркеров. Его размер зависит от настроек СУБД и мощности железа.
Фактически, она уже ограничена настройками СУБД (одна из настроек - макс. кол-во подключений).
Офлайн
Можно использовать одно подключение.
Найдите опытным путем то кол-во воркеров, которое спокойно тянет ваше железо.
Допустим, это будет 100.
Тогда выставляете максимально возможное кол-во активных воркеров (потоков) от 50 до 70, если на этом же сервере выполняются дополнительно другие задачи.
Если других задач нет, размер пула можно ставить 80-90, оставляя небольшой запас на пики.
Последнее верно, если ваш сервер не работает в режиме 24/7. Если он работает круглосуточно, то см. первый вариант и доп. задач быть не должно.
Офлайн
Lexander
В общем, сделал через SQLAlchemy, там встроенный пул соединений. Диспатчер достает из базы определенное число сообщений и пихает их в питоновскую очередь, меняя в базе им статус. С питоновской же очередью в многопоточной обработке проблем не возникает.
Офлайн