阿里一面:如何统计十秒内连续登录失败超过3次的用户?
这是一个典型的问题,在面试和实际业务中都很常见(例如风控、安全审计等)。我给你整理一个的思路。
这是一个典型的滑动窗口统计 + 规则判定问题,在面试和实际业务中都很常见(例如风控、安全审计等)。我给你整理一个既能应对面试,又能落地实现的思路。
1. 需求分析
我们要实现:
- 条件:在最近 10 秒内,同一用户连续登录失败次数 ≥ 3
- 输出:符合条件的用户列表(或触发告警 / 锁定)
这里有几个关键点:
- 连续失败:失败之间没有成功登录打断
- 时间窗口:最近 10 秒(滑动窗口)
- 统计粒度:按用户维度统计

2. 方案设计
2.1 实时统计(推荐)
适合需要实时拦截恶意登录的场景,例如 Web 应用安全防护。
技术选型
- Redis
(高性能 + 支持过期时间 + 原子操作)
-
数据结构:
ZSET存储每次失败的时间戳(score = 时间戳,value = 请求 ID 或空)
-
或用
String+ 过期时间记录次数(简单但不精确)
流程
-
用户登录失败时:
-
用
ZADD向login_fail:user:{userId}添加当前时间戳 -
设置 key 过期时间 = 10 秒(自动清理旧数据)
-
-
统计时:
-
用
ZCOUNT key (now-10s +inf统计最近 10 秒内的失败次数
-
-
如果次数 ≥ 3,则认为触发规则

Redis + Java 示例
String key = "login_fail:user:" + userId;long now = System.currentTimeMillis();// 添加本次失败记录redisTemplate.opsForZSet().add(key, UUID.randomUUID().toString(), now);// 设置过期时间(10秒后自动清理)redisTemplate.expire(key, 10, TimeUnit.SECONDS);// 统计最近10秒失败次数Long count = redisTemplate.opsForZSet().count(key,now - 10_000,now);if (count != null && count >= 3) {System.out.println("用户 " + userId + " 10秒内连续登录失败超过3次!");// 触发锁定或告警}
2.2 批量分析(非实时)
适合离线统计或日志分析场景。
技术选型
-
登录日志写入 Kafka / 数据库
-
用 滑动窗口 SQL 或 Flink / Spark Streaming 统计

SQL 示例(假设用 Kafka + Flink SQL)
SELECTuser_id,COUNT(*) AS fail_countFROM login_logWHERE result = 'fail'GROUP BY user_idTUMBLE(login_time, INTERVAL '10' SECOND)HAVING COUNT(*) >= 3;
3. 注意事项
-
连续失败 vs 累计失败
-
如果要求 “连续”,需要确保中间没有成功登录,否则要重置计数
-
例如:成功登录时删除该用户的失败记录 key
-
-
并发问题
-
用 Redis 单命令(如
ZADD+ZCOUNT)避免竞态 -
或加分布式锁
-
-
性能
-
Redis 方案 O (1) 写入,O (logN) 统计
-
适合高并发场景
-
-
过期策略
-
对每个用户的失败记录设置 TTL,自动清理过期数据
-
4. 扩展
- 滑动窗口优化:可以用 Redis 分桶计数(固定时间片)来减少 ZSET 大小
- 安全策略:触发规则后,可以临时锁定账号、增加验证码或延迟响应
- 持久化:失败记录可落库用于后续安全分析
面试回答思路
对于 “十秒内连续登录失败超过 3 次的用户” 统计,我会用滑动时间窗口思想,结合 Redis 来实现:
-
每次登录失败,用 ZSET 记录时间戳,并设置过期时间 10 秒
-
每次失败后统计最近 10 秒内的次数,如果 >= 3 则触发规则
-
如果用户登录成功,则清空该用户的失败记录
-
优点是实时性高、性能好,适合高并发系统
-
如果是离线分析,可以用 Flink/Kafka 或数据库滑动窗口 SQL 来统计
更多推荐
所有评论(0)