系统设计题回答思路和举例

  • 第一步:像面试官不断提问,搞清楚系统的使用场景
  • 系统的功能是什么
  • 系统的目标群体是什么
  • 系统的用户量有多大
  • 希望每秒钟处理多少请求?
  • 希望处理多少数据?
  • 希望的读写比率?
  • 第二步:创造一个高层级的设计
  • 画出主要的组件和连接 例如设计一个网络爬虫,在这一步只需要画出一个抽象的架构图即可,不需要很具体。

系统的一些性能指标

    1. 响应时间 响应时间指从发出请求开始到收到最后响应数据所需的时间,响应时间是系统最重要的性能指标其直观地反映了系统的“快慢”。
    2. 并发数 并发数指系统能够同时处理请求的数目,这个数字反映了系统的负载特性。
    3. 吞吐量 吞吐量指单位时间内系统处理的请求数量,体现系统的整体处理能力。 QPS(Query Per Second):服务器每秒可以执行的查询次数 TPS(Transaction Per Second):服务器每秒处理的事务数 并发数=QPS*平均响应时间
    4. 经常听到的一些系统活跃度的名词
  • PV(Page View) 页面点击量或者浏览量,用户每次对网站中的每个页面访问均被记录一个PV,多次访问则会累计。
    • MAU(monthly active users):月活跃用户人数。
    • DAU(Daily Active User):日活跃用户数量。
    • IP(Internet Protocol) 指一天内访问某站点的IP总数,以用户的IP地址作为统计的指标,相同IP多次访问某站点算一次 IP和UV的区别: 在同一个IP地址下,两个不同的账号访问同一个站点,UV算两次,IP算一次
    • UV(Unique visitor) 独立访客,统计一天内访问网站的用户数,一个用户多次访问网站算一个用户
  1. 常用软件的QPS 通过了解这些软件的QPS可以更清楚地找出系统的瓶颈所在。
  •         Nginx:一般Nginx的QPS是比较大的,单机的可达到30万
    • Memcached:大概在几十万左右
    • Tomcat:单机 Tomcat 的QPS 在 2万左右。
    • Redis:大概在几万左右,像set命令甚至可达10万
    • MySQL:对于读操作可达几百k,对于写操作更低,大概只有100k

经典系统设计题与思路

  • 这里列举了一些比较经典的系统设计题,并给出了解题思路,该部分内容来源于Gitbook

分布式ID生成器

  • 如何设计一个分布式ID生成器(Distributed ID Generator),并保证ID按时间粗略有序?
应用场景(Scenario)
  • 现实中很多业务都有生成唯一ID的需求,例如:
    • 用户ID
    • 微博ID
    • 聊天消息ID
    • 帖子ID
    • 订单ID
需求(Needs)
  • 这个ID往往会作为数据库主键,所以需要保证全局唯一。数据库会在这个字段上建立聚集索引(Clustered Index,参考 MySQL InnoDB),即该字段会影响各条数据再物理存储上的顺序。 ID还要尽可能,节省内存,让数据库索引效率更高。基本上64位整数能够满足绝大多数的场景,但是如果能做到比64位更短那就更好了。需要根据具体业务进行分析,预估出ID的最大值,这个最大值通常比64位整数的上限小很多,于是我们可以用更少的bit表示这个ID。 查询的时候,往往有分页或者排序的需求,所以需要给每条数据添加一个时间字段,并在其上建立普通索引(Secondary Index)。但是普通索引的访问效率比聚集索引慢,如果能够让ID按照时间粗略有序,则可以省去这个时间字段。为什么不是按照时间精确有序呢?因为按照时间精确有序是做不到的,除非用一个单机算法,在分布式场景下做到精确有序性能一般很差。 这就引出了ID生成的三大核心需求:
    • 全局唯一(unique)
    • 按照时间粗略有序(sortable by time)
    • 尽可能短
  • 下面介绍一些常用的生成ID的方法。
UUID
  • 用过MongoDB的人会知道,MongoDB会自动给每一条数据赋予一个唯一的ObjectId,保证不会重复,这是怎么做到的呢?实际上它用的是一种UUID算法,生成的ObjectId占12个字节,由以下几个部分组成,
    • 4个字节表示的Unix timestamp,
    • 3个字节表示的机器的ID
    • 2个字节表示的进程ID
    • 3个字节表示的计数器
  • UUID是一类算法的统称,具体有不同的实现。UUID的优点是每台机器可以独立产生ID,理论上保证不会重复,所以天然是分布式的,缺点是生成的ID太长,不仅占用内存,而且索引查询效率低。
多台MySQL服务器
  • 既然MySQL可以产生自增ID,那么用多台MySQL服务器,能否组成一个高性能的分布式发号器呢?显然可以。 假设用8台MySQL服务器协同工作,第一台MySQL初始值是1,每次自增8,第二台MySQL初始值是2,每次自增8,依次类推。前面用一个 round-robin load balancer 挡着,每来一个请求,由 round-robin balancer 随机地将请求发给8台MySQL中的任意一个,然后返回一个ID。 Flickr就是这么做的,仅仅使用了两台MySQL服务器。可见这个方法虽然简单无脑,但是性能足够好。不过要注意,在MySQL中,不需要把所有ID都存下来,每台机器只需要存一个MAX_ID就可以了。这需要用到MySQL的一个REPLACE INTO特性。 这个方法跟单台数据库比,缺点是ID是不是严格递增的,只是粗略递增的。不过这个问题不大,我们的目标是粗略有序,不需要严格递增。
Twitter Snowflake
  • 比如 Twitter 有个成熟的开源项目,就是专门生成ID的,Twitter Snowflake 。Snowflake的核心算法如下:

    最高位不用,永远为0,其余三组bit占位均可浮动,看具体的业务需求而定。默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器,序列号支持1毫秒产生4095个自增序列id。 Instagram用了类似的方案,41位表示时间戳,13位表示shard Id(一个shard Id对应一台PostgreSQL机器),最低10位表示自增ID,怎么样,跟Snowflake的设计非常类似吧。这个方案用一个PostgreSQL集群代替了Twitter Snowflake 集群,优点是利用了现成的PostgreSQL,容易懂,维护方便。 有的面试官会问,如何让ID可以粗略的按照时间排序?上面的这种格式的ID,含有时间戳,且在高位,恰好满足要求。如果面试官又问,如何保证ID严格有序呢?在分布式这个场景下,是做不到的,要想高性能,只能做到粗略有序,无法保证严格有序。

短网址系统

  • 如何设计一个短网址服务(TinyURL)?
使用场景(Scenario)
  • 微博和Twitter都有140字数的限制,如果分享一个长网址,很容易就超出限制,发布出去。短网址服务可以把一个长网址变成短网址,方便在社交网络上传播。
需求(Needs)
  • 很显然,要尽可能的。长度设计为多少才合适呢?
短网址的长度
  • 当前互联网上的网页总数大概是 45亿,45亿超过了 2^{32}=4294967296232=4294967296,但远远小于64位整数的上限值,那么用一个64位整数足够了。 微博的短网址服务用的是长度为7的字符串,这个字符串可以看做是62进制的数,那么最大能表示{62}^7=352161****208627=3521614606208个网址,远远大于45亿。所以长度为7就足够了。 一个64位整数如何转化为字符串呢?,假设我们只是用大小写字母加数字,那么可以看做是62进制数,log_{62} {(2^{64}-1)}=10.7log62(264−1)=10.7,即字符串最长11就足够了。 实际生产中,还可以再短一点,比如新浪微博采用的长度就是7,因为 62^7=352161****208627=3521614606208,这个量级远远超过互联网上的URL总数了,绝对够用了。 现代的web服务器(例如Apache, Nginx)大部分都区分URL里的大小写了,所以用大小写字母来区分不同的URL是没问题的。 因此,正确答案:长度不超过7的字符串,由大小写字母加数字共62个字母组成
一对一还是一对多映射?
  • 一个长网址,对应一个短网址,还是可以对应多个短网址?这也是个重大选择问题 一般而言,一个长网址,在不同的地点,不同的用户等情况下,生成的短网址应该不一样,这样,在后端数据库中,可以更好的进行数据分析。如果一个长网址与一个短网址一一对应,那么在数据库中,仅有一行数据,无法区分不同的来源,就无法做数据分析了。 以这个7位长度的短网址作为唯一ID,这个ID下可以挂各种信息,比如生成该网址的用户名,所在网站,HTTP头部的 User Agent等信息,收集了这些信息,才有可能在后面做大数据分析,挖掘数据的价值。短网址服务商的一大盈利来源就是这些数据。 正确答案:一对多
如何计算短网址
  • 现在我们设定了短网址是一个长度为7的字符串,如何计算得到这个短网址呢? 最容易想到的办法是哈希,先hash得到一个64位整数,将它转化为62进制整,截取低7位即可。但是哈希算***有冲突,如何处理冲突呢,又是一个麻烦。这个方法只是转移了矛盾,没有解决矛盾,抛弃。 **正确答案:**分布式ID生成器
如何存储
  • 如果存储短网址和长网址的对应关系?以短网址为 primary key, 长网址为value, 可以用传统的关系数据库存起来,例如MySQL, PostgreSQL,也可以用任意一个分布式KV数据库,例如Redis, LevelDB。 如果你手痒想要手工设计这个存储,那就是另一个话题了,你需要完整地造一个KV存储引擎轮子。当前流行的KV存储引擎有LevelDB和RockDB,去读它们的源码吧
301还是302重定向
  • 这也是一个有意思的问题。这个问题主要是考察你对301和302的理解,以及浏览器缓存机制的理解。 301是永久重定向,302是临时重定向。短地址一经生成就不会变化,所以用301是符合http语义的。但是如果用了301, Google,百度等搜索引擎,搜索的时候会直接展示真实地址,那我们就无法统计到短地址被点击的次数了,也无法收集用户的Cookie, User Agent 等信息,这些信息可以用来做很多有意思的大数据分析,也是短网址服务商的主要盈利来源。 所以,正确答案是302重定向。 可以抓包看看新浪微博的短网址是怎么做的,使用 Chrome 浏览器,是我事先发微博自动生成的短网址。来抓包看看返回的结果是啥


     
  • 可见新浪微博用的就是302临时重定向。
预防攻击
  • 如果一些别有用心的黑客,短时间内向TinyURL服务器发送大量的请求,会迅速耗光ID,怎么办呢? 首先,限制IP的单日请求总数,超过阈值则直接拒绝服务。 光限制IP的请求数还不够,因为黑客一般手里有上百万台肉鸡的,IP地址大大的有,所以光限制IP作用不大。 可以用一台Redis作为缓存服务器,存储的不是 ID->长网址,而是 长网址->ID,仅存储一天以内的数据,用LRU机制进行淘汰。这样,如果黑客大量发同一个长网址过来,直接从缓存服务器里返回短网址即可,他就无法耗光我们的ID了。
<think>嗯,用户想了解系统设计面试中的常见问基础知识。首先,我需要回忆一下系统设计通常涵盖哪些方面。系统设计面试通常涉及架构设计、可扩展性、可用性、一致性等主。比如,设计一个短链服务或者分布式系统需要考虑的因素。 接下来,我应该整理常见的系统设计。例如,设计推特、设计电商系统、设计分布式缓存等。这些都是经典目。用户可能希望了解这些问的解思路,而不仅仅是问本身。所以需要结合实例,说明每个问的关键点需要考虑的组件。 然后,用户提到八股文,也就是那些常被问到的基础知识。比如CAP定理、负载均衡策略、数据库分片等。这部分需要简明扼要地列出概念,并给出实际应用的例子。例如,解释CAP定理时,要说明一致性、可用性、分区容忍性之间的权衡,以及不同系统如何选择。 用户提供的引用中有提到应用场景实际案例的重要性,比如引用[1]引用[2]。所以在回答时,每个问或概念都应结合实际应用场景,比如说明在什么情况下使用缓存,或者如何解决高并发系统的瓶颈。例如,在讨论数据库优化时,可以提到读写分离分库分表,并结合电商大促的场景。 另外,用户可能对系统设计中的具体技术实现感兴趣,比如如何设计API网关、服务发现机制等。这些需要简要解释其作用,并举例说明。比如,API网关负责路由、鉴权、限流,可以引用微服务架构中的实际应用。 还需要注意系统设计中的权衡,比如在一致性可用性之间如何选择,不同的存储方案优缺点比较。这部分需要结合CAP定理实际系统,如金融系统更强调一致性,而社交平台可能更注重可用性。 最后,生成的相关问需要覆盖系统设计的各个方面,比如性能优化、容错机制、数据一致性等,帮助用户进一步深入理解。同时,确保回答结构清晰,分点列出,便于用户逐步掌握系统设计的核心要点。</think># 系统设计面试常见问与基础知识 ## 一、核心设计原则 1. **可扩展性** - 垂直扩展(增加单机资源)与水平扩展(增加机器数量)的对比 - 例如:电商系统通过分库分表实现水平扩展[^1] 2. **可用性** $$ \text{可用性} = \frac{\text{系统正常运行时间}}{\text{总运行时间}} \times 100\% $$ - 常用SLA指标:99.9%(年停机时间≤8.76小时) 3. **一致性模型** - 强一致性(CP系统) vs 最终一致性(AP系统)[^2] ## 二、高频设计目 1. **短链系统设计** - 核心组件:哈希算法(如Base62)、分布式ID生成器、缓存层(Redis) - 存储方案:长链与短链映射关系存储,考虑冷热数据分离 2. **分布式缓存设计** ```java // 典型缓存穿透解决方案示例 public Object getData(String key) { Object value = cache.get(key); if (value == null) { synchronized(this) { value = db.get(key); cache.set(key, value, TTL); } } return value; } ``` 3. **秒杀系统设计** - 流量削峰:令牌桶限流、队列缓冲 - 库存扣减:Redis原子操作+Lua脚本保证一致性[^3] ## 三、关键技术点 1. **CAP定理应用** | 系统类型 | 典型选择 | 应用场景 | |----------|------------|-------------------| | CP | ZooKeeper | 分布式协调 | | AP | Cassandra | 社交网络数据存储 | 2. **负载均衡策略** - 轮询(Round Robin) - 加权轮询(Weighted Round Robin) - 最少连接(Least Connections)[^4] 3. **数据库优化** - 读写分离架构:主库处理写操作,从库处理读操作 - 分库分表策略:按用户ID哈希分片 ## 四、典型场景解决方案 1. **高并发读场景** - 使用CDN加速静态资源分发 - 浏览器缓存策略设置(Cache-Control头) 2. **数据一致性保障** - 二阶段提交(2PC)协议 - 最终一致性补偿机制(消息队列+重试) 3. **容灾设计** - 多可用区部署 - 灰度发布机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值