Python Boto Dynamodb очень медленная производительность для поиска небольших наборов записей на клавишах диапазона

Я тестирую dynamodb через boto и нашел удивительно медленным получение наборов данных на основе hashkey, запросов условия keykey. Я видел некоторое обсуждение о странности, которая заставляет ssl (is_secure) выполнять примерно в 6 раз быстрее, чем не-ssl, и я могу подтвердить это обнаружение. Но даже используя ssl, я вижу 1-2 секунды для извлечения 300 записей с использованием условия ключа hashkey/range на довольно небольшом наборе данных (менее 1K записей).

Запуск профилирующего профиля профиля. Я вижу много постороннего времени, потраченного в ssl.py, на порядок 20617 ncalls для извлечения 300 записей. Кажется, что даже при 10 звонках за запись это еще 6 раз больше, чем я ожидал бы. Это относится к среднему экземпляру, хотя одни и те же результаты происходят на микро-экземпляре. 500 Чтение/сек 1000 операций записи/сек без регистрации дросселей.

Я посмотрел на выполнение пакетного запроса, но невозможность использовать условия ключевых слов исключает эту возможность для меня.

Любые идеи о том, где я теряю время, будут очень благодарны!

  144244 function calls in 2.083 CPU seconds

Упорядочено по: кумулятивному времени, внутреннему времени, количеству вызовов

  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)

Ответ 1

Это не полный ответ, но я подумал, что стоит опубликовать его в это время.

Я слышал подобные сообщения от нескольких человек за последние несколько недель. Я смог воспроизвести аномалию HTTPS значительно быстрее, чем HTTP, но не смог ее отслеживать. Похоже, эта проблема была уникальной для Python/boto, но оказалось, что такая же проблема была обнаружена на С#/.NET и выяснилось, что было обнаружено, что основной проблемой было использование Nagle в библиотеках Python и .Net. В .Net, это легко отключить, но это не так просто в Python, к сожалению.

Чтобы проверить это, я написал простой script, который выполнил 1000 запросов GetItem в цикле. Элемент, который был извлечен, был очень маленьким, хорошо под 1K. Выполнение этого на Python 2.6.7 на экземпляре m1.medium в области us-east-1 произвело эти результаты:

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

Обратите внимание, что в таблице имеется достаточная резервная емкость, чтобы избежать дросселирования службы, и неожиданный разрыв между HTTP и HTTPS ясен.

Затем я запускал тот же тест в 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

Итак, 2.7, похоже, исправил эту проблему. Затем я применил простой патч к httplib.py в 2.6.7. Патч просто устанавливает свойство TCP_NO_DELAY сокета, связанного с объектом HTTPConnection, например:

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

Затем я повторил тест на 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

Еще лучше, хотя все же ожидается более быстрое время с HTTPS, чем HTTP. Трудно понять, значительна ли эта разница или нет.

Итак, я ищу способы программной настройки сокета для объектов HTTPConnection для правильной настройки TCP_NO_DELAY. Нелегко это понять в httplib.py. Мой лучший совет на данный момент - использовать Python 2.7, если это возможно.