Object Storage ও File
ছবি, video, document কোথায় রাখবে
User এর profile ছবি, note এর সাথের ছবি, invoice এর PDF, product এর video। এগুলো কোথায় রাখবে? Database এ? Server এর disk এ? দুটোই ভুল উত্তর। আধুনিক system এ এগুলোর জায়গা object storage: Amazon S3, Cloudflare R2, Google Cloud Storage, Azure Blob, বা নিজে চালাতে চাইলে MinIO। এই অধ্যায়ে দেখবো কেন, আর কীভাবে নিরাপদে আর দক্ষভাবে file রাখতে ও দিতে হয়।
#তিন ধরনের storage
| ধরন | কী | উদাহরণ | কখন |
|---|---|---|---|
| Block storage | কাঁচা disk, একটা server এর সাথে যুক্ত | AWS EBS, VPS এর SSD | Database এর data, OS |
| File storage | Folder-file এর গঠন, কয়েকটা server share করতে পারে | NFS, AWS EFS | পুরনো app যারা file system চায় |
| Object storage | Key → object (file + metadata), HTTP দিয়ে | S3, R2, GCS, MinIO | ছবি, video, document, backup, log |
#কেন object storage
Database এ ছবি রাখলে:
- Database বিশাল হয়, backup আর restore ধীর আর দামি
- প্রতিটা ছবি দেখাতে database আর app server দিয়ে যেতে হয়
- Database এর memory (cache) ছবি দিয়ে ভরে, আসল query ধীর হয়
Server এর disk এ রাখলে:
- দুইটা server হলে ছবি এক server এ, request গেল আরেকটায়: "ছবি নেই" (stateless না)
- Container নতুন করে বানালে disk এর সব হারায়
- Disk ভরে গেলে পুরো server বিপদে
Object storage এ:
- প্রায় সীমাহীন জায়গা, ব্যবহার অনুযায়ী দাম (GB প্রতি মাসে কয়েক সেন্ট)
- অত্যন্ত টেকসই: data কয়েকটা জায়গায় copy, বছরে একটা file হারানোর সম্ভাবনা কার্যত শূন্য
- সব server একই জায়গা থেকে পড়ে
- সরাসরি HTTP তে দেওয়া যায়, সামনে CDN বসানো সহজ
#মূল ধারণা
- Bucket: সবচেয়ে বড় ধারক, যেমন
notes-app-uploads - Object: একটা file, তার key (পুরো নাম, যেমন
users/42/avatar/7f3c.webp) আর metadata (content type, আকার) - Folder আসলে নেই:
users/42/শুধু key এর অংশ, দেখতে folder এর মতো - Object বদলানো যায় না, পুরোটা নতুন করে লেখা যায়
#Database আর storage এর ভাগাভাগি
Database এ পুরো URL না, শুধু key রাখো। URL পরে বদলাতে পারে (CDN বদলানো, signed URL), key বদলায় না।
#Upload: দুই পদ্ধতি
১. App server দিয়ে (ছোট file): client → API → storage। সহজ, server যাচাই করতে পারে (API advanced অধ্যায়ের উদাহরণ)।
২. Pre-signed URL দিয়ে সরাসরি (বড় file): API শুধু একটা অস্থায়ী, স্বাক্ষরিত upload URL দেয়, client সরাসরি storage এ upload করে। App server এর bandwidth আর worker বাঁচে।
import boto3
s3 = boto3.client(
"s3",
endpoint_url=settings.s3_endpoint, # R2/MinIO হলে, AWS এ লাগে না
aws_access_key_id=settings.s3_key,
aws_secret_access_key=settings.s3_secret,
)
def presign_upload(key: str, content_type: str, max_bytes: int) -> dict:
return s3.generate_presigned_post(
Bucket=BUCKET,
Key=key,
Fields={"Content-Type": content_type},
Conditions=[
{"Content-Type": content_type},
["content-length-range", 1, max_bytes], # আকারের সীমা storage নিজেই মানাবে
],
ExpiresIn=600,
)Upload শেষে client API কে জানায় ("upload শেষ, key এটা"), তখন server database এ রেকর্ড করে, আর চাইলে একটা background job দিয়ে file যাচাই করে (আসলেই ছবি কিনা, virus scan, thumbnail)।
#Download: public নাকি private
| File | উপায় |
|---|---|
| Public (product এর ছবি, restaurant এর logo) | Public bucket বা public path, সামনে CDN, লম্বা cache |
| Private (invoice, NID এর ছবি, ব্যক্তিগত document) | Private bucket + signed download URL (কয়েক মিনিট মেয়াদী), শুধু যার অনুমতি আছে তাকে |
def presign_download(key: str) -> str:
return s3.generate_presigned_url("get_object", Params={"Bucket": BUCKET, "Key": key}, ExpiresIn=300)#ছবি process করা
User ৮ MB এর ছবি তুললো (আধুনিক phone এর camera)। List এ সেটা ১০০ px এর thumbnail হিসেবে দেখাবে। পুরো ৮ MB নামানো অপচয়।
- Upload হলে background job (Celery) মূল ছবি থেকে কয়েকটা আকার বানায়:
thumb(২০০ px),medium(৮০০ px), WebP/AVIF format এ - অথবা CDN এর on-the-fly resize ব্যবহার করো (
?width=200&format=webp) - Flutter app screen অনুযায়ী ঠিক আকারেরটা চায়
আর upload এর আগেই Flutter এ ছবি ছোট করে নাও (image_picker এর maxWidth, imageQuality)। User এর mobile data বাঁচে, upload দ্রুত হয়।
#Lifecycle আর খরচ
- Lifecycle rule: অস্থায়ী upload ২৪ ঘণ্টা পর মুছে ফেলো; ৯০ দিনের পুরনো log সস্তা storage class এ সরাও; ৭ বছরের পুরনো invoice archive এ
- Orphan file: note মুছলে তার ছবি ও মুছতে হবে, না হলে আজীবন টাকা দিচ্ছো। Background job দিয়ে মাঝে মাঝে database এ নেই এমন file খুঁজে মোছো।
- Egress (বের হওয়ার) খরচ: অনেক cloud এ storage সস্তা কিন্তু data বের হওয়া দামি। CDN সামনে রাখলে এই খরচ অনেক কমে। (Cloudflare R2 এর বড় আকর্ষণ হলো egress এ টাকা লাগে না।)
- Versioning: ভুল করে overwrite বা মুছে ফেললে ফেরানোর জন্য গুরুত্বপূর্ণ bucket এ চালু রাখো
#অনুশীলন
#নিজেকে যাচাই করো
ছবি server এর disk এ রাখলে horizontal scaling এ কী সমস্যা?
ছবি থাকে শুধু একটা server এ। পরের request অন্য server এ গেলে সেখানে ছবি নেই। আর container নতুন বানালে disk এর সব হারায়। Object storage এ রাখলে সব server একই জায়গা থেকে পড়ে।
Database এ ছবির পুরো URL না রেখে key কেন রাখবে?
URL বদলাতে পারে (CDN বা domain বদল, signed URL এর মেয়াদ)। Key স্থির থাকে, দেখানোর সময় key থেকে তখনকার সঠিক URL বানানো যায়।
Pre-signed upload URL এর সুবিধা কী?
বড় file app server এর উপর দিয়ে যায় না, সরাসরি storage এ যায়। App server এর bandwidth আর worker বাঁচে, আর server তবুও নিয়ন্ত্রণ রাখে (কোন key তে, কত বড়, কতক্ষণের জন্য)।
NID এর ছবির মতো ব্যক্তিগত document কীভাবে দেবে?
Private bucket এ রাখবে, আর অনুমতি যাচাই করে কয়েক মিনিটের মেয়াদী signed download URL দেবে। কখনো public bucket বা অনুমানযোগ্য URL এ না।
চিহ্ন দিলে sidebar আর রোডম্যাপে এই অধ্যায়ের station ভরে যাবে।