10

我正在通过 boto 测试 dynamodb,发现它在检索基于 hashkey、rangekey 条件查询的数据集时速度非常慢。我已经看到一些关于导致 ssl (is_secure) 执行速度比非 ssl 快 6 倍的奇怪的讨论,我可以确认这一发现。但即使使用 ssl,我也看到在相当小的数据集(少于 1K 条记录)上使用 hashkey/range 键条件检索 300 条记录需要 1-2 秒。

运行 profilehooks profiler 我看到在 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)
4

1 回答 1

13

这不是一个完整的答案,但我认为此时值得发布它。

在过去的几周里,我从几个人那里听到了这样的报告。我能够重现 HTTPS 比 HTTP 快得多的异常,但无法追踪它。这个问题似乎是 Python/boto 独有的,但事实证明在 C#/.Net 上发现了同样的问题,并调查发现根本问题是在 Python 和 .Net 库中使用Nagle 算法。在 .Net 中,很容易将其关闭,但不幸的是,在 Python 中就没有那么容易了。

为了测试这一点,我编写了一个简单的脚本,循环执行 1000 个 GetItem 请求。正在提取的项目非常小,远低于 1K。在 us-east-1 区域的 m1.medium 实例上的 Python 2.6.7 上运行此程序会产生以下结果:

>>> 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 似乎已经解决了这个问题。然后我在 2.6.7 中对 httplib.py 应用了一个简单的补丁。该补丁只是设置与 HTTPConnection 对象关联的套接字的 TCP_NO_DELAY 属性,如下所示:

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。

于 2012-04-13T13:10:07.500 回答