架构师面试笔记

架构师面试笔记

参考资料:Martin Fowler 软件架构、The Difference Between Architecture and Design

1 服务分层

经典的三层后台服务架构为:接入层、逻辑层、存储层,划分原则是让同层次的系统专注处理自己的事情。

  • 接入层:负责前端与后台服务的接入连通、安全认证和数据转发;
  • 逻辑层:负责处理不同业务的无状态逻辑服务;
  • 存储层:负责业务数据的存储。

分层的好处:各层依据业务特点专注自己的工作,提高系统复用性、降低业务耦合度。中小型网站中三层架构的典型实现是 Nginx(接入层)、Apache/Tomcat(逻辑层)、MySQL/Redis(存储层)。

2 缓存击穿、雪崩的应对方法

  • 缓存穿透:查询一个必然不存在的数据,每次都打到数据库。解决:布隆过滤器拦截,或缓存空值。
  • 缓存击穿:某个热点 key 失效瞬间被大量并发请求打挂后端。解决:互斥锁(setnx)、热点 key 逻辑不过期。
  • 缓存雪崩:大量 key 在同一时间一起失效,请求全部涌向数据库。解决:过期时间加随机值分散、多级缓存。

详见《Redis 缓存穿透/击穿/雪崩》一文。

3 秒杀系统的设计

特点

  • 高性能:秒杀瞬间流量是平时的数十甚至上百倍,库存只有一份,所有请求集中读写同一个数据,DB 存在单点;
  • 高一致性:100 件商品不能出现 200 人下单成功;
  • 高可用:不能让秒杀拖垮其他无关模块。

方案

高性能

  1. 浏览器/客户端层面:前端脚本控制点击频率,过快时只提示不真正发请求;
  2. DNS 层面:域名 CNAME 到不同地区的服务集群,不同地区线路的客户由不同集群提供服务;
  3. 业务层面:
    • 数据拆分:动态页面改造成适合缓存的静态页面;
    • 静态页面:浏览器、CDN、服务端三层缓存;
    • 数据整合:动静分离后,前端组织动态数据有两种方案:
      • ESI(Edge Side Includes):Web 代理服务器上请求动态数据并插入静态页面,用户看到的是完整页面。服务端性能要求高,用户体验好;
      • CSI(Client Side Include):代理只返回静态页面,前端单独发起异步 JS 请求动态数据。服务端性能友好、能挡部分脚本请求,秒杀场景比较合适。

一致性

假定商品数量为 N:

  1. 引入 Redis 集群缓存层实现一个令牌桶,令牌桶个数与商品数相同,每个桶的 key 前缀相同、后缀为 1 到 N 的数字;
  2. 业务层 server 维护一个局部计数器,请求到达 +1,超过商品数就取模,保证不超过商品数量;
  3. 获取并删除令牌的操作用 Lua 脚本封装成原子操作:
    • 第一步先判断令牌 key 是否存在,不存在直接返回,告知用户抢单失败;
    • 如果令牌 key 存在,则删除它并通知业务层 server;
  4. 将 Redis 令牌桶 key 与 DB 中的商品 id 关联,业务层获取令牌成功后,才真正与 DB 交互(实际只有 N 个连接进入 DB,DB 压力大大减小),再创建订单并返回抢单成功。

高可用

  1. DNS 分区域调度和解析保证整个系统可用性;
  2. Redis 组建多主多从的高可用集群;
  3. 应用层无状态化 + 负载均衡,便于横向扩容。
阅读 — · 全站 —
🎸 我的歌单 0 首