Sub-Millisecond Feature Flags in Django: High-Density Targeting with Redis Bitmaps & Bloom Filters

Evaluating feature flags on every incoming HTTP request via SQL queries cripples API latency. Discover how to architect sub-millisecond feature toggles, percentage rollouts, and tenant targeting in Django using Redis Bitmaps, consistent hashing, and Bloom filters.

The Architecture of High-Frequency Feature Evaluation

Modern continuous delivery pipelines rely heavily on feature flags (toggles) to decouple code deployment from release cycles. Whether rolling out a new checkout flow to 10% of users, granting beta access to enterprise tenants, or executing a kill-switch during an outage, feature flag evaluation occurs on nearly every incoming HTTP request.

However, querying a relational database like PostgreSQL to check feature flag rules for every user request creates severe read amplification and drives up p99 latency. Even with read replicas and ORM caching, evaluating 20 flags across 5,000 requests per second requires 100,000 database lookups every second. To achieve true sub-millisecond evaluation, we must eliminate database queries entirely by utilizing Redis Bitmaps and deterministic mathematical hashing.

1. Redis Bitmaps: Storing Millions of Flags in Kilobytes

A Redis Bitmap is not an independent data type, but a set of bit-oriented operations applied directly to standard Redis Strings. Because Strings are binary-safe and can grow up to 512MB, a single Redis key can represent up to 4.29 billion individual binary bits (flag on/off states).

If your application has integer user IDs, checking whether User 45,821 has a specific beta feature enabled requires reading exactly one bit at offset 45821:

# Enable feature 'beta_voice_v2' for user ID 45821
SETBIT feature:beta_voice_v2 45821 1

# Check if user ID 45821 has the feature enabled (Returns 1 or 0)
GETBIT feature:beta_voice_v2 45821

The memory efficiency of Redis Bitmaps is extraordinary compared to traditional database rows or JSON caching:

Storage Mechanism Memory for 1,000,000 Users Evaluation Latency Network Bandwidth Overhead
PostgreSQL Table (user_id, feature_id) ~64 MB (indexes + tuples) 1.5ms - 4.0ms High (SQL protocol handshake)
Redis Hash / Set (SISMEMBER) ~48 MB 0.4ms - 0.8ms Moderate
Redis Bitmap (GETBIT) 122 Kilobytes 0.1ms - 0.2ms Negligible (Single bit response)

Storing the targeting status for one million users consumes a mere 122KB of RAM. You could track 100 distinct feature flags across 10 million users in less than 120MB of Redis memory.

2. Deterministic Percentage Rollouts with Consistent Hashing

When rolling out a feature to a randomized percentage of users (e.g., 25% canary rollout), you must ensure consistency: User A must always see the new feature on every visit, while User B must never see it, without storing persistent user IDs in a database table. This is achieved using deterministic hashing:

# flags.py
import mmh3 # MurmurHash3 (Ultra-fast, non-cryptographic hash)

def is_feature_enabled_for_percentage(feature_name: str, user_id: str, percentage: int) -> bool:
    # Deterministically computes whether a user falls within a rollout percentage bracket.
    # Guarantees consistent assignment without storing state in a database.
    if percentage <= 0:
        return False
    if percentage >= 100:
        return True

    # Combine feature name with user ID to prevent rollout correlations across features
    hash_key = f"{feature_name}:{user_id}"
    # MurmurHash3 yields a 32-bit unsigned integer (0 to 4,294,967,295)
    hash_value = mmh3.hash(hash_key, signed=False)
    
    # Map hash value onto a 0-99 distribution
    bucket = hash_value % 100
    return bucket < percentage

3. Production Django Feature Flag Service

Below is a production-ready feature flag service integrating Redis Bitmaps, percentage rollouts, and a local Python memory cache to achieve zero-network evaluations on hot paths:

# services/feature_flags.py
import redis
from django.conf import settings
from functools import lru_cache
import mmh3

redis_client = redis.Redis.from_url(settings.REDIS_URL, decode_responses=False)

class FeatureFlagService:
    @staticmethod
    def is_enabled(flag_name: str, user=None) -> bool:
        # Check global master kill-switch first
        global_state = redis_client.get(f"flag:global:{flag_name}")
        if global_state == b"0":
            return False
        if global_state == b"1":
            return True

        if not user or not user.is_authenticated:
            return False

        # Check explicit user entitlement via Redis Bitmap
        user_bit = redis_client.getbit(f"flag:bitmap:{flag_name}", user.id)
        if user_bit == 1:
            return True

        # Check percentage rollout configuration
        rollout_pct = redis_client.get(f"flag:rollout:{flag_name}")
        if rollout_pct:
            pct = int(rollout_pct)
            hash_key = f"{flag_name}:{user.id}"
            if (mmh3.hash(hash_key, signed=False) % 100) < pct:
                return True

        return False

4. Fast-Reject Tenant Checks with Bloom Filters

For B2B multi-tenant applications where features are enabled by Tenant UUID rather than integer user IDs, Redis Bitmaps cannot be indexed directly by integer offsets. Instead, deploying a Redis Bloom Filter (via RedisStack BF.EXISTS) allows the application to verify if an organization belongs to an enterprise feature cohort in under 200 microseconds with zero false negatives.

Combine feature flags with OpenTelemetry Distributed Tracing to evaluate real-time performance impacts across active feature cohorts. Explore our full suite of Software Engineering Consulting Services.

Architectural Continuity & Deep Dives

For related production architectures and system implementations, explore these companion guides:

All Insights
Chat on WhatsApp