App Engine Deferred:追踪内存泄漏
App Engine Deferred: Tracking Down Memory Leaks
我们有一个 App Engine 应用程序,可以将许多相对较大的文件写入 Google Cloud Store。这些文件是动态创建的 CSV,因此我们使用 Python 的 StringIO.StringIO
作为缓冲区,并使用 csv.writer
作为写入该缓冲区的接口。
一般来说,我们的流程是这样的:
# imports as needed
# (gcs is the Google Cloud Store client)
buffer = StringIO.StringIO()
writer = csv.writer(buffer)
# ...
# write some rows
# ...
data = file_buffer.getdata()
filename = 'someFilename.csv'
try:
with gcs.open(filename, content_type='text/csv', mode='w') as file_stream:
file_stream.write(data)
file_stream.close()
except Exception, e:
# handle exception
finally:
file_buffer.close()
据我们了解,csv.writer
本身不需要关闭。相反,只有上面的 buffer
和 file_stream
需要关闭。
我们 运行 在一个 deferred
中的上述过程,由 App Engine 的任务队列调用。最终,在我们的任务调用几次后,我们得到以下错误:
Exceeded soft private memory limit of 128 MB with 142 MB after servicing 11 requests total
很明显,我们的应用程序存在内存泄漏。但是,如果上面的代码是正确的(我们承认可能不是这种情况),那么我们唯一的另一个想法是通过为我们的请求提供服务(如错误消息所示)持有大量内存。
因此,我们想知道在执行 deferred
期间 App Engine 是否保留了某些实体。我们还应该注意到,尽管有这些错误消息,我们的 CSV 最终还是成功写入了。
所描述的症状不一定表示应用程序内存泄漏。可能的替代解释包括:
- 应用程序的基线内存占用(对于像 python 这样的脚本语言沙箱,它可能比实例启动时的内存占用更大,请参阅 Memory usage differs greatly (and strangely) between frontend and backend) may be too high for the instance class configured for the app/module. To fix - chose a higher memory instance class(作为副作用,也意味着更快的 class 实例。或者,如果由于超出内存限制而导致的实例终止率是可以容忍的,只需让 GAE 回收实例 :)
- activity 的峰值,尤其是在启用多线程请求处理的情况下,意味着更高的内存消耗以及内存垃圾收集器的潜在过载。限制并行执行的请求数量、在较低优先级的延迟任务处理中添加(更高)延迟以及其他类似措施降低每个实例的平均请求处理速率可以帮助垃圾收集器有机会清理请求中的剩余部分。可扩展性不应受到损害(使用 dynamic scaling),因为将启动其他实例以帮助达到 activity 峰值。
相关问答:
- How does app engine (python) manage memory across requests (Exceeded soft private memory limit)
我们有一个 App Engine 应用程序,可以将许多相对较大的文件写入 Google Cloud Store。这些文件是动态创建的 CSV,因此我们使用 Python 的 StringIO.StringIO
作为缓冲区,并使用 csv.writer
作为写入该缓冲区的接口。
一般来说,我们的流程是这样的:
# imports as needed
# (gcs is the Google Cloud Store client)
buffer = StringIO.StringIO()
writer = csv.writer(buffer)
# ...
# write some rows
# ...
data = file_buffer.getdata()
filename = 'someFilename.csv'
try:
with gcs.open(filename, content_type='text/csv', mode='w') as file_stream:
file_stream.write(data)
file_stream.close()
except Exception, e:
# handle exception
finally:
file_buffer.close()
据我们了解,csv.writer
本身不需要关闭。相反,只有上面的 buffer
和 file_stream
需要关闭。
我们 运行 在一个 deferred
中的上述过程,由 App Engine 的任务队列调用。最终,在我们的任务调用几次后,我们得到以下错误:
Exceeded soft private memory limit of 128 MB with 142 MB after servicing 11 requests total
很明显,我们的应用程序存在内存泄漏。但是,如果上面的代码是正确的(我们承认可能不是这种情况),那么我们唯一的另一个想法是通过为我们的请求提供服务(如错误消息所示)持有大量内存。
因此,我们想知道在执行 deferred
期间 App Engine 是否保留了某些实体。我们还应该注意到,尽管有这些错误消息,我们的 CSV 最终还是成功写入了。
所描述的症状不一定表示应用程序内存泄漏。可能的替代解释包括:
- 应用程序的基线内存占用(对于像 python 这样的脚本语言沙箱,它可能比实例启动时的内存占用更大,请参阅 Memory usage differs greatly (and strangely) between frontend and backend) may be too high for the instance class configured for the app/module. To fix - chose a higher memory instance class(作为副作用,也意味着更快的 class 实例。或者,如果由于超出内存限制而导致的实例终止率是可以容忍的,只需让 GAE 回收实例 :)
- activity 的峰值,尤其是在启用多线程请求处理的情况下,意味着更高的内存消耗以及内存垃圾收集器的潜在过载。限制并行执行的请求数量、在较低优先级的延迟任务处理中添加(更高)延迟以及其他类似措施降低每个实例的平均请求处理速率可以帮助垃圾收集器有机会清理请求中的剩余部分。可扩展性不应受到损害(使用 dynamic scaling),因为将启动其他实例以帮助达到 activity 峰值。
相关问答:
- How does app engine (python) manage memory across requests (Exceeded soft private memory limit)