Master Binary State Stats with Redis Bitmap: Efficient Login & Sign‑In Tracking
Learn how to efficiently store and query massive binary state data—such as user login status and daily sign‑in records—using Redis Bitmap, covering underlying structures, memory advantages, key design, and practical commands like SETBIT, GETBIT, BITCOUNT, BITPOS, and BITOP for real‑world analytics.
In mobile application scenarios we often need to associate a key with a collection of data.
Common scenarios include:
Given a userId, determine the user's login status;
Show a user's monthly sign‑in count and the first sign‑in time;
For 200 million users, count the total number of users who have signed in consecutively for seven days.
Typically the number of users and the volume of accesses are huge, ranging from millions to tens of millions, or even hundreds of millions of records.
Therefore we must choose a collection type that can efficiently aggregate massive data (e.g., at the hundred‑million level).
To select the appropriate data collection we first need to understand common statistical patterns and apply suitable data types to solve real problems.
Four statistical types:
Binary state statistics;
Aggregate statistics;
Sorted statistics;
Cardinality statistics.
This article uses the binary state statistics type as the opening of a practical series, employing the extended Redis data type Bitmap instead of the usual String, Set, Zset, List, or Hash.
The commands can be tested with the online Redis client at https://try.redis.io/ .
Binary State Statistics
Binary state means each element in a collection can only have the value 0 or 1. In login or sign‑in scenarios we only need to record 签到(1) or 未签到(0), and 已登录(1) or 未登录(0).
If we store user login status with Redis String (key → userId, value 0 for offline, 1 for online) for one million users, we would need one million strings, which incurs large memory overhead.
String type stores not only the actual data but also additional metadata such as length and allocated space. When the stored data is a string, Redis uses the Simple Dynamic String (SDS) structure:
len : 4 bytes, the used length of the buffer;
alloc : 4 bytes, the total allocated length (usually > len);
buf : byte array storing the actual data, with an extra terminating "\0" byte.
Besides the buffer, the RedisObject structure adds overhead for metadata common to all data types (e.g., last access time, reference count). Redis stores this metadata in a RedisObject that points to the actual data.
For binary state scenarios we can use Bitmap. For example, representing login status with a single bit means one hundred million users only require 100,000,000 bits ≈ 12 MB of memory. Space (MB) ≈ ($offset / 8 / 1024 / 1024) Bitmap’s underlying structure uses the SDS string to store a bit array, where each byte’s 8 bits represent the binary state of an element.
Bitmap can be viewed as an array indexed by offset, each position holding either 0 or 1.
Visually, each byte is displayed as a row of 8 bits:
Eight bits form one byte, so Bitmap dramatically reduces storage space.
Determining User Login State
Bitmap provides GETBIT and SETBIT operations. Using a key such as login_status, the user ID is used as the offset; setting the bit to 1 marks the user online, 0 marks offline. GETBIT checks the user’s status. One hundred million users require only about 6 MB.
SETBIT command SETBIT <key> <offset> <value> Sets or clears the bit at offset (value must be 0 or 1).
GETBIT command GETBIT <key> <offset> Returns the bit value at offset; if the key does not exist, returns 0.
Example for user ID 10086: SETBIT login_status 10086 1 Check login status (returns 1 if logged in): GETBIT login_status 10086 Log out by clearing the bit:
SETBIT login_status 10086 0User Monthly Sign‑In Tracking
Each day’s sign‑in is represented by one bit; a year needs 365 bits, a month at most 31 bits.
Key pattern: uid:sign:{userId}:{yyyyMM}. The day of the month (minus 1) is used as the offset.
Step 1 – Record sign‑in on 2021‑05‑16 for user 89757: SETBIT uid:sign:89757:202105 15 1 Step 2 – Check if the user signed in on that day: GETBIT uid:sign:89757:202105 15 Step 3 – Count total sign‑ins in May using BITCOUNT: BITCOUNT uid:sign:89757:202105 To find the first sign‑in date in the month, use BITPOS: BITPOS uid:sign:89757:202105 1 Remember to add 1 to the returned offset because offsets start at 0.
Counting Users with Consecutive Sign‑Ins
Store each day’s sign‑in as a separate Bitmap key, using userId as the offset. To find users who signed in for seven consecutive days, perform a bitwise AND across the seven daily Bitmaps and count the resulting bits set to 1.
Redis command for bitwise operations: BITOP operation destkey key [key ...] Example – AND three daily Bitmaps and count the result:
// AND operation
BITOP AND destmap bitmap:01 bitmap:02 bitmap:03
// Count bits set to 1
BITCOUNT destmapA Bitmap of 100 million bits occupies about 12 MB; seven such Bitmaps need roughly 84 MB. Setting an expiration on these keys helps free memory.
Summary
The key insight is that when a statistical scenario only requires binary states—such as whether a user exists, whether an IP is blacklisted, or sign‑in tracking—using Bitmap is ideal.
One bit can represent 0 or 1, dramatically reducing memory consumption when handling massive datasets.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.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.
