TAG — Tigris Acceleration Gateway
TAG is a high-performance S3-compatible caching proxy for Tigris object storage. You deploy it between your application and Tigris, and it transparently caches objects on local NVMe storage — giving you sub-millisecond read latency without sacrificing S3 API compatibility.
You don't need to change any application code. Just point your S3 client at TAG instead of Tigris and your reads are automatically accelerated.
Why TAG
Object storage is durable and scalable, but every read crosses the network. If you're serving ML models, running real-time analytics, or pushing data through high-throughput pipelines, those round-trips add up fast.
TAG eliminates them for repeated reads. It maintains a local RocksDB-backed cache that serves objects in microseconds instead of milliseconds. Unlike a generic HTTP cache, TAG understands S3 natively — it coalesces concurrent requests into a single upstream fetch, serves range requests from cached full objects, revalidates stale entries with conditional requests, and invalidates cache entries the moment you write or delete an object.
Bottom line: One endpoint change. Zero code changes. Sub-millisecond reads.
Use Cases
ML Model Training
Cache training datasets on local NVMe so multi-epoch training runs don't re-fetch data from remote storage on every epoch. The first epoch populates the cache; subsequent epochs read entirely from local storage, removing the network bottleneck without requiring you to pre-download datasets, shard data into tar archives, or adopt a new storage API. Works with PyTorch DataLoaders, S3 Connector for PyTorch, and any S3-compatible data loading library.
Inference Data Caching
Cache model weights, configuration files, or other assets that inference workloads read repeatedly. Reduces cold-start latency and eliminates redundant network traffic.
High-Throughput Data Pipelines
For real-time analytics or data processing pipelines that repeatedly read the same objects, TAG eliminates redundant network round-trips and serves data at local NVMe speeds.
Performance
Benchmarked on AWS (c6in.16xlarge client, i3en.24xlarge server with NVMe storage):
| Object Size | Ops/sec | Bandwidth | TTFB p50 |
|---|---|---|---|
| 1 KiB | 75,717 | 73.9 MiB/s | < 1 ms |
| 100 KiB | 33,350 | 3.2 GiB/s | < 1 ms |
| 1 MiB | 10,955 | 10.7 GiB/s | Single-digit ms |
| 4 MiB | 2,775 | 10.8 GiB/s | Single-digit ms |
TAG saturates a 100 Gbps NIC at 85+ Gbps for 1 MiB+ objects, with CPU utilization at only about 12%, leaving significant headroom for additional workloads.
These numbers reflect cache-warm steady state. First requests for uncached objects incur a round-trip to Tigris.
For full methodology, environment specs, and complete warp and go-ycsb
results, see Benchmarks.
Key Features
S3-Compatible API
TAG implements the S3 REST API for commonly used Tigris operations. Clients interact with TAG using standard AWS SDKs, the AWS CLI, or any S3-compatible library. The only change is the endpoint URL.
TAG supports path-style addressing only (http://host:port/bucket/key).
Virtual-hosted style is not supported. Configure your S3 client accordingly.
Transparent Proxy Mode
In default mode, TAG preserves the client's original AWS SigV4 Authorization header and forwards requests to Tigris as-is. TAG adds cryptographically signed proxy headers so Tigris can validate both the client's identity and TAG's identity in a single round-trip.
TAG never sees or stores client secret keys. Clients authenticate directly with Tigris using their own credentials.
Embedded Cache with RocksDB
Each TAG node runs an embedded cache backed by RocksDB, optimized for NVMe storage. Objects are stored using a two-key pattern:
| Key | Stored data |
|---|---|
meta|my-bucket|photo.jpg | Content-Type, ETag, Content-Length, Last-Modified |
body|my-bucket|photo.jpg | Raw object bytes |
Separating metadata from body enables efficient HEAD requests and conditional operations without reading the full object.
Request Coalescing
If four clients ask for the same uncached object at the same time, TAG doesn't make four trips to Tigris. It fetches once and streams the result to everyone:
Range Request Optimization
When you send a byte-range request, TAG serves it from the cached full object if available. On a range miss, TAG does two things at once: it serves you the requested range directly from Tigris while also fetching the full object in the background. After that, any future range request for any byte range comes straight from cache.
This is especially useful for ML workloads that access model weights with random-access patterns. The first range request warms the full object into cache.
Write-Through Invalidation
When you write, delete, or copy an object through TAG, it invalidates the corresponding cache entry before forwarding the request to Tigris. A tombstone mechanism prevents any in-flight background cache writes from accidentally resurrecting objects you've already deleted.
Objects modified directly on Tigris (bypassing TAG) remain cached until the TTL
expires (default 60 minutes) or a client forces revalidation with
Cache-Control: no-cache. Route writes through TAG for immediate consistency.
Optional Multi-Node Clustering
When a single node's storage isn't enough, you can run multiple TAG nodes as a distributed cache cluster. They coordinate automatically:
Nodes discover each other via gossip, consistent hashing spreads keys across the cluster, and gRPC forwards requests for remote keys transparently. You don't need to manually assign keys or configure sharding.
Architecture
Here's how a request flows through TAG's internals:
Request Flows
Cache hit: Your request arrives, TAG validates your SigV4 signature locally,
finds the object in cache, and returns it with X-Cache: HIT. Tigris is never
contacted.
Cache miss: TAG forwards your request to Tigris, streams the response back
to you while writing it to cache, and returns X-Cache: MISS. The next request
for the same object is a hit.
Coalesced request: Multiple clients GET the same uncached object — the first becomes the fetcher, the rest attach as broadcast listeners. Everyone gets the data simultaneously from a single upstream request.
Range request: You send Range: bytes=0-1023 — if the full object is
cached, TAG serves your range from cache. If not, it serves the range from
Tigris while fetching the full object in the background for future requests.
Ports
| Port | Protocol | Purpose |
|---|---|---|
| 8080 | HTTP/HTTPS | S3 API (client-facing) |
| 7000 | TCP | Memberlist gossip (cluster discovery) |
| 9000 | TCP | gRPC (cache key routing between nodes) |
On macOS, port 7000 is used by AirPlay Receiver. Use ports 17000 (gossip) and
19000 (gRPC) instead when running TAG locally on macOS. See
Configuration Reference for details.
S3 API Coverage
TAG supports commonly used S3 operations, validated against 214 tests from the
ceph/s3-tests compatibility suite.
| Category | Operations |
|---|---|
| Objects | Get, Head, Put, Delete, Copy, Tagging, ACL |
| Buckets | List, Create, Delete, Head, ListV1/V2, Location, Versioning, ACL, Policy, CORS, Tagging, Lifecycle, DeleteObjects (bulk) |
| Multipart Uploads | Initiate, UploadPart, UploadPartCopy, Complete, Abort, ListParts, ListMultipartUploads |
| Auth | SigV4 headers, presigned URLs, chunked encoding |
Object versioning, server-side encryption (SSE-C/S3/KMS), Object Lock, POST object (browser uploads), multi-range requests, and virtual-hosted style addressing.
For client SDK examples (AWS CLI, Python boto3, and more), see S3 Client Usage.
Cache Behavior
TAG adds an X-Cache response header to every response:
| Value | Meaning |
|---|---|
HIT | Served from cache (includes successful revalidations) |
MISS | Fetched from Tigris, now cached |
REVALIDATED | Revalidated with Tigris; object changed and new content returned |
BYPASS | Cache skipped (client sent Cache-Control: no-store) |
DISABLED | Caching turned off server-side |
What gets cached: HTTP 200 responses within the size threshold (default 1
GiB) that do not include Cache-Control: no-store or private.
What does not: Non-200 responses, objects above the size threshold, and objects with cache-prevention headers.
For revalidation, client cache-control headers, and automatic invalidation details, see Cache Control and Revalidation.
Security Model
Your clients sign requests with their own Tigris credentials, and TAG forwards them to Tigris as-is — it never sees or stores your secret keys. After a client's first request, TAG learns derived signing keys from Tigris (encrypted with AES-256-GCM), so it can validate subsequent requests locally without calling home.
TAG requires its own Tigris credentials (AWS_ACCESS_KEY_ID /
AWS_SECRET_ACCESS_KEY) with read-only access to all buckets in the same
organization as clients it serves.
Authorization is per-bucket. Access to one bucket does not grant access to others. Entries are revoked immediately on a Tigris 403 response.
For the full authentication flow, authorization lifecycle, proxy header security, and endpoint validation, see Security and Access Control.
Monitoring
TAG exposes 30+ Prometheus metrics at /metrics covering request throughput,
cache effectiveness, request coalescing, upstream health, authentication, and
connection stats.
For the full metrics reference, PromQL examples, alerting recommendations, and scrape configuration, see Metrics Reference.