
一、携程一面
1. 项目,解决问题,优化方案
回答思路 :围绕"业务价值+技术问题+落地手段"展开,突出问题分析→方案选型→效果验证的闭环。
-
示例(以电商订单系统为例):
-
业务背景:订单量峰值10万+/日,并发下库存超卖、接口响应超时(平均2s+)。
-
核心问题:高并发库存一致性、接口性能瓶颈。
-
优化方案:
- 库存防超卖:Redis预减库存(秒杀场景)+ MySQL最终扣减(事务保证),结合乐观锁(
version字段)防止并发冲突; - 接口性能:分库分表(订单表按用户ID哈希拆分)、SQL索引优化(覆盖索引减少回表)、异步化(非核心流程如短信通知走MQ);
- 效果:库存超卖率从5%降至0,核心接口响应时间优化至200ms内。
- 库存防超卖:Redis预减库存(秒杀场景)+ MySQL最终扣减(事务保证),结合乐观锁(
-
2. Redis分布式锁(很多问题)
核心考点:分布式锁的原理、常见问题(锁超时、误删、集群脑裂)及解决方案。
-
原理:利用Redis的
SET key value NX PX timeout原子性命令,实现多进程/服务的互斥访问。 -
常见问题与解决方案:
- 锁超时 (业务未执行完,锁过期):Redisson的Watchdog机制(自动续期,默认30s内每10s续一次);
- 锁误删 (其他线程删除自己的锁):给锁加唯一标识(UUID) ,删除前校验
value是否为自身生成的UUID; - 集群脑裂 (主从切换导致锁失效):采用Redlock算法(多主节点投票,需至少N/2+1节点成功),但需权衡性能(一般中小厂用单主+重试兜底)。
3. 算法:最大子数组和
考点:动态规划(Kadane算法),考察代码简洁性与时间复杂度优化。
-
思路:遍历数组,维护
currentSum(当前子数组和)和maxSum(全局最大和)。若currentSum < 0,则重置为当前元素(负数累加无意义);否则继续累加。 -
代码示例:
inipublic int maxSubArray(int[] nums) { int max = nums[0], current = nums[0]; for (int i = 1; i < nums.length; i++) { current = Math.max(current + nums[i], nums[i]); max = Math.max(max, current); } return max; }
二、携程二面
1. 自我介绍以及项目难点,自己参与度高的案例
回答模板:
【自我介绍】我是XX,专注后端开发X年,擅长分布式/高并发领域,主导过XX项目(如亿级流量秒杀系统)。
【项目难点】在XX项目中,需解决高并发库存超卖+接口性能问题。原有方案是DB悲观锁,导致TPS仅50,超卖率10%。
【参与度】主导技术方案:① 引入Redis预减库存(原子操作)+ MySQL乐观锁(
version校验)保证一致性;② 分库分表(订单表按用户ID哈希)拆分单表压力;③ 非核心流程异步化(MQ解耦)。上线后TPS提升至2000+,超卖率0,接口耗时从2s→200ms。
2. 大批量数据导出文件如何优化?
核心思路 :异步+分治+流式IO+压缩,避免内存溢出与请求超时。
-
步骤:
- 异步触发:前端发起导出请求,后端写入MQ,立即返回"任务创建中",前端轮询/WS查询状态;
- 分批查询 :DB分页(
LIMIT offset, size),避免全量数据加载到内存; - 流式写入 :用POI的
SXSSFWorkbook(流式Excel,仅保留内存中指定行数)或EasyExcel(基于事件模型)写文件;CSV直接通过FileOutputStream逐行输出; - 压缩打包:导出完成后,用ZIP压缩(减少传输体积),支持断点续传;
- 异常重试:MQ消费失败时,重试+死信队列兜底,保证数据不丢失。
3. 分布式事务相关(本地消息表 + 消息队列)
考点:可靠消息最终一致性方案,考察落地细节(异常处理、幂等)。
-
流程:
- 本地事务 :业务操作(如扣库存)与插入本地消息表 (记录消息状态
待发送)在同一DB事务中完成; - 消息投递 :定时任务扫描本地消息表,将
待发送消息发往MQ,成功后更新消息状态为已发送; - 消费端处理 :消费者订阅MQ,执行业务逻辑(如创建订单),成功后回调通知生产者更新消息状态为
已完成;
- 本地事务 :业务操作(如扣库存)与插入本地消息表 (记录消息状态
-
异常处理:
- 消息发送失败:定时任务重试(需保证幂等,如消息ID去重);
- 消费失败:MQ重试(设置重试次数)+ 死信队列人工介入;
- 补偿机制:定时对账(如检查DB与MQ消息状态一致性)。
4. 设计模式优化代码
回答策略 :结合场景讲设计模式,突出解耦、扩展性、可读性。
-
示例(以促销活动为例):
- 问题:原代码用
if-else区分满减、折扣、赠品,新增活动需修改主逻辑,维护性差。 - 方案:策略模式 。定义
PromotionStrategy接口(calculate()方法),实现类ManjianStrategy(满减)、ZhekouStrategy(折扣)等。上下文类PromotionContext持有策略引用,运行时根据活动类型切换策略。 - 效果:新增活动只需加实现类,无需修改原有代码;逻辑分散到各策略类,可读性提升。
- 问题:原代码用
5. 面试官发来一段代码,讲讲有没有可以改进的地方
通用思路 :从可读性、性能、健壮性、设计原则四维度切入。
-
示例(假设代码是"统计用户订单数"):
- 命名:变量
a→userOrderCount,方法count()→statUserOrderNum(); - 性能:循环内重复查询DB→批量查询+缓存;字符串拼接用
StringBuilder; - 健壮性:参数为空判断(如
userId == null抛异常)、try-catch细化(不笼统catch Exception); - 设计:若有多类统计(订单、退款、积分),提取
StatsService抽象类,实现类继承(开闭原则); - 并发:若统计全局数据,
AtomicLong代替long,或Redis原子计数。
- 命名:变量
三、携程三面(资深/Leader面)
1. 自我介绍以及项目
重点 :突出技术深度、架构设计、业务影响力。
-
示例:
我是XX,负责电商中台交易域,主导过"亿级订单履约系统"从0到1建设。核心挑战是高并发订单创建+分布式事务+全链路监控。
技术亮点:采用Spring Cloud Alibaba微服务架构,订单服务+库存+支付+物流解耦;Redis预减库存+MySQL乐观锁防超卖;Canal订阅Binlog异步更新缓存;Prometheus+Grafana监控QPS/响应时间/错误率。
成果:支撑双11峰值10万订单/分钟,系统可用性99.99%。
2. 用的啥技术栈?
分层梳理:后端→中间件→前端→工具链。
- 后端:Spring Boot/Spring Cloud(Nacos注册中心、Sentinel限流)、MyBatis-Plus(ORM)、Redis(缓存/分布式锁)、RocketMQ(异步/解耦)、MySQL(分库分表);
- 中间件:Elasticsearch(搜索)、MinIO(文件存储)、SkyWalking(链路追踪);
- 前端:Vue3 + Element Plus(若有前端协同);
- 工具链:Git(代码管理)、Maven(依赖)、Docker(容器化)、K8s(集群部署)、Jenkins(CI/CD)。
3. 引入这些中间件带来的优化是什么?
按中间件分类,讲核心价值:
- Redis:缓存热点数据(如首页推荐、用户会话),降低DB QPS 80%;分布式锁保证并发场景下的库存/订单一致性;
- RocketMQ:削峰填谷(如秒杀订单异步处理,下游服务按吞吐量消费);解耦系统(订单创建后发消息,物流/积分系统订阅,新增系统无需修改订单逻辑);
- MySQL:分库分表(订单表按用户ID哈希,单表数据从千万级→百万级);读写分离(主库写,从库读,降低主库压力30%);
- Elasticsearch:复杂查询(如商品多条件搜索)响应时间从2s→200ms;支持分词、聚合(如销量统计);
- 监控系统(Prometheus+Grafana):实时感知系统瓶颈(如某接口响应突增),5分钟内定位故障(如Redis连接池耗尽)。
4. 项目的运转/数据流程
以"用户下单→履约"为例,梳理全链路:
- 用户提交订单→网关(鉴权/限流)→订单服务(创建订单,Redis预减库存→锁定库存);
- 订单服务调用库存服务(MySQL最终扣减库存,失败则回滚Redis);
- 订单服务发送MQ(订单创建事件)→物流服务创建运单、积分服务增加积分;
- 支付服务回调订单服务(标记订单已支付)→订单服务发MQ通知物流履约;
- 全链路数据流向:DB(订单、库存)→Redis(库存缓存、分布式锁)→MQ(事件驱动)→ES(订单搜索)。
5. 消息队列应用
场景+落地+避坑:
-
场景:解耦(订单与物流系统)、异步(短信/积分通知)、削峰(秒杀流量缓冲);
-
落地:Spring Cloud Stream封装生产者/消费者,注解
@SendTo发消息,@StreamListener消费; -
避坑:
- 幂等性:消息携带唯一ID(如订单号),消费前查Redis去重;
- 顺序性:RocketMQ的MessageQueue选择器,保证同一订单消息发往同一队列;
- 重试机制:消费失败后,MQ自动重试3次,仍失败则发往死信队列。
6. MySQL慢查询如何优化?
五步法:定位→分析→索引→SQL→架构。
- 定位慢SQL :开启慢查询日志(
slow_query_log=ON,long_query_time=1),抓取执行时间>1s的SQL; - 分析执行计划 :
EXPLAIN看type(是否全表扫)、key(是否命中索引)、rows(扫描行数); - 优化索引:添加联合索引(遵循最左匹配)、覆盖索引(查询字段全在索引中,避免回表);
- SQL改写 :避免
SELECT *、减少JOIN表数、分页优化(大数据量用延迟关联,如SELECT t1.* FROM t1 JOIN (SELECT id FROM t1 LIMIT 100000, 10) t2 ON t1.id=t2.id); - 架构兜底:读写分离(MyCat/ShardingSphere)、分库分表(ShardingSphere)。
7. Redis的应用
高频场景+代码示例:
- 缓存:热点数据(如商品详情)缓存,设置过期时间(
EXPIRE key 3600)+ 淘汰策略(LRU); - 分布式锁:Redisson的
RLock(lock.lock(leaseTime, unit)自动续期); - 计数器:点赞数(
INCR post:100:like),原子性保证数据一致; - 限流:令牌桶算法(Redis + Lua脚本,每秒生成10个令牌,请求时
DECR token,值为负则拒绝); - 延迟队列:ZSET实现(
score为执行时间戳,定时任务扫ZRANGEBYSCORE获取到期任务)。
8. 缓存/DB 一致性如何保证?
核心方案:Cache-Aside + 重试兜底,接受"最终一致"。
- 更新逻辑:先更DB,再删缓存(避免"先删缓存→更DB失败→读DB旧数据");
- 异常处理:删缓存失败时,发MQ到重试队列,消费端循环删缓存(需限制重试次数,避免死循环);
- 补充:订阅Binlog(如Canal),异步更新缓存(适合读多写少场景,保证最终一致)。
9. 设计一下 用Redis做社交软件点赞;Redis集群下的数据排序
点赞设计:
-
数据结构:
- 点赞关系:
Set<user:like:{postId}>存储点赞用户ID(去重); - 点赞数:
String<like:count:{postId}>记录总数(INCR/DECR原子操作);
- 点赞关系:
-
功能:点赞(
SADD + INCR)、取消点赞(SREM + DECR)、查询是否点赞(SISMEMBER)、获取点赞列表(SMEMBERS)、点赞数(GET)。
集群下的数据排序(如按点赞数排热门帖):
-
问题:Redis集群分片(CRC16算法),不同Key可能在不同Slot,无法跨Slot排序;
-
方案:
- 哈希标签 :Key设计为
{hot}:post:{postId},{hot}作为哈希标签,强制同一Tag的Key在同一Slot; - 本地聚合+定时同步:每个节点维护本地TopN列表,定时(如每小时)汇总到中心节点生成全局TopN;
- 异步计算 :点赞事件发MQ,后台服务消费后维护全局ZSET(
ZADD hot_posts 100 postId),定期更新排序。
- 哈希标签 :Key设计为
10. 项目的开发测试流程
敏捷+DevOps闭环:
- 需求阶段:产品PRD评审,技术团队拆分用户故事,评估工时;
- 开发阶段:分支管理(Feature分支)、Code Review(SonarLint代码扫描)、单元测试(JUnit+Mockito);
- 测试阶段:测试环境Docker化部署(Compose),QA执行功能测试(Postman)、性能测试(JMeter)、安全测试(OWASP ZAP);
- 发布阶段:灰度发布(Nginx权重路由,5%流量试点),监控告警(Prometheus+Alertmanager),无问题则全量发布(K8s滚动更新);
- 迭代阶段:收集用户反馈,复盘技术债务,规划下一迭代。
以上答案结合技术深度+实战场景+架构思维,既覆盖知识点,又体现解决问题的能力,适合大厂面试应答~