2012-04-12 10 views
10

Testuję dynamodb przez Boto i odkryłem, że jest zaskakująco wolny w pobieraniu zestawów danych w oparciu o hashkey, zapytania warunkowe rangekey. Widziałem pewną dyskusję na temat osobliwości, która powoduje, że ssl (is_secure) wykonuje około 6x szybciej niż non-ssl i mogę potwierdzić to odkrycie. Ale nawet używając ssl widzę 1-2 sekundy, aby pobrać 300 rekordów przy użyciu warunku klucza hashkey/range na dość małym zbiorze danych (mniej niż 1K rekordów).Python Boto Dynamodb bardzo powolna wydajność do pobierania małych zestawów rekordów na kluczach zakresu

Uruchamianie profilera profilowania Widzę wiele dodatkowego czasu spędzonego w ssl.py do porządku 20617 ncalls w celu pobrania 300 rekordów. Wygląda na to, że nawet przy 10 połączeniach na płytę wciąż jest 6 razy więcej, niż się spodziewam. To jest na średniej instancji - choć takie same wyniki występują w przypadku mikro instancji. 500 Odczyty/sek. 1000 zapisów/sek.

Przyjrzałem się wykonaniu żądania wsadowego, ale niemożność użycia warunków klucza zakresu eliminuje tę opcję dla mnie.

Wszelkie pomysły na temat tego, gdzie tracę czas byłyby bardzo mile widziane!

144244 function calls in 2.083 CPU seconds 

Zleceniodawca: skumulowany czas, czas wewnętrznej, zadzwoń liczyć

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

Dzięki za dane. To jest coś, nad czym ostatnio się zastanawiałem. Różnica między HTTP i HTTPS jest co najmniej zagadkowa. Czy to pochodzi z instancji EC2? Jaka jest zapewniona przepustowość dla stołu? – garnaat

+1

Obsługiwany przy 500 odczytach/sekundach i 1000 zapisów/s na instancji amazon EC2-medium. Próbowałem zwiększyć i zmniejszyć przepustowość, a także różne wielkości instancji bez istotnych zmian w wynikach. Zmniejszenie zwracanych atrybutów (z 10 do 2) ma niewielki wpływ. – jaredmsaul

+1

Widzę, że wszystkie informacje znajdują się w oryginalnym wpisie. Przepraszam. Jeśli nie widzisz żadnych dławiących zdarzeń (i nie powinieneś znajdować się na tym poziomie udostępniania), problem jest po stronie klienta. Próbowałeś wykonać znacznie więcej żądań (na przykład około 10 KB). To rozgrzeje pamięci podręczne i da lepszą reprezentację potencjalnej przepustowości. Jednak oczywiste jest, że coś dziwnego dzieje się w httplib. Sprawdzam, czy mogę go wyśledzić. – garnaat

Odpowiedz

12

To nie jest pełna odpowiedź, ale myślałem, że warto było umieszczenie go w tym czasie.

Słyszałem raporty od kilku osób w ciągu ostatnich kilku tygodni. Udało mi się odtworzyć anomalię HTTPS znacznie szybciej niż HTTP, ale nie udało mi się go wykryć. Wydawało się, że ten problem był unikalny dla Python/boto, ale okazało się, że ten sam problem został znaleziony w C#/.Net i zbadano, że odkryto, że podstawowym problemem było użycie Nagle's algorithm w bibliotekach Python i .Net. W .Net łatwo to wyłączyć, ale niestety nie jest to łatwe w Pythonie.

Aby to przetestować, napisałem prosty skrypt, który wykonał 1000 żądań GetItem w pętli. Przedmiot, który był pobierany, był bardzo mały, czyli znacznie poniżej 1K. Bieganie to na Python 2.6.7 na przykład m1.medium w regionie us-wschód-1 produkowane te wyniki:

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

Należy pamiętać, że istnieje wystarczająca pojemność zaopatrzony w tabeli, aby uniknąć dławienia od służby i nieoczekiwana luka między HTTP i HTTPS jest jasna.

I następny prowadził ten sam test w Pythonie 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 

Tak, 2.7 wydaje się być ustalony ten problem. Następnie zastosowałem prostą łatę do httplib.py w wersji 2.6.7. Plaster po prostu ustawia właściwość TCP_NO_DELAY z gniazda związanego z obiektem httpconnection coś takiego:

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

I wtedy ponownie prowadził badania na 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 

Nawet lepiej, choć nadal spodziewany czas szybszy z HTTPS niż HTTP. Trudno powiedzieć, czy ta różnica jest znacząca, czy nie.

Poszukuję sposobów programowej konfiguracji gniazda dla obiektów HTTPConnection tak, aby poprawnie skonfigurowano TCP_NO_DELAY. Nie jest łatwo o tym dowiedzieć się w httplib.py.Moja najlepsza porada na razie jest użycie Pythona 2.7, jeśli to możliwe.

+0

+1 za szczegółową analizę i opublikowanie już, zagadkową zagadkę - dzięki bardzo! –

Powiązane problemy