Pastebin system design case study. Client posts text snippets via HTTPS through a CDN and Load Balancer to the paste-svc. paste-svc generates a base62 short ID (8 chars), stores the body in S3 under sharded prefixes, and persists metadata (lang, ttl, s3_key, visibility) in Postgres. Hot pastes are cached in Redis. Reads are served via CDN for /raw views and rendered HTML pages bypass the CDN to keep view counts accurate. A TTL cleanup cron sweeps expired pastes from S3, Postgres and Redis. ADRs: KV store choice (S3 + Postgres metadata), ID generation strategy (base62 hash with collision retry), CDN caching for raw views. Capacity: 10M DAU, 1M new pastes/day, 10:1 read:write, viral pastes 100x burst. Six scenarios: create paste, view with cache miss, raw CDN hit, viral burst absorbed by CDN+Redis, TTL cron cleanup, abuse rate limiting.
The service creates an immutable text paste, returns a short URL, serves rendered HTML and raw text, supports optional expiration and user deletion, and rejects abuse. Private pastes require authorization; an unlisted URL is not an authorization mechanism.
Exercise workload: 10M creates/month and 100M reads/month. For a 30-day month this is about 3.86 average writes/s and 38.6 average reads/s, not hundreds of requests per second. Peaks are separate assumptions: for example 20× create peak and a viral raw object at 10K reads/s. At 10KB average body size, raw new data is about 100GB/month and 6TB over five years before replication, versions, metadata and logs.
Eight base62 characters give M = 62^8 = 218,340,105,584,896 possible values. With n = 600,000,000 created pastes, the expected number of colliding pairs is approximately n(n-1)/(2M) ≈ 824. The probability of at least one collision is therefore effectively 100%, not negligible.
The design uses 12 uniform base62 characters from an operating-system CSPRNG in every Paste Service replica. Then M = 62^12 ≈ 3.226 × 10^21 and the same five-year horizon gives expected colliding pairs about 5.58 × 10^-5, or about 0.0056% probability of at least one collision under the uniform model. This is small, not zero. A UNIQUE constraint is still the authority; on conflict the replica generates a fresh independent ID and retries a bounded number of times.
Hash(content + timestamp) is avoided: clocks and predictable inputs are not a substitute for entropy, identical content should not create accidental coupling, and local CSPRNG generation removes the central ID service SPOF. RFC 4086 explains why clock/limited-range sources are guessable.
SQL and S3-compatible storage do not share a transaction. The service therefore uses visible states:
If the process dies, a reconciler claims old PENDING rows. A missing object leads to ABORTED; a matching object can be activated only when all metadata is complete; an unexpected orphan is deleted. Operations are idempotent and keyed by paste ID plus object version.
S3 documents strong read-after-write behavior for a single object key, but no atomic update across keys. The application state machine is still required.
On an origin read, metadata status, expiration and visibility are checked first. A cache key includes immutable object version so an old body cannot be confused with a recreated ID. Rendered content is escaped before highlighting, returned with a restrictive CSP, and raw content uses text/plain plus X-Content-Type-Options: nosniff.
The public raw path can be cached at the CDN. Its max-age is no greater than min(5 minutes, remaining paste lifetime). This is an explicit bounded stale-read trade-off, not an instant-delete guarantee.
The sweeper atomically changes ACTIVE → DELETING and inserts an outbox event. From that commit onward origin reads fail closed. An idempotent worker then invalidates every raw CDN path/cache variant, evicts Redis, deletes the exact object version and finalizes a DELETED tombstone. CDN invalidation is asynchronous and retried until its provider reports completion.
CloudFront documents that an object must be invalidated to remove it from edge caches before TTL, and that invalidations cannot be cancelled after submission. Browser or intermediary copies can outlive a purge. Therefore a product promising immediate hard delete must either perform an edge authorization/status check for each request or disable public caching for that class of content. This design promises a bounded public-cache window and exposes purge backlog as an SLO.
If object-store versioning is enabled, a simple DELETE can create only a delete marker; permanent erasure requires deleting the specified version and applying noncurrent-version lifecycle policy. The worker records version IDs and distinguishes logical unavailability from physical erasure.
Putting bodies in Postgres may be simplest at MVP scale. Object storage reduces database/WAL pressure later but adds a cross-system state machine. Syntax highlighting can be lazy because many pastes are never viewed. Exact view counts conflict with CDN hits; use edge logs/analytics or accept approximate counters rather than bypassing CDN solely for a vanity number.
Смотрите [CONCEPT]back-of-envelope, [CONCEPT]caching-patterns, [CONCEPT]rate-limiting-algorithms, [CONCEPT]sharding-strategies, [CASE]object-storage-s3 и [CASE]cdn-design. Практический cache-aside: Cache-Aside.
Введите числа или выберите пресет