AppEngine 能否*拉入*超过 32MB 的数据?
Can AppEngine *pull* in data over 32MB?
我正在写一个 API 需要摄取高清视频(至少 100MB)。我只能通过 HTTP XML 提要访问视频,所以我只能在获得视频的 URL 后 拉取 视频(使用 GET)。计划将视频存储在 GCS 中。
但在我 upload/write 到 GCS 之前,我 运行 进入了 AppEngine 中每个请求 32MB 的限制。
是否有解决这两个限制的 GAE 方法:
- 需要是 AppEngine 可以发起的 GET
- 需要能够将数据导入 GCS
我知道 Amazon S3,如果我必须在 Google 云产品之外,但我不知道它是否可以配置为提取大数据。
谢谢。
根据 Paul Collingwood 的建议,我提出了以下建议。
我决定不将块写入 GCS 然后再将它们拼接在一起。相反,我选择全部在内存中完成,但我可能会根据资源成本更改它(必须 运行 F4@512MB 以避免超过 F2 的 256MB 软限制)。
def get(self):
# Work with GAE's 32MB-per-request limit, set to 30MB to stay under
RANGE = 30*(1024**2)
url = self.request.get('url')
request = urllib2.Request(url)
request.get_method = lambda: 'HEAD'
response = urllib2.urlopen(request)
info = response.info()
logging.debug('Downloading {}B video'.format(info.get('Content-length')))
request.get_method = lambda: 'GET'
_buffer = ''
start = 0
while True:
end = start + RANGE
request.headers['Range'] = 'bytes={}-{}'.format(start, end)
logging.debug('Buffering bytes {} to {}'.format(start, end))
_bytes = urllib2.urlopen(request, timeout=60).read()
_buffer += _bytes
logging.info('Buffered bytes {} to {}'.format(start, end))
# If there are less bytes than requested then all bytes
# have been received, break to avoid an HTTP 416
if len(_bytes) < (end - start):
break
start += (RANGE + 1)
filename = '/MY-BUCKET/video/test_large.mp4'
with gcs.open(filename, 'w', content_type='video/mp4') as f:
f.write(_buffer)
logging.info('Wrote {}B video to GCS'.format(len(_buffer)))
在日志中看起来像这样:
DEBUG 2015-05-01 02:02:00,947 video.py:27] Buffering bytes 0 to 31457280
INFO 2015-05-01 02:02:11,625 video.py:30] Buffered bytes 0 to 31457280
DEBUG 2015-05-01 02:02:11,625 video.py:27] Buffering bytes 31457281 to 62914561
INFO 2015-05-01 02:02:22,768 video.py:30] Buffered bytes 31457281 to 62914561
DEBUG 2015-05-01 02:02:22,768 video.py:27] Buffering bytes 62914562 to 94371842
INFO 2015-05-01 02:02:32,920 video.py:30] Buffered bytes 62914562 to 94371842
...
Writing to GCS
...
INFO 2015-05-01 02:02:41,274 video.py:42] Wrote 89635441B video to GCS
更新,6/May/15
按照 Kekito 的建议,我将 GCS 写入移动到循环中,在整个持续时间内保持文件句柄打开。
url = self.request.get('url')
request = urllib2.Request(url)
request.get_method = lambda: 'HEAD'
response = urllib2.urlopen(request)
info = response.info()
content_length = int(info.get('Content-length'))
logging.debug('Downloading {}B video'.format(content_length))
del(info)
del(response)
del(request)
request = urllib2.Request(url)
start = 0
filename = '/MY-BUCKET/video/test_large.mp4'
f = gcs.open(filename, 'w', content_type='video/mp4')
while True:
end = start + RANGE
request.headers['Range'] = 'bytes={}-{}'.format(start, end)
f.write(urllib2.urlopen(request, timeout=60).read())
if end >= content_length:
break
start = end + 1
f.close()
按照建议here,我使用top
监控GAE本地开发服务器Python进程运行,开始上传,记录内存下载和上传周期之间的足迹。
我还尝试更改一次处理的块大小:将块大小从 30 MB 降低到 20 MB,最大内存使用量减少了约 50 MB。在下图中,正在摄取一个 560 MB 的文件,我正在尝试跟踪:
- GC:内存占用最低,而
urlopen()
是G设置C大量数据
- WC:内存使用峰值,而
f.write()
是W,即C大块头到 GCS
20-MB-Chunk-Test 的最大值为 230 MB,而 30-MB-Chunk-Test 的最大值为 281 MB。因此,我可以 运行 一个只有 256 MB 的实例,但在 512 MB 时 运行 可能会感觉更好。我也可以尝试更小的块大小。
我正在写一个 API 需要摄取高清视频(至少 100MB)。我只能通过 HTTP XML 提要访问视频,所以我只能在获得视频的 URL 后 拉取 视频(使用 GET)。计划将视频存储在 GCS 中。
但在我 upload/write 到 GCS 之前,我 运行 进入了 AppEngine 中每个请求 32MB 的限制。
是否有解决这两个限制的 GAE 方法:
- 需要是 AppEngine 可以发起的 GET
- 需要能够将数据导入 GCS
我知道 Amazon S3,如果我必须在 Google 云产品之外,但我不知道它是否可以配置为提取大数据。
谢谢。
根据 Paul Collingwood 的建议,我提出了以下建议。
我决定不将块写入 GCS 然后再将它们拼接在一起。相反,我选择全部在内存中完成,但我可能会根据资源成本更改它(必须 运行 F4@512MB 以避免超过 F2 的 256MB 软限制)。
def get(self):
# Work with GAE's 32MB-per-request limit, set to 30MB to stay under
RANGE = 30*(1024**2)
url = self.request.get('url')
request = urllib2.Request(url)
request.get_method = lambda: 'HEAD'
response = urllib2.urlopen(request)
info = response.info()
logging.debug('Downloading {}B video'.format(info.get('Content-length')))
request.get_method = lambda: 'GET'
_buffer = ''
start = 0
while True:
end = start + RANGE
request.headers['Range'] = 'bytes={}-{}'.format(start, end)
logging.debug('Buffering bytes {} to {}'.format(start, end))
_bytes = urllib2.urlopen(request, timeout=60).read()
_buffer += _bytes
logging.info('Buffered bytes {} to {}'.format(start, end))
# If there are less bytes than requested then all bytes
# have been received, break to avoid an HTTP 416
if len(_bytes) < (end - start):
break
start += (RANGE + 1)
filename = '/MY-BUCKET/video/test_large.mp4'
with gcs.open(filename, 'w', content_type='video/mp4') as f:
f.write(_buffer)
logging.info('Wrote {}B video to GCS'.format(len(_buffer)))
在日志中看起来像这样:
DEBUG 2015-05-01 02:02:00,947 video.py:27] Buffering bytes 0 to 31457280
INFO 2015-05-01 02:02:11,625 video.py:30] Buffered bytes 0 to 31457280
DEBUG 2015-05-01 02:02:11,625 video.py:27] Buffering bytes 31457281 to 62914561
INFO 2015-05-01 02:02:22,768 video.py:30] Buffered bytes 31457281 to 62914561
DEBUG 2015-05-01 02:02:22,768 video.py:27] Buffering bytes 62914562 to 94371842
INFO 2015-05-01 02:02:32,920 video.py:30] Buffered bytes 62914562 to 94371842
...
Writing to GCS
...
INFO 2015-05-01 02:02:41,274 video.py:42] Wrote 89635441B video to GCS
更新,6/May/15
按照 Kekito 的建议,我将 GCS 写入移动到循环中,在整个持续时间内保持文件句柄打开。
url = self.request.get('url')
request = urllib2.Request(url)
request.get_method = lambda: 'HEAD'
response = urllib2.urlopen(request)
info = response.info()
content_length = int(info.get('Content-length'))
logging.debug('Downloading {}B video'.format(content_length))
del(info)
del(response)
del(request)
request = urllib2.Request(url)
start = 0
filename = '/MY-BUCKET/video/test_large.mp4'
f = gcs.open(filename, 'w', content_type='video/mp4')
while True:
end = start + RANGE
request.headers['Range'] = 'bytes={}-{}'.format(start, end)
f.write(urllib2.urlopen(request, timeout=60).read())
if end >= content_length:
break
start = end + 1
f.close()
按照建议here,我使用top
监控GAE本地开发服务器Python进程运行,开始上传,记录内存下载和上传周期之间的足迹。
我还尝试更改一次处理的块大小:将块大小从 30 MB 降低到 20 MB,最大内存使用量减少了约 50 MB。在下图中,正在摄取一个 560 MB 的文件,我正在尝试跟踪:
- GC:内存占用最低,而
urlopen()
是G设置C大量数据 - WC:内存使用峰值,而
f.write()
是W,即C大块头到 GCS
20-MB-Chunk-Test 的最大值为 230 MB,而 30-MB-Chunk-Test 的最大值为 281 MB。因此,我可以 运行 一个只有 256 MB 的实例,但在 512 MB 时 运行 可能会感觉更好。我也可以尝试更小的块大小。