Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LZ4 Ultra-Fast Compression

LZ4 is an extremely fast compression algorithm ideal for high-throughput scenarios where CPU time is more valuable than bandwidth.

Benefits

FeatureLZ4GzipBrotli
Compression Speed700 MB/s35 MB/s8 MB/s
Decompression Speed4 GB/s300 MB/s400 MB/s
Compression Ratio50-60%70-80%75-85%
CPU UsageVery LowMediumHigh
Best ForHigh throughput, real-timeGeneral useBandwidth-constrained

When to Use LZ4

Use LZ4 when:

  • High throughput (100k+ req/s)
  • Low latency is critical (< 10ms P99)
  • CPU is more expensive than bandwidth
  • Real-time applications
  • Internal APIs (microservices communication)

Don’t use LZ4 when:

  • Bandwidth is extremely expensive
  • Users on slow connections (use Brotli)
  • Maximum compression ratio needed

Quick Start

Basic Configuration

use grpc_graphql_gateway::{Gateway, CompressionConfig};

let gateway = Gateway::builder()
    .with_compression(CompressionConfig::ultra_fast())  // LZ4!
    .build()?;

Advanced Configuration

use grpc_graphql_gateway::CompressionConfig;

let config = CompressionConfig {
    enabled: true,
    level: CompressionLevel::Fast,
    min_size_bytes: 256,  // Lower threshold for LZ4
    algorithms: vec!["lz4".into()],
};

Multi-Algorithm Support

// Prefer LZ4, fallback to gzip for browsers
let config = CompressionConfig {
    algorithms: vec![
        "lz4".into(),    // For high-performance clients
        "gzip".into(),   // For browsers
    ],
    ..Default::default()
};

Client Support

JavaScript/TypeScript

// Axios example
import axios from 'axios';

const client = axios.create({
  baseURL: 'http://localhost:8888/graphql',
  headers: {
    'Accept-Encoding': 'lz4, gzip, deflate',
  },
  // Add LZ4 decompression
  transformResponse: [(data) => {
    // Handle LZ4 decompression if needed
    return JSON.parse(data);
  }],
});

Rust Client

use reqwest::Client;

let client = Client::builder()
    .gzip(true)
    .build()?;

// The gateway will automatically use LZ4 if client supports it
let response = client
    .post("http://localhost:8888/graphql")
    .header("Accept-Encoding", "lz4, gzip")
    .json(&graphql_query)
    .send()
    .await?;

Go Client

import (
    "github.com/pierrec/lz4"
    "net/http"
)

client := &http.Client{
    Transport: &lz4Transport{},
}

// Add LZ4 decompression support
type lz4Transport struct{}

func (t *lz4Transport) RoundTrip(req *http.Request) (*http.Response, error) {
    req.Header.Set("Accept-Encoding", "lz4, gzip")
    // ... handle LZ4 decompression
}

Performance Comparison

Benchmark: 1KB GraphQL Response

AlgorithmCompression TimeDecompression TimeCompressed Size
LZ40.002ms0.001ms580 bytes
Gzip0.15ms0.05ms320 bytes
Brotli2.5ms0.08ms280 bytes

Result: LZ4 is 75x faster to compress than gzip with acceptable size.

Benchmark: 100KB GraphQL Response

AlgorithmCompression TimeDecompression TimeCompressed Size
LZ40.14ms0.05ms52 KB
Gzip12ms3ms28 KB
Brotli180ms4ms24 KB

Result: LZ4 is 85x faster to compress, 60x faster to decompress.

Cost Impact at 100k req/s

Scenario: 2KB average response size

With Gzip:

CPU: 4 cores @ 100% = 4 vCPU
Cost: ~$140/mo
Bandwidth: 155 MB/s compressed
Latency: +2ms P99

With LZ4:

CPU: 2 cores @ 40% = 0.8 vCPU
Cost: ~$28/mo (80% reduction!)
Bandwidth: 180 MB/s compressed
Latency: +0.3ms P99

Savings: $112/month on compression CPU alone

Integration Examples

Example 1: Ultra-Fast Internal APIs

For microservices communication where throughput matters more than bandwidth:

let gateway = Gateway::builder()
    .with_compression(CompressionConfig {
        enabled: true,
        algorithms: vec!["lz4".into()],
        min_size_bytes: 256,
        level: CompressionLevel::Fast,
    })
    .build()?;

Example 2: Hybrid Strategy

Use LZ4 for internal calls, Brotli for external:

// In middleware
async fn compression_selector(req: Request) -> CompressionConfig {
    if is_internal_request(&req) {
        CompressionConfig::ultra_fast()  // LZ4
    } else {
        CompressionConfig::best()  // Brotli
    }
}

Example 3: Content-Type Based

Use LZ4 for JSON, Gzip for HTML:

let config = if response_is_json {
    CompressionConfig::ultra_fast()
} else {
    CompressionConfig::default()
};

Cache Optimization with LZ4

Use LZ4 to compress cached responses for better memory efficiency:

use grpc_graphql_gateway::Lz4CacheCompressor;

// Store in cache
let json = serde_json::to_string(&response)?;
let compressed = Lz4CacheCompressor::compress(&json)?;
cache.set("key", compressed).await?;

// Retrieve from cache
let compressed = cache.get("key").await?;
let json = Lz4CacheCompressor::decompress(&compressed)?;
let response: GraphQLResponse = serde_json::from_str(&json)?;

Result: 50-60% memory savings in cache with minimal CPU overhead.

Advanced: Custom Middleware

Add LZ4 compression as custom middleware:

use grpc_graphql_gateway::lz4_compression_middleware;
use axum::{Router, middleware};

let app = Router::new()
    .route("/graphql", post(graphql_handler))
    .layer(middleware::from_fn(lz4_compression_middleware));

Monitoring

Track LZ4 compression effectiveness:

// Export metrics
gauge!("compression_ratio_lz4", compression_ratio);
histogram!("compression_time_lz4_ms", compression_time.as_millis() as f64);
counter!("bytes_saved_lz4", bytes_saved);

Best Practices

1. Set Reasonable Thresholds

CompressionConfig {
    min_size_bytes: 256,  // Don't compress tiny responses
    // ...
}

2. Combine with Caching

LZ4 + caching = maximum performance:

Gateway::builder()
    .with_response_cache(cache_config)
    .with_compression(CompressionConfig::ultra_fast())
    .build()?

3. Monitor CPU vs Bandwidth Trade-off

// If CPU > 80%: Use LZ4
// If bandwidth > 80%: Use Brotli
// Otherwise: Use Gzip
let config = match (cpu_usage, bandwidth_usage) {
    (cpu, _) if cpu > 0.8 => CompressionConfig::ultra_fast(),
    (_, bw) if bw > 0.8 => CompressionConfig::best(),
    _ => CompressionConfig::default(),
};

4. Test with Your Data

use grpc_graphql_gateway::{compress_lz4, compression};

let sample_response = get_typical_graphql_response();
let compressed = compress_lz4(sample_response.as_bytes())?;

let ratio = compressed.len() as f64 / sample_response.len() as f64;
println!("Compression ratio: {:.1}%", ratio * 100.0);

Production Deployment

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: graphql-gateway
spec:
  template:
    spec:
      containers:
      - name: gateway
        env:
        - name: COMPRESSION_ALGORITHM
          value: "lz4"
        - name: COMPRESSION_MIN_SIZE
          value: "256"
        resources:
          requests:
            cpu: "500m"  # LZ4 uses less CPU
            memory: "512Mi"

Docker

FROM rust:1.75-alpine AS builder
RUN apk add --no-cache lz4-dev

# ... build gateway with LZ4 support

ENTRYPOINT ["./gateway", "--compression=lz4"]

FAQ

Q: Is LZ4 supported by browsers? A: Not natively. Use gzip/brotli for browser clients, LZ4 for server-to-server.

Q: Can I use both LZ4 and Gzip? A: Yes! The gateway automatically selects based on Accept-Encoding header.

Q: Does LZ4 work with CloudFlare? A: CloudFlare doesn’t support LZ4. Use it for origin-to-CloudFlare, let CloudFlare handle client compression.

Q: How much CPU does LZ4 save? A: 60-80% less CPU than gzip at 100k req/s (see benchmarks above).