系统设计面试题¶
以对话形式回答,模拟真实面试场景
20. 编程题:了解的负载均衡算法有什么?实现一个负载均衡算法。¶
面试官:你了解哪些负载均衡算法?能实现一个吗?
回答:我了解的负载均衡算法有这些:
轮询算法最简单,就是按顺序分配请求;加权轮询可以根据服务器性能设置权重;随机算法是随机选择服务器;加权随机也是考虑权重的随机选择。
还有最少连接算法,选择当前连接数最少的服务器;一致性哈希算法,根据请求的某个标识哈希到固定的服务器;IP哈希算法,根据客户端IP哈希选择服务器。
面试官:那你实现一个轮询算法吧。
回答:好的,我来实现一个简单的轮询算法。
首先定义一个结构体,包含服务器列表、当前索引和互斥锁:
然后实现获取服务器的方法:
func (r *RoundRobinBalancer) GetServer(clientID string) (*Server, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
if len(r.servers) == 0 {
return nil, fmt.Errorf("no available servers")
}
next := atomic.AddInt64(&r.current, 1)
index := int(next-1) % len(r.servers)
return r.servers[index], nil
}
面试官:为什么用原子操作?
回答:因为在高并发场景下,多个 goroutine 可能同时调用这个方法,用原子操作可以保证 current 字段的线程安全,避免竞态条件。虽然有读写锁保护,但原子操作的性能更好。
面试官:还能优化吗?
回答:可以考虑几个方面:加入健康检查机制,过滤掉不健康的服务器;支持动态添加和删除服务器;或者实现加权轮询,根据服务器性能分配不同的权重。
在实际项目中,我还会考虑响应时间、当前连接数等因素,实现更智能的负载均衡策略。比如结合服务器的响应时间和当前连接数来计算一个综合分数,选择分数最高的服务器。
面试官:一致性哈希了解吗?
回答:了解的。一致性哈希主要用于分布式缓存场景,可以在节点数量变化时最小化数据迁移。
基本思路是把哈希值空间想象成一个环,服务器和数据都映射到这个环上,数据存储到顺时针方向第一个服务器上。当服务器增减时,只影响相邻的服务器,大部分数据不需要迁移。
为了解决数据分布不均的问题,还会引入虚拟节点,每个物理服务器对应多个虚拟节点,这样可以让数据分布更加均匀。
高并发系统设计¶
系统架构设计¶
面试官:如果让你设计一个高并发的电商系统,你会怎么设计?
回答:我会从几个维度来考虑:
架构分层: - 接入层:使用 Nginx 做负载均衡和反向代理 - 网关层:API 网关处理认证、限流、监控 - 服务层:按业务拆分微服务,用户服务、商品服务、订单服务等 - 数据层:读写分离,分库分表,缓存层
缓存策略: - 多级缓存:浏览器缓存、CDN、Redis、本地缓存 - 缓存预热:提前加载热点数据 - 缓存更新:使用消息队列异步更新
数据库设计: - 垂直分库:按业务模块分离 - 水平分表:按用户ID或时间分片 - 读写分离:主库写,从库读 - 分布式事务:使用 TCC 或 Saga 模式
高可用设计¶
容错机制: - 熔断器:防止级联故障 - 降级策略:核心功能优先保障 - 超时控制:避免长时间等待 - 重试机制:指数退避算法
监控告警: - 业务监控:订单量、支付成功率 - 系统监控:CPU、内存、网络 - 应用监控:响应时间、错误率 - 日志分析:ELK 栈进行日志收集分析
性能优化¶
数据库优化: - 索引优化:合理设计索引 - SQL 优化:避免 N+1 查询 - 连接池:复用数据库连接 - 分页优化:游标分页替代 offset
应用优化: - 对象池:减少 GC 压力 - 异步处理:消息队列解耦 - 批量操作:减少网络开销 - 压缩传输:gzip 压缩响应
分布式系统常见问题¶
分布式锁¶
实现方式: 1. 基于 Redis:SET NX EX 实现 2. 基于 ZooKeeper:临时顺序节点 3. 基于数据库:唯一索引约束
注意事项: - 锁超时:防止死锁 - 锁续期:防止业务执行时间过长 - 锁释放:原子性操作 - 锁重入:支持同一线程多次获取
分布式事务¶
解决方案:
两阶段提交(2PC): - 准备阶段:所有参与者投票 - 提交阶段:根据投票结果执行 - 问题:阻塞,单点故障
TCC 模式: - Try:尝试执行,预留资源 - Confirm:确认执行,提交资源 - Cancel:取消执行,释放资源
Saga 模式: - 将长事务拆分为多个本地事务 - 每个本地事务都有对应的补偿操作 - 适用于长流程业务
服务治理¶
服务发现: - 客户端发现:Eureka - 服务端发现:Consul + Nginx - 服务网格:Istio
负载均衡: - 轮询:简单均匀分配 - 加权轮询:根据服务器性能 - 最少连接:选择连接数最少的 - 响应时间:选择响应最快的
限流策略: - 令牌桶:允许突发流量 - 漏桶:平滑限制流量 - 计数器:简单但不够平滑 - 滑动窗口:更精确的控制
秒杀系统设计¶
系统特点¶
- 高并发:瞬时大量请求
- 读多写少:大量查询,少量购买
- 时间集中:特定时间点爆发
设计方案¶
前端优化: - 静态化:商品页面静态化 - CDN:就近访问 - 防刷:验证码、限制频率
后端优化: - 异步处理:消息队列削峰 - 库存预扣:Redis 原子操作 - 分层过滤:多级验证
数据库优化: - 读写分离:查询走从库 - 分库分表:分散压力 - 缓存优化:热点数据缓存
核心流程¶
- 商品预热:提前加载到缓存
- 流量控制:网关层限流
- 库存扣减:Redis 原子操作
- 订单创建:异步处理
- 支付处理:独立服务
微服务架构¶
服务拆分原则¶
按业务拆分: - 用户服务:注册、登录、个人信息 - 商品服务:商品管理、库存管理 - 订单服务:下单、支付、物流 - 营销服务:优惠券、活动管理
拆分考虑: - 业务边界清晰 - 数据独立性 - 团队组织结构 - 技术栈选择
服务间通信¶
同步通信: - HTTP/REST:简单易用 - gRPC:高性能二进制协议 - GraphQL:灵活的查询语言
异步通信: - 消息队列:RabbitMQ、Kafka - 事件驱动:发布订阅模式 - 任务队列:异步任务处理
数据一致性¶
强一致性: - 分布式事务 - 性能代价高 - 适用于核心业务
最终一致性: - 事件驱动更新 - 性能好,复杂度高 - 适用于非核心业务
面试建议¶
系统设计思路¶
- 需求分析:明确功能和非功能需求
- 容量估算:用户量、QPS、存储量
- 架构设计:分层、分模块设计
- 技术选型:根据需求选择合适技术
- 优化方案:性能、可用性、扩展性
常见考察点¶
- 高并发处理:缓存、分库分表、异步处理
- 高可用设计:冗余、故障转移、降级
- 数据一致性:事务、锁、最终一致性
- 性能优化:数据库、缓存、网络
- 监控运维:日志、监控、告警
回答技巧¶
- 结构化思考:按层次、模块组织答案
- 权衡取舍:说明设计选择的原因
- 实际经验:结合项目经验说明
- 持续优化:提及后续改进方向