参考
系统设计问题
System Design Interviews: A step by step guide
- 需求澄清
- 系统接口设计
- Back-of the envelope estimation 粗略估计
- 系统规模(what scale is expected from the system)
- 存储需求
- 贷款需求
- 定义数据模型(Defining data model)
- 高级设计(High-level design)
- 架构图
- 细节设计(Detailed design)
- 分布式存储
- 多级缓存设
- 负载均衡
- 找到并解决系统瓶颈(Identify and resolving bottlenecks)
- 单点问题
- 存储备份
- 熔断限流
- 兜底设计
Designing a URL Shortening service like TinyURL
需求背景
系统需求及目标
- 功能需求(Functional Requirement)
-
给定一个URL,可以产出一个唯一的短的URL,短链接
-
当用户点击短链接,可以重定向原始链接
-
用户可以定制化短链接
-
短链接应该有个默认的过期时间,用户可定制
-
- 非功能需求(Non-Functional Requirement)
- 系统高可用
- URL重定向应该实时的,并且最小化延迟
- 短链接应该不可预测
- 扩展需求(Extented Requirement)
容量预估及限制
系统是一个读比较多的系统,假设读写比例100:1
- 吞吐预估(Traffic estimates)
-
假设一个月有500M的新URL
-
QPS预估,创建新URL
-
考虑到读写比100:1, URL重定向/每秒
-
- 存储预估(Storage estimates)
-
假设每个短链接存储5年。因为500M/月的新建,链接数:
-
假设每个短链接500字节,存储容量:
-
- 带宽预估(Bandwidth estimates)
-
对于写请求200个/s,每秒请求大小:
-
对于读请求,20K/s重定向:
-
- 内存预估(Memory estimates)
-
按照八二法则,20%的URL占用了80%贷款,我们可以缓存20%的URL
-
我们有20K/s请求,那么一天的请求:
-
缓存20%:
-
有很多duplicate请求,实际的存储低于170 GB
-
- 高水平评估(High level estimates):假设一个月新建500 million URLs,读写比例100:1 | 类别 | 预估 | | --- | --- | | New URLs | | | URL重定向 | | | 入数据 | | | 出数据 | | | 存储5年 | 170GB$ |
系统API
/**
* @param api_dev_key: The API developer key of a registed account.
* @param orignal_url: Original URL to be shortened
* @param custom_alias: Optional custom key for the URL
* @param user_name: Optinal user name to be used in encoding
* @param expire_date: Optinal expiration date for the shortened URL
*
* @return: succ: the shorened URL, fail: error code
*/
createURL(api_dev_key, orignal_url, custom_alias=None, user_name=None, expire_data=None)
/**
* @param api_dev_key: The API developer key of a registed account.
* @param url_key: representing the shortened URL to be retrieved
*
* @return: succ: 'URL Removed'
*/
deleteURL(api_dev_key, url_key)
数据库设计
基础系统设计及算法
两种方案:
Encoding actual URL
计算每个URL的唯一hash(MD5或者SHA256算法),我们仅仅预留了8字节后缀,MD5和Base64都超标了
Generating keys offline
使用KEY服务(Key Generation Service KGS)
- 并发问题
- KGS使用两个表存储keys:一张已用的表,一张未用的表,并且可以使用缓存加快速度
- 使用锁
- Key数据库大小:使用5字节KEY,总共可以产生68.7B唯一的keys
- 单点问题:使用副本
- 每个应用服务器可以缓存keys:加快速度
- key查找
- Custom aliases限制
数据分区及副本
- 范围分区
- 基于首字母:带来数据不平衡
- Hash分区
Cache
- 需要多少缓存:20%的热点数据缓存,170GB左右
- 缓存回收策略(Cache eviction):LRU(Least Recently Used)
- 副本更新
负载均衡
三个地方可以使用负载均衡
- 客户端和服务端
- 服务端和数据库
- 服务端和缓存服务
负载均衡算法:
- Round-Robin(轮询调度算法):如果有台服务变慢,无法感知
数据清理(Purging or DB cleanup)
Lazy清理
- 当用于访问过期的链接,我们可以删除这个链接,并返回错误给用户
- 有个单独的清理服务,周期性从DB和Cache删除过期的链接
- 每个链接设置一个默认的过期时间
- 删除链接后,可以将此key重新放入key数据库,可以被重用
- 可以删除长期未被访问的链接
监控(Telemetry)
- 短链接被使用次数
- 用户位置
- 怎样存储这些采集数据
- 热点数据击穿问题