学习本文可以有以下收获
1、了解如何设计大型系统
2、拿捏面试
面试中我们常常被问到系统设计这一块的问题,那么作为系统设计的新手,我们首先需要对通用原则具有基本的了解,知道它们是什么,怎么使用它们以及它们的缺点。话不多说,直接进入正题。
- 垂直缩放
- 水平缩放
- 缓存
- 负载均衡
- 数据库复制
- 数据库分区
- 涵盖的内容:
- 首先可以观看可扩展性视频讲座哈佛可扩展性讲座https://www.youtube.com/watch?v=-W9F__D3oY4
- 查看可扩展性文章可扩展性http://www.lecloud.net/tagged/scalability/chrono当我们学习完上面的知识后,那么接下来我们需要更高的层次去权衡
- 性能与可扩展性
- 延迟与吞吐量
- 可用性与一致性
- 克隆
- 数据库
- 缓存
- 异步
- 涵盖的主题
性能与可扩展性
如果服务以与添加的资源成比例的方式提高性能,则服务是**可扩展的。**通常,提高性能意味着服务更多的工作单元,但也可以处理更大的工作单元,例如当数据集增长时。
另一种查看性能与可扩展性的方法:
- 如果您有性能问题,您的系统对于单个用户来说很慢。
- 如果您有可扩展性问题,您的系统对于单个用户来说速度很快,但在重负载下速度很慢。
我们可以进一步的阅读了解
- 了解延迟与吞吐量
https://community.cadence.com/cadence_blogs_8/b/sd/archive/2010/09/13/understanding-latency-vs-throughput
- 可扩展性、可用性、稳定性、模式
- http://www.slideshare.net/jboner/scalability-availability-stability-patterns/
延迟与吞吐量
延迟是执行某些操作或产生某些结果的时间。
吞吐量是单位时间内此类操作或结果的数量。
通常,您应该以可接受延迟的最大吞吐量为目标。
深入学习可以进一步阅读
- 了解延迟与吞吐量
https://community.cadence.com/cadence_blogs_8/b/sd/archive/2010/09/13/understanding-latency-vs-throughput
可用性与一致性
CAP
资料来源(重新审视CAP定理):http://robertgreiner.com/2014/08/cap-theorem-revisited
在分布式计算机系统中,您只能支持以下两种保证:
- 一致性- 每次读取都会收到最近的写入或错误
- 可用性- 每个请求都会收到响应,但不保证它包含最新版本的信息
- 分区容限- 尽管由于网络故障导致任意分区,系统仍继续运行
网络不可靠,因此您需要支持分区容错。您需要在一致性和可用性之间进行软件权衡。
CP - 一致性和分区容错
等待来自分区节点的响应可能会导致超时错误。如果您的业务需要原子读写,CP 是一个不错的选择。
AP - 可用性和分区容错
响应返回任何节点上可用的最容易获得的数据版本,这可能不是最新的。解析分区后,写入可能需要一些时间才能传播。
如果业务需求允许最终的一致性,或者当系统需要在外部错误的情况下继续工作时,AP 是一个不错的选择。
进一步阅读:
- 重新审视 CAP 定理
http://robertgreiner.com/2014/08/cap-theorem-revisited/)
- CAP 定理的简单英文介绍
http://ksat.me/a-plain-english-introduction-to-cap-theorem
- CAP 常见问题
https://github.com/henryr/cap-fa
- CAP 定理
https://www.youtube.com/watch?v=k-Yaq8AHlF
一致性
拥有一致的数据视图。回想一下CAP 定理中一致性定义——每次读取都会收到最近的写入或错误。
弱一致性
写入后,读取可能会或可能不会看到它。采取了尽力而为的方法。
这种方法见于 memcached 等系统。弱一致性适用于实时用例,例如 VoIP、视频聊天和实时多人游戏。例如,如果您正在接听电话并在几秒钟内无法接收信号,那么当您重新连接时,您将听不到在连接中断期间所说的内容。
最终一致性
写入后,读取最终会看到它(通常在几毫秒内)。数据是异步复制的。
这种方法见于 DNS 和电子邮件等系统。最终一致性在高可用性系统中运行良好。
强一致性
写入后,读取将看到它。数据同步复制。
这种方法出现在文件系统和 RDBMS 中。强一致性在需要事务的系统中运行良好。
到这里我们可以进一步阅读
- 跨数据中心的交易
http://snarfed.org/transactions_across_datacenters_io.html
可用性模式
支持高可用性有两种互补模式:故障转移和复制。
故障转移
主动-被动
使用主动-被动故障转移,心跳会在备用的主动和被动服务器之间发送。如果心跳中断,则被动服务器接管主动服务器的 IP 地址并恢复服务。
停机时间的长短取决于被动服务器是否已经在“热”备用状态下运行,或者它是否需要从“冷”备用状态启动。只有活动服务器处理流量。
主动-被动故障转移也可以称为主从故障转移。
主动-主动
在主动-主动中,两台服务器都在管理流量,在它们之间分散负载。
如果服务器面向公众,则 DNS 需要了解两台服务器的公共 IP。如果服务器是面向内部的,则应用程序逻辑需要了解两台服务器。
主动-主动故障转移也可以称为主-主故障转移。
缺点:故障转移
- 故障转移增加了更多的硬件和额外的复杂性。
- 如果主动系统在任何新写入的数据可以复制到被动系统之前发生故障,则可能会丢失数据。
复制
主从复制和主主复制
数据库部分将进一步讨论该主题:
- 主从复制
https://github.com/donnemartin/system-design-primer#master-slave-replication
- 主主复制
https://github.com/donnemartin/system-design-primer#master-master-replication
分片
分片将数据分布在不同的数据库中,这样每个数据库只能管理数据的一个子集。以用户数据库为例,随着用户数量的增加,集群中会添加更多的分片。
分片导致更少的读写流量、更少的复制和更多的缓存命中。索引大小也减少了,这通常会通过更快的查询来提高性能。如果一个分片出现故障,其他分片仍然可以运行,尽管您需要添加某种形式的复制以避免数据丢失。与联邦一样,没有单个中央主控序列化写入,允许您并行写入并增加吞吐量。
对用户表进行分片的常用方法是通过用户的姓氏首字母或用户的地理位置。
缺点:分片
- 再平衡增加了额外的复杂性。基于一致性哈希的分片功能可以减少传输的数据量。
- 您需要更新应用程序逻辑以使用分片,这可能会导致复杂的 SQL 查询。
- 分片中的数据分布可能会变得不平衡。例如,与其他分片相比,分片上的一组高级用户可能会导致该分片的负载增加。
- 连接来自多个分片的数据更加复杂。
- 分片增加了更多的硬件和额外的复杂性。
域名系统
域名系统 (DNS) 将诸如www.example.com之类的域名转换为 IP 地址。
DNS 是分层的,顶层有一些权威服务器。您的路由器或 ISP 提供有关在进行查找时要联系的 DNS 服务器的信息。较低级别的 DNS 服务器缓存映射,这可能由于 DNS 传播延迟而变得陈旧。DNS 结果也可以由您的浏览器或操作系统缓存一段时间,由生存时间 (TTL)确定。
NS 记录(名称服务器) - 为您的域/子域指定 DNS 服务器。
MX 记录(邮件交换) - 指定接受邮件的邮件服务器。
记录(地址) - 将名称指向 IP 地址。
CNAME(规范) - 将名称指向另一个名称或CNAME(example.com 到www.example.com)或A记录。
CloudFlare和Route 53等服务提供托管 DNS 服务。一些 DNS 服务可以通过各种方法路由流量:
加权循环
- 防止流量进入维护中的服务器
- 不同集群大小之间的平衡
- A/B 测试
基于延迟
基于地理位置
DNS的缺点
访问DNS服务器会带来轻微的延迟,尽管上述缓存可以缓解这种延迟。DNS服务器管理可能很复杂,通常由政府、ISP 和大公司管理。DNS服务最近受到DDoS 攻击,阻止用户在不知道 Twitter 的 IP 地址的情况下访问 Twitter 等网站。
内容网络分发
来源(为什么要使用CDN):https://www.creative-artworks.eu/why-use-a-content-delivery-network-cdn/
内容交付网络 (CDN) 是一个全球分布的代理服务器网络,从更靠近用户的位置提供内容。通常,静态文件(如 HTML/CSS/JS、照片和视频)从 CDN 提供,尽管一些 CDN(如 Amazon 的 CloudFront)支持动态内容。该站点的 DNS 解析将告诉客户端要联系哪个服务器。
从 CDN 提供内容可以通过两种方式显著提高性能:
- 用户从靠近他们的数据中心接收内容
- 您的服务器不必为 CDN 满足的请求提供服务
推送 CDN
每当您的服务器发生更改时,推送 CDN 都会接收新内容。您对提供内容、直接上传到 CDN 以及重写 URL 以指向 CDN 负全部责任。您可以配置内容何时过期以及何时更新。仅在内容是新的或更改时才上传内容,从而最大限度地减少流量,但最大限度地增加存储空间。
流量较少的站点或内容不经常更新的站点可以很好地与推送 CDN 配合使用。内容被放置在 CDN 上一次,而不是定期重新拉取。
拉取 CDN
当第一个用户请求内容时,拉取 CDN 从您的服务器中获取新内容。您将内容留在服务器上并重写 URL 以指向 CDN。这会导致请求变慢,直到内容缓存在 CDN 上。
生存时间 (TTL)确定缓存内容的时间长度。拉取 CDN 可最大限度地减少 CDN 上的存储空间,但如果文件过期并在文件实际更改之前被拉取,则会产生冗余流量。
流量大的网站可以很好地使用拉式 CDN,因为流量分布更均匀,只有最近请求的内容保留在 CDN 上。
缺点:CDN
- CDN 成本可能很大,具体取决于流量,尽管这应该与不使用 CDN 所产生的额外成本相权衡。
- 如果在 TTL 过期之前更新内容,则内容可能已过时。
- CDN 需要更改静态内容的 URL 以指向 CDN。
来源和进一步阅读
- 全球分布式内容交付
- 推式和拉式 CDN 的区别
- 维基百科
负载均衡器
来源(资料来源:可扩展系统设计模式):http://horicky.blogspot.com/2010/10/scalable-system-design-patterns.html
负载平衡器将传入的客户端请求分发到计算资源,例如应用程序服务器和数据库。在每种情况下,负载均衡器都会将来自计算资源的响应返回给适当的客户端。负载均衡器在以下方面有效:
- 防止请求进入不健康的服务器
- 防止资源过载
- 帮助消除单点故障
- 负载均衡器可以使用硬件(昂贵的)或软件(例如 HAProxy)来实现。
其他好处包括:
SSL 终止- 解密传入请求并加密服务器响应,因此后端服务器不必执行这些潜在的昂贵操作 无需在每台服务器上安装X.509 证书 会话持久性- 如果 Web 应用程序不跟踪会话,则发出 cookie 并将特定客户端的请求路由到同一实例 为了防止出现故障,通常设置多个负载均衡器,无论是主动-被动还是主动-主动模式。
负载均衡器可以根据各种指标路由流量,包括:
- 随机负载
- 最小负载
- 循环或加权循环
- 传输层负载
- 应用层负载
负载均衡的缺点:
- 如果负载均衡器没有足够的资源或配置不正确,它可能会成为性能瓶颈。
- 引入负载平衡器以帮助消除单点故障会导致复杂性增加。
- 单个负载均衡器是单点故障,配置多个负载均衡器会进一步增加复杂性。
缓存
缓存可以缩短页面加载时间,并可以减少服务器和数据库的负载。在这个模型中,调度器会先查找之前是否已经发出过请求,并尝试找到之前的结果返回,以保存实际执行。
数据库通常受益于跨其分区的读取和写入的均匀分布。热门商品可能会扭曲分布,导致瓶颈。将缓存放在数据库前面可以帮助吸收不均匀的负载和流量峰值。
- 客户端缓存
- CDN缓存
- Web服务器缓存
- 数据库缓存
- 中间件缓存
缓存缺点
- 一致性问题
- 节点故障带来延迟
- 额外的开销和编码复杂度
异步
异步工作流有助于减少成本高昂的操作的请求时间,否则这些操作将在线执行。他们还可以通过提前完成耗时的工作来提供帮助,例如定期汇总数据。
消息队列
消息队列接收、保存和传递消息。如果操作太慢而无法内联执行,您可以使用具有以下工作流程的消息队列:
- 应用程序将作业发布到队列,然后通知用户作业状态
- 工作人员从队列中取出作业,对其进行处理,然后发出作业完成的信号
用户未被阻止,作业在后台处理。在此期间,客户端可能会选择性地进行少量处理,以使任务看起来像是已完成。例如,如果发布一条推文,这条推文可能会立即发布到您的时间线上,但可能需要一些时间才能将您的推文实际发送给您的所有关注者。
Redis作为一个简单的消息代理很有用,但消息可能会丢失。
RabbitMQ很受欢迎,但需要您适应“AMQP”协议并管理自己的节点。
Amazon SQS是托管的,但可能具有很高的延迟,并且有可能将消息传递两次。
任务队列
任务队列接收任务及其相关数据,运行它们,然后传递它们的结果。它们可以支持调度,并可用于在后台运行计算密集型作业。
Celery支持调度,主要支持 python。
背压
如果队列开始显著增长,队列大小可能会变得大于内存,从而导致缓存未命中、磁盘读取,甚至性能下降。背压可以通过限制队列大小来提供帮助,从而为队列中的作业保持高吞吐率和良好的响应时间。队列填满后,客户端会收到服务器繁忙或 HTTP 503 状态代码,以便稍后重试。客户端可以稍后重试请求,可能使用指数退避。
缺点:异步
- 廉价计算和实时工作流等用例可能更适合同步操作,因为引入队列会增加延迟和复杂性。
安全
安全是一个广泛的话题。除非您有丰富的经验、安全背景,或者正在申请需要安全知识的职位,否则您可能只需要了解基础知识:
- 在传输和静止时加密。
- 清理所有用户输入或暴露给用户的任何输入参数,以防止XSS和SQL 注入。
- 使用参数化查询来防止 SQL 注入。
- 使用最小权限原则。
以上就是系统设计的大体模块了,快学习起来吧。