Alexey Suvorov dev blog

Мой разработческий блог

Archive for Апрель 2011

mongodb: «old lock file, terminating»

with one comment

Короткий пост, про конкретную проблему.

Очень неприятный момент, особенно у нас, где сервера даже у «хорошего» хостера иногда падают от перебоев с питанием, причём падают как будто из них действительно шнур выдёргивали. Работая на 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

Written by alexeysuvorov

18.04.2011 at 8:11 пп

Опубликовано в .net, MongoDb