22

系统设计面试题学习笔记

 4 years ago
source link: https://blog.callmewhy.com/post/xi-tong-she-ji-mian-shi-ti-xue-xi-bi-ji/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

通用模板

系统设计的面试题是一个开放式的对话,大体可以分成四个步骤:

第一步:明确需求

  • 需求是无止境的,需要明确一个范畴,专注讨论范畴内的需求用例
  • 目标用户是谁,用户规模大概多大
  • 有哪些功能,核心功能的输入输出是什么
  • 有哪些边界情况需要注意
  • 预期的数据量和处理速度

第二步:设计架构

  • 做一个高层次设计,画出核心组件的架构
  • 用连线代表核心组件之间的交互

第三步:细化实现

  • 具体到每个系统组件,提供具体的解决方案
  • 演示所有功能的交互流程和解决方案

第四步:扩展设计

  • 不用直接得出最终设计,通过 benchmark/load/profile 迭代分析瓶颈
  • 可参考方案:DNS、CDN、负载均衡、水平扩展、反向代理、应用层、缓存、主从复制
  • 论述可能的解决办法和代价,每件事情需要权衡利弊做出取舍

案例一:粘贴板分享平台

第一步:明确需求

我们将问题的范畴限定在如下用例:

  • 用户:输入文本,保存后得到一个随机链接
    • 默认不会过期
    • 设置过期时间
  • 用户:输入一个链接,可以查看分享的内容
  • 服务:用户行为统计与分析,可以使用外部服务(Google Analytics)
  • 服务:自动删除过期的内容
  • 服务:高可用,冗余+自动故障转移

范畴之外的用例:

  • 用户:可以注册、登录、查看历史记录
  • 用户:可以设置可见性、过期时间

状态假设:

  • 访问流量不是均匀分布的
  • 打开一个短链接应该是很快的
  • pastes 只能是文本
  • 页面访问分析数据可以不用实时
  • 一千万的用户量,每个月一千万的 paste 写入量,一亿的 paste 读取量,读写比例在 10:1

估算使用情况:

  • 每个 paste 的大小,每条数据大约 2kb
  • 每个月新的 paste 内容在 20GB
  • 平均 4 paste/s 的写入频率
  • 平均 40 paste/s 的读取频率

第二步:设计架构

可以先实现一个比较通用的架构:Client -> Web Server -> API -> SQL/Store -> Analytics

ymIFVza.png!web

第三步:细化实现

  • 用一个关系型数据库作为哈希表,用来把生成的 url 映射到一个包含 paste 文件的文件服务器和路径上
  • 为了避免托管一个文件服务器,我们可以用一个托管的对象存储,比如 Amazon 的 S3

用例1:输入文本,保存后得到一个随机链接

  • Client 发送一个创建 paste 的请求到反向代理
  • 反向代理转发请求给写接口服务器
  • 写接口服务器执行如下操作:
    • 生成一个唯一的 url
      • MD5 做哈希,Base62 做编码
      • 检查这个 url 在 SQL 数据库 里面是否是唯一的
      • 如果这个 url 不是唯一的,生成另外一个 url
      • 如果我们支持自定义 url,我们可以使用用户提供的 url(也需要检查是否重复)
    • 把生成的 url 存储到 SQL 数据库 的 pastes 表里面
    • 存储 paste 的内容数据到 对象存储 里面
    • 返回生成的 url

用例2:输入一个链接,可以查看分享的内容

  • Client 发送一个获取 paste 的请求到反向代理
  • 反向代理转发请求给读接口服务器
  • 读接口服务器执行如下操作:
    • 在 SQL 数据库 检查这个生成的 url
    • 如果这个 url 在 SQL 数据库 里面,则从 对象存储 获取这个 paste 的内容
    • 否则,返回一个错误页面给用户

用例3:用户行为统计与分析

非实时分析的功能可以通过 MapReduce 之类的服务来计算点击率之类的数据

第四步:扩展设计

  • 迭代地执行这样的操作:
    • Benchmark/Load 测试
    • Profile 出瓶颈
    • 在评估替代方案和权衡时解决瓶颈
    • 重复前面
  • 重要的是讨论在初始设计中可能遇到的瓶颈,以及如何解决每个瓶颈
U73aQfU.png!web

上面给出的方案中,主要是优化了以下几个方面:

  • DNS:根据用户所在地址分配到不同的服务器上
  • CDN:内容分发加速,客户端访问速度更快
  • Load Balancer:反向代理层做负载均衡,缓解单个 web server 的访问压力
  • Memory Cache:高频热数据放在内存缓存中,缓解数据库查询压力
  • SQL Write Master-Slave & Read Replicas:主从分离提高数据安全性和可用性,slave 上做查询可以缓解生产服务器访问压力过大的问题。
  • SQL Analytics:分析 SQL 的执行耗时,优化应用层的 SQL 语句性能

附录一:如何实现高可用

方法论上,高可用是通过冗余+自动故障转移来实现的。

整个互联网分层系统架构的高可用,又是通过每一层的冗余+自动故障转移来综合实现的,具体的:

(1)【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

(2)【反向代理层】到【站点层】的高可用,是通过站点层的冗余实现的,常见实践是 nginx 与 web-server 之间的存活性探测与自动故障转移

(3)【站点层】到【服务层】的高可用,是通过服务层的冗余实现的,常见实践是通过 service-connection-pool 来保证自动故障转移

(4)【服务层】到【缓存层】的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与 sentinel 保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性

(5)【服务层】到【数据库读】的高可用,是通过读库的冗余实现的,常见实践是通过 db-connection-pool 来保证自动故障转移

(6)【服务层】到【数据库写】的高可用,是通过写库的冗余实现的,常见实践是 keepalived + virtual IP 自动故障转移

附录二:常用的优化方案和原理

比如,在多个 Web 服务器上添加 负载平衡器可以解决哪些问题? CDN 解决哪些问题?Master-Slave Replicas 解决哪些问题? 替代方案是什么?怎么对每一个替代方案进行权衡比较?

  • DNS
  • CDN
  • 负载均衡器
  • 水平扩展
  • 反向代理(web 服务器)
  • 应用层
  • 缓存
  • 关系型数据库管理系统 (RDBMS)
  • SQL write master-slave failover
  • 主从复制
  • 一致性模式
  • 可用性模式

参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK