Archive for Апрель 2011
mongodb: «old lock file, terminating»
Короткий пост, про конкретную проблему.
Очень неприятный момент, особенно у нас, где сервера даже у «хорошего» хостера иногда падают от перебоев с питанием, причём падают как будто из них действительно шнур выдёргивали. Работая на Mongo 1.6.5 такой проблемы нет, но перейдя на 1.8.1 однажды утром выяснилось, что база сайта недоступна и сервак жутко тормозит.
В логах было что то вроде
exception in initAndListen std::exception: old lock file, terminating
На деле выяснилось, что Mongo с какой то версии стал создавать mongod.lock файл в директории с данными и при жёстком (без возможности корректно завершить работу сервиса или mongod процесса) выключении он этот файл не удаляет. После загрузки монго проверяет этот файл и видя в нём старые данные повисает в бесконечном цыкле пытаясь запуститься при этом отъедая весь процессор. Проблема решалась переводом сервиса монго в состояние Disabled, удалением lock файла и запуском службы, но это всё руками и вконечно в production такого допускать нельзя.
Проблема решилась относительно просто, выясняя как правильно хостить монго в сервисе, который я уже собрался написать как workaround всплыл такой код:
if ( oldFile ) { // we check this here because we want to see if we can get the lock // if we can't, then its probably just another mongod running string errmsg; if (cmdLine.dur) { if (!dur::haveJournalFiles()) { vector<string> dbnames; getDatabaseNames( dbnames ); if ( dbnames.size() == 0 ) { // this means that mongod crashed // between initial startup and when journaling was initialized // it is safe to continue } else { errmsg = str::stream() << "************** \n" << "old lock file: " << name << ". probably means unclean shutdown,\n" << "but there are no journal files to recover.\n" << "this is likely human error or filesystem corruption.\n" << "found " << dbnames.size() << " dbs.\n" << "see: http://dochub.mongodb.org/core/repair for more information\n" << "*************"; } } } else { errmsg = str::stream() << "************** \n" << "old lock file: " << name << ". probably means unclean shutdown\n" << "recommend removing file and running --repair\n" << "see: http://dochub.mongodb.org/core/repair for more information\n" << "*************"; } if (!errmsg.empty()) { cout << errmsg << endl; #ifdef WIN32 CloseHandle( lockFileHandle ); #else close ( lockFile ); #endif lockFile = 0; uassert( 12596 , "old lock file" , 0 ); } }
Отмечу лишь, что лучше сразу идти на http://www.mongodb.org/display/DOCS/Journaling. При установке mongo нужно указать
--journal
что решает проблему со старым lock фалом, но добавляет небольшие (по заверениям разработчиков) накладные расходы при записи + будет тратится время на обработку этих журналов после hard reset, что в моей ситуации более чем приемлимо.
PS: Интересно было посмотреть в сорцы монго,встречаются комментарии
//instance.cpp line 773 /* This ought to be an unlink(), but Eliot says the last time that was attempted, there was a race condition with acquirePathLock(). */
Скажет — как отрежет.
Update:
При включении опции —journal и попытке подключить существующие файлы баз данных возможна ошибка:
Tue Apr 19 20:53:58 [dur] lsn set 477451
Tue Apr 19 20:54:23 [initandlisten] connection accepted from 127.0.0.1:1196 #2
Tue Apr 19 20:54:23 [conn2] createPrivateMap failed *:/****/****/*******.* errno:8 Недостаточно памяти для обработки команды.
Tue Apr 19 20:54:23 [conn2] Assertion: 13636:createPrivateMap failed (look in log for error)
Tue Apr 19 20:54:23 [conn2] end connection 127.0.0.1:1196