Loading
Loading
Storage Internals
Metadata in the database, bytes in object storage, uploads that bypass your servers, and a CDN in front of the reads.
By the end of this chapter
A user's profile photo is two things: a few hundred bytes of facts — owner, size, content type, upload time, processing state — and a few megabytes of pixels. The facts are queried, joined and updated. The pixels are written once and read whole. Those are opposite access patterns, and they belong in different stores.
| Metadata | Bytes | |
|---|---|---|
| Size | Hundreds of bytes | Kilobytes to gigabytes |
| Access | Queried, filtered, joined | Fetched whole by key |
| Changes | Often (status, title, visibility) | Rarely; usually replaced by a new object |
| Home | Database | Object storage |
The naive upload sends the file to the API, which forwards it to storage. Every byte crosses your servers twice, and each slow mobile upload holds a connection and memory for its whole duration. The better shape is to have the API hand out permission and let the client send the bytes straight to storage.
Components (7): Client [client]; API [api] — issues presigned URL; Metadata DB [database] — row: pending → ready; Object storage [object_storage] — original + derived files; Upload events [queue]; Media worker [worker] — thumbnails, transcodes, scans; CDN [cdn] — serves reads Connections (9): Client -> API (1. request upload); API -> Metadata DB (2. insert pending row); Client -> Object storage (3. PUT bytes via presigned URL); Object storage ~> Upload events (4. object created); Upload events ~> Media worker; Media worker -> Object storage (5. write derived files); Media worker -> Metadata DB (6. mark ready); Client -> CDN (7. GET media); CDN -> Object storage (cache miss) Legend: -> synchronous, ~> asynchronous, => replication.
An app receives an illustrative 1 million uploads a day, averaging 4 MB each, many from phones on slow uplinks.Ingress ≈ 1,000,000 × 4 MB = 4 TB/dayBefore any derived versions are generated.Average ≈ 4 TB / 86,400 s ≈ 46 MB/sPeaks could plausibly be several times this.One upload at 1 Mbps uplink: 32 Mb / 1 Mbps ≈ 32 sA proxied upload holds an API connection for all of that.Storage growth ≈ 4 TB × 365 ≈ 1.5 PB/year, originals onlyLifecycle rules (cheaper tiers, expiry) matter early.Direct-to-storage uploads remove terabytes a day and many long-held connections from the API tier.Media is the ideal CDN workload: large, read many times, and rarely changed. The one thing that makes it hard is changing an object in place. If a user replaces their avatar and the new file is written under the same key, every edge that cached the old one keeps serving it until its cache entry expires or is explicitly purged.
Sign in to keep a note here. It is free, and nobody else can see it.
Sign inWhat this chapter was for: