1. 高并发场景下,如何设计一个限流系统?
问题:假设有一个秒杀系统,瞬时流量可能达到10万QPS,如何设计限流策略防止服务崩溃?
参考答案:
-
核心目标:控制请求速率,保护后端服务。
-
方案:
-
令牌桶算法:系统以固定速率生成令牌,请求获取令牌后才能被处理,允许突发流量。
-
漏桶算法:请求以恒定速率处理,超出容量的请求被丢弃或排队。
-
分布式限流:使用Redis或集群协调工具(如ZooKeeper)统计全局请求量,避免单节点限流不均。
-
自适应限流:根据系统负载(如CPU、线程池状态)动态调整限流阈值。
-
-
相关实践:结合内部中间件(如TARS的流量控制)或开源工具(如Sentinel)。
2. 如何避免Redis缓存穿透、击穿和雪崩?
问题:描述这三种场景的区别,并给出解决方案。
参考答案:
-
缓存穿透:查询不存在的数据(如不存在的ID),绕过缓存直接击穿到数据库。
-
方案:布隆过滤器(Bloom Filter)拦截非法请求;缓存空值(设置短过期时间)。
-
-
缓存击穿:热点Key突然失效,大量请求直接访问数据库。
-
方案:互斥锁(如Redis的SETNX),保证只有一个线程回源重建缓存;永不过期(逻辑过期时间+异步更新)。
-
-
缓存雪崩:大量Key同时失效,导致数据库压力激增。
-
方案:随机过期时间;多级缓存(本地缓存+Redis);服务降级与熔断。
-
3. 如何排查用户访问网站时快时慢的问题?
问题:用户反馈访问网站不稳定,时快时慢,可能有哪些原因?如何定位?
参考答案:
-
可能原因:
-
网络波动(用户端CDN节点不稳定、DNS解析问题)。
-
服务端负载不均(某些实例CPU/IO过高)。
-
慢查询或数据库锁竞争。
-
中间件瓶颈(如Redis连接池耗尽、MQ堆积)。
-
-
排查步骤:
-
用户侧:检查网络链路(traceroute)、浏览器控制台(前端资源加载)。
-
服务端:监控系统(CPU、内存、磁盘IO);日志分析(慢请求、错误码)。
-
中间件:检查Redis/MQ状态;数据库慢查询日志(如MySQL的slow log)。
-
分布式跟踪:通过TraceID追踪全链路耗时(如SkyWalking、Zipkin)。
-
4. 设计一个分布式锁服务,需考虑哪些因素?
问题:如何实现一个高可用的分布式锁?会遇到哪些挑战?
参考答案:
-
核心要求:互斥性、容错性(锁自动释放)、高可用、避免死锁。
-
实现方案:
-
Redis:使用SETNX + Lua脚本保证原子性,设置过期时间;Redlock算法解决单点问题。
-
ZooKeeper:通过临时顺序节点实现,Watch机制监听锁释放。
-
-
挑战与解决:
-
时钟漂移:Redis的Redlock依赖时钟同步,可能需物理时钟约束。
-
锁续期:客户端需定期续约(如使用看门狗线程)。
-
脑裂问题:ZooKeeper的Leader选举机制相比Redis更可靠。
-
5. 如何保证微服务架构中的数据一致性?
问题:订单服务和库存服务需要跨服务更新数据,如何保证两者的一致性?
参考答案:
-
方案:
-
本地消息表:业务与消息表在同一个事务中提交,异步重试确保最终一致。
-
Saga模式:将事务拆分为多个本地事务,通过补偿机制回滚(如TCC模式:Try-Confirm/Cancel)。
-
消息队列:使用可靠消息(如RocketMQ事务消息)确保消息投递。
-
分布式事务框架:如Seata的AT模式(自动补偿)。
-
-
权衡:强一致(性能低) vs 最终一致(需业务容忍延迟)。
6. TCP三次握手和四次挥手
问题:详细说明过程,并解释为什么挥手需要四次?
参考答案:
-
三次握手(建立连接):
-
Client→Server:SYN=1, seq=x。
-
Server→Client:SYN=1, ACK=1, seq=y, ack=x+1。
-
Client→Server:ACK=1, seq=x+1, ack=y+1。
-
目的:确保双方收发能力正常,防止历史连接干扰。
-
-
四次挥手(关闭连接):
-
Client→Server:FIN=1, seq=u。
-
Server→Client:ACK=1, seq=v, ack=u+1(Server进入CLOSE_WAIT)。
-
Server→Client:FIN=1, ACK=1, seq=w, ack=u+1。
-
Client→Server:ACK=1, seq=u+1, ack=w+1(Client进入TIME_WAIT)。
-
为什么四次:TCP是全双工,需双方分别关闭。Server收到FIN后可能还有数据要发送,因此ACK和FIN分开发送。
-
7. 如何设计一个支持海量数据存储的分布式文件系统?
问题:假设要设计一个类似腾讯云COS的对象存储系统,如何保证高可用、高性能和扩展性?
参考答案:
-
核心目标:数据分片、冗余存储、负载均衡。
-
方案:
-
分片策略:将大文件切分为固定大小的块(如64MB),分散存储到不同节点。
-
冗余机制:使用纠删码(Erasure Coding)或副本(如3副本)保证数据可靠性。
-
元数据管理:用分布式KV存储(如etcd)或专用元数据节点记录文件与分片映射关系。
-
负载均衡:通过一致性哈希算法动态分配数据块,避免热点。
-
-
相关实践:参考腾讯云COS的架构,结合CDN加速访问。
8. 如何优化一个慢查询的MySQL数据库?
问题:某业务表数据量达到亿级,查询性能下降,如何分析和优化?
参考答案:
-
分析步骤:
-
使用
EXPLAIN
分析执行计划,关注全表扫描、索引失效、临时表等。 -
检查慢查询日志,定位耗时最长的SQL。
-
监控数据库锁(
SHOW ENGINE INNODB STATUS
)。
-
-
优化手段:
-
索引优化:添加覆盖索引、联合索引;避免冗余索引。
-
分库分表:按时间或业务键水平拆分(如腾讯TDSQL的自动分片)。
-
冷热分离:历史数据归档到廉价存储(如HBase)。
-
缓存:高频查询结果缓存到Redis。
-
9. 微服务拆分后如何保证接口性能?
问题:系统从单体架构拆分为微服务后,接口响应时间变长,如何解决?
参考答案:
-
可能原因:服务间调用链路过长、序列化开销、网络延迟。
-
优化方案:
-
合并请求:使用批量接口(如一次获取多个资源)减少RPC次数。
-
并行调用:通过CompletableFuture或RxJava异步并发调用多个服务。
-
本地缓存:缓存依赖服务的部分数据(如用户基本信息)。
-
协议优化:用Protobuf替代JSON减少序列化体积;HTTP/2多路复用降低延迟。
-
服务治理:腾讯北极星(Polaris)实现服务发现和动态路由。
-
10. 如何设计一个实时排行榜系统?
问题:某游戏需要实时更新全球玩家积分排行榜(Top 1000),如何高效实现?
参考答案:
-
核心需求:低延迟更新、高并发读取。
-
方案:
-
数据结构:使用Redis的Sorted Set(ZSET),天然支持分数排序。
-
写入优化:直接调用
ZADD
更新玩家分数。 -
读取优化:用
ZREVRANGE
获取Top N;缓存Top结果减少重复计算。 -
分片策略:按玩家ID哈希分片到多个Redis实例,缓解单点压力。
-
最终一致性:异步同步到数据库(如MySQL)持久化。
-
11. 如何实现服务优雅发布(不停机更新)?
问题:如何保证服务在发布新版本时不影响线上用户?
参考答案:
-
核心原则:流量隔离、平滑切换、回滚预案。
-
方案:
-
蓝绿发布:同时部署新旧两套环境,通过负载均衡切换流量。
-
灰度发布:逐步切量(如按用户ID或地域),监控异常后暂停。
-
优雅下线:服务实例关闭前,先通知注册中心(如Nacos)摘除节点,等待处理完存量请求。
-
相关实践:结合Kubernetes的滚动更新和腾讯云TKE的Ingress流量管理。
-
12. 如何解决HTTP API的幂等性问题?
问题:支付接口因网络抖动可能被重复调用,如何避免用户被扣款多次?
参考答案:
-
幂等核心:相同请求多次执行结果一致。
-
方案:
-
Token机制:客户端先获取唯一Token,请求时携带,服务端校验后标记为已使用。
-
唯一键约束:数据库对业务唯一键(如订单ID)加唯一索引,重复请求直接报错。
-
状态机:业务逻辑设计为状态流转(如“已支付”状态不可重复更新)。
-
分布式锁:对关键操作加锁(如用户ID+订单号)。
-
13. 如何应对DDoS攻击?
问题:某服务突然遭遇大规模流量攻击,如何快速响应?
参考答案:
-
防护分层:
-
网络层:通过运营商或云服务(如腾讯云DDoS防护)清洗流量。
-
应用层:限制单个IP请求频率;验证码或人机校验拦截机器人。
-
服务层:弹性扩容分散流量;熔断机制保护核心服务。
-
-
监控与告警:实时监控流量突增,自动触发防护策略。
14. 如何设计一个短链生成系统?
问题:类似腾讯云短链服务,如何保证短链唯一性和高并发生成?
参考答案:
-
核心逻辑:长链映射到短链(如62进制转换)。
-
方案:
-
发号器:用分布式ID生成器(如Snowflake算法)获取唯一ID,转换为短码。
-
哈希冲突:对长链做MD5后取部分值,若冲突则追加随机盐重试。
-
缓存优化:热点短链预生成并存到Redis,降低数据库压力。
-
存储:MySQL记录短码与长链映射,Redis缓存高频访问条目。
-
15. 如何实现分布式系统的全局唯一ID?
问题:在分布式系统中,如何生成高性能、无冲突的唯一ID?
参考答案:
-
常见方案:
-
Snowflake算法:时间戳+机器ID+序列号(腾讯可基于内部机器号分配)。
-
数据库号段:批量申请ID段(如一次取1000个),减少数据库访问。
-
Redis原子操作:用
INCR
或INCRBY
生成连续ID。 -
UUID:简单但无序,影响数据库索引性能。
-
-
相关实践:可能结合TDSQL的分布式自增ID能力。