Binary State Statistics with Redis Bitmap: Efficient User Login and Sign‑In Tracking
This article explains how to use Redis Bitmap for binary state statistics such as user login status and daily sign‑in tracking, comparing memory usage with String types, and demonstrates practical commands like SETBIT, GETBIT, BITCOUNT, BITPOS, and BITOP for massive user datasets.
In mobile application scenarios we often need to store a key that maps to a collection of data, such as determining a user's login status, showing a user's monthly sign‑in count, or aggregating the number of users who have signed in for seven consecutive days among hundreds of millions of users.
Because the number of users and accesses can reach millions or even billions, we must choose a collection type that can efficiently handle such massive data.
The article introduces four statistical types—binary state, aggregate, sorted, and cardinality—and focuses on binary state statistics as the first practical example.
For binary state scenarios (e.g., login or sign‑in), each element only needs a value of 0 or 1. Storing one million users' login status with Redis String would require one million separate strings, leading to high memory overhead due to the SDS (Simple Dynamic String) structure, which stores length, allocation size, and a terminating byte.
Redis also adds a RedisObject header to store metadata such as last access time and reference count, further increasing memory consumption.
Using a Bitmap solves this problem: one bit per user means 100 000 000 users occupy only about 12 MB (100 000 000 / 8 / 1024 / 1024). The Bitmap is implemented on top of the SDS structure, treating each byte as eight bits, where each bit represents the binary state of an element.
To check a user's login status, Redis provides GETBIT and SETBIT . A single key (e.g., login_status ) stores the bitmap, the user ID is used as the offset, and setting the bit to 1 marks the user as online, 0 as offline. Example commands:
SETBIT login_status 10086 1 GETBIT login_status 10086 SETBIT login_status 10086 0For monthly sign‑in tracking, each day of a month is represented by one bit. A key pattern like uid:sign:{userId}:{yyyyMM} stores a user's sign‑in bitmap for a specific month, with offset = day‑1 . Example commands to record, query, and count sign‑ins:
SETBIT uid:sign:89757:202105 15 1 GETBIT uid:sign:89757:202105 15 BITCOUNT uid:sign:89757:202105To find the first sign‑in day of a month, Redis offers BITPOS , which returns the offset of the first bit set to 1. Adding 1 to the returned offset yields the calendar day.
BITPOS uid:sign:89757:202105 1For counting users who have signed in for seven consecutive days, each day's bitmap uses the user ID as the offset. By applying a bitwise AND across the seven daily bitmaps with BITOP AND , the resulting bitmap contains 1 only for users present in all seven days. A subsequent BITCOUNT yields the total number of continuous sign‑ins.
// AND operation
BITOP AND destmap bitmap:01 bitmap:02 bitmap:03
// Count bits set to 1
BITCOUNT destmapThe memory cost of a bitmap with 100 million bits is roughly 12 MB; seven such bitmaps require about 84 MB, which is still modest. Setting an expiration on these keys helps reclaim memory after the data becomes stale.
In summary, when a statistical scenario only requires binary states—such as user existence, blacklist checks, or sign‑in tracking—using Redis Bitmap dramatically reduces memory usage while providing fast bitwise operations for massive datasets.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.