How to Track Online Users in Real‑Time with Redis ZSET in SpringBoot
Learn a practical approach to count online users in real time by leveraging Redis sorted sets (zset) with SpringBoot, covering user identification via tokens or browser fingerprinting, key Redis commands (zadd, zrangeByScore, zremrangeByScore, zrem), and scheduled cleanup logic.
Overview
This guide shows how to implement a lightweight real‑time online‑user counter in a Spring Boot application using Redis sorted sets (zset). Each online user is stored as a member of a sorted set; the member’s score is the expiration timestamp of the session. Adding, querying, and cleaning up the set with zadd, zrangebyscore, zremrangebyscore and zrem yields an accurate online‑user count.
1. Identify an online user
If the application requires authentication, the validity of the JWT or session token can be used as the online‑user identifier. For public sites without login, generate a stable identifier on the client side, e.g., a browser fingerprint. The fingerprint can be built from User‑Agent, headers, screen resolution, timezone, language, installed plugins, etc. Libraries such as FingerprintJS or ClientJS simplify this process.
// Install FingerprintJS
npm install @fingerprintjs/fingerprintjs
// Example usage in the browser
import FingerprintJS from '@fingerprintjs/fingerprintjs';
FingerprintJS.load().then(fp => {
fp.get().then(result => {
const visitorId = result.visitorId; // unique per browser
console.log(visitorId);
// Store visitorId in a cookie or request header for the backend
});
});2. Add a user to the sorted set
When a request arrives, compute an expiration time (e.g., now + timeoutSeconds) and add the identifier to the sorted set. The expiration timestamp is used as the score so that the most recent login always overwrites older entries.
// Java (Spring Boot) – add or refresh a user
// expireTimeout: number of seconds a session stays valid
LocalDateTime expireTime = LocalDateTime.now().plusSeconds(expireTimeout);
// Convert to a numeric timestamp (e.g., epoch milliseconds)
long expireScore = expireTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
// userId can be a token, visitorId, etc.
redisService.zadd("user:online", (double) expireScore, userId);3. Query the current online users
Retrieve all members whose score is greater than the current time. The size of the returned set equals the number of online users.
// Java – get online users
long now = Instant.now().toEpochMilli();
Set<String> onlineUsers = redisService.zrangeByScore(
"user:online", (double) now, Double.POSITIVE_INFINITY);
int onlineCount = onlineUsers.size();4. Periodically remove expired entries
Because Redis does not automatically delete members whose scores have passed, schedule a cleanup task that removes all members with a score less than the current timestamp.
// Java – scheduled cleanup (Spring @Scheduled)
@Scheduled(fixedDelay = 60000) // run every minute
public void cleanExpiredUsers() {
long now = Instant.now().toEpochMilli();
// Remove members with score < now
redisService.zremrangeByScore("user:online", Double.NEGATIVE_INFINITY, (double) now);
}5. Remove a user on explicit logout
When a user logs out, delete the corresponding member from the sorted set.
// Java – logout handling
redisService.zrem("user:online", userId);Diagram
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.
