【后端开发面试题】每日 3 题(十八)
✍个人博客:Pandaconda-CSDN博客
📣专栏地址:https://blog.csdn.net/newin2020/category_12903849.html
📚专栏简介:在这个专栏中,我将会分享后端开发面试中常见的面试题给大家,每天的题目都是独立且随机的,之前的面试题不会影响接下来的学习~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
题目 1: 什么是分布式事务?有哪些常见的解决方案?
答案:
分布式事务是指在分布式系统中,多个服务或数据库需要共同完成一个事务,保证数据的一致性。由于涉及多个节点,传统的单机事务(如 ACID)无法直接应用。
常见解决方案:
-
两阶段提交 (2PC, Two-Phase Commit)
- 原理:分为准备阶段和提交阶段。协调者先向所有参与者发送准备请求,确认是否可以提交;如果所有参与者都同意,则进入提交阶段。
- 优点:强一致性。
- 缺点:性能较差,存在单点故障风险。
-
补偿事务 (TCC, Try-Confirm-Cancel)
- 原理:将事务分为三个步骤:尝试(Try)、确认(Confirm)和取消(Cancel)。每个操作都需要支持回滚逻辑。
- 优点:灵活性高,适合复杂业务场景。
- 缺点:实现复杂,需要手动编写补偿逻辑。
-
消息队列最终一致性
- 原理:通过消息队列(如 Kafka、RabbitMQ)传递事务消息,确保上下游服务的数据最终一致。
- 优点:高性能,解耦性强。
- 缺点:可能存在短暂的不一致状态。
-
SAGA 模式
- 原理:将事务拆分为多个小事务,每个小事务完成后触发下一个事务。如果某个事务失败,则执行补偿操作回滚之前的操作。
- 优点:适合长事务,扩展性强。
- 缺点:实现复杂,可能需要额外的监控机制。
总结:
- 对于强一致性要求高的场景,选择 2PC 或 TCC。
- 对于高并发和最终一致性要求的场景,选择消息队列或 SAGA 模式。
题目 2: 如何优化 API 的响应时间?请列举至少五种方法并简要说明。
答案:
优化 API 响应时间是提升用户体验的重要手段。以下是五种常见的优化方法:
-
缓存数据
- 使用缓存(如 Redis、Memcached)存储频繁访问的数据,减少数据库查询次数。
- 示例:缓存热门商品信息,避免每次请求都查询数据库。
-
压缩传输内容
- 使用 Gzip 或 Brotli 压缩 API 的响应数据,减少网络传输时间。
- 示例:对 JSON 数据进行压缩后再返回给客户端。
-
异步处理
- 将耗时操作(如文件上传、邮件发送)放入消息队列异步处理,提升 API 的响应速度。
- 示例:用户下单后,订单处理逻辑通过消息队列异步完成。
-
优化数据库查询
- 添加索引、优化 SQL 语句、分库分表,减少查询时间。
- 示例:为订单表的用户 ID 字段添加索引,加快查询速度。
-
使用 CDN
- 对静态资源(如图片、CSS 文件)使用 CDN 加速,减少服务器负载。
- 示例:将图片存储在 CDN 上,用户直接从最近的节点获取资源。
-
减少不必要的依赖
- 移除或延迟加载非关键的第三方服务调用,降低整体响应时间。
- 示例:延迟加载广告或推荐模块的内容。
题目 3: 什么是限流?它的作用是什么?如何实现限流?
答案:
限流是一种用于控制系统的请求速率的技术,防止因流量过大导致系统崩溃。
作用:
- 保护系统稳定性
限制请求速率,避免系统过载。 - 提高服务质量
优先处理重要请求,保障核心功能的可用性。 - 防止恶意攻击
防止 DDoS 攻击或爬虫行为消耗系统资源。
实现限流的方法:
-
计数器算法
- 在固定时间窗口内统计请求次数,超过阈值则拒绝请求。
- 示例:每秒最多允许 100 次请求。
-
滑动窗口算法
- 将时间窗口划分为多个小窗口,动态计算请求速率。
- 示例:每秒 100 次请求,但不会集中在某一瞬间。
-
令牌桶算法
- 系统以固定速率生成令牌,每个请求需要消耗一个令牌。如果令牌不足,则拒绝请求。
- 示例:每秒生成 50 个令牌,超出部分等待或拒绝。
-
漏桶算法
- 请求以恒定速率从“桶”中流出,超出桶容量的请求被丢弃或排队。
- 示例:每秒处理 100 个请求,多余请求进入队列等待。
实现工具:
- 使用 Nginx 的限流模块(如
limit_req
)。 - 使用 Redis 实现分布式限流。
- 使用开源框架(如 Sentinel、Resilience4j)。
示例:
以下是一个基于 Redis 的简单限流实现:
import redis
import time
def is_allowed(user_id, limit, window):
r = redis.Redis()
key = f"rate_limit:{user_id}"
current_time = time.time()
# 清理过期请求
r.zremrangebyscore(key, 0, current_time - window)
# 统计当前窗口内的请求数
request_count = r.zcard(key)
if request_count < limit:
r.zadd(key, {current_time: current_time})
return True
return False