How to Efficiently Check Username Uniqueness: From DB Queries to Redis Bloom Filters

This article compares three approaches for verifying username uniqueness during app registration—direct database queries, Redis caching, and Redis-backed Bloom filters—detailing their performance, scalability, memory usage, and trade‑offs, and provides Java code examples for each solution.

21CTO
21CTO
21CTO
How to Efficiently Check Username Uniqueness: From DB Queries to Redis Bloom Filters

Introduction

When users register for an app, they often encounter messages that the chosen username, email, or phone number is already taken, prompting them to try another one. This article examines three technical solutions for checking username uniqueness and evaluates their pros and cons.

Database Approach

The traditional method queries the database to verify whether a username already exists. This approach suffers from several drawbacks:

Significant latency due to network round‑trips between the application server and the database, especially with large data volumes.

High database load, as each registration triggers a SELECT query that consumes CPU and I/O resources.

Poor scalability; vertical scaling of the database can be costly and has limits, while increasing concurrent connections may overwhelm the server.

Database approach diagram
Database approach diagram

Cache Solution with Redis

To reduce database load and latency, an in‑memory Redis cache can be introduced. The following Java code demonstrates how to store and check usernames using a Redis hash map via Redisson:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.api.RMap;

public class UserExistenceChecker {
    // Redis hash map name to store user information
    private static final String USER_HASH_NAME = "users";

    public static void main(String[] args) {
        // Create a Redisson client
        RedissonClient redisson = createRedissonClient();

        // Retrieve the hash map to store user information
        RMap<String, String> users = redisson.getMap(USER_HASH_NAME);

        // Add a user to the hash map
        users.put("user123", "someUserInfo"); // could be JSON, UUID, etc.

        // Check if a user exists
        boolean exists = users.containsKey("user123");
        System.out.println("User 'user123' exists? " + exists);

        // Check for a non‑existent user
        exists = users.containsKey("user456");
        System.out.println("User 'user456' exists? " + exists);

        // Shutdown the Redisson client
        redisson.shutdown();
    }

    private static RedissonClient createRedissonClient() {
        Config config = new Config();
        config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379") // Adjust to your Redis address
                .setPassword("yourpassword"); // Optional password
        return Redisson.create(config);
    }
}

This caching approach still requires memory proportional to the number of stored usernames; storing one billion usernames would need roughly 15 GB of RAM.

Total memory ≈ 15 GB (15 bytes per record × 1 billion records).

Bloom Filter Solution

To further reduce memory consumption, a Bloom filter can be employed. A Bloom filter is a probabilistic data structure that uses a bit array and multiple hash functions to test set membership with a configurable false‑positive rate.

Bloom filter concept
Bloom filter concept

When inserting a value, each of the k hash functions maps the value to a position in the bit array, and the corresponding bits are set to 1. To query, the same hash functions are applied; if all mapped bits are 1, the element is *possibly* present, otherwise it is definitely absent.

Bit array illustration
Bit array illustration

Redis natively supports Bloom filters via the Redisson client. The following Java example shows how to create and use a Bloom filter for username existence checks:

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class UserExistenceChecker {
    private static final String BLOOM_FILTER_NAME = "user_existence_filter";

    public static void main(String[] args) {
        RedissonClient redisson = createRedissonClient();
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter(BLOOM_FILTER_NAME);
        bloomFilter.tryInit(100000L, 0.001); // expected elements, false‑positive rate

        bloomFilter.add("user123");
        boolean exists = bloomFilter.contains("user123"); // true
        System.out.println("User 'user123' exists? " + exists);

        exists = bloomFilter.contains("user456"); // may be false positive
        System.out.println("User 'user456' exists? " + exists);

        redisson.shutdown();
    }

    private static RedissonClient createRedissonClient() {
        Config config = new Config();
        config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379"); // Adjust to your Redis address
        // .setPassword("yourpassword"); // Optional
        return Redisson.create(config);
    }
}

Advantages of the Bloom filter approach include:

Memory efficiency: storing one billion entries with a false‑positive probability of 0.001 requires about 1.67 GB, far less than the 15 GB needed for a plain hash map.

Constant‑time lookups (O(1)) without scanning the entire dataset.

Drawbacks are:

False positives: the filter may incorrectly report that a non‑existent username exists, though it never reports a missing username as present.

Inability to delete individual elements, as removal would affect other entries and increase the false‑positive rate.

Conclusion

Using a Redis‑backed Bloom filter provides an efficient, memory‑saving solution for large‑scale username uniqueness verification, balancing speed and resource consumption while accepting a low false‑positive rate.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaredisbloom-filterbackend optimizationusername uniqueness
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.