编辑
2026-02-19
java炒饭
00

让我先深入了解你的代码实现,再出针对性的面试题。

[1 tool called]

已深入分析你的

编辑
2026-01-10
java炒饭
00

该文章已加密,点击 阅读全文 并输入密码后方可查看。

编辑
2026-01-09
redis
00

单节点的redis并发能力有限,因此我们需要搭建主从集群,实现读写分离。一般是主节点进行写,从节点进行读。

主从同步:

  • 全量同步:从结点第一次与主节点同步数据时使用的方案。从节点向主结点发送同步请求,携带参数replicationId,offset,主节点会根据replicationId来判断是否是第一次同步,如果是第一次同步(Id不一致),则主节点会把自己的replicationId和offset发给从节点,同时主节点执行bgsave生成rdb文件。在生成的同时,会开启一个缓冲区记录该期间收到的所有写命令,最后把rdb和这个缓冲区的信息(类似日志)一起发送给从节点。
  • 增量同步:还是从节点发送请求,主节点判断是不是第一次请求,不是则获取从节点的offset,并把从结点的offset和自身offset之间的数据同步给从节点。

高可用:

哨兵模式(sentinel):

  • 本质自己也是一个redis服务
  • 每1s向集群的每个实例发送ping请求。如果在规定时间收不到响应,认为该结点主观下线。
  • 当指定数量的哨兵认为某个结点都下线了,则认为该节点客观下线。这个数量一般不低于哨兵数量的一半。
  • 当主节点下线了,哨兵会推选一个新的主节点。选主规则:
    • 如果该结点与原来的主节点断开连接时间超过指定值,则不纳入考虑。
    • 根据结点的优先级来判断,优先选择优先级高的,可在配置文件中设置优先级。
    • 优先级相同时选择offset大的节点
    • 以上条件都相同时选择运行ID最小的节点

脑裂:

  • 由于网络原因,哨兵监测不到主结点,认为主节点挂了,实际上主节点并没挂,此时客户端还在与原来的主节点发送请求,然而哨兵却选择了一个新的主节点,原来的主节点变成了从节点,在同步数据的时候,期间所写的数据就失效了。
  • 解决方案:可以通过配置min-slaves-to-write(最少从节点数)和min-slaves-max-lag(最大延迟秒数)。当主节点的从节点数量少于配置值,或者从节点的延迟时间超过配置值时,主节点会拒绝写入请求,从而避免数据不一致。这是一种 “宁可拒绝写入,也要保证数据一致性” 的取舍。在脑裂期间,被孤立的旧主节点会提供高可用性。
编辑
2026-01-09
redis
00

redis实现的分布式锁:

  • 使用setnx命令时,需要设置 ttl,防止系统故障导致锁无法释放。
  • 自己实现的分布式锁的缺陷:我们并不知道准确的业务执行时间,因此这个过期时间不好控制。
  • 不可重入

因此我们使用第三方工具redisson:

  • 提供看门狗(WatchDog),一个线程获取锁成功之后,WatchDog会给持有锁的线程续期(默认每隔10s续期)
  • 可重入,底层采用了一个hash结构,用线程id和该锁锁的次数作为依据,如果发现锁已经被获取了,但是是当前线程获取的,我们就可以再次获得锁,并把次数加1。如果发现这个线程id不是自己的,则无法获取锁。释放锁的时候让次数减1即可。
  • 不能做到主从的强一致性,如果需要,可以使用zookeeper实现的分布式锁。
  • 底层还是setnx和lua
编辑
2026-01-07
java炒饭
00

JWT双Token认证方案

一、核心设计

双Token机制

  • AccessToken:短期(15分钟),前端localStorage存储,每次请求校验
  • RefreshToken:长期(7天),后端HttpOnly Cookie + MySQL存储,仅刷新时校验

验证策略

  • AccessToken:Redis黑名单验证(被吊销的才记录)
  • RefreshToken:MySQL白名单验证(有效的才记录)

二、核心流程

1. 登录流程

用户登录成功 → 生成双Token → AccessToken返回前端存入localStorage → RefreshToken存入MySQL并设置HttpOnly Cookie。

2. API请求流程

前端携带AccessToken → 后端解析JWT(验证签名和过期)→ 查询Redis黑名单 → 不在黑名单则放行 → 处理业务返回结果。

3. 刷新流程(关键)

前端收到401 → 调用刷新接口(Cookie自动携带RefreshToken)→ 后端从MySQL查询RefreshToken进行匹配验证 → 验证通过则:

  1. 生成新双Token
  2. 旧AccessToken加入Redis黑名单(15分钟TTL)
  3. 更新MySQL中的RefreshToken为新值
  4. 新RefreshToken设置到HttpOnly Cookie
  5. 返回新AccessToken给前端

重要:RefreshToken验证只查MySQL,不查Redis黑名单。

4. 登出流程

用户登出 → 当前AccessToken加入Redis黑名单 → 删除MySQL中的RefreshToken记录 → 清除HttpOnly Cookie。

5. 安全事件处理

密码修改等安全事件 → 删除MySQL中的RefreshToken记录 → 强制重新登录。

三、存储设计

Redis黑名单

只存储被吊销的AccessToken,键格式:blacklist:access_token:{token_hash},TTL 15分钟(与AccessToken有效期一致)。

MySQL白名单

user_tokens表存储有效的RefreshToken,每个用户一条记录(user_id唯一约束),验证时只查询此表。

四、验证逻辑

AccessToken验证(黑名单逻辑)

默认所有AccessToken都有效,除非在Redis黑名单中。验证顺序:1.JWT解析 → 2.查Redis黑名单。

RefreshToken验证(白名单逻辑)

默认所有RefreshToken都无效,除非在MySQL白名单中且匹配。验证时只查MySQL,不查Redis。

五、性能与安全

性能优化

  • AccessToken高频验证:Redis内存操作
  • RefreshToken低频验证:MySQL查询,15分钟一次,可接受

安全设计

  • AccessToken:短期有效,泄露风险小,可加入黑名单立即吊销
  • RefreshToken:HttpOnly Cookie防XSS,每次刷新后失效(MySQL更新)
  • 无RefreshToken黑名单:简化设计,通过MySQL更新保证旧Token失效

六、运维管理

监控重点

  • Redis:黑名单大小、内存使用
  • MySQL:查询性能、连接数
  • 业务:刷新频率、401错误率

数据清理

  • Redis:自动过期,无需手动清理
  • MySQL:定期清理过期记录(每天凌晨)

故障处理

  • Redis故障:降级为仅JWT验证(牺牲吊销能力)
  • MySQL故障:刷新功能不可用,需重新登录

七、方案优势

  1. 高性能:高频操作用Redis,低频操作用MySQL
  2. 高安全:双Token分离,HttpOnly Cookie防护
  3. 简化设计:无RefreshToken黑名单,通过MySQL更新保证安全
  4. 易管理:AccessToken黑名单自动清理,MySQL便于审计

核心要点:RefreshToken验证只查MySQL白名单,不查Redis黑名单;安全事件通过删除MySQL记录使RefreshToken失效。