CouchDB: история одной аварии

в 9:54, , рубрики: couchdb, fail, nosql, метки: ,

CouchDB: история одной аварии
Хочу поделиться историей, как наш проект слёг на полтора часа, и опытом выяснения причин.

В один прекрасный момент мы понимает, что часть сайта грузится с 15-минутной задержкой, а другая часть попросту не работает, выдавая 504 ошибку.

Занимаюсь я проектом, который использует в качестве БД CouchDB. Есть на нём раздел «Афиша», в который можно добавлять события, в частности можно добавить периодическое событие, задав дату начала периода и дату окончания.
После добавления события в базе создаётся документ события, и в отдельное его поле добавляется на каждый день периода временной промежуток. По этим промежуткам делается выборка для вывода на сайте. Выборка, по сути, просто из всех документов выбирает промежутки временные.

Таким образом, добавив событие на 7 дней, мы получаем документ, в котором в поле периодов находится 7 записей, и в вид у нас выводится 7 записей.

Fail

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

Пользователь-пакостник

Появляется пользователь с платным аккаунтом, и, баловства ради, добавляет событие, указав конечную дату мероприятия 2100 год.
На сервере начинает мощно работать php-fpm, начав добавление 365*100 событий. Добавить-то он добавил, да пользователь не дождался сообщения об успешном добавлении, решив, вероятно, что что-то глюкнуло или инет отвалился, и нажал на добавление события снова, изменив немного время события. Процесс пошёл второй раз. Не то, чтобы php-fpm дал какую-то серьёзную нагрузку, но в списке по команде top на сервере было больше процессов php-fpm, чем обычно, что сбило с толку и заставило думать какое-то время в неверном направлении.

В итоге имеем 2 документа в БД с временными промежутками количеством 365*100 в каждом. CouchDB начинает обновлять вид, что ему никак не даётся.

В логах сервера что-то вроде:
[<0.738.0>] Exit from linked
pid: {<0.742.0>,
{timeout,
{gen_server,call,
[couch_query_servers,
{get_proc,<<"javascript">>}]}}}

При попытке зайти в базу в Futon видим ошибку os_process_error. В разделе Status в Futon видим не исчезающую надпись с пометкой, что это именно в базе событий (см. 1 строку):
CouchDB: история одной аварии
Была мысль, что что-то глюкнуло или побилась база, но service couchdb restart не помог, также, как и замена базы на сервере на последнюю копию с репликации на другом сервере.

После гугления, было найдено в архиве почтовой рассылки CouchDB решение — база наталкивалась при обновлении вида на os_process_timeout = 5000 (5 секунд). Вид просто не успевал в отведенное ему время обработать документ. Увеличив в конфиге значение до 15 секунд, наконец удалось добиться применения изменений и сайт заработал в штатном режиме.

Разобравшись с причиной того, что сайт просто не грузился, выдавая 504 ошибку и разобравшись с базой, наконец был восстановлен сценарий и приняты меры — чтобы подобного больше не повторилось.

К слову, созданные 2 документа в базе пришлось удалять быстренько написанным скриптом, т.к. открывать документ в Futon браузер просто отказывался, зависая намертво, очевидно, пытаясь обработать массив с временными промежутками.

Последовательность событий восстанавливалась в примерно обратном моему повествованию порядке, что заставило изрядно понервничать, т.к. с таким, лично мне, пришлось столкнуться впервые (надо отдать должное начальству, которое не бегало вокруг, требуя срочно разобраться и поднять сайт, а тихо спокойно позволило разобраться с проблемой).

Исходя из описанного, напрашиваются некоторые выводы:
— не храните много данных в одном документе, особенно, если это массив, который учавствует в выборке. Тут, правда, ещё спорный вопрос, что лучше — много мелких документов, или мало больших, но слишком большие документы в нашем случае показали себя не с лучшей стороны;
— если, зайдя в базу, появляется ошибка os_process_error, а в логах слово timeout — попробуйте увеличить os_process_timeout в конфиге, это позволит базе начать снова работать и возвращать результаты, обработав последние изменения;
— золотое правило, которым мы, увы, не воспользовались в конкретном случае — проверяйте введённые пользователем данные, думайте, как хитрый пользователь-пакостник.

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

P.S. Полезная статья на Хабре: 16 практических советов по работе с CouchDB.

Автор: Makaveli

Поделиться

* - обязательные к заполнению поля