Java高频面试场景题(二)
1、百万数据如何导出解决办法 单线程 1. 首先查询出表总数 2. 根据总数进行分页查询 3. 通过流的形式导出到excel中 多线程 1.思路不变但是分页数据查询和写入变更为多线程处理2、OOM如何定位、排查定位方法 1. 工具 [Java VisualVM](https://visualvm.github.io/download.html) 2. 查看堆内存大小 jmap -heap ID 3. 查看当前正在运行Jar包的IDjps -l 4. 系统挂了前提设置了 -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathdump文件输出路径如果没设置无法追溯只能根据报错日志排查定位设置了则根据dump工具进行排查 5. 系统没有挂导出dump文件jmap -dump:formatb,filexxxxx.hprof ID;不导出文件可以使用jmap -histo:live ID查看堆内存情况 原因 1. List对象太大了比如一次性查询全部数据 2. 内存资源耗尽没有及时释放 3. 本身堆内存不足不能满足业务场景 解决方法 1. 分批查询数据 2. 及时释放对象 3. 扩大堆内存空间3、线上CPU飙升如何定位问题定位方法 1. top命令查询PID 2. top -H -p PID找到线程ID然后将ID转换为16进制printf 0x%x\n PID 3. jstack PID | grep 16进制ID -A 行数 4、如何定位避免死锁问题定位方法 1. jps找到线程ID 2. jstack ID  产生原因 1. 互斥 2. 占有且等待其他资源 3. 不可抢占 4. 循环等待 避免方法 1. 使用原子性计算 2. 合并资源统一分配 3. 通过Lock设置等待超时 4. 破坏循环等待按相同顺序加锁5、如何设计一个秒杀系统明确面试官的痛点 1. 瞬时并发量大 2. 库存少不能出现超卖问题 解决思路 1. 首先从从访问层开始处理商品页面资源静态化CDN/或资源信息通过oss分摊服务器压力 2. 前端增加限制如活动前按钮无法点击、提交后按钮置灰无法点击、验证码减少不必要的请求 3. 四级负载均衡硬件负载均衡F5/LVS、Nginx负载均衡、网关层Rabbion、客户端负载均衡 4. Dockerk8s进行动态扩容在秒杀开始前进行动态扩容节点 5. Redis热点数据预热、Redis的Lua脚本保证库存的原子性或者使用分布式锁、防止重复提交设置请求ID 6. 下单完成后通过MQ进行削峰填谷在秒杀成功后给MQ发送下单消息然后由下单服务进行消费 7. 如果数据量太大可以考虑使用数据库的读写分离分库分表 a. 场景区分强一致性和弱一致性强一致性可以在操作后强制走主库进行查询弱一致性允许短暂的不一致商品列表等 b. 还可以通过主从数据库数据比对如果数据不一致则以主库为主6、订单超时后自动取消如何实现1. 通过延时队列DelayQueue 优点简单无需依赖三方插件 缺点应用重启后数据丢失需要冲数据库重新加载取消订单到队列占用内存空间如果数据量大内存耗费严重 2. 通过MQ定时消息实现 优点使用简单和发送普通消息一样只需增加定时时间支持分布式精度高 缺点最大时间为24H使用成本高MQ的存储空间占用大同一时刻的订单过期会对消费者造成压力导致分发延迟 3. Redis过期监听 优点同MQ 缺点不可靠应用重启通知可能会丢失订单无法关闭可以选择定时任务做补偿机制 4. 定时任务处理 优点稳定性强成本低7、如何限制重复下单幂等性问题解决办法 1. 前端通过按钮置灰 2. 后端通过setNXtoken url key8、 人肉刷机如何防止1. 前端增加验证码校验 2. 限流自动扩容 3. 注册时增加手机号码验证接码平台太多 4. 判定账号异常新账号/老账号无评论、无操作 5. 同IP限制 6. 实名认证 7. 增加消费门槛 8. 限制中奖次数 9. 增加忠诚度和中间几率绑定 10.黑名单标记 10. 大数据画像通过多维度判断用户是否为正常9、 扫码登录原理步骤 1. 生成二维码 2. 扫码 3. 登录 10、分布式日志存储架构如何设计单体 logbacklog4j直接存储到文件即可 分布式 1. mongodb存储适合日志量大、数据格式多样、进行复杂的查询 2. ElkElasticsearchLogStash/fileBeatkibana 3. Grafana11、redis的击穿、雪崩、穿透缓存击穿某一个热点数据过期 解决方案 1. 热点数据永不过期 2. 加同步锁排队分布式时可以使用分布式锁 缓存雪崩批量热点数据过期/redis挂了 解决方案 1. 热点数据随机失效针对批量数据过期 2. 增加redis集群配置针对redis挂了 缓存穿透请求查询的数据redis、sql中都不存在 解决方案 1. 增加参数校验无效的参数、无法完全过滤 2. 增加缓存空对象查询为空直接增加到redis中并设置实效时间可能会出现大量的无效数据 3. 增加布隆过滤器12、如何记录用户连续登录天数解决方案 使用redis的bitmap [bitmap参考](https://blog.csdn.net/u011397981/article/details/130693847)13、一亿redis key统计共同好友解决方案 1. 使用redis自带命令查询交集 SINTERSTORE userid:new userid:1 userid:2 2. Neo4j 3. 通过大数据套件解决14、redis用户实时积分排行榜解决方案 1. redis的zSet 2. 分通存储比如积分0-100100-200存储15、内存受限读取超出内存空间的文件并统计次数解决方案 1. 通过缓冲区分块读取内容重复数据多 2. 文件分片存储针对每一个分片文件单独统计然后汇总16、查询200条数据耗时200ms如何做到500ms内查询1000条数据解决方案 1. 多线程并行查询最种组合查询结果17、Spring boot线程池百万数据批量插入解决方案 1. 多线程分批插入18、Spring boot默认可以同时处理多少请求默认最大连接数8192 最大等待数10019、Sql的执行过程1. 建立连接、鉴权 2. 服务层缓存查询5.7版本前默认不开启8.0后已经弃用 3. 解析器词法解析、语法解析 4. 预处理器判断表名、字段名 5. 优化器优化Sql选择最佳的执行路径、生成执行计划 6. 执行器操作存储引擎返回执行结果20、单表多大数据需要分表单表数据达500W表大小超过2G需要分表21、B树和B树的区别相同 1. 索引都是小的在左大的在右 不同 - B树更高层级更多 B树只有三层结构更宽且根节点不存储数据数据都存储在叶子节点 - B树叶子节点没有双向链表结构范围查询效率低 B树叶子节点有双向链表结构范围查询效率高22、InnoDB引擎的undolog、redolog、binlong23、主键索引和非主键索引的区别聚簇、非聚簇区别 非主键索引查询时如果涉及查询非索引数据这时候需要回表 主键索引子节点存储的是整行数据无需回表总结特性维度主键索引 (聚簇索引)非主键索引 (二级索引)数量限制一张表只能有 1 个一张表可以有多个叶子节点存储内容完整的行数据(所有列的值)索引列的值 主键值查询数据过程直接获取数据效率最高通常需要先查主键 ID再回表查数据 (覆盖索引除外)物理存储顺序数据行在磁盘上按主键顺序物理存储与物理存储顺序无关是逻辑上的排序主键依赖性自身即为数据的物理组织方式必须依赖主键索引 (叶子节点需存储主键)维护成本较高 (插入数据时若主键非自增易发生页分裂)较低 (更新数据时只需维护索引树不移动数据行)24、count(1),count(*),count(name)有什么区别区别 count(name)会自动排除字段为NULL的数据而count(1)、count(*)不会 count(1)、count(*)性能上无区别因为mysql的优化器会把count(*)优化成count(0)如果非要说性能谁好count(1)好一点点mysql不会对sql进行优化25、左模糊查询导致索引实效原因 因为sql中“%xxx”左侧索引不确定所以没办法确认索引信息需要全表扫描 解决方案 1. 数据反转比如数据为AB存为BA这样可以使用右模糊查询 2. 增加范围条件 3. 使用索引覆盖26、分库分表后ID冲突问题解决方法 1. 雪花算法 2. 业务ID不依赖主键ID在设计之初增加单独且唯一的业务ID27、深分页速度为什么慢怎么解决原因 mysql执行时不是直接定位到分页位置而是将查询你需要分页的数量然后在进行分页返回这里如果没有索引覆盖还会造成二次回表效率更慢 解决 1. 查询字段要索引覆盖避免二次回表如果非要查询非二级索引的字段可以通过子查询的形式去避免回表 2. 如果ID是自增主键的话可以使用范围查询必须需要定位5W可以id50000作为条件然后在limit分页 3. 业务层可以考虑限制深分页的数量比如只能分到50页前提是业务允许的情况下28、MVCC多版本并发控制器JUC线程池和Spring线程池的区别