Открытие и закрытие 16000 экземпляров базы данных Mongo в PHP


В настоящее время я работаю над некоторыми личными тестами и тестами, чтобы сравнить рабочий процесс и эффективность использования MongoDB и MySQL с данными примеров из реального мира.

Чтобы настроить свои данные в каждой базе данных, я выполняю несколько тысяч циклов и произвольно создаю объекты данных для вставки в базу данных.

Однако у меня возникли некоторые проблемы с использованием класса Mongo в PHP, которые я не могу решить. Проблема заключается в следующем:

У меня есть цикл, который создает новый экземпляр Mongo и подключение, вставляет небольшой массив в коллекцию, а затем закрывает соединение. Этот цикл должен выполняться 20000 раз. Однако он всегда терпит неудачу в 16300-м цикле (с минимумом 16200 и максимумом 16350, я бы сказал, после нескольких запусков), когда он пытается создать экземпляр/установить соединение.

Код в цикле приведен ниже:

$data = get_random_user_data();

$mongo = new Mongo('mongodb://admin:password@localhost:27017/test');

    if ($mongo->test->users->insert($data)) {
        $users[] = array('id' => $data['_id'], 'name' => $data['username']);
    echo $i." - Added user: ".$data['username'].'<br/>';
    }

$mongo->close();

Get_random_user_data() просто возвращает простой ассоциативный массив.

Ошибка, которую я получаю, такова:

Fatal error: Uncaught exception 'MongoConnectionException' with message 'Unknown error'

На линии:

$mongo = new Mongo('mongodb://admin:password@localhost:27017/test');

Есть идеи? Есть ли что-то фундаментальное, чего мне не хватает, например, какой-то безопасности или предотвращения спама?

Заранее благодарю.

Дополнительная информация:

Сценарий умирает примерно через 114,9797 секунды. Это не проблема с памятью PHP или временем, так как все ограничения подняты, и вчера я запустил свои тесты MySQL, вставив 120000 строк (с тем же методом циклического открытия соединения, вставки, закрытия соединения) в течение примерно часа без проблем.

Запуск Версия PHP 5.3.5

Информация о Phpinfo Монго:

MongoDB Support enabled
Version 1.2.0-
Directive   Local Value Master Value
mongo.allow_empty_keys  0   0
mongo.allow_persistent  1   1
mongo.auto_reconnect    1   1
mongo.chunk_size    262144  262144
mongo.cmd   $   $
mongo.default_host  localhost   localhost
mongo.default_port  27017   27017
mongo.long_as_object    0   0
mongo.native_long   0   0
mongo.no_id 0   0
mongo.utf8  1   1
Author: Community, 2012-01-15

3 answers

Ваша операционная система имеет ограниченное количество сокетов, которые она готова открыть. Когда вы открываете сокет, а затем закрываете его, ОС не сразу помещает его обратно в "доступный" пул, он некоторое время зависает в состоянии "время ожидания", которое Нат упоминает в своем ответе.

Вы можете увеличить количество сокетов, которые будет открывать ваша ОС, см. http://www.mongodb.org/display/DOCS/Too +Много+Открытых+файлов (каждый сокет является открытым "файлом").

Кроме того, вы используете довольно старая версия драйвера, возможно, вы захотите рассмотреть возможность обновления.

 6
Author: kristina, 2017-05-23 12:28:10

Я подтверждаю, что такое же поведение и у драйвера ruby. Я повторил аналогичный случай с ruby mongo, который вставляет 20000 записей, каждый раз открывая/закрывая экземпляр mongo. И он продолжает терпеть неудачу между 14110 и 14200 годами.

Это сообщение об ошибке

 uncaught throw #<Mongo::ConnectionFailure: Failed to connect to host localhost and port 27017: Cannot assign requested address - connect(2)>

Это полная трассировка стека

Failed to connect to host localhost and port 27017: Cannot assign requested address - connect(2)
["/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:171:in `rescue in checkout_new_socket'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:166:in `checkout_new_socket'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:267:in `block (2 levels) in checkout'", "<internal:prelude>:10:in `synchronize'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:259:in `block in checkout'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:252:in `loop'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/pool.rb:252:in `checkout'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/connection.rb:496:in `checkout_writer'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/networking.rb:34:in `send_message'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/collection.rb:948:in `block in insert_documents'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/util/logging.rb:28:in `instrument'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/collection.rb:944:in `insert_documents'", "/home/ramesh/.rvm/gems/ruby-1.9.2-p290/gems/mongo-1.5.2/lib/mongo/collection.rb:343:in `insert'", "/home/ramesh/Desktop/load_test.rb:15:in `block in load_test'", "/home/ramesh/Desktop/load_test.rb:6:in `times'", "/home/ramesh/Desktop/load_test.rb:6:in `load_test'", "(irb):2:in `irb_binding'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:273:in `signal_status'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:155:in `eval_input'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:70:in `block in start'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:69:in `catch'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/irb.rb:69:in `start'", "/home/ramesh/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'"]
ArgumentError: uncaught throw #<Mongo::ConnectionFailure: Failed to connect to host localhost and port 27017: Cannot assign requested address - connect(2)>
    from /home/ramesh/Desktop/load_test.rb:21:in `throw'
    from /home/ramesh/Desktop/load_test.rb:21:in `rescue in block in load_test'
    from /home/ramesh/Desktop/load_test.rb:7:in `block in load_test'
    from /home/ramesh/Desktop/load_test.rb:6:in `times'
    from /home/ramesh/Desktop/load_test.rb:6:in `load_test'

Также, как сказал @Chrisui, я также не испытываю никаких провалов в памяти.

Это сценарий, который я пробовал

require 'mongo'

def load_test
    start = Time.now
    puts 'starting at :' + start.to_s 
    20000.times do |i|    
            begin
                puts i      
            doc = {"name" => "MongoDB", "type" => "database", "count" => 1,"info" => {"x" => 203, "y" => '102'}}
            con = Mongo::Connection.new("localhost")
            db   = con['bulktest']
            coll = db['test']
            coll.insert(doc)
            con.close
                con,db,coll=nil,nil,nil
        rescue Exception => e  
            puts e.message  
            puts e.backtrace.inspect  
            throw e 
        end

    end
    stop = Time.now
    puts 'stoping at :' + stop.to_s 
    puts 'elapsed time is ' + (stop-start).to_s + ' seconds'
end
 3
Author: RameshVel, 2012-01-15 09:01:10

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

 1
Author: Nat, 2012-01-17 13:40:13