Java常见场景题:
1、如何实现10亿条数据判重?
1、如果这是实时流(如日志、点击流)且内存有限,允许极低概率的误判:可以选择 布隆过滤器(本地内存Guara或Redis版)。
-- 思路1:布隆过滤器:存在不一定存在,不存在则一定不存在
2、如果是离线处理一批文件,需要100%准确:可以选择 哈希分片 + 文件Set,或者使用 Spark 进行离线清洗。
-- 思路2: 分块处理:将10亿数据分成多个小块,每块在可接受的内存范围内。
然后,对每个小块进行判重,并将结果保存到另一个集合中。
最后,对这个集合进行判重以得到最终的不重复数据。
3、如果这是业务数据库导入,需要确保唯一性,并且数据是增量的:可以考虑 分库分表的数据库 或 支持去重的大数据OLAP引擎。
-- 思路3:可以使用大数据组件HDFS、clickhouse等。
如果是使用数据库的话,需要分表存储
2、线程池核心线程数为0,任务队列为10亿,最大线程数为10.。。
当核心线程数为 0 时,当来了一个任务之后,会先将任务添加到任务队列,同时也会判断当前工作的线程数是否为 0,
如果为 0,则会创建线程来执行线程池的任务
3、100万条数据插入redis,如何设计实现方案?
思路:数据分批处理、多个线程异步同事处理; 插入前:可以去重或压缩 (根据场景来定义)
(1)批处理 -- redis客户端使用管道技术批量发送命令到服务端。
Redis 批处理的手段有以下两个:
使用管道技术(Pipeline):允许客户端发送多个命令到服务器,而不需要等待每个命令的回复。这减少了网络延迟的影响,提高了写入速度。
使用批量操作指令:如使用 MSET 或 HMSET 命令可以一次设置多个键值对或哈希表字段,这比单独使用 SET 或 HSET 要快得多。
(2)数据分片 -- 服务端使用redis集群,数据会分片存放。
数据分片指的是使用 Redis 的分片功能,将数据分布在多个 Redis 实例或节点上,可以考虑使用 Redis 集群。集群模式下,数据可以分布在多个节点上,从而分散负载并提高写入吞吐量。
(3)使用 Lua 脚本
也可以通过 Lua 脚本将多个操作组合成一个原子操作,减少客户端与服务器之间的通信次数。
(4)异步加载
将一个大任务分成多个小任务,然后再通过异步加载的方式批量写入 Redis,这样可以避免阻塞主线程,提高应用的整体响应性。
4、线上如何发现Kafka消息积压问题?导致消息积压的原因有哪些?
原因:
消费者处理速度慢:消费者的处理逻辑复杂或资源不足。
生产者速度过快:生产者生成消息的速度超过消费者的处理能力。
生产者key分布不均,造成数据倾斜。
对于线上kafka 消息大量积压的问题,我总结了这几点:
我们要做好监控和告警,当消息积压到一定程度的时候,就要告警,通知负责人,提前处理。
不要上来就新建临时topic,去快速处理大量积压问题。应该先排查是不是bug,优化消费者的代码。
如果消息设置了超时时间,因为百万消息积压,没来得及处理就过期清理,可以设置定时任务拉起来重发一下。
5、使用缓存有哪些坑?你是怎么解决的?
防止雪崩 -> TTL随机化 + 熔断。
-- 定义:大量的缓存数据在同一时间过期失效,或者Redis节点宕机。此时大量请求直接打到数据库,导致数据库压力剧增甚至崩溃。
-- 解决方案: 1、过期时间打散 2、本地缓存 3、redis采用集群方式 4、限流
防止击穿 -> 互斥锁(分布式锁)。
-- 定义:某一个热点Key失效,某个爆款商品的缓存正好过期
-- 解决方案:
-- 更新数据库加锁:只让一个线程去数据库查询数据并重建缓存,其他线程等待,重建完成后从缓存获取
-- 过期时间:不设置物理过期时间,而是在Value中存储一个逻辑过期时间字段。当检测到逻辑过期时,尝试获取分布式锁,由拿到锁的线程去更新缓存,其他线程直接返回旧数据(短暂的脏读),保证系统可用
防止穿透 -> 布隆过滤器 + 空值缓存。
-- 定义:查询一个根本不存在的数据。由于缓存中没查到,请求直接打到数据库,比如恶意攻击
-- 解决方案:
缓存空对象: 即使数据库查询结果为空,也在缓存中设置一个空值(例如 null 或特殊标识),并设置一个较短的过期时间(如30-60秒)。这样可以避免恶意请求穿透到DB
布隆过滤器(Bloom Filter): 在缓存之前加一层布隆过滤器,存储所有可能存在的Key。当请求过来时,先判断Key是否可能存在。如果布隆过滤器说"不存在",则直接返回
保证一致性 -> 先更新DB后删缓存 + 兜底binlog。
需要容忍redis和数据库短暂的数据不一致问题。
6、如何避免超卖和少卖问题?
超卖(卖出了超过库存数量的商品)
少卖(本来有货但被限制购买,影响用户体验)
方案一:数据库乐观锁
-- 适用场景:适用于小型应用或低频场景
-- 原理:在数据库表(如 stock 表)中增加一个版本号字段 version
优点:实现简单,无锁冲突
缺点:不适合高并发场景,并发高时,大量请求会失败。用户体验就是一直抢不到(少卖)
方案二:利用Redis单线程 + Lua脚本(主流方案)
这是目前应对高并发秒杀、抢购最成熟的技术方案。利用 Redis 的单线程特性和 Lua 脚本的原子性,将所有判断和扣减逻辑封装在脚本中执行
库存预热:活动开始前,通过后台将库存数量写入 Redis
通过redis来扣减库存,适用lua脚本保证操作的原子性
执行与落库:
前端请求进来,后端执行该 Lua 脚本。
如果 Redis 返回 1,说明扣减成功,此时可以异步发送消息给 MQ(或写入队列),由后端服务慢慢去创建真正的数据库订单。
方案三:分布式锁(Redisson)------ 适用于非秒杀的普通下单
如果并发不是极端高(例如 QPS 几千),也可以用分布式锁来保护库存资源。
如何避免"少卖"?
库存预热要准:Redis 中的初始库存必须和数据库一致
兜底:Redis 扣减成功了,但后续数据库订单创建失败了怎么办?这会导致少卖
解决方案1:设置库存补偿。如果数据库落单失败,发送一条消息重新加回 Redis 库存(需要做好幂等)
解决方案1:在解决方案1的基础上,添加解决方案2,定时对比redis和数据库的数据,做好数据一致性保证。
7、订单支付失败且支付客户端未响应该如何处理?
问题一:要避免重复支付
在支付超时场景下,用户可能会因为不确定是否支付成功,而尝试重新支付。这可能导致一个订单支付了两次。
解决方案:
幂等性设计:支付系统需要保证一笔订单只能被支付一次(金额不能被累加)
前端轮训查询结果,比如每隔几秒查一次,查询订单状态
定时对账:
订单系统 和 支付系统 要提供支付结果状态查询接口,需要定时对账,查询两个系统的支付状态是否一致。
如果订单支付失败,扣款成功,那么就需要退款
如果订单支付失败,扣款失败,则只需要通知用户重新下单即可
8、如何实现百万级数据导入数据库?
风险:如果一次性读取100万条数据到内存再处理,可能会OOM。
如果直接使用逐条INSERT,可能会因为事务过大、网络开销或索引维护导致性能极差,甚至影响线上业务
方案一:业务代码处理的话:分批提交 + 批量INSERT + 多线程并发插入(通用方案)
如果你无法直接操作数据库文件(如云数据库限制),或者数据需要先经过业务逻辑处理,只能使用INSERT语句,那么推荐采用分批 + 批量的方式。
方案二:使用数据导入工具(数据迁移工具),直接操作数据库
方案三:插入一张临时表,插入完成后,再命名为业务查询的表,这样可以避免插入过程耗时过长导致业务中断。
9、百万级数据库分页查询比较慢,该如何优化?
方案一:延迟关联(Deferred Join)------ 最推荐
思路:先快速定位主键,再回表查询完整数据
原理:利用覆盖索引快速查到需要的行的主键 ID,然后用这些 ID 去关联原表获取所有列。这样可以避免数据库在扫描大量数据时加载不需要的行数据。
方案二:使用搜索引擎(Elasticsearch)
如果分页条件非常复杂(多字段组合排序、全文搜索),且数据量巨大(千万级以上),数据库很难满足要求。
10、某个频繁查询数据库的场景要怎么优化?
-- 分析性能是否达标:
-- 考虑使用缓存,避免多次查询数据库
-- 多次单条查询 -> 单词批量查询
11、设计数据库时表数据量过大,有什么解决方案?
1、数据表分区:将数据按条件分布到不同文件,降低查询范围,提高查询效率。 表拆分:水平拆分 + 垂直拆分
2、读写分离:增加多个读实例应对读多写少的互联网场景。
3、数据异构:根据不同业务需求保存多份数据。 -- 冷热数据分离(ES + MySQL)
-- 热数据/事务数据:放在MySQL,支撑业务交易
-- 引入ES,需要模糊搜索、聚合统计
4、热点数据处理:注意处理经常查询的数据。
12、有100万请求同时访问你的数据库该怎么办?
假设这是秒杀下单场景下的100万请求:
第一步:请求先到网关,进行IP限流和User-Agent校验,过滤掉一部分爬虫。
第二步:请求进入应用集群,尝试读Redis缓存(例如校验库存)。
第三步:校验通过后,不直接写数据库,而是将一条"创建订单"的消息发送到RocketMQ,然后直接告诉用户"正在处理中"。
第四步:后端一个单独的消费者服务,以固定的速率(例如每秒1000条)从MQ拉取消息,批量写入数据库。
13、实际开发中遇到过哪些慢查询的场景?
最经典的错误:深分页(Offset 过大)
索引失效:函数操作或隐式转换
关联查询过多,未使用索引
查询了不必要的行和列
14、100万条数据插入HashMap会有什么问题?
-- 内存溢出(OOM)------ 最直接的风险
-- 哈希冲突加剧 -- 如果哈希冲突严重,链表会变得非常长
一定要用HashMap的话:
指定初始容量,避免频繁resize。
估算内存,确保JVM堆内存足够(设置-Xmx)。
确保Key的hashCode均匀。
15、高TPS问题: 一个EXCEL文件有千万条数据,如何上传?
1、分片上传:切片 + 多线程上传
2、流式读取,不要一次性加载所有数据到内存中
3、批量入库(高效写入)
4、异步处理 + 前端轮训查询结果
16、如何防止短信盗刷和短信轰炸?
添加图形验证码:用户发送短信前,需要先输入正确的图形验证码,或拖动验证码等验证,验证通过之后,才能正常发送短信验证码。因为图形验证码的破解难度非常大,所以就避免了自动发送短信程序的执行。
添加 IP 限制:对请求 IP 的发送次数进行限制,避免短信盗刷和短信轰炸的问题。例如,每个 IP 每天只能发送 10 条短信。
开启 IP 黑名单:限制某个 IP 短信发送功能,从而禁止自动发送短信程序的执行。
限制发送频次:一个手机号不能一直不停的发送验证码(即使更换了多个 IP 也不行),设置一个手机号,每分钟内只能发送 1 次验证码;一小时之内,只能发送 5 次验证码;一天之内,只能发送 10 次验证码。
开启短信提供商的防控和报警功能:几乎所有的短信提供商都提供了,异常短信的防控和提醒功能,开启这些保护措施,可以尽可能的避免短信盗刷的问题。
17、如何设置生产环境下线程的数量?
第一步:区分任务类型(核心依据) -- 一般
CPU密集型任务:线程数 = CPU核心数 + 1
IO密集型任务:CPU核心数 * 2
18、某个后端接口使用了多线程执行任务,怎么样才能保证所有的线程任务已完成?
方案一:使用 CountDownLatch(计数器)
初始化一个计数器,数值等于线程数。每个线程执行完毕后,调用countDown()让计数器减一。
主线程调用await()阻塞,直到计数器归零
方案二:使用 Thread.join()
如果自己创建和管理Thread对象,可以使用join()方法。
方案四:使用 CompletableFuture(最现代、最推荐)
原理:使用allOf()等待所有异步任务完成,然后组合结果。
19、如何实现多级缓存?
前端资源缓存:CDN 缓存
后端缓存:redis分布式缓存、本地缓存
20、你是如何设计限流功能的?
方案A:单机限流(小规模/基础组件) -- Guava的RateLimiter(令牌桶)或Java Semaphore(信号量,控制并发数)。
方案B:分布式限流(微服务/集群)
-- nginx层做限流:ALB 层 --
-- 微服务网关层限流:Sentinel
21、项目中是如何使用多线程的?
-- 接口性能不达标,异步处理任务
-- 处理大数量量,如导入excel时,多个线程并行处理数据
线程池 + CompletableFuture 使用。
22、如何设计一个高并发系统?
层级 核心技术 解决的问题
接入层 CDN、Nginx、LVS 流量分发、静态加速、安全防护
应用层 无状态化、集群、限流熔断 水平扩容、自我保护
缓存层 多级缓存、Redis集群 加速读请求、保护数据库
异步层 消息队列、线程池 削峰填谷、解耦
数据层 读写分离、分库分表、NoSQL 突破单库存储与写入瓶颈
一个典型混合使用的例子:
在秒杀系统中:
线程池:在接收到请求后,用线程池并发验证用户资格和库存(都在本地缓存和本地JVM内)。
MQ:验证通过后,将创建订单的请求发往MQ,由另一个服务异步处理真正的订单入库
23、怎么避免重复下单的问题?
前端控制:通过前端脚本防止用户重复提交表单,但这并不能完全解决问题,尤其是在网络错误的情况下。
使用唯一请求 ID:在用户进入订单提交界面时,调用后端获取唯一 ID,并在提交时检查该 ID 是否已使用。如果未使用,则继续处理;如果已使用,则提示重复提交。
数据库约束:在数据库中设置主键唯一约束,确保每个订单的唯一性。如果重复下单,插入操作将失败。
使用 Redis 锁:在用户下单时,为每个用户分配一把锁,确保同一用户的多次请求中只有一个请求能成功执行。
幂等性设计:确保多次请求的效果与一次请求相同,从而避免重复下单。
24、线上环境偶尔出现重复的数据?他的原因是啥,如何分析和解决?
26、出现OOM的场景有哪些?如何解决?
堆内存溢出(Heap OOM)
原因:堆内存不足,通常由以下情况引起:创建了大量对象且未及时释放、内存泄漏导致对象无法被GC回收。
元空间溢出(Metaspace OOM):
动态生成大量类(如使用CGLIB动态代理)
减少动态类生成,优化类加载逻辑。
检查类加载器是否正确实现资源释放。
栈内存溢出(Stack OOM)
原因:线程栈内存不足,通常由以下情况引起:
递归调用过深。
堆外内存溢出(Direct Memory OOM)
原因:使用NIO分配了过多的直接内存(Direct Memory),未及时释放
27、如何排查生产环境JVM问题?
生产环境中的JVM问题,通常表现为应用变慢、CPU飙升、频繁GC、甚至直接宕机。这些问题往往不是单一原因导致,而是多种因素叠加的结果。
28、如何排查CPU间接性100%的问题?
top -> 进程
top -Hp 找线程
打印线程快照信息,使用jstack
29、线上用什么命令可以看JVM使用的是什么垃圾收集器?
jinfo -flags [pid] | grep -i gc
30、项目再本地能运行,但发布线上就运行不了,你分析一下原因?
1、配置问题:
1.1. 配置文件未生效或配置错误
2、环境问题:如第三方服务无法连接、数据库连接不上
31、线上某个接口执行非常慢?应该如何排查和处理?
运维监控 + 链路追踪
32、如果有大量请求访问redis中一个很大的value,这种情况
拆分成多个小Value:将大Value 拆分成多个小Value,使用 mget 批量读取
数据压缩
启用内存淘汰策略
33、redis宕机后过期数据是否存在?
34、Springboot某个接口返回值有敏感字段,怎么脱敏?
方式一:AOP切面处理
方式二:写一个公共的工具类
35、什么机制能保证任务只被集群中的一台机器执行?
-- 分布式锁
-- 分布式任务调度框架
36、推送平台对接多家厂商使用哪些设计模式?
策略模式 + 工厂模式(最核心)
适配器模式
模板方法模式
37、SQL稳定性问题:同一个SQL查询,where中查询值不同
38、开发中遇到某个接口返回结果很慢,如何排查和解决问题?
告警监控 + 链路追踪 + SQL优化
39、如何设计10万级的并发系统?
41、如何设计一个分布式框架下的日志系统?
42、系统上线一年后,发现运行变慢了,如何排查和解决?
第一步:确认变化与范围
变慢是什么时候开始的? 和那次大版本发布有关吗?还是慢慢变慢的?
是所有操作都慢,还是特定功能慢?(例如:用户查询慢,但订单提交不慢)
是白天高峰期慢,还是一直慢?(如果是高峰期慢,可能是容量问题;一直慢,可能是数据量问题)
运维系统查看哪些接口不达标 + 链路最终看慢在哪里
43、工作中有没有遇到OOM的问题?你是如何排查和解决的?
44、CAS会不会出现两个线程同事比较都成功更新的场景?
ABA问题会
45、调用某个三方支付(微信、支付宝)回调接口未响应或出错,应该怎么解决?
-- 重试调用
-- 调用支付结果查询接口
-- 接口回调时需要记录日志,处理状态
必须做幂等:重复回调是常态。
必须有对账机制:异步处理和重试并不能保证100%一致,日终对账是最后一道防线。
监控告警:监控回调接口的成功率、异常率。如果成功率突然掉到90%以下,立刻告警人工介入。
46、100w骑手小哥存活状态更新问题
分析:难点在于:100万骑手,假设每隔几秒就上报一次GPS和状态,对后端存储和计算是巨大的压力。
高并发写入:每秒处理数万甚至数十万次的状态更新。
最终一致性:可以容忍几秒钟的数据延迟,但最终必须准确。
节省存储成本:历史轨迹数据巨大,需要冷热分离。
第一层:接入层(门面) 使用TCP长连接或WebSocket,而不是HTTP短连接。因为HTTP的握手开销太大,无法支撑百万长连。
第二层:消息队列(削峰填谷) 瞬时高峰(如整点上报)可能高达几十万TPS,后端服务可能扛不住,数据库更扛不住
第三层:核心处理层(流式计算)
第四层:存储层(冷热分离)
热数据(最新状态):存放在 Redis,响应毫秒级,支撑C端用户查看骑手位置。
冷数据(历史轨迹):存放在 HBase 或 时序数据库(如InfluxDB、TDengine)。这些数据库专门为海量时序数据设计,写入性能极高,压缩比好。主要用于事后回溯、运力分析、费用计算。
47、未支付订单到期之后如何关闭订单?
方案一:被动关闭(用户访问时触发)
-- 用户查询订单时,在查询逻辑中判断订单是否超时未支付。如果超时,则执行关闭操作,更新订单状态和释放库存。
方案二:定时任务扫表(最常见)
-- 每分钟执行一次,扫描订单表中所有超时未支付的订单,批量关闭。
方案三:延迟消息 / 时间轮(最优雅)
使用RocketMQ延迟消息
综合方案(推荐)
在实际生产中,通常采用方案二(定时任务)+ 方案三(延迟消息)的混合模式
主力:使用RocketMQ延迟消息,实现订单的准时关闭,最理想。
兜底:同时保留一个定时任务(频率可以很低,比如每小时跑一次),扫描那些因为各种原因(如MQ消息丢失、消费失败)漏掉的订单,进行状态补偿。
48、假设有40亿QQ号,但是内存只有1G,如何实现去重?
-- 分批去重
-- 布隆过滤器
-- 位图(Bitmap)
-- 大数据组件 如Hbase
49、如何实现查询附近的人?
-- 方案一:Redis + GeoHash(中小型应用,实时性高)
-- 方案二:MySQL + 空间索引(中小型应用,数据持久化)
-- 方案三:GeoHash 算法 + 数据库扫描(通用方案)
核心思想:将二维的经纬度(如 116.397, 39.913)通过算法转换为一个一维的字符串。这个字符串有一个特点:字符串越相似,代表地理位置越近。
50、如何实现亿级别页面的IP统计功能?
方案一:实时UV:使用 Redis HyperLogLog -- 误差:标准误差约为 0.81%。
方案二:位图法(精确统计,内存可控);100%准确,但是每个页面都需要独立的512MB位图,页面多了内存爆炸
-- 开源实现:jdk中的Bitset、redis中的bitmap;redis的话,key为状态,offset为uid,一个用户占用1bit,10亿用户就是125M左右
方案三:离线/全量分析: 将日志接入 Doris/ClickHouse,利用其高效的聚合能力做日报、周报。
51、redis内存会被用完吗?redis的最大内存是多少?
默认行为:在64位操作系统上,maxmemory的默认值是0,这意味着不限制内存使用,理论上可以用到机器所有的物理内存
通用建议:通常可以设置为系统可用内存的 70% ~ 75%
52、Redis内存满了之后会崩溃吗?
Redis内存满了之后通常不会直接崩溃
情况一:正确配置了淘汰策略(正常情况),不开启的话,默认新的请求存入数据会失败
53、你项目有什么亮点?
54、项目开发中遇到了哪些记忆深刻的问题?你是怎么解决的?
55、使用MQ时,怎么才能保证消息一定不丢失?
56、怎么快速判断两个文件是否一致?
快速判断一致性: 使用哈希值比较。
逐行对比: 适合文本文件,能发现具体行的差异。
57、如何优化一个高并发的JavaWeb应用?
先看监控,定位瓶颈(是CPU、数据库还是IO?)。
如果是慢SQL,优先数据库层优化(索引、SQL改写)。
如果是读压力大,强化缓存层。
如果是写压力大,引入异步层。
如果单机撑不住,做应用层的水平扩容。
58、如何优化数据库查询性能?
第一层:SQL与索引优化(性价比最高)
SQL重写
第二层:数据库结构优化 -- 适当冗余:用空间换时间,减少JOIN, 分区表,
第三层:缓存层
第四层:读写分离
使用ES
59、分布式下如何设计一个ID生成器?
UUID、雪花算法、数据库自增
60、MySQL机器故障怎么排查?
看进程:ps 检查MySQL是否活着。
看磁盘:df -h 和 df -i,这往往是第一元凶。
看日志:tail -100 /var/log/mysql/error.log。
看连接:SHOW PROCESSLIST; 抓出正在执行的SQL。
看慢查询:分析是否存在需要优化的SQL语句。
看锁:分析是否存在锁等待或事务未提交的情况。
61、like前缀模糊查询不走索引怎么优化?
-- 索引是按照从左到右的顺序建立搜索树的,当通配符 % 出现在最左边时,数据库无法判断需要从树的哪个节点开始查找,只能进行全表扫描。
方案一:覆盖索引(最推荐)
方案二:反向存储(适用于后缀查询)
方案三:Elasticsearch(专业搜索引擎) -- 复杂度最高
62、如何设计一个高效的缓存机制?
核心在于平衡三个关键要素:命中率(节省的时间)、一致性(数据的准确性)和成本(资源与复杂度)。没有万能的方案,只有根据业务场景做出的最佳权衡。
本地缓存:不会变化的数据,查询最快,大小受限制,数据一致性问题
分布式缓存: 容量大,所有节点共享
数据库(最终存储):
读操作:优先读本地 -> 未命中读分布式 -> 未命中读数据库。
回写:读数据库后,逐级回写。
63、如何保证多级缓存的数据一致性?
追求数据强一致性:就不要使用缓存,直接查数据库
能容忍短暂的不一致:
方案一:定时刷新
方案二:主动失效 + 广播通知(最常用)
原理:当数据更新时,不仅删除Redis缓存,还通过MQ广播通知所有服务节点删除本地缓存。
方案三:Canel 监听 Binlog(终极方案)
64、如何实现亿级用户的状态统计?
分析:亿级用户状态统计的核心难点在于数据量巨大,且状态往往是实时变化的(比如在线/离线、签到/未签、VIP等级等)
方案一:基于 Redis 的实时统计(适用于在线状态、实时计数)
这是最常用的方案,利用 Redis 纯内存、高并发的特性来承载读写。
方案二: 亿级用户在线状态压缩(BitMap)
以日期为Key,如 user:online:20231027。
每个用户ID对应 BitMap 中的一个偏移量(Offset) -- 需要维护一个 用户ID 到 Offset 的映射关系(通常直接用数字ID作为偏移量即可)
方案三:基于数据库分表 + 异步批量(适用于持久化统计)
Flink 消费 MQ 里的用户状态日志。将结果写入 OLAP 数据库(如 ClickHouse)供运营分析
65、怎么在1亿条数据中判断一个手机号是否为新用户?
分析:核心在于解决两个问题:存储成本(1亿条数据占多大空间)和查询速度(如何快速判断)
方案一:布隆过滤器(最推荐,适用于允许极小误判的场景) + 数据库查询 ; 不存在则一定不存在
方案二:Redis + 位图(精确判重,适用于手机号可转为数字的场景)
方案三:Redis Set(精确判重,适用于内存足够的场景)
内存计算:
1亿个手机号,每个手机号按字符串存储约11字节。
Redis的Set有额外开销(dict entry、指针等),实际占用约 50-70字节/个。
1亿 × 50字节 ≈ 5GB。
66、如果有100w数据批量写入到数据库会发生什么?怎么解决
方案一:分批 + 批量插入(最常用) + 多线程处理(可选,对性能要求可以加)
方案二:专用的数据导入工具
67、让你设计一个消息队列,你会怎么设计?
任何MQ最核心的抽象只有两个角色:生产者 和 消费者,中间是Broker(服务端)。
基本功能
生产者:建立长连接(或短连接),发送消息到Broker,Broker返回写入结果(成功/失败)。
消费者:有两种基本的消费模式
Pull(拉模式):客户端主动来拉取数据,主动权在客户端(如 Kafka)。
Push(推模式):服务端有数据就主动推给客户端,实时性好但需要处理背压问题(如 RocketMQ 的 Push 模式底层也是 Pull 的封装)
68、有100G的数据需要排序,但内存只有12G,如何处理?
方案一:
第一步:分割(Split)------生成有序子文件
第二步:归并(Merge)------多路归并
方案二:
如果数据量级达到TB/PB,可以考虑大数据框架hadoop、spark
69、设计三方接口时,需要考虑什么问题?
1、认证和鉴权
2、https数据加密传输
3、幂等
4、处理结果查询 -- 新增或更新 ;
5、查询的话,如果是列表查询,需要注意分页
6、限流
70、如何实现上亿用户的积分实时排行榜功能?
方案一:Redis 有序集合(千万级)
如果用户量在几千万以内,Redis 的 Sorted Set 是最简单直接的方案。
方案二:分区排序 + 合并(亿级)
核心思想:将用户按积分范围或用户ID哈希分到多个桶(Bucket)中,每个桶独立排序,查询 TopN 时从各个桶取数据合并。
方案四:大数据组件 + 异步计算(百亿级)
当用户量达到十亿级且积分变化频繁时,实时计算已不现实,需要引入大数据组件进行准实时计算。
流式计算(Flink/Spark Streaming)
方案五:预计算 + 结果缓存
每小时/每天离线计算全量排名(Spark/Hive)
将 TopN 结果缓存到 Redis
71、在某个大文件中,如何查询出现次数最多的10个url ?
第一阶段:预处理与切分(Divide)
目标:将大文件拆分成小文件,确保每个小文件可以被加载到内存中处理。
第二阶段:逐个击破与聚合(Conquer)
目标:统计每个小文件中每个URL的出现次数,然后汇总得到全局Top 10。