Открытие и закрытие 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
3 answers
Ваша операционная система имеет ограниченное количество сокетов, которые она готова открыть. Когда вы открываете сокет, а затем закрываете его, ОС не сразу помещает его обратно в "доступный" пул, он некоторое время зависает в состоянии "время ожидания", которое Нат упоминает в своем ответе.
Вы можете увеличить количество сокетов, которые будет открывать ваша ОС, см. http://www.mongodb.org/display/DOCS/Too +Много+Открытых+файлов (каждый сокет является открытым "файлом").
Кроме того, вы используете довольно старая версия драйвера, возможно, вы захотите рассмотреть возможность обновления.
Я подтверждаю, что такое же поведение и у драйвера 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
Ваш ориентир не имеет смысла. Не поддерживайте открытую/закрытую связь. Вы должны повторно использовать сохраненное соединение вместо того, чтобы каждый раз открывать/закрывать его. Если вы быстро откроете и закроете сокет, у вас будет слишком много сокетов в состоянии ожидания по времени, которые все еще используют файловые дескрипторы