2012-04-12 2 views
10

Sto testando dynamodb via boto e ho trovato sorprendentemente lento nel recuperare set di dati basati su hashkey, query di condizioni rangekey. Ho visto alcune discussioni sulla stranezza che causa ssl (is_secure) per eseguire circa 6 volte più veloce di non-ssl e posso confermare quella scoperta. Ma anche usando ssl vedo 1-2 secondi per recuperare 300 record usando una condizione chiave hashkey/range su un set di dati abbastanza piccolo (meno di 1K di record).Python Boto Dynamodb prestazioni molto lente per il recupero di piccoli set di record su chiavi di intervallo

Esecuzione di profiler profilehooks Vedo un sacco di tempo estraneo trascorso in ssl.py nell'ordine di 20617 ncalls per recuperare i 300 record. Sembra che anche a 10 chiamate per record sia ancora 6 volte più di quanto mi aspetterei. Questo è su un'istanza media-- sebbene gli stessi risultati si verifichino su una micro-istanza. 500 letture/sec 1000 scritture/sec di provisioning senza throttles registrati.

Ho esaminato una richiesta batch ma l'impossibilità di utilizzare le condizioni chiave di intervallo elimina l'opzione per me.

Qualsiasi idea su dove sto perdendo il tempo sarebbe molto apprezzata !!

144244 function calls in 2.083 CPU seconds 

Ordinati per: tempo totale, tempo interno, chiamare contare

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 0.001 0.001 2.083 2.083 eventstream.py:427(session_range) 
    107 0.006 0.000 2.081 0.019 dynamoDB.py:36(rangeQ) 
    408 0.003 0.000 2.073 0.005 layer2.py:493(query) 
    107 0.001 0.000 2.046 0.019 layer1.py:435(query) 
    107 0.002 0.000 2.040 0.019 layer1.py:119(make_request) 
    107 0.006 0.000 1.988 0.019 connection.py:699(_mexe) 
    107 0.001 0.000 1.916 0.018 httplib.py:956(getresponse) 
    107 0.002 0.000 1.913 0.018 httplib.py:384(begin) 
    662 0.049 0.000 1.888 0.003 socket.py:403(readline) 
20617 0.040 0.000 1.824 0.000 ssl.py:209(recv) 
20617 0.036 0.000 1.785 0.000 ssl.py:130(read) 
20617 1.748 0.000 1.748 0.000 {built-in method read} 
    107 0.002 0.000 1.738 0.016 httplib.py:347(_read_status) 
    107 0.001 0.000 0.170 0.002 mimetools.py:24(__init__) 
    107 0.000 0.000 0.165 0.002 rfc822.py:88(__init__) 
    107 0.007 0.000 0.165 0.002 httplib.py:230(readheaders) 
    107 0.001 0.000 0.031 0.000 __init__.py:332(loads) 
    107 0.001 0.000 0.028 0.000 decoder.py:397(decode) 
    107 0.008 0.000 0.026 0.000 decoder.py:408(raw_decode) 
    107 0.001 0.000 0.026 0.000 httplib.py:910(request) 
    107 0.003 0.000 0.026 0.000 httplib.py:922(_send_request) 
    107 0.001 0.000 0.025 0.000 connection.py:350(authorize) 
    107 0.004 0.000 0.024 0.000 auth.py:239(add_auth) 
3719 0.011 0.000 0.019 0.000 layer2.py:31(item_object_hook) 
    301 0.010 0.000 0.018 0.000 item.py:38(__init__) 
22330 0.015 0.000 0.015 0.000 {method 'append' of 'list' objects} 
    107 0.001 0.000 0.012 0.000 httplib.py:513(read) 
    214 0.001 0.000 0.011 0.000 httplib.py:735(send) 
    856 0.002 0.000 0.010 0.000 __init__.py:1034(debug) 
    214 0.001 0.000 0.009 0.000 ssl.py:194(sendall) 
    107 0.000 0.000 0.008 0.000 httplib.py:900(endheaders) 
    107 0.001 0.000 0.008 0.000 httplib.py:772(_send_output) 
    107 0.001 0.000 0.008 0.000 auth.py:223(string_to_sign) 
    856 0.002 0.000 0.008 0.000 __init__.py:1244(isEnabledFor) 
    137 0.001 0.000 0.008 0.000 httplib.py:603(_safe_read) 
    214 0.001 0.000 0.007 0.000 ssl.py:166(send) 
    214 0.007 0.000 0.007 0.000 {built-in method write} 
3311 0.006 0.000 0.006 0.000 item.py:186(__setitem__) 
    107 0.001 0.000 0.006 0.000 auth.py:95(sign_string) 
    137 0.001 0.000 0.006 0.000 socket.py:333(read) 
+2

Grazie per i dati. Questo è qualcosa che ho cercato di recente. Il delta tra HTTP e HTTPS è a dir poco sconcertante. È questo da un'istanza EC2? Qual è il throughput fornito per la tabella? – garnaat

+1

Provisionato a 500 letture/se 1000 scritture/s su un'istanza Amazon EC2-media. Ho provato ad aumentare e ridurre il throughput e anche le diverse istanze senza cambiamenti sostanziali nei risultati. Diminuire gli attributi restituiti (da 10 a 2) ha un piccolo effetto. – jaredmsaul

+1

Vedo che le informazioni erano tutte nel tuo post originale. Scusate. Se non vedi eventi di limitazione (e non dovresti essere a quel livello di provisioning), il problema è tutto sul lato client. Hai provato a fare molte più richieste (ad esempio 10k circa). Questo riscalderà le cache e fornirà una migliore rappresentazione del potenziale throughput. Tuttavia, è chiaro che sta succedendo qualcosa di strano in httplib. Sto indagando per vedere se riesco a rintracciarlo. – garnaat

risposta

12

Questa non è una risposta completa, ma ho pensato che valeva la pena pubblicarlo in questo momento.

Ho sentito rapporti come questo da un paio di persone nelle ultime settimane. Sono stato in grado di riprodurre l'anomalia di HTTPS che è notevolmente più veloce di HTTP, ma non è stato in grado di rintracciarlo. Sembrava che il problema fosse unico per Python/boto ma si è scoperto che lo stesso problema era stato riscontrato in C#/.Net e che si è scoperto che il problema sottostante era l'uso di Nagle's algorithm nelle librerie Python e .Net. In .Net, è facile disattivarlo, ma sfortunatamente non è così facile in Python.

Per verificarlo, ho scritto uno script semplice che eseguiva 1000 richieste GetItem in un ciclo. L'oggetto che stava recuperando era molto piccolo, ben al di sotto di 1K. L'esecuzione di questo su Python 2.6.7 su un'istanza m1.medium nella regione ci-est-1 ha fornito questi risultati:

>>> http_data = speed_test(False, 1000) 
dynamoDB_speed_test - RUNTIME = 53.120193 
Throttling exceptions: 0 
>>> https_data = speed_test(True, 1000) 
dynamoDB_speed_test - RUNTIME = 8.167652 
Throttling exceptions: 0 

Si noti che non v'è sufficiente capacità di provisioning nella tabella per evitare qualsiasi limitazione del servizio e il divario imprevisto tra HTTP e HTTPS è chiaro.

ho prossima corse la stessa prova in Python 2.7.2:

>>> http_data = speed_test(False, 1000) 
dynamoDB_speed_test - RUNTIME = 5.668544 
Throttling exceptions: 0 
>>> https_data = speed_test(True, 1000) 
dynamoDB_speed_test - RUNTIME = 7.425210 
Throttling exceptions: 0 

Quindi, 2.7 sembra aver risolto questo problema. Ho quindi applicato una semplice patch a httplib.py in 2.6.7. La patch imposta semplicemente la proprietà TCP_NO_DELAY della presa associato all'oggetto HTTPConnection, in questo modo:

self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 

I poi ri-eseguito il test 2.6.7:

>>> http_data = speed_test(False, 1000) 
dynamoDB_speed_test - RUNTIME = 5.914109 
Throttling exceptions: 0 
>>> https_data = speed_test(True, 1000) 
dynamoDB_speed_test - RUNTIME = 5.137570 
Throttling exceptions: 0 

Ancora meglio anche se ancora un tempo atteso più veloce con HTTPS di HTTP. È difficile sapere se tale differenza sia significativa o meno.

Quindi, sto cercando modi per configurare in modo programmatico il socket per gli oggetti HTTPConnection affinché TCP_NO_DELAY sia configurato correttamente. Non è facile da ottenere in httplib.py.Il mio miglior consiglio per il momento è usare Python 2.7, se possibile.

+0

+1 per l'analisi dettagliata e postarla già, un puzzle enigmatico davvero - grazie mille! –