如何提升PyMongo读取MongoDB大集合的扩展性并以原始BSON写入S3?
解决方案:用原生BSON格式读取MongoDB集合并写入S3
完全可以用原始BSON格式处理,这比转JSON高效得多——BSON是MongoDB的原生存储格式,序列化/反序列化开销小,文件体积也更小,能大幅降低内存占用和处理时间,刚好解决你遇到的超时问题。
先说说你当前代码的几个关键问题:
- 把
col.find()的结果直接转成list,等于一次性把所有文档加载到内存里,数据量越大内存占用越高,Lambda的资源瓶颈会直接导致超时。 - 循环里每次调用
object.put(Body=...),会覆盖之前写入的内容,最后S3里只会保留最后一条文档,完全不符合批量备份的需求。
下面是优化后的代码思路和实现:
- 保留cursor的迭代器特性,不一次性加载所有文档,逐批处理
- 用
bson.encode直接把文档序列化成BSON字节,跳过JSON转换的额外开销 - 把BSON数据批量写入S3(用内存缓冲区暂存后一次性上传,避免多次IO请求)
优化后的代码示例:
import boto3 import pymongo from bson import encode from datetime import date from io import BytesIO def lambda_handler(event, context): # 连接MongoDB try: client = pymongo.MongoClient( "mongodb://<username>:<password>/?tls=true&tlsCAFile=rds-combined-ca-bundle.pem&retryWrites=false" ) db = client["<db_name>"] col = db.<collection_name> # 保持cursor为迭代器,不转成list cursor = col.find().sort([("$natural", 1)]).limit(75000) except pymongo.errors.OperationFailure as e: return str(e) except Exception as e: return str(e) # 处理BSON数据并写入S3 try: file_name = f"test_{date.today().strftime('%d-%m-%Y')}.bson" s3 = boto3.client('s3') bucket_name = "<bucket_name>" # 用内存缓冲区暂存BSON数据,避免写本地文件 bson_buffer = BytesIO() # 逐文档序列化到缓冲区 for doc in cursor: bson_buffer.write(encode(doc)) # 重置缓冲区指针到开头,一次性上传到S3 bson_buffer.seek(0) s3.put_object( Bucket=bucket_name, Key=file_name, Body=bson_buffer ) return 'S3上传成功' except Exception as e: return str(e)
如果数据量极大到内存缓冲区也放不下,可以改成按批次拆分多个S3文件,比如每处理10000条就上传一个名为test_<日期>_part_1.bson的文件,避免内存溢出。
另外可以调整Lambda配置:把内存调高到1024MB以上(Lambda内存越高,CPU性能同步提升),超时时间拉到最大值15分钟,进一步降低超时概率。
内容的提问来源于stack exchange,提问作者Aditya Gupta
相关产品推荐
相关产品推荐

