2012-01-14 8 views
8

Attualmente sto lavorando su alcuni test e benchmark personali per confrontare il flusso di lavoro e l'efficienza tra l'utilizzo di MongoDB e MySQL con dati di esempio reali.Apertura e chiusura di 16000 istanze di Mongo DB in PHP

Per configurare i miei dati in ogni database, sto facendo diverse migliaia di cicli e creando in modo casuale oggetti dati da inserire nel database.

Tuttavia, sto riscontrando alcuni problemi con la classe Mongo in PHP che non riesco a risolvere. Il problema è così:

Ho un ciclo che crea una nuova istanza e connessione Mongo, inserisce una piccola matrice in una raccolta e quindi chiude la connessione. Questo ciclo dovrebbe essere eseguito 20000 volte. Tuttavia, fallisce sempre attorno al ciclo 16300nd (con un minimo di 16200 e un massimo di 16350 direi dopo poche esecuzioni) quando tenta di creare l'istanza/effettuare una connessione.

Il codice del ciclo è inferiore:

$data = get_random_user_data(); 

$mongo = new Mongo('mongodb://admin:[email protected]: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() solo restituisce un array associativo semplice.

L'errore che ottengo è:

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

Sulla linea:

$mongo = new Mongo('mongodb://admin:[email protected]:27017/test'); 

Tutte le idee? C'è qualcosa di fondamentale che mi manca come sicurezza o prevenzione dello spam?

Grazie in anticipo.

Info extra:

Lo script muore a circa 114,9797 secondi. Non è una memoria PHP o un problema basato sul tempo, poiché tutti i limiti vengono risolti e ho eseguito i miei benchmark MySQL ieri inserendo 120000 righe (con lo stesso metodo di connessione aperta, inserimento, connessione chiusa) per circa un'ora senza problemi.

Eseguire PHP versione 5.3.5

phpinfo informazioni Mongo:

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 
+1

Hmm, interessante. Potresti riutilizzare la connessione? Forse è una cosa per processo? Cosa succede se provi la stessa cosa in, per esempio, Python? Hai sfruttato il sorgente MongoDB (e/o il driver PHP) per "Errore sconosciuto"? Cosa succede se si dorme un po 'tra le connessioni? – Cameron

+0

Impossibile davvero riutilizzare la connessione poiché è una cosa che voglio includere nel benchmark. Al momento di questo commento qualcuno ha detto di avere lo stesso problema con il loro driver Ruby. Non ho esaminato la fonte, ma lo farò quando avrò la possibilità. Grazie per la risposta. :) – Chrisui

+0

Sì, capisco il benchmark, mi stavo chiedendo se sono le molte connessioni che stanno causando il problema (che sembra verosimilmente data la risposta di Ramesh) – Cameron

risposta

6

Il tuo sistema operativo ha un numero limitato di socket che è disposto ad aprire. Quando si apre un socket e poi lo si chiude, il sistema operativo non lo rimette immediatamente nel pool "disponibile", si blocca per un po 'nello stato "time wait", che Nat menziona in his answer.

È possibile aumentare il numero di socket del sistema operativo aperto, vedere http://www.mongodb.org/display/DOCS/Too+Many+Open+Files (ogni socket è un "file" aperto).

Inoltre, si sta utilizzando una versione piuttosto vecchia del driver, si potrebbe voler considerare l'aggiornamento.

+0

Grazie per l'aiuto! – Chrisui

3

Confermo che questo è lo stesso comportamento da autista rubino troppo. Ho replicato un caso simile con ruby ​​mongo, che inserisce 20000 record aprendo/chiudendo l'istanza di mongo ogni volta. E si continua a non aver tra 14110 a 14200.

Questo è il messaggio di errore

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

questa è la completa analisi dello stack

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' 

anche come detto @Chrisui, sono anche non avvertendo ogni ricordo cala.

Questo è lo script ho provato

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 
1

Il vostro punto di riferimento non ha senso.Non mantenere la connessione aperta/chiusa. Dovresti riutilizzare la connessione persistente invece di aprire/chiudere ogni volta. Se apri e chiudi il socket rapidamente, avrai troppi socket nello stato di attesa temporizzata che usano ancora i descrittori di file

+0

Ha senso. L'idea è di confrontare il tempo necessario per aprire una connessione, fare qualcosa e chiudere. Vale a dire. Replica di una richiesta rapida migliaia di volte. Potresti spiegare questo "tempo di attesa" più per favore? – Chrisui

+0

dai un'occhiata a http://stackoverflow.com/questions/1803566/che-è-il costo-del-mano-tempo-wait-on-il-server-side – Nat