我有几个守护程序,可以使用boto从Amazon S3读取许多文件。每两天一次,我遇到了一个情况,即从内部boto中抛出了一个httplib.IncompleteRead。如果我尝试重试该请求,它将立即失败,并显示另一个IncompleteRead。即使我呼叫bucket.connection.close()
,所有其他请求仍然会出错。
我觉得我可能在这里偶然发现了boto中的一个错误,但似乎没有其他人遇到它。难道我做错了什么?所有的守护程序都是单线程的,我尝试了两种方式都设置is_secure
。
Traceback (most recent call last):
...
File "<file_wrapper.py",> line 22, in next
line = self.readline()
File "<file_wrapper.py",> line 37, in readline
data = self.fh.read(self.buffer_size)
File "<virtualenv/lib/python2.6/site-packages/boto/s3/key.py",> line 378, in read
self.close()
File "<virtualenv/lib/python2.6/site-packages/boto/s3/key.py",> line 349, in close
self.resp.read()
File "<virtualenv/lib/python2.6/site-packages/boto/connection.py",> line 411, in read
self._cached_response = httplib.HTTPResponse.read(self)
File "/usr/lib/python2.6/httplib.py", line 529, in read
s = self._safe_read(self.length)
File "/usr/lib/python2.6/httplib.py", line 621, in _safe_read
raise IncompleteRead(''.join(s), amt)
环境:
这很可能是boto中的错误,但是您描述的症状并非唯一。参见
https://dev.twitter.com/discussions/9554
由于httplib出现在您的追溯中,因此在这里提出了一种解决方案:
http://bobrochel.blogspot.in/2010/11/bad-servers-chunked-encoding-and.html?showComment=1358777800048
免责声明:我没有boto的经验。这仅基于研究,并且由于没有其他回应而发布。
我一直在为此问题苦苦挣扎,正在运行长时间运行的进程,这些进程从S3中读取大量数据。我决定将解决方案发布在这里,以供后代使用。
首先,我确定@Glenn所指的黑客是可行的,但我选择不使用它,因为我认为它具有侵入性(攻击httplib)且不安全(它盲目返回所得到的信息,即return e.partial
,尽管事实可能是真实错误的情况。
这是我最后想出的解决方案,似乎很奏效。
我正在使用此通用重试功能:
import time, logging, httplib, socket
def run_with_retries(func, num_retries, sleep = None, exception_types = Exception, on_retry = None):
for i in range(num_retries):
try:
return func() # call the function
except exception_types, e:
# failed on the known exception
if i == num_retries - 1:
raise # this was the last attempt. reraise
logging.warning(f'operation {func} failed with error {e}. will retry {num_retries-i-1} more times')
if on_retry is not None:
on_retry()
if sleep is not None:
time.sleep(sleep)
assert 0 # should not reach this point
[现在,当从S3读取文件时,我正在使用此功能,在发生IncompleteRead
错误的情况下,该功能在内部执行重试。发生错误时,在重试之前,我会呼叫key.close()
。
def read_s3_file(key):
"""
Reads the entire contents of a file on S3.
@param key: a boto.s3.key.Key instance
"""
return run_with_retries(
key.read, num_retries = 3, sleep = 0.5,
exception_types = (httplib.IncompleteRead, socket.error),
# close the connection before retrying
on_retry = lambda: key.close()
)
如果要从S3读取大量数据,则可能必须对读/写进行大块/多部分处理。
这里有一个很好的例子,可以做多部分(http://www.bogotobogo.com/DevOps/AWS/aws_S3_uploading_large_file.php)