หน่วยความจำรั่วในแอป Google App Engine / Datastore / Flask / Python
ฉันได้สร้างไซต์รวบรวมข่าวสารอย่างง่ายซึ่งการใช้หน่วยความจำของอินสแตนซ์ App Engine ทั้งหมดของฉันจะเพิ่มขึ้นเรื่อย ๆ จนกว่าจะถึงขีด จำกัด และจึงถูกปิดลง
ฉันได้เริ่มที่จะกำจัดทุกอย่างออกจากแอปของฉันเพื่อให้เป็นเวอร์ชันที่ทำซ้ำได้น้อยที่สุด นี่คือสิ่งที่ฉันมีตอนนี้:
app = Flask(__name__)
datastore_client = datastore.Client()
@app.route('/')
def root():
query = datastore_client.query(kind='source')
query.order = ['list_sequence']
sources = query.fetch()
for source in sources:
pass
สถิติแสดงรูปแบบฟันเลื่อยทั่วไป: เมื่อเริ่มต้นอินสแตนซ์จะไปที่ 190 - 210 Mb จากนั้นตามคำขอบางคำขอ แต่ไม่ใช่คำขอทั้งหมดการใช้หน่วยความจำจะเพิ่มขึ้น 20 - 30 Mb (โดยประมาณนี้จะสอดคล้องกับขนาดโดยประมาณของผลการสืบค้นแม้ว่าฉันจะไม่แน่ใจว่านี่เป็นข้อมูลที่เกี่ยวข้องก็ตาม) สิ่งนี้จะเกิดขึ้นเรื่อย ๆ จนกระทั่งเกิน 512 Mb เมื่อปิดตัวลง โดยปกติจะเกิดขึ้นในช่วงเวลาประมาณวันที่ 50 - 100 คำขอถึง "/" ไม่มีการร้องขออื่นใดในระหว่างนี้
ตอนนี้ถ้าฉันกำจัดวัฏจักร "สำหรับ" และมีเพียงการสืบค้นเท่านั้นปัญหาจะหายไปการใช้หน่วยความจำยังคงอยู่ที่ 190 Mb คงที่ไม่เพิ่มขึ้นแม้จะมีคำขอมากกว่า 100 คำขอ
gc.collect () ในตอนท้ายไม่ช่วย ฉันได้ลองดูความแตกต่างของสถิติ tracemalloc ที่จุดเริ่มต้นและจุดสิ้นสุดของฟังก์ชันแล้วฉันไม่พบว่ามีประโยชน์อะไร
มีใครเคยมีประสบการณ์คล้าย ๆ กันบ้างไหม? มีความคิดอะไรที่อาจผิดพลาดที่นี่? คุณสามารถแนะนำการทดสอบ / การสอบสวนเพิ่มเติมอะไรได้บ้าง? นี่อาจเป็นปัญหาของ Google App Engine / Datastore ที่ฉันไม่สามารถควบคุมได้หรือไม่
ขอขอบคุณ.
คำตอบ
@ Alex ในคำตอบอื่น ๆ ได้การวิจัยที่ดีงามดังนั้นฉันจะตามด้วยคำแนะนำนี้: ลองใช้ห้องสมุด NDB การโทรทั้งหมดที่มีไลบรารีนี้ต้องรวมอยู่ในตัวจัดการบริบทซึ่งควรรับประกันการล้างข้อมูลหลังจากปิด ที่สามารถช่วยแก้ไขปัญหาของคุณ:
ndb_client = ndb.Client(**init_client)
with ndb_client.context():
query = MyModel.query().order(MyModel.my_column)
sources = query.fetch()
for source in sources:
pass
# if you try to query DataStore outside the context manager, it will raise an error
query = MyModel.query().order(MyModel.my_column)
ตอนนี้ถ้าฉันกำจัดวัฏจักร "สำหรับ" และมีเพียงการสืบค้นเท่านั้นปัญหาจะหายไปการใช้หน่วยความจำยังคงอยู่ที่ 190 Mb คงที่ไม่เพิ่มขึ้นแม้จะมีคำขอมากกว่า 100 คำขอ
query.fetch() ส่งคืนตัววนซ้ำไม่ใช่อาร์เรย์จริงของผลลัพธ์
https://googleapis.dev/python/datastore/latest/queries.html#google.cloud.datastore.query.Query.fetch
เมื่อดูที่ซอร์สโค้ดดูเหมือนว่าตัววนซ้ำนี้จะมีโค้ดสำหรับดึงข้อมูลในหน้าถัดไปของแบบสอบถาม ดังนั้นคุณจะต้องใช้ for-loop บังคับให้ดึงข้อมูลทุกหน้าของผลลัพธ์ อันที่จริงฉันไม่คิดว่ามันจะดึงข้อมูลอะไรมาได้จนกว่าคุณจะเริ่มทำซ้ำ นั่นคือเหตุผลที่การลบ for-loop ของคุณจะสร้างความแตกต่าง
น่าเสียดายที่ฉันไม่แน่ใจเนื่องจากเมื่อคุณขุดซอร์สโค้ดคุณก็พบกับต้นขั้ว GRPC อย่างรวดเร็วและไม่ชัดเจนว่ามีปัญหาอยู่ที่นั่นหรือไม่
datastore.Client()มีคำถามนี้ที่คล้ายกับของคุณที่ถามที่พบการรั่วไหลของหน่วยความจำที่เกี่ยวข้องกับการเป็นอินสแตนซ์ ฉันจะตรวจสอบหน่วยความจำรั่วเมื่อใช้ไลบรารี Python ของ Google Cloud Datastore ได้อย่างไร
ท้ายที่สุดแล้วสิ่งนี้เชื่อมโยงกับปัญหาใน GRPC ซึ่ง GRPC จะรั่วไหลหากไม่ถูกปิด https://github.com/grpc/grpc/issues/22123
หวังว่านี่จะชี้ให้คุณไปในทิศทางที่ถูกต้อง