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, если это возможно.