太极 Java开发 二面

#JAVA##JAVA面经##JAVA内推#

1. JWT 无状态架构下,如何实现分布式会话的强制下线、拉黑功能?

回答思路

  • 核心锚定:JWT本身无状态、无法主动撤销,需通过「外部存储+前置校验」突破无状态限制,核心逻辑是「黑名单/状态表拦截 + 短有效期兜底」;
  • 分层拆解实现方案
    1. 核心方案:JWT黑名单/状态表
      • 存储层:Redis(高性能、支持过期)存储需强制下线的JWT token或用户ID,设置过期时间与JWT有效期一致;
      • 校验流程:网关/接口层接收请求后,先校验JWT签名有效性,再查询Redis是否存在该token/用户ID,存在则拒绝请求(强制下线/拉黑);
      • 触发逻辑:用户登出/被拉黑时,将token/用户ID写入Redis;
    2. 兜底方案:缩短JWT有效期
      • JWT有效期设为15-30分钟,配合刷新token机制(refresh token),即使黑名单失效,短有效期也能快速终止非法会话;
    3. 进阶优化
      • 按用户维度拉黑:存储用户ID而非token,避免token过多;
      • 分布式缓存:Redis集群保证高可用,避免单点故障;
  • 核心结论:通过Redis维护JWT/用户黑名单,网关层前置校验,配合短有效期,解决JWT无状态下的强制下线/拉黑问题。

标准答案

JWT无状态架构下实现强制下线/拉黑的核心方案:① 基于Redis构建JWT黑名单:用户登出/被拉黑时,将其JWT token(或用户ID)写入Redis(过期时间与JWT一致);② 网关/接口层前置校验:先验证JWT签名,再查询Redis是否存在该token/用户ID,存在则拒绝请求;③ 兜底优化:将JWT有效期缩短至15-30分钟,配合refresh token机制,即使黑名单失效,也能快速终止非法会话。核心是通过外部存储突破JWT无状态限制,实现主动拦截。

2. JWT 存在哪些安全风险,如何在分布式网关层做防护?

回答思路

  • 核心锚定:JWT风险聚焦「签名/传输/有效期/载荷泄露」,网关层防护需覆盖「校验+限流+加密+监控」;
  • 分层拆解风险与防护
    JWT安全风险 网关层防护方案
    签名算法被篡改(如none算法) 网关强制指定签名算法(如HS256/RS256),拒绝none算法,校验签名有效性;
    token传输泄露(HTTP) 网关强制HTTPS,禁止HTTP访问,防止token被抓包;
    token过期时间过长 网关校验token有效期,拒绝过期token,且限制JWT有效期≤30分钟;
    载荷明文泄露(如用户敏感信息) 网关禁止JWT载荷存储敏感信息(如密码),仅存用户ID等非敏感字段;
    token重放攻击 网关维护近期token黑名单(Redis),结合nonce随机数+时间戳,拒绝重复请求;
    暴力破解签名密钥 网关对异常请求限流(如1分钟内同一IP请求>100次),监控密钥破解风险;
  • 核心结论:网关层从「签名校验、传输加密、有效期控制、防重放、限流」多维度防护,覆盖JWT全链路风险。

标准答案

JWT核心安全风险及网关层防护:① 签名风险:网关强制指定签名算法(如RS256),拒绝none算法,严格校验签名;② 传输风险:网关强制HTTPS,禁止HTTP暴露token;③ 重放攻击:网关结合nonce随机数+时间戳,维护近期token黑名单(Redis);④ 有效期风险:网关校验token过期时间,限制JWT有效期≤30分钟;⑤ 载荷泄露:网关禁止JWT存储敏感信息,仅保留用户ID等非敏感字段;⑥ 暴力破解:网关对异常IP/用户限流,监控密钥破解行为。

3. Docker 沙箱在高并发判题场景下,如何避免资源争抢与容器反复创建?

回答思路

  • 核心锚定:高并发判题痛点是「容器创建销毁开销大+资源抢占」,解决方案围绕「容器池化+资源隔离+任务调度」;
  • 分层拆解方案
    1. 容器池化(核心)
      • 预创建固定数量的Docker容器池(如100个),判题任务直接复用空闲容器,避免反复创建销毁;
      • 容器状态管理:通过Redis/ZooKeeper维护容器「空闲/运行/异常」状态,任务调度器只分配空闲容器;
    2. 资源隔离与限制
      • 为每个容器设置CPU/内存配额(如--cpus=0.5 --memory=512M),防止单个判题任务占满资源;
      • 容器网络隔离:使用独立网络命名空间,禁止容器间通信;
    3. 任务调度优化
      • 按任务类型(如Java/Python判题)分组容器池,避免不同类型任务争抢资源;
      • 限流削峰:通过MQ缓冲高并发任务,避免容器池过载;
    4. 异常处理
      • 容器执行异常(如死循环)时,强制销毁并重新创建,补充到容器池;
      • 监控容器资源使用率,动态扩容/缩容容器池;
  • 核心结论:容器池化复用避免反复创建,资源配额隔离防止争抢,任务调度削峰保证稳定性。

标准答案

高并发判题场景下Docker沙箱优化方案:① 容器池化:预创建固定数量的容器池,判题任务复用空闲容器,避免反复创建销毁;② 资源隔离:为每个容器设置CPU/内存配额(如--cpus=0.5 --memory=512M),防止单任务抢占资源;③ 任务调度:按语言类型分组容器池,通过MQ缓冲高并发任务,削峰填谷;④ 异常处理:容器异常时自动销毁重建,监控资源使用率动态扩缩容容器池。核心是「池化复用+资源隔离」,兼顾性能与稳定性。

4. 代码沙箱如何防止恶意代码攻击(如死循环、占满内存、文件读写)?

回答思路

  • 核心锚定:代码沙箱防护核心是「资源限制+操作拦截+环境隔离」,从「执行、资源、文件、网络」多维度管控;
  • 分层拆解防护措施
    1. 执行限制(防死循环)
      • 设置CPU时间限制(如1秒),超过则强制终止进程;
      • 检测进程执行指令数,超过阈值则kill;
    2. 资源限制(防内存/CPU占满)
      • 内存限制:通过cgroup/ulimit限制进程最大内存(如256M),超限制则终止;
      • CPU限制:绑定CPU核心,设置CPU使用率上限(如50%);
    3. 文件系统限制(防读写)
      • 只读挂载:沙箱内文件系统设为只读,禁止写入;
      • 临时目录:仅允许写入指定临时目录,执行完立即清理;
      • 系统调用拦截:通过seccomp拦截文件读写、进程创建等危险系统调用;
    4. 网络限制(防网络攻击)
      • 禁用网络:沙箱容器/进程禁止联网,拦截socket相关系统调用;
    5. 环境隔离
      • 独立进程/容器:每个判题任务运行在独立进程/容器,互不影响;
      • 权限降级:以非root用户运行沙箱进程,降低攻击危害;
  • 核心结论:通过时间/内存/CPU资源限制、系统调用拦截、环境隔离,全面阻断恶意代码的危险行为。

标准答案

代码沙箱防恶意代码攻击的核心措施:① 执行限制:设置CPU时间上限(如1秒),超过则终止进程,防止死循环;② 资源限制:通过cgroup限制进程最大内存(如256M)、CPU使用率(如50%),避免资源耗尽;③ 文件限制:沙箱文件系统只读,仅开放临时目录,通过seccomp拦截文件读写系统调用;④ 网络限制:禁用沙箱网络,拦截socket相关调用;⑤ 环境隔离:独立进程/容器运行,非root权限执行,防止攻击扩散。

5. HashMap 在 JDK 8 下为什么要引入红黑树,树化与退化的条件是什么?

回答思路

  • 核心锚定:引入红黑树是为解决「链表过长导致查询性能下降」,树化/退化平衡查询与插入性能;
  • 分层拆解
    1. 引入红黑树的原因
      • JDK 7中HashMap链表过长时,查询时间复杂度从O(1)退化为O(n);
      • 红黑树查询时间复杂度为O(logn),大幅提升长链表的查询性能;
    2. 树化条件(两个条件同时满足)
      • 链表长度 ≥ 8;
      • 数组容量 ≥ 64;
      • 补充:若数组容量<64,先扩容而非树化;
    3. 退化条件(满足其一)
      • 红黑树节点数 ≤ 6;
      • HashMap扩容时,重新哈希后红黑树拆分,可能退化为链表;
  • 核心结论:红黑树优化长链表查询性能,树化/退化条件平衡查询与插入效率,避免过度树化增加开销。

标准答案

JDK 8 HashMap引入红黑树的核心原因:解决链表过长导致的查询性能退化(链表查询O(n)→红黑树O(logn))。树化条件:① 链表长度≥8;② 数组容量≥64(容量<64时优先扩容)。退化条件:① 红黑树节点数≤6;② HashMap扩容重新哈希后,红黑树拆分退化为链表。

6. 线程池在任务堆积、队列满、拒绝策略触发时的底层执行流程是什么?

回答思路

  • 核心锚定:线程池执行流程遵循「核心线程→队列→非核心线程→拒绝策略」,需拆解每一步的触发条件和执行逻辑;
  • 分层拆解执行流程
    graph TD
    A[提交任务] --> B{核心线程数是否满?};
    B -- 否 --> C[创建核心线程执行任务];
    B -- 是 --> D{任务队列是否满?};
    D -- 否 --> E[任务入队等待];
    D -- 是 --> F{线程数是否达最大线程数?};
    F -- 否 --> G[创建非核心线程执行任务];
    F -- 是 --> H[触发拒绝策略];
    
    补充细节:
    • 核心线程默认不销毁(allowCoreThreadTimeOut=false),非核心线程空闲超时(keepAliveTime)后销毁;
    • 拒绝策略默认AbortPolicy(抛异常),可选CallerRunsPolicy(调用者执行)、DiscardOldestPolicy(丢弃最老任务)、Disca

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务