Python-Flask+boto3上传1-3MB图片至Amazon S3耗时16-18秒,求优化建议
Hey there! Let's figure out why your 1-3MB image uploads to S3 are taking 16-18 seconds—way longer than they should be. I'll walk through common configuration oversights and optimizations you can apply right away.
First, let's recap your setup for clarity:
- Frontend: A basic file input with preview using
readAsDataURL, paired with a form targeting your Flask endpoint. - Backend: A Flask route using
boto3.client.upload_fileobjto send files directly to S3.
Your Current Code (Formatted)
Frontend
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <form id="upload_form" action="/updateuser" method="POST" enctype="multipart/form-data"> <label for="file">Choose file</label> <input type="file" id="fileinput" /> <img id="source_image"> <input type="button" id="upload" value="uploadimage"> </form> <script> function readFile(evt) { var file = evt.target.files[0]; var reader = new FileReader(); output_format = "jpg"; reader.onload = function(event) { var i = document.getElementById("source_image"); i.src = event.target.result; i.onload = function(){ image_width=$(i).width(), image_height=$(i).height(); if(image_width > image_height){ i.style.width="320px"; }else{ i.style.height="300px"; } i.style.display = "block"; console.log("Image loaded"); } }; console.log("Filename:" + file.name); console.log("Filesize:" + (parseInt(file.size) / 1024) + " Kb"); console.log("Type:" + file.type); reader.readAsDataURL(file); return false; } document.getElementById('fileinput').addEventListener('change', readFile, false); </script>
Backend
import boto3 import time from flask import Flask, request from config import S3_KEY, S3_SECRET, S3_BUCKET app = Flask(__name__) # Ajax function to support upload image call from UI @app.route('/user/uploadimage',methods=['GET','POST']) def uploadimage(): print("In uploadimage()") starttime = int(round(time.time() * 1000)) print("Start Monitoring uploadimage()", starttime) try: s3 = boto3.client( "s3", aws_access_key_id=S3_KEY, aws_secret_access_key=S3_SECRET ) except Exception as e: print(str(e)) try: file = request.files['file'] s3.upload_fileobj( file, S3_BUCKET, file.filename, ExtraArgs={ "ACL": "public-read", "ContentType": file.content_type } ) print("File uploaded successfully") print("Stop Monitoring uploadimage()", (int(round(time.time() * 1000)) - starttime)) except Exception as e: print("Error while Saving Image on Amazon S3 : ", e)
Key Optimizations to Fix Slow Uploads
1. Specify Your S3 Bucket's Region in Boto3
By default, boto3 uses us-east-1 as the default region. If your S3 bucket is in a different region (e.g., eu-west-1, ap-southeast-1), this forces cross-region data transfer which adds massive latency.
Fix this by adding the region_name parameter when creating the S3 client:
s3 = boto3.client( "s3", aws_access_key_id=S3_KEY, aws_secret_access_key=S3_SECRET, region_name='ap-southeast-1' # Replace with your bucket's actual region )
2. Enable S3 Transfer Acceleration
Transfer Acceleration routes your uploads through CloudFront's global edge network, drastically reducing latency for users/servers far from your bucket's region.
First, enable Transfer Acceleration in your S3 bucket's settings (AWS Console > S3 > Your Bucket > Properties > Transfer Acceleration). Then update your Boto3 client to use the accelerated endpoint:
s3 = boto3.client( "s3", aws_access_key_id=S3_KEY, aws_secret_access_key=S3_SECRET, region_name='ap-southeast-1', endpoint_url=f'https://{S3_BUCKET}.s3-accelerate.amazonaws.com' )
3. Optimize Boto3 Transfer Configuration
Tweak boto3's transfer settings to use parallel threads and smaller chunk sizes (even for sub-8MB files, which use single-part upload by default). This improves throughput over slow connections.
Add a TransferConfig when calling upload_fileobj:
from boto3.s3.transfer import TransferConfig # Configure transfer settings transfer_config = TransferConfig( multipart_threshold=1024 * 256, # Use multipart for files >256KB max_concurrency=10, # Number of parallel threads multipart_chunksize=1024 * 256, # Chunk size per thread use_threads=True # Enable parallel transfers ) # Use the config in your upload s3.upload_fileobj( file, S3_BUCKET, file.filename, ExtraArgs={"ACL": "public-read", "ContentType": file.content_type}, Config=transfer_config )
4. Fix Frontend Upload Logic (Avoid Unnecessary Encoding)
Your frontend uses readAsDataURL for preview, which is fine—but make sure you're uploading the original file (not the base64-encoded version). If you're using AJAX to submit (since your form has a button instead of a submit input), use FormData to send the raw file efficiently:
Add this script for your upload button:
document.getElementById('upload').addEventListener('click', function() { const fileInput = document.getElementById('fileinput'); const file = fileInput.files[0]; if (!file) { alert("Please select a file first!"); return; } const formData = new FormData(); formData.append('file', file); fetch('/user/uploadimage', { method: 'POST', body: formData }) .then(response => { if (response.ok) { console.log("Upload successful!"); // Add success UI updates here } else { throw new Error("Upload failed"); } }) .catch(error => console.error("Error during upload:", error)); });
5. Check Server-to-S3 Network Path
- If your Flask app is running on AWS EC2: Use an S3 VPC Endpoint to route traffic directly within AWS's private network (no public internet hop). This eliminates external latency and reduces costs.
- If your server is outside AWS: Ensure your server has sufficient upload bandwidth. A 3MB file taking 18 seconds implies ~1.7Mbps speed—way below typical broadband. Contact your hosting provider if this is unexpected.
6. Update Boto3 and Botocore
Older versions of boto3 and botocore can have performance bugs or lack optimizations. Upgrade to the latest versions:
pip install --upgrade boto3 botocore
Final Notes
Start with the region fix first—it's the most common culprit for slow S3 uploads. Then test Transfer Acceleration if you're uploading from a location far from your bucket's region.
内容的提问来源于stack exchange,提问作者Vinayak Mahajan

