系统设计_系统设计报告 - CSDN
精华内容
参与话题
  • 系统架构设计

    万次阅读 2018-09-06 14:03:25
    系统架构就类似于工程的结构。 一、传统架构 用传统的架构,1000并发量需要2太服务器做tomca集群 但是由于系统用的人越来越多,并发量越来越大待到并发量为10000时,需要20台服务器做tomcat集群。当tomcat...

    什么是架构?

    架构就相当于我们要盖一栋楼时的框架。系统架构就类似于工程的结构。

    一、传统架构

    这里写图片描述
    用传统的架构,1000并发量需要2太服务器做tomca集群
    这里写图片描述
    但是由于系统用的人越来越多,并发量越来越大待到并发量为10000时,需要20台服务器做tomcat集群。当tomcat集群中节点数量增加,服务器能量先增加后下降。所以集群中节点的数量不能太多,一般也就5个左右。难以实现高数据量的并发,5台服务器难以正常工作。
    什么是集群?
    集群就是多个服务器做的是同一件事、运行同一个工程。也就是说同一个工程部署到多台服务器上。

    二、分布式架构

    能用硬件解决的问题就不用软件解决、硬件解决不了就用软件解决。
    如何用软件解决?
    当并发数高时,需要按照功能吧系统拆分,拆分成独立的功能。单独为某一个节点添加服务器。需要系统之间配合才能完成整个业务逻辑,叫做分布式
    分布式架构:把系统安装模块拆分成多个子系统,多个子系统相互协作才能完成业务流程,系统之间需要进行通信。
    这里写图片描述
    分布式架构优点:

    1. 把模块拆分,使用接口通信,降低模块之间的耦合度。
    2. 把项目拆分成若干个子项目,不同的软对负责不同的子项目。
    3. 增加功能时,只需要增加一个子项目,调用其他系统的接口就可以。
    4. 可以灵活的进行分布式部署。

    分布式的缺点:

    • 系统之间交互需要使用远程通信,接口开发增加工作量。
    • 各个模块有一些通用的业务逻辑无法使用。

    三、基于SOA的架构

    为了解决分布式的架构的缺点,我们可以使用基于SOA的架构。SOA:Service Oriented Architecture 面向服务架构。也就是把工程拆分成服务层、表现层两个工程。服务层中包含业务逻辑,只需要对外提供服务即可。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。
    这里写图片描述

    四、小编做的网上商城项目的系统架构如下:

    这里写图片描述

    • dubbo实现系统之间的通信
    • 用MyCat实现数据库集群
    • redis实现缓存
    • solr服务用于维护索引库
    • 消息队列MQ用于实现系统之间解耦用的。
    展开全文
  • 图书管理系统设计

    千次阅读 2019-03-27 22:37:42
    图书管理系统设计 设计要求: 设计图书管理数据库,基础数据包括图书信息、读者信息、读者借阅图书联系。 画出E-R图,并使用sql实现数据的定义,注意关系的完整性约束条件。 需求分析 学生可以查看自己借阅...

    图书管理系统设计

    设计要求:

     

    设计图书管理数据库,基础数据包括图书信息、读者信息、读者借阅图书联系。

     

    画出E-R图,并使用sql实现数据的定义,注意关系的完整性约束条件。

    • 需求分析
    1. 学生可以查看自己借阅的书籍、可以查阅书籍信息。
    2. 管理可以查看所有学生借阅的书籍。
    3. 学生归还图书之后,系统自动修改书籍的借阅信息。
    4. 管理员可以增加、修改、删除图书。
    5. 管理员可以注销学生信息。
    • 具体设计
    1. E-R图设计

    学生实体具有学号、专业、姓名、年龄、性别属性。

    图书实体具有图书编号、书名、图书分类、数量、出版日期、登记日期属性。

    1. R图如下图(1)所示。

     

    1. 表结构设计

    Book表

    Student表

    • 系统展示
    1. 学生表

    1. 图书表

     

    3.代码展示

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localhost_3306
    Source Server Version : 80012
    Source Host           : 127.0.0.1:3306
    Source Database       : class
    
    Target Server Type    : MYSQL
    Target Server Version : 80012
    File Encoding         : 65001
    
    Date: 2019-03-27 22:31:27
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for book
    -- ----------------------------
    DROP TABLE IF EXISTS `book`;
    CREATE TABLE `book` (
      `id` char(10) NOT NULL,
      `name` char(20) NOT NULL,
      `subject` char(20) DEFAULT NULL,
      `number` int(4) DEFAULT NULL,
      `publish_date` date DEFAULT NULL,
      `read_date` date DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of book
    -- ----------------------------
    INSERT INTO `book` VALUES ('a-20', '尼采自转', '哲学', '10', '2017-05-08', '2019-03-10');
    INSERT INTO `book` VALUES ('c-20', 'python', '计算机', '10', '2017-05-08', '2019-03-10');
    INSERT INTO `book` VALUES ('c-21', 'c', '计算机', '10', '2017-05-08', '2019-03-09');
    INSERT INTO `book` VALUES ('c-22', 'java', '计算机', '10', '2017-05-08', '2019-03-04');
    
    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localhost_3306
    Source Server Version : 80012
    Source Host           : 127.0.0.1:3306
    Source Database       : class
    
    Target Server Type    : MYSQL
    Target Server Version : 80012
    File Encoding         : 65001
    
    Date: 2019-03-27 22:31:34
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for student
    -- ----------------------------
    DROP TABLE IF EXISTS `student`;
    CREATE TABLE `student` (
      `id` int(5) NOT NULL,
      `name` char(10) NOT NULL,
      `subject` char(10) DEFAULT NULL,
      `age` int(2) DEFAULT NULL,
      `sex` char(2) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    INSERT INTO `student` VALUES ('1', '张三', '计科', '20', '男');
    INSERT INTO `student` VALUES ('2', '李四', '计科', '20', '男');
    INSERT INTO `student` VALUES ('3', '王五', '计科', '20', '女');
    

     

     

    展开全文
  • 系统设计入门

    万次阅读 2018-01-13 22:19:26
    译文地址:系统设计入门 译文出自:掘金翻译计划 译者:XatMassacrE、L9m、Airmacho、xiaoyusilen、jifaxu 这个 链接 用来查看本翻译与英文版是否有差别(如果你没有看到 README.md 发生变化,那就意味着这份...

    系统设计入门

    jj3A5N8.png

    翻译

    有兴趣参与翻译? 以下是正在进行中的翻译:

    目的

    学习如何设计大型系统。

    为系统设计的面试做准备。

    学习如何设计大型系统

    学习如何设计可扩展的系统将会有助于你成为一个更好的工程师。

    系统设计是一个很宽泛的话题。在互联网上,关于系统设计原则的资源也是多如牛毛。

    这个仓库就是这些资源的组织收集,它可以帮助你学习如何构建可扩展的系统。

    从开源社区学习

    这是一个不断更新的开源项目的初期的版本。

    欢迎贡献

    为系统设计的面试做准备

    在很多科技公司中,除了代码面试,系统设计也是技术面试过程中的一个必要环节

    实践常见的系统设计面试题并且把你的答案和例子的解答进行对照:讨论,代码和图表。

    面试准备的其他主题:

    抽认卡

    zdCAkB3.png

    这里提供的抽认卡堆使用间隔重复的方法,帮助你记忆关键的系统设计概念。

    随时随地都可使用。

    代码资源:互动式编程挑战

    你正在寻找资源以准备编程面试吗?

    b4YtAEN.png

    请查看我们的姐妹仓库互动式编程挑战,其中包含了一个额外的抽认卡堆:

    贡献

    从社区中学习。

    欢迎提交 PR 提供帮助:

    • 修复错误
    • 完善章节
    • 添加章节

    一些还需要完善的内容放在了正在完善中

    请查看贡献指南

    系统设计主题的索引

    各种系统设计主题的摘要,包括优点和缺点。每一个主题都面临着取舍和权衡

    每个章节都包含着更的资源的链接。

    jrUBAF7.png

    学习指引

    基于你面试的时间线(短、中、长)去复习那些推荐的主题。

    Imgur

    问:对于面试来说,我需要知道这里的所有知识点吗?

    答:不,如果只是为了准备面试的话,你并不需要知道所有的知识点。

    在一场面试中你会被问到什么取决于下面这些因素:

    • 你的经验
    • 你的技术背景
    • 你面试的职位
    • 你面试的公司
    • 运气

    那些有经验的候选人通常会被期望了解更多的系统设计的知识。架构师或者团队负责人则会被期望了解更多除了个人贡献之外的知识。顶级的科技公司通常也会有一次或者更多的系统设计面试。

    面试会很宽泛的展开并在几个领域深入。这回帮助你了解一些关于系统设计的不同的主题。基于你的时间线,经验,面试的职位和面试的公司对下面的指导做出适当的调整。

    • 短期 - 以系统设计主题的广度为目标。通过解决一些面试题来练习。
    • 中期 - 以系统设计主题的广度初级深度为目标。通过解决很多面试题来练习。
    • 长期 - 以系统设计主题的广度高级深度为目标。通过解决大部分面试题来联系。
    短期 中期 长期
    阅读 系统设计主题 以获得一个关于系统如何工作的宽泛的认识 :+1: :+1:
    阅读一些你要面试的公司工程博客的文章 :+1: :+1:
    阅读 真实架构 :+1: :+1:
    复习 如何处理一个系统设计面试题 :+1: :+1:
    完成 系统设计的面试题和解答 一些 很多
    完成 面向对象设计的面试题和解答 一些 很多
    复习 其它的系统设计面试题 一些 很多

    如何处理一个系统设计的面试题

    系统设计面试是一个开放式的对话。他们期望你去主导这个对话。

    你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

    第一步:描述使用场景,约束和假设

    把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

    • 谁会使用它?
    • 他们会怎样使用它?
    • 有多少用户?
    • 系统的作用是什么?
    • 系统的输入输出分别是什么?
    • 我们希望处理多少数据?
    • 我们希望每秒钟处理多少请求?
    • 我们希望的读写比率?

    第二步:创造一个高级的设计

    使用所有重要的组件来描绘出一个高级的设计。

    • 画出主要的组件和连接
    • 证明你的想法

    第三步:设计核心组件

    对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

    • 生成并储存一个完整 url 的 hash
      • MD5Base62
      • Hash 碰撞
      • SQL 还是 NoSQL
      • 数据库模型
    • 将一个 hashed url 翻译成完整的 url
      • 数据库查找
    • API 和面向对象设计

    第四步:度量设计

    确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成拓展性的议题吗?

    • 负载均衡
    • 水平拓展
    • 缓存
    • 数据库分片

    论述可能的解决办法和代价。每件事情需要取舍。可以使用可拓展系统的设计原则来处理瓶颈。

    信封背面的计算

    你或许会被要求通过手算进行一些估算。涉及到的附录涉及到的是下面的这些资源:

    相关资源和延伸阅读

    查看下面的链接以获得我们期望的更好的想法:

    系统设计的面试题和解答

    普通的系统设计面试题和相关事例的论述,代码和图表。

    与内容有关的解答在 solutions/ 文件夹中。

    问题
    设计 Pastebin.com (或者 Bit.ly) 解答
    设计 Twitter 时间线和搜索 (或者 Facebook feed 和搜索) 解答
    设计一个网页爬虫 解答
    设计 Mint.com 解答
    为一个社交网络设计数据结构 解答
    为搜索引擎设计一个 key-value 储存 解答
    通过分类特性设计 Amazon 的销售排名 解答
    在 AWS 上设计一个百万用户级别的系统 解答
    添加一个系统设计问题 贡献

    设计 Pastebin.com (或者 Bit.ly)

    查看实践与解答

    Imgur

    设计 Twitter 时间线和搜索 (或者 Facebook feed 和搜索)

    查看实践与解答

    Imgur

    设计一个网页爬虫

    查看实践与解答

    Imgur

    设计 Mint.com

    查看实践与解答

    Imgur

    为一个社交网络设计数据结构

    查看实践与解答

    Imgur

    为搜索引擎设计一个 key-value 储存

    查看实践与解答

    Imgur

    设计按类别分类的 Amazon 销售排名

    查看实践与解答

    Imgur

    在 AWS 上设计一个百万用户级别的系统

    查看实践与解答

    Imgur

    面向对象设计的面试问题及解答

    常见面向对象设计面试问题及实例讨论,代码和图表演示。

    与内容相关的解决方案在 solutions/ 文件夹中。

    注:此节还在完善中

    问题
    设计 hash map 解决方案
    设计 LRU 缓存 解决方案
    设计一个呼叫中心 解决方案
    设计一副牌 解决方案
    设计一个停车场 解决方案
    设计一个聊天服务 解决方案
    设计一个环形数组 待解决
    添加一个面向对象设计问题 待解决

    系统设计主题:从这里开始

    不熟悉系统设计?

    首先,你需要对一般性原则有一个基本的认识,知道它们是什么,怎样使用以及利弊。

    第一步:回顾可扩展性(scalability)的视频讲座

    哈佛大学可扩展性讲座

    • 主题涵盖
      • 垂直扩展(Vertical scaling)
      • 水平扩展(Horizontal scaling)
      • 缓存
      • 负载均衡
      • 数据库复制
      • 数据库分区

    第二步:回顾可扩展性文章

    可扩展性

    接下来的步骤

    接下来,我们将看看高阶的权衡和取舍:

    • 性能可扩展性
    • 延迟吞吐量
    • 可用性一致性

    记住每个方面都面临取舍和权衡

    然后,我们将深入更具体的主题,如 DNS、CDN 和负载均衡器。

    性能与可扩展性

    如果服务性能的增长与资源的增加是成比例的,服务就是可扩展的。通常,提高性能意味着服务于更多的工作单元,另一方面,当数据集增长时,同样也可以处理更大的工作单位。1

    另一个角度来看待性能与可扩展性:

    • 如果你的系统有性能问题,对于单个用户来说是缓慢的。
    • 如果你的系统有可扩展性问题,单个用户较快但在高负载下会变慢。

    来源及延伸阅读

    延迟与吞吐量

    延迟是执行操作或运算结果所花费的时间。

    吞吐量是单位时间内(执行)此类操作或运算的数量。

    通常,你应该以可接受级延迟最大化吞吐量为目标。

    来源及延伸阅读

    可用性与一致性

    CAP 理论

    bgLMI2u.png
    来源:再看 CAP 理论

    在一个分布式计算系统中,只能同时满足下列的两点:

    • 一致性 ─ 每次访问都能获得最新数据但可能会收到错误响应
    • 可用性 ─ 每次访问都能收到非错响应,但不保证获取到最新数据
    • 分区容错性 ─ 在任意分区网络故障的情况下系统仍能继续运行

    网络并不可靠,所以你应要支持分区容错性,并需要在软件可用性和一致性间做出取舍。

    CP ─ 一致性和分区容错性

    等待分区节点的响应可能会导致延时错误。如果你的业务需求需要原子读写,CP 是一个不错的选择。

    AP ─ 可用性与分区容错性

    响应节点上可用数据的最近版本可能并不是最新的。当分区解析完后,写入(操作)可能需要一些时间来传播。

    如果业务需求允许最终一致性,或当有外部故障时要求系统继续运行,AP 是一个不错的选择。

    来源及延伸阅读

    一致性模式

    有同一份数据的多份副本,我们面临着怎样同步它们的选择,以便让客户端有一致的显示数据。回想 CAP 理论中的一致性定义 ─ 每次访问都能获得最新数据但可能会收到错误响应

    弱一致性

    在写入之后,访问可能看到,也可能看不到(写入数据)。尽力优化之让其能访问最新数据。

    这种方式可以 memcached 等系统中看到。弱一致性在 VoIP,视频聊天和实时多人游戏等真实用例中表现不错。打个比方,如果你在通话中丢失信号几秒钟时间,当重新连接时你是听不到这几秒钟所说的话的。

    最终一致性

    在写入后,访问最终能看到写入数据(通常在数毫秒内)。数据被异步复制。

    DNS 和 email 等系统使用的是此种方式。最终一致性在高可用性系统中效果不错。

    强一致性

    在写入后,访问立即可见。数据被同步复制。

    文件系统和关系型数据库(RDBMS)中使用的是此种方式。强一致性在需要记录的系统中运作良好。

    来源及延伸阅读

    可用性模式

    有两种支持高可用性的模式: 故障切换(fail-over)复制(replication)

    故障切换

    工作到备用切换(Active-passive)

    关于工作到备用的故障切换流程是,工作服务器发送周期信号给待机中的备用服务器。如果周期信号中断,备用服务器切换成工作服务器的 IP 地址并恢复服务。

    宕机时间取决于备用服务器处于“热”待机状态还是需要从“冷”待机状态进行启动。只有工作服务器处理流量。

    工作到备用的故障切换也被称为主从切换。

    双工作切换(Active-active)

    在双工作切换中,双方都在管控流量,在它们之间分散负载。

    如果是外网服务器,DNS 将需要对两方都了解。如果是内网服务器,应用程序逻辑将需要对两方都了解。

    双工作切换也可以称为主主切换。

    缺陷:故障切换

    • 故障切换需要添加额外硬件并增加复杂性。
    • 如果新写入数据在能被复制到备用系统之前,工作系统出现了故障,则有可能会丢失数据。

    复制

    主─从复制和主─主复制

    这个主题进一步探讨了数据库部分:

    域名系统

    IOyLj4i.jpg
    来源:DNS 安全介绍

    域名系统是把 www.example.com 等域名转换成 IP 地址。

    域名系统是分层次的,一些 DNS 服务器位于顶层。当查询(域名) IP 时,路由或 ISP 提供连接 DNS 服务器的信息。较底层的 DNS 服务器缓存映射,它可能会因为 DNS 传播延时而失效。DNS 结果可以缓存在浏览器或操作系统中一段时间,时间长短取决于存活时间 TTL

    • NS 记录(域名服务) ─ 指定解析域名或子域名的 DNS 服务器。
    • MX 记录(邮件交换) ─ 指定接收信息的邮件服务器。
    • A 记录(地址) ─ 指定域名对应的 IP 地址记录。
    • CNAME(规范) ─ 一个域名映射到另一个域名或 CNAME 记录( example.com 指向 www.example.com )或映射到一个 A 记录。

    CloudFlareRoute 53 等平台提供管理 DNS 的功能。某些 DNS 服务通过集中方式来路由流量:

    • 加权轮询调度
      • 防止流量进入维护中的服务器
      • 在不同大小集群间负载均衡
      • A/B 测试
    • 基于延迟路由
    • 基于地理位置路由

    缺陷:DNS

    • 虽说缓存可以减轻 DNS 延迟,但连接 DNS 服务器还是带来了轻微的延迟。
    • 虽然它们通常由政府,网络服务提供商和大公司管理,但 DNS 服务管理仍可能是复杂的。
    • DNS 服务最近遭受 DDoS 攻击,阻止不知道 Twtter IP 地址的用户访问 Twiiter。

    来源及延伸阅读

    内容分发网络(CDN)

    h9TAuGI.jpg
    来源:为什么使用 CDN

    内容分发网络(CDN)是一个全球性的代理服务器分布式网络,它从靠近用户的位置提供内容。通常,HTML/CSS/JS,图片和视频等静态内容由 CDN 提供,虽然亚马逊 CloudFront 等也支持动态内容。CDN 的 DNS 解析会告知客户端连接哪台服务器。

    将内容存储在 CDN 上可以从两个方面来提供性能:

    • 从靠近用户的数据中心提供资源
    • 通过 CDN 你的服务器不必真的处理请求

    CDN 推送(push)

    当你服务器上内容发生变动时,推送 CDN 接受新内容。直接推送给 CDN 并重写 URL 地址以指向你的内容的 CDN 地址。你可以配置内容到期时间及何时更新。内容只有在更改或新增是才推送,流量最小化,但储存最大化。

    CDN 拉取(pull)

    CDN 拉取是当第一个用户请求该资源时,从服务器上拉取资源。你将内容留在自己的服务器上并重写 URL 指向 CDN 地址。直到内容被缓存在 CDN 上为止,这样请求只会更慢,

    存活时间(TTL)决定缓存多久时间。CDN 拉取方式最小化 CDN 上的储存空间,但如果过期文件并在实际更改之前被拉取,则会导致冗余的流量。

    高流量站点使用 CDN 拉取效果不错,因为只有最近请求的内容保存在 CDN 中,流量才能更平衡地分散。

    缺陷:CDN

    • CDN 成本可能因流量而异,可能在权衡之后你将不会使用 CDN。
    • 如果在 TTL 过期之前更新内容,CDN 缓存内容可能会过时。
    • CDN 需要更改静态内容的 URL 地址以指向 CDN。

    来源及延伸阅读

    负载均衡器

    h81n9iK.png
    来源:可扩展的系统设计模式

    负载均衡器将传入的请求分发到应用服务器和数据库等计算资源。无论哪种情况,负载均衡器将从计算资源来的响应返回给恰当的客户端。负载均衡器的效用在于:

    • 防止请求进入不好的服务器
    • 防止资源过载
    • 帮助消除单一的故障点

    负载均衡器可以通过硬件(昂贵)或 HAProxy 等软件来实现。
    增加的好处包括:

    • SSL 终结 ─ 解密传入的请求并加密服务器响应,这样的话后端服务器就不必再执行这些潜在高消耗运算了。
    • Session 留存 ─ 如果 Web 应用程序不追踪会话,发出 cookie 并将特定客户端的请求路由到同一实例。

    通常会设置采用工作─备用双工作 模式的多个负载均衡器,以免发生故障。

    负载均衡器能基于多种方式来路由流量:

    四层负载均衡

    四层负载均衡根据监看传输层的信息来决定如何分发请求。通常,这会涉及来源,目标 IP 地址和请求头中的端口,但不包括数据包(报文)内容。四层负载均衡执行网络地址转换(NAT)来向上游服务器转发网络数据包。

    七层负载均衡器

    七层负载均衡器根据监控应用层来决定怎样分发请求。这会涉及请求头的内容,消息和 cookie。七层负载均衡器终结网络流量,读取消息,做出负载均衡判定,然后传送给特定服务器。比如,一个七层负载均衡器能直接将视频流量连接到托管视频的服务器,同时将更敏感的用户账单流量引导到安全性更强的服务器。

    以损失灵活性为代价,四层负载均衡比七层负载均衡花费更少时间和计算资源,虽然这对现代商用硬件的性能影响甚微。

    水平扩展

    负载均衡器还能帮助水平扩展,提高性能和可用性。使用商业硬件的性价比更高,并且比在单台硬件上垂直扩展更贵的硬件具有更高的可用性。相比招聘特定企业系统人才,招聘商业硬件方面的人才更加容易。

    缺陷:水平扩展

    • 水平扩展引入了复杂度并涉及服务器复制
      • 服务器应该是无状态的:它们也不该包含像 session 或资料图片等与用户关联的数据。
      • session 可以集中存储在数据库或持久化缓存(Redis、Memcached)的数据存储区中。
    • 缓存和数据库等下游服务器需要随着上游服务器进行扩展,以处理更多的并发连接。

    缺陷:负载均衡器

    • 如果没有足够的资源配置或配置错误,负载均衡器会变成一个性能瓶颈。
    • 引入负载均衡器以帮助消除单点故障但导致了额外的复杂性。
    • 单个负载均衡器会导致单点故障,但配置多个负载均衡器会进一步增加复杂性。

    来源及延伸阅读

    反向代理(web 服务器)

    n41Azff.png
    资料来源:维基百科

    反向代理是一种可以集中地调用内部服务,并提供统一接口给公共客户的 web 服务器。来自客户端的请求先被反向代理服务器转发到可响应请求的服务器,然后代理再把服务器的响应结果返回给客户端。

    带来的好处包括:

    • 增加安全性 - 隐藏后端服务器的信息,屏蔽黑名单中的 IP,限制每个客户端的连接数。
    • 提高可扩展性和灵活性 - 客户端只能看到反向代理服务器的 IP,这使你可以增减服务器或者修改它们的配置。
    • 本地终结 SSL 会话 - 解密传入请求,加密服务器响应,这样后端服务器就不必完成这些潜在的高成本的操作。
      • 免除了在每个服务器上安装 X.509 证书的需要
    • 压缩 - 压缩服务器响应
    • 缓存 - 直接返回命中的缓存结果
    • 静态内容 - 直接提供静态内容
      • HTML/CSS/JS
      • 图片
      • 视频
      • 等等

    负载均衡器与反向代理

    • 当你有多个服务器时,部署负载均衡器非常有用。通常,负载均衡器将流量路由给一组功能相同的服务器上。
    • 即使只有一台 web 服务器或者应用服务器时,反向代理也有用,可以参考上一节介绍的好处。
    • NGINX 和 HAProxy 等解决方案可以同时支持第七层反向代理和负载均衡。

    不利之处:反向代理

    • 引入反向代理会增加系统的复杂度。
    • 单独一个反向代理服务器仍可能发生单点故障,配置多台反向代理服务器(如故障转移)会进一步增加复杂度。

    来源及延伸阅读

    应用层

    yB5SYwm.png
    资料来源:可缩放系统构架介绍

    将 Web 服务层与应用层(也被称作平台层)分离,可以独立缩放和配置这两层。添加新的 API 只需要添加应用服务器,而不必添加额外的 web 服务器。

    单一职责原则提倡小型的,自治的服务共同合作。小团队通过提供小型的服务,可以更激进地计划增长。

    应用层中的工作进程也有可以实现异步化

    微服务

    与此讨论相关的话题是 微服务,可以被描述为一系列可以独立部署的小型的,模块化服务。每个服务运行在一个独立的线程中,通过明确定义的轻量级机制通讯,共同实现业务目标。https://smartbear.com/learn/api-design/what-are-microservices>1

    例如,Pinterest 可能有这些微服务: 用户资料、关注者、Feed 流、搜索、照片上传等。

    服务发现

    ConsulEtcdZookeeper 这样的系统可以通过追踪注册名、地址、端口等信息来帮助服务互相发现对方。Health checks 可以帮助确认服务的完整性和是否经常使用一个 HTTP 路径。Consul 和 Etcd 都有一个内建的 key-value 存储 用来存储配置信息和其他的共享信息。

    不利之处:应用层

    • 添加由多个松耦合服务组成的应用层,从架构、运营、流程等层面来讲将非常不同(相对于单体系统)。
    • 微服务会增加部署和运营的复杂度。

    来源及延伸阅读

    数据库

    Xkm5CXz.png
    资料来源:扩展你的用户数到第一个一千万

    关系型数据库管理系统(RDBMS)

    像 SQL 这样的关系型数据库是一系列以表的形式组织的数据项集合。

    校对注:这里作者 SQL 可能指的是 MySQL

    ACID 用来描述关系型数据库事务的特性。

    • 原子性 - 每个事务内部所有操作要么全部完成,要么全部不完成。
    • 一致性 - 任何事务都使数据库从一个有效的状态转换到另一个有效状态。
    • 隔离性 - 并发执行事务的结果与顺序执行事务的结果相同。
    • 持久性 - 事务提交后,对系统的影响是永久的。

    关系型数据库扩展包括许多技术:主从复制主主复制联合分片非规范化SQL调优

    C9ioGtn.png
    资料来源:可扩展性、可用性、稳定性、模式

    主从复制

    主库同时负责读取和写入操作,并复制写入到一个或多个从库中,从库只负责读操作。树状形式的从库再将写入复制到更多的从库中去。如果主库离线,系统可以以只读模式运行,直到某个从库被提升为主库或有新的主库出现。

    不利之处:主从复制
    • 将从库提升为主库需要额外的逻辑。
    • 参考不利之处:复制中,主从复制和主主复制共同的问题。

    krAHLGg.png
    资料来源:可扩展性、可用性、稳定性、模式

    主主复制

    两个主库都负责读操作和写操作,写入操作时互相协调。如果其中一个主库挂机,系统可以继续读取和写入。

    不利之处: 主主复制
    • 你需要添加负载均衡器或者在应用逻辑中做改动,来确定写入哪一个数据库。
    • 多数主-主系统要么不能保证一致性(违反 ACID),要么因为同步产生了写入延迟。
    • 随着更多写入节点的加入和延迟的提高,如何解决冲突显得越发重要。
    • 参考不利之处:复制中,主从复制和主主复制共同的问题。
    不利之处:复制
    • 如果主库在将新写入的数据复制到其他节点前挂掉,则有数据丢失的可能。
    • 写入会被重放到负责读取操作的副本。副本可能因为过多写操作阻塞住,导致读取功能异常。
    • 读取从库越多,需要复制的写入数据就越多,导致更严重的复制延迟。
    • 在某些数据库系统中,写入主库的操作可以用多个线程并行写入,但读取副本只支持单线程顺序地写入。
    • 复制意味着更多的硬件和额外的复杂度。
    来源及延伸阅读

    联合

    U3qV33e.png
    资料来源:扩展你的用户数到第一个一千万

    联合(或按功能划分)将数据库按对应功能分割。例如,你可以有三个数据库:论坛用户产品,而不仅是一个单体数据库,从而减少每个数据库的读取和写入流量,减少复制延迟。较小的数据库意味着更多适合放入内存的数据,进而意味着更高的缓存命中几率。没有只能串行写入的中心化主库,你可以并行写入,提高负载能力。

    不利之处:联合
    • 如果你的数据库模式需要大量的功能和数据表,联合的效率并不好。
    • 你需要更新应用程序的逻辑来确定要读取和写入哪个数据库。
    • server link 从两个库联结数据更复杂。
    • 联合需要更多的硬件和额外的复杂度。
    来源及延伸阅读:联合

    分片

    wU8x5Id.png
    资料来源:可扩展性、可用性、稳定性、模式

    分片将数据分配在不同的数据库上,使得每个数据库仅管理整个数据集的一个子集。以用户数据库为例,随着用户数量的增加,越来越多的分片会被添加到集群中。

    类似联合的优点,分片可以减少读取和写入流量,减少复制并提高缓存命中率。也减少了索引,通常意味着查询更快,性能更好。如果一个分片出问题,其他的仍能运行,你可以使用某种形式的冗余来防止数据丢失。类似联合,没有只能串行写入的中心化主库,你可以并行写入,提高负载能力。

    常见的做法是用户姓氏的首字母或者用户的地理位置来分隔用户表。

    不利之处:分片
    • 你需要修改应用程序的逻辑来实现分片,这会带来复杂的 SQL 查询。
    • 分片不合理可能导致数据负载不均衡。例如,被频繁访问的用户数据会导致其所在分片的负载相对其他分片高。
      • 再平衡会引入额外的复杂度。基于一致性哈希的分片算法可以减少这种情况。
    • 联结多个分片的数据操作更复杂。
    • 分片需要更多的硬件和额外的复杂度。

    来源及延伸阅读:分片

    非规范化

    非规范化试图以写入性能为代价来换取读取性能。在多个表中冗余数据副本,以避免高成本的联结操作。一些关系型数据库,比如 PostgreSQl 和 Oracle 支持物化视图,可以处理冗余信息存储和保证冗余副本一致。

    当数据使用诸如联合分片等技术被分割,进一步提高了处理跨数据中心的联结操作复杂度。非规范化可以规避这种复杂的联结操作。

    在多数系统中,读取操作的频率远高于写入操作,比例可达到 100:1,甚至 1000:1。需要复杂的数据库联结的读取操作成本非常高,在磁盘操作上消耗了大量时间。

    不利之处:非规范化
    • 数据会冗余。
    • 约束可以帮助冗余的信息副本保持同步,但这样会增加数据库设计的复杂度。
    • 非规范化的数据库在高写入负载下性能可能比规范化的数据库差。
    来源及延伸阅读:非规范化

    SQL 调优

    SQL 调优是一个范围很广的话题,有很多相关的可以作为参考。

    利用基准测试性能分析来模拟和发现系统瓶颈很重要。

    • 基准测试 - 用 ab 等工具模拟高负载情况。
    • 性能分析 - 通过启用如慢查询日志等工具来辅助追踪性能问题。

    基准测试和性能分析可能会指引你到以下优化方案。

    改进模式
    • 为了实现快速访问,MySQL 在磁盘上用连续的块存储数据。
    • 使用 CHAR 类型存储固定长度的字段,不要用 VARCHAR
      • CHAR 在快速、随机访问时效率很高。如果使用 VARCHAR,如果你想读取下一个字符串,不得不先读取到当前字符串的末尾。
    • 使用 TEXT 类型存储大块的文本,例如博客正文。TEXT 还允许布尔搜索。使用 TEXT 字段需要在磁盘上存储一个用于定位文本块的指针。
    • 使用 INT 类型存储高达 2^32 或 40 亿的较大数字。
    • 使用 DECIMAL 类型存储货币可以避免浮点数表示错误。
    • 避免使用 BLOBS 存储对象,存储存放对象的位置。
    • VARCHAR(255) 是以 8 位数字存储的最大字符数,在某些关系型数据库中,最大限度地利用字节。
    • 在适用场景中设置 NOT NULL 约束来提高搜索性能
    使用正确的索引
    • 你正查询(SELECTGROUP BYORDER BYJOIN)的列如果用了索引会更快。
    • 索引通常表示为自平衡的 B 树,可以保持数据有序,并允许在对数时间内进行搜索,顺序访问,插入,删除操作。
    • 设置索引,会将数据存在内存中,占用了更多内存空间。
    • 写入操作会变慢,因为索引需要被更新。
    • 加载大量数据时,禁用索引再加载数据,然后重建索引,这样也许会更快。
    避免高成本的联结操作
    • 有性能需要,可以进行非规范化。
    分割数据表
    • 将热点数据拆分到单独的数据表中,可以有助于缓存。
    调优查询缓存
    来源及延伸阅读

    NoSQL

    NoSQL 是键-值数据库文档型数据库列型数据库图数据库的统称。数据库是非规范化的,表联结大多在应用程序代码中完成。大多数 NoSQL 无法实现真正符合 ACID 的事务,支持最终一致

    BASE 通常被用于描述 NoSQL 数据库的特性。相比 CAP 理论,BASE 强调可用性超过一致性。

    • 基本可用 - 系统保证可用性。
    • 软状态 - 即使没有输入,系统状态也可能随着时间变化。
    • 最终一致性 - 经过一段时间之后,系统最终会变一致,因为系统在此期间没有收到任何输入。

    除了在 SQL 还是 NoSQL 之间做选择,了解哪种类型的 NoSQL 数据库最适合你的用例也是非常有帮助的。我们将在下一节中快速了解下 键-值存储文档型存储列型存储图存储数据库。

    键-值存储

    抽象模型:哈希表

    键-值存储通常可以实现 O(1) 时间读写,用内存或 SSD 存储数据。数据存储可以按字典顺序维护键,从而实现键的高效检索。键-值存储可以用于存储元数据。

    键-值存储性能很高,通常用于存储简单数据模型或频繁修改的数据,如存放在内存中的缓存。键-值存储提供的操作有限,如果需要更多操作,复杂度将转嫁到应用程序层面。

    键-值存储是如文档存储,在某些情况下,甚至是图存储等更复杂的存储系统的基础。

    来源及延伸阅读

    文档类型存储

    抽象模型:将文档作为值的键-值存储

    文档类型存储以文档(XML、JSON、二进制文件等)为中心,文档存储了指定对象的全部信息。文档存储根据文档自身的内部结构提供 API 或查询语句来实现查询。请注意,许多键-值存储数据库有用值存储元数据的特性,这也模糊了这两种存储类型的界限。

    基于底层实现,文档可以根据集合、标签、元数据或者文件夹组织。尽管不同文档可以被组织在一起或者分成一组,但相互之间可能具有完全不同的字段。

    MongoDB 和 CouchDB 等一些文档类型存储还提供了类似 SQL 语言的查询语句来实现复杂查询。DynamoDB 同时支持键-值存储和文档类型存储。

    文档类型存储具备高度的灵活性,常用于处理偶尔变化的数据。

    来源及延伸阅读:文档类型存储

    列型存储

    n16iOGk.png
    资料来源: SQL 和 NoSQL,一个简短的历史

    抽象模型:嵌套的 ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>> 映射

    类型存储的基本数据单元是列(名/值对)。列可以在列族(类似于 SQL 的数据表)中被分组。超级列族再分组普通列族。你可以使用行键独立访问每一列,具有相同行键值的列组成一行。每个值都包含版本的时间戳用于解决版本冲突。

    Google 发布了第一个列型存储数据库 Bigtable,它影响了 Hadoop 生态系统中活跃的开源数据库 HBase 和 Facebook 的 Cassandra。像 BigTable,HBase 和 Cassandra 这样的存储系统将键以字母顺序存储,可以高效地读取键列。

    列型存储具备高可用性和高可扩展性。通常被用于大数据相关存储。

    来源及延伸阅读:列型存储

    图数据库

    fNcl65g.png
    资料来源:图数据库

    抽象模型: 图

    在图数据库中,一个节点对应一条记录,一个弧对应两个节点之间的关系。图数据库被优化用于表示外键繁多的复杂关系或多对多关系。

    图数据库为存储复杂关系的数据模型,如社交网络,提供了很高的性能。它们相对较新,尚未广泛应用,查找开发工具或者资源相对较难。许多图只能通过 REST API 访问。

    相关资源和延伸阅读:图

    来源及延伸阅读:NoSQL

    SQL 还是 NoSQL

    wXGqG5f.png
    资料来源:从 RDBMS 转换到 NoSQL

    选取 SQL 的原因:

    • 结构化数据
    • 严格的模式
    • 关系型数据
    • 需要复杂的联结操作
    • 事务
    • 清晰的扩展模式
    • 既有资源更丰富:开发者、社区、代码库、工具等
    • 通过索引进行查询非常快

    选取 NoSQL 的原因:

    • 半结构化数据
    • 动态或灵活的模式
    • 非关系型数据
    • 不需要复杂的联结操作
    • 存储 TB (甚至 PB)级别的数据
    • 高数据密集的工作负载
    • IOPS 高吞吐量

    适合 NoSQL 的示例数据:

    • 埋点数据和日志数据
    • 排行榜或者得分数据
    • 临时数据,如购物车
    • 频繁访问的(“热”)表
    • 元数据/查找表
    来源及延伸阅读:SQL 或 NoSQL

    缓存

    Q6z24La.png
    资料来源:可扩展的系统设计模式

    缓存可以提高页面加载速度,并可以减少服务器和数据库的负载。在这个模型中,分发器先查看请求之前是否被响应过,如果有则将之前的结果直接返回,来省掉真正的处理。

    数据库分片均匀分布的读取是最好的。但是热门数据会让读取分布不均匀,这样就会造成瓶颈,如果在数据库前加个缓存,就会抹平不均匀的负载和突发流量对数据库的影响。

    客户端缓存

    缓存可以位于客户端(操作系统或者浏览器),服务端或者不同的缓存层。

    CDN 缓存

    CDN 也被视为一种缓存。

    Web 服务器缓存

    反向代理和缓存(比如 Varnish)可以直接提供静态和动态内容。Web 服务器同样也可以缓存请求,返回相应结果而不必连接应用服务器。

    数据库缓存

    数据库的默认配置中通常包含缓存级别,针对一般用例进行了优化。调整配置,在不同情况下使用不同的模式可以进一步提高性能。

    应用缓存

    基于内存的缓存比如 Memcached 和 Redis 是应用程序和数据存储之间的一种键值存储。由于数据保存在 RAM 中,它比存储在磁盘上的典型数据库要快多了。RAM 比磁盘限制更多,所以例如 least recently used (LRU)缓存无效算法可以将「热门数据」放在 RAM 中,而对一些比较「冷门」的数据不做处理。

    Redis 有下列附加功能:

    • 持久性选项
    • 内置数据结构比如有序集合和列表

    有多个缓存级别,分为两大类:数据库查询对象

    • 行级别
    • 查询级别
    • 完整的可序列化对象
    • 完全渲染的 HTML

    一般来说,你应该尽量避免基于文件的缓存,因为这使得复制和自动缩放很困难。

    数据库查询级别的缓存

    当你查询数据库的时候,将查询语句的哈希值与查询结果存储到缓存中。这种方法会遇到以下问题:

    • 很难用复杂的查询删除已缓存结果。
    • 如果一条数据比如表中某条数据的一项被改变,则需要删除所有可能包含已更改项的缓存结果。

    对象级别的缓存

    将您的数据视为对象,就像对待你的应用代码一样。让应用程序将数据从数据库中组合到类实例或数据结构中:

    • 如果对象的基础数据已经更改了,那么从缓存中删掉这个对象。
    • 允许异步处理:workers 通过使用最新的缓存对象来组装对象。

    建议缓存的内容:

    • 用户会话
    • 完全渲染的 Web 页面
    • 活动流
    • 用户图数据

    何时更新缓存

    由于你只能在缓存中存储有限的数据,所以你需要选择一个适用于你用例的缓存更新策略。

    缓存模式

    ONjORqk.png
    资料来源:从缓存到内存数据网格

    应用从存储器读写。缓存不和存储器直接交互,应用执行以下操作:

    • 在缓存中查找记录,如果所需数据不在缓存中
    • 从数据库中加载所需内容
    • 将查找到的结果存储到缓存中
    • 返回所需内容
    def get_user(self, user_id):
        user = cache.get("user.{0}", user_id)
        if user is None:
            user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)
            if user is not None:
                key = "user.{0}".format(user_id)
                cache.set(key, json.dumps(user))
        return user
    [Memcached](https://memcached.org/) 通常用这种方式使用。 添加到缓存中的数据读取速度很快。缓存模式也称为延迟加载。只缓存所请求的数据,这避免了没有被请求的数据占满了缓存空间。 ##### 缓存的缺点: - 请求的数据如果不在缓存中就需要经过三个步骤来获取数据,这会导致明显的延迟。 - 如果数据库中的数据更新了会导致缓存中的数据过时。这个问题需要通过设置 TTL 强制更新缓存或者直写模式来缓解这种情况。 - 当一个节点出现故障的时候,它将会被一个新的节点替代,这增加了延迟的时间。 #### 直写模式

    0vBc0hN.png
    资料来源:可扩展性、可用性、稳定性、模式

    应用使用缓存作为主要的数据存储,将数据读写到缓存中,而缓存负责从数据库中读写数据。

    • 应用向缓存中添加/更新数据
    • 缓存同步地写入数据存储
    • 返回所需内容

    应用代码:

    set_user(12345, {"foo":"bar"})
    缓存代码:
    def set_user(user_id, values):
        user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
        cache.set(user_id, user)
    由于存写操作所以直写模式整体是一种很慢的操作,但是读取刚写入的数据很快。相比读取数据,用户通常比较能接受更新数据时速度较慢。缓存中的数据不会过时。 ##### 直写模式的缺点: - 由于故障或者缩放而创建的新的节点,新的节点不会缓存,直到数据库更新为止。缓存应用直写模式可以缓解这个问题。 - 写入的大多数数据可能永远都不会被读取,用 TTL 可以最小化这种情况的出现。 #### 回写模式

    rgSrvjG.png
    资料来源:可扩展性、可用性、稳定性、模式

    在回写模式中,应用执行以下操作:

    • 在缓存中增加或者更新条目
    • 异步写入数据,提高写入性能。
    回写模式的缺点:
    • 缓存可能在其内容成功存储之前丢失数据。
    • 执行直写模式比缓存或者回写模式更复杂。

    刷新

    kxtjqgE.png
    资料来源:从缓存到内存数据网格

    你可以将缓存配置成在到期之前自动刷新最近访问过的内容。

    如果缓存可以准确预测将来可能请求哪些数据,那么刷新可能会导致延迟与读取时间的降低。

    刷新的缺点:
    • 不能准确预测到未来需要用到的数据可能会导致性能不如不使用刷新。

    缓存的缺点:

    • 需要保持缓存和真实数据源之间的一致性,比如数据库根据缓存无效
    • 需要改变应用程序比如增加 Redis 或者 memcached。
    • 无效缓存是个难题,什么时候更新缓存是与之相关的复杂问题。

    相关资源和延伸阅读

    异步

    54GYsSx.png
    资料来源:可缩放系统构架介绍

    异步工作流有助于减少那些原本顺序执行的请求时间。它们可以通过提前进行一些耗时的工作来帮助减少请求时间,比如定期汇总数据。

    消息队列

    消息队列接收,保留和传递消息。如果按顺序执行操作太慢的话,你可以使用有以下工作流的消息队列:

    • 应用程序将作业发布到队列,然后通知用户作业状态
    • 一个 worker 从队列中取出该作业,对其进行处理,然后显示该作业完成

    不去阻塞用户操作,作业在后台处理。在此期间,客户端可能会进行一些处理使得看上去像是任务已经完成了。例如,如果要发送一条推文,推文可能会马上出现在你的时间线上,但是可能需要一些时间才能将你的推文推送到你的所有关注者那里去。

    Redis 是一个令人满意的简单的消息代理,但是消息有可能会丢失。

    RabbitMQ 很受欢迎但是要求你适应「AMQP」协议并且管理你自己的节点。

    Amazon SQS 是被托管的,但可能具有高延迟,并且消息可能会被传送两次。

    任务队列

    任务队列接收任务及其相关数据,运行它们,然后传递其结果。 它们可以支持调度,并可用于在后台运行计算密集型作业。

    Celery 支持调度,主要是用 Python 开发的。

    背压

    如果队列开始明显增长,那么队列大小可能会超过内存大小,导致高速缓存未命中,磁盘读取,甚至性能更慢。背压可以通过限制队列大小来帮助我们,从而为队列中的作业保持高吞吐率和良好的响应时间。一旦队列填满,客户端将得到服务器忙活着 HTTP 503 状态码,以便稍后重试。客户端可以在稍后时间重试该请求,也许是指数退避

    异步的缺点:

    • 简单的计算和实时工作流等用例可能更适用于同步操作,因为引入队列可能会增加延迟和复杂性。

    相关资源和延伸阅读

    通讯

    5KeocQs.jpg
    资料来源:OSI 7层模型

    超文本传输协议(HTTP)

    HTTP 是一种在客户端和服务器之间编码和传输数据的方法。它是一个请求/响应协议:客户端和服务端针对相关内容和完成状态信息的请求和响应。HTTP 是独立的,允许请求和响应流经许多执行负载均衡,缓存,加密和压缩的中间路由器和服务器。

    一个基本的 HTTP 请求由一个动词(方法)和一个资源(端点)组成。 以下是常见的 HTTP 动词:

    动词 描述 *幂等 安全性 可缓存
    GET 读取资源 Yes Yes Yes
    POST 创建资源或触发处理数据的进程 No No Yes,如果回应包含刷新信息
    PUT 创建或替换资源 Yes No No
    PATCH 部分更新资源 No No Yes,如果回应包含刷新信息
    DELETE 删除资源 Yes No No

    多次执行不会产生不同的结果

    HTTP 是依赖于较低级协议(如 TCPUDP)的应用层协议。

    来源及延伸阅读:HTTP

    传输控制协议(TCP)

    JdAsdvG.jpg
    资料来源:如何制作多人游戏

    TCP 是通过 IP 网络的面向连接的协议。 使用握手建立和断开连接。 发送的所有数据包保证以原始顺序到达目的地,用以下措施保证数据包不被损坏:

    如果发送者没有收到正确的响应,它将重新发送数据包。如果多次超时,连接就会断开。TCP 实行流量控制拥塞控制。这些确保措施会导致延迟,而且通常导致传输效率比 UDP 低。

    为了确保高吞吐量,Web 服务器可以保持大量的 TCP 连接,从而导致高内存使用。在 Web 服务器线程间拥有大量开放连接可能开销巨大,消耗资源过多,也就是说,一个 memcached 服务器。连接池 可以帮助除了在适用的情况下切换到 UDP。

    TCP 对于需要高可靠性但时间紧迫的应用程序很有用。比如包括 Web 服务器,数据库信息,SMTP,FTP 和 SSH。

    以下情况使用 TCP 代替 UDP:

    • 你需要数据完好无损。
    • 你想对网络吞吐量自动进行最佳评估。

    用户数据报协议(UDP)

    yzDrJtA.jpg
    资料来源:如何制作多人游戏

    UDP 是无连接的。数据报(类似于数据包)只在数据报级别有保证。数据报可能会无序的到达目的地,也有可能会遗失。UDP 不支持拥塞控制。虽然不如 TCP 那样有保证,但 UDP 通常效率更高。

    UDP 可以通过广播将数据报发送至子网内的所有设备。这对 DHCP 很有用,因为子网内的设备还没有分配 IP 地址,而 IP 对于 TCP 是必须的。

    UDP 可靠性更低但适合用在网络电话、视频聊天,流媒体和实时多人游戏上。

    以下情况使用 UDP 代替 TCP:

    • 你需要低延迟
    • 相对于数据丢失更糟的是数据延迟
    • 你想实现自己的错误校正方法

    来源及延伸阅读:TCP 与 UDP

    远程过程调用协议(RPC)

    iF4Mkb5.png
    Source: Crack the system design interview

    在 RPC 中,客户端会去调用另一个地址空间(通常是一个远程服务器)里的方法。调用代码看起来就像是调用的是一个本地方法,客户端和服务器交互的具体过程被抽象。远程调用相对于本地调用一般较慢而且可靠性更差,因此区分两者是有帮助的。热门的 RPC 框架包括 ProtobufThriftAvro

    RPC 是一个“请求-响应”协议:

    • 客户端程序 ── 调用客户端存根程序。就像调用本地方法一样,参数会被压入栈中。
    • 客户端 stub 程序 ── 将请求过程的 id 和参数打包进请求信息中。
    • 客户端通信模块 ── 将信息从客户端发送至服务端。
    • 服务端通信模块 ── 将接受的包传给服务端存根程序。
    • 服务端 stub 程序 ── 将结果解包,依据过程 id 调用服务端方法并将参数传递过去。

    RPC 调用示例:

    GET /someoperation?data=anId
    
    POST /anotheroperation
    {
      "data":"anId";
      "anotherdata": "another value"
    }
    RPC 专注于暴露方法。RPC 通常用于处理内部通讯的性能问题,这样你可以手动处理本地调用以更好的适应你的情况。 当以下情况时选择本地库(也就是 SDK): * 你知道你的目标平台。 * 你想控制如何访问你的“逻辑”。 * 你想对发生在你的库中的错误进行控制。 * 性能和终端用户体验是你最关心的事。 遵循 **REST** 的 HTTP API 往往更适用于公共 API。 #### 缺点:RPC * RPC 客户端与服务实现捆绑地很紧密。 * 一个新的 API 必须在每一个操作或者用例中定义。 * RPC 很难调试。 * 你可能没办法很方便的去修改现有的技术。举个例子,如果你希望在 [Squid](http://www.squid-cache.org/) 这样的缓存服务器上确保 [RPC 被正确缓存](http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/)的话可能需要一些额外的努力了。 ### 表述性状态转移(REST) REST 是一种强制的客户端/服务端架构设计模型,客户端基于服务端管理的一系列资源操作。服务端提供修改或获取资源的接口。所有的通信必须是无状态和可缓存的。 RESTful 接口有四条规则: * **标志资源(HTTP 里的 URI)** ── 无论什么操作都使用同一个 URI。 * **表示的改变(HTTP 的动作)** ── 使用动作, headers 和 body。 * **可自我描述的错误信息(HTTP 中的 status code)** ── 使用状态码,不要重新造轮子。 * **[HATEOAS](http://restcookbook.com/Basics/hateoas/)(HTTP 中的HTML 接口)** ── 你的 web 服务器应该能够通过浏览器访问。 REST 请求的例子:
    GET /someresources/anId
    
    PUT /someresources/anId
    {"anotherdata": "another value"}
    REST 关注于暴露数据。它减少了客户端/服务端的耦合程度,经常用于公共 HTTP API 接口设计。REST 使用更通常与规范化的方法来通过 URI 暴露资源,[通过 header 来表述](https://github.com/for-GET/know-your-http-well/blob/master/headers.md)并通过 GET、POST、PUT、DELETE 和 PATCH 这些动作来进行操作。因为无状态的特性,REST 易于横向扩展和隔离。 #### 缺点:REST * 由于 REST 将重点放在暴露数据,所以当资源不是自然组织的或者结构复杂的时候它可能无法很好的适应。举个例子,返回过去一小时中与特定事件集匹配的更新记录这种操作就很难表示为路径。使用 REST,可能会使用 URI 路径,查询参数和可能的请求体来实现。 * REST 一般依赖几个动作(GET、POST、PUT、DELETE 和 PATCH),但有时候仅仅这些没法满足你的需要。举个例子,将过期的文档移动到归档文件夹里去,这样的操作可能没法简单的用上面这几个 verbs 表达。 * 为了渲染单个页面,获取被嵌套在层级结构中的复杂资源需要客户端,服务器之间多次往返通信。例如,获取博客内容及其关联评论。对于使用不确定网络环境的移动应用来说,这些多次往返通信是非常麻烦的。 * 随着时间的推移,更多的字段可能会被添加到 API 响应中,较旧的客户端将会接收到所有新的数据字段,即使是那些它们不需要的字段,结果它会增加负载大小并引起更大的延迟。 ### RPC 与 REST 比较 | 操作 | RPC | REST | | ———– | —————————————- | —————————————- | | 注册 | **POST** /signup | **POST** /persons | | 注销 | **POST** /resign
    {
    ”personid”: “1234”
    } | **DELETE** /persons/1234 | | 读取用户信息 | **GET** /readPerson?personid=1234 | **GET** /persons/1234 | | 读取用户物品列表 | **GET** /readUsersItemsList?personid=1234 | **GET** /persons/1234/items | | 向用户物品列表添加一项 | **POST** /addItemToUsersItemsList
    {
    ”personid”: “1234”;
    ”itemid”: “456”
    } | **POST** /persons/1234/items
    {
    ”itemid”: “456”
    } | | 更新一个物品 | **POST** /modifyItem
    {
    ”itemid”: “456”;
    ”key”: “value”
    } | **PUT** /items/456
    {
    ”key”: “value”
    } | | 删除一个物品 | **POST** /removeItem
    {
    ”itemid”: “456”
    } | **DELETE** /items/456 |

    资料来源:你真的知道你为什么更喜欢 REST 而不是 RPC 吗

    来源及延伸阅读:REST 与 RPC

    安全

    这一部分需要更多内容。一起来吧

    安全是一个宽泛的话题。除非你有相当的经验、安全方面背景或者正在申请的职位要求安全知识,你不需要了解安全基础知识以外的内容:

    • 在运输和等待过程中加密
    • 对所有的用户输入和从用户那里发来的参数进行处理以防止 XSSSQL 注入
    • 使用参数化的查询来防止 SQL 注入。
    • 使用最小权限原则

    来源及延伸阅读

    附录

    一些时候你会被要求做出保守估计。比如,你可能需要估计从磁盘中生成 100 张图片的缩略图需要的时间或者一个数据结构需要多少的内存。2 的次方表每个开发者都需要知道的一些时间数据(译注:OSChina 上有这篇文章的译文)都是一些很方便的参考资料。

    2 的次方表

    Power           Exact Value         Approx Value        Bytes
    ---------------------------------------------------------------
    7                             128
    8                             256
    10                           1024   1 thousand           1 KB
    16                         65,536                       64 KB
    20                      1,048,576   1 million            1 MB
    30                  1,073,741,824   1 billion            1 GB
    32                  4,294,967,296                        4 GB
    40              1,099,511,627,776   1 trillion           1 TB
    #### 来源及延伸阅读 * [2 的次方](https://en.wikipedia.org/wiki/Power_of_two) ### 每个程序员都应该知道的延迟数
    Latency Comparison Numbers
    --------------------------
    L1 cache reference                           0.5 ns
    Branch mispredict                            5   ns
    L2 cache reference                           7   ns                      14x L1 cache
    Mutex lock/unlock                          100   ns
    Main memory reference                      100   ns                      20x L2 cache, 200x L1 cache
    Compress 1K bytes with Zippy            10,000   ns       10 us
    Send 1 KB bytes over 1 Gbps network     10,000   ns       10 us
    Read 4 KB randomly from SSD*           150,000   ns      150 us          ~1GB/sec SSD
    Read 1 MB sequentially from memory     250,000   ns      250 us
    Round trip within same datacenter      500,000   ns      500 us
    Read 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memory
    Disk seek                           10,000,000   ns   10,000 us   10 ms  20x datacenter roundtrip
    Read 1 MB sequentially from 1 Gbps  10,000,000   ns   10,000 us   10 ms  40x memory, 10X SSD
    Read 1 MB sequentially from disk    30,000,000   ns   30,000 us   30 ms 120x memory, 30X SSD
    Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms
    
    Notes
    -----
    1 ns = 10^-9 seconds
    1 us = 10^-6 seconds = 1,000 ns
    1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns
    基于上述数字的指标: * 从磁盘以 30 MB/s 的速度顺序读取 * 以 100 MB/s 从 1 Gbps 的以太网顺序读取 * 从 SSD 以 1 GB/s 的速度读取 * 以 4 GB/s 的速度从主存读取 * 每秒能绕地球 6-7 圈 * 数据中心内每秒有 2,000 次往返 #### 延迟数可视化 ![](https://camo.githubusercontent.com/77f72259e1eb58596b564d1ad823af1853bc60a3/687474703a2f2f692e696d6775722e636f6d2f6b307431652e706e67) #### 来源及延伸阅读 * [每个程序员都应该知道的延迟数 — 1](https://gist.github.com/jboner/2841832) * [每个程序员都应该知道的延迟数 — 2](https://gist.github.com/hellerbarde/2843375) * [关于建设大型分布式系统的的设计方案、课程和建议](http://www.cs.cornell.edu/projects/ladis2009/talks/dean-keynote-ladis2009.pdf) * [关于建设大型可拓展分布式系统的软件工程咨询](https://static.googleusercontent.com/media/research.google.com/en//people/jeff/stanford-295-talk.pdf) ### 其它的系统设计面试题 > 常见的系统设计面试问题,给出了如何解决的方案链接 | 问题 | 引用 | | ———————– | —————————————- | | 设计类似于 Dropbox 的文件同步服务 | [youtube.com](https://www.youtube.com/watch?v=PE4gwstWhmc) | | 设计类似于 Google 的搜索引擎 | [queue.acm.org](http://queue.acm.org/detail.cfm?id=988407)
    [stackexchange.com](http://programmers.stackexchange.com/questions/38324/interview-question-how-would-you-implement-google-search)
    [ardendertat.com](http://www.ardendertat.com/2012/01/11/implementing-search-engines/)
    [stanford.edu](http://infolab.stanford.edu/~backrub/google.html) | | 设计类似于 Google 的可扩展网络爬虫 | [quora.com](https://www.quora.com/How-can-I-build-a-web-crawler-from-scratch) | | 设计 Google 文档 | [code.google.com](https://code.google.com/p/google-mobwrite/)
    [neil.fraser.name](https://neil.fraser.name/writing/sync/) | | 设计类似 Redis 的建值存储 | [slideshare.net](http://www.slideshare.net/dvirsky/introduction-to-redis) | | 设计类似 Memcached 的缓存系统 | [slideshare.net](http://www.slideshare.net/oemebamo/introduction-to-memcached) | | 设计类似亚马逊的推荐系统 | [hulu.com](http://tech.hulu.com/blog/2011/09/19/recommendation-system.html)
    [ijcai13.org](http://ijcai13.org/files/tutorial_slides/td3.pdf) | | 设计类似 Bitly 的短链接系统 | [n00tc0d3r.blogspot.com](http://n00tc0d3r.blogspot.com/) | | 设计类似 WhatsApp 的聊天应用 | [highscalability.com](http://highscalability.com/blog/2014/2/26/the-whatsapp-architecture-facebook-bought-for-19-billion.html) | | 设计类似 Instagram 的图片分享系统 | [highscalability.com](http://highscalability.com/flickr-architecture)
    [highscalability.com](http://highscalability.com/blog/2011/12/6/instagram-architecture-14-million-users-terabytes-of-photos.html) | | 设计 Facebook 的新闻推荐方法 | [quora.com](http://www.quora.com/What-are-best-practices-for-building-something-like-a-News-Feed)
    [quora.com](http://www.quora.com/Activity-Streams/What-are-the-scaling-issues-to-keep-in-mind-while-developing-a-social-network-feed)
    [slideshare.net](http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture) | | 设计 Facebook 的时间线系统 | [facebook.com](https://www.facebook.com/note.php?note_id=10150468255628920)
    [highscalability.com](http://highscalability.com/blog/2012/1/23/facebook-timeline-brought-to-you-by-the-power-of-denormaliza.html) | | 设计 Facebook 的聊天系统 | [erlang-factory.com](http://www.erlang-factory.com/upload/presentations/31/EugeneLetuchy-ErlangatFacebook.pdf)
    [facebook.com](https://www.facebook.com/note.php?note_id=14218138919&id=9445547199&index=0) | | 设计类似 Facebook 的图表搜索系统 | [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-building-out-the-infrastructure-for-graph-search/10151347573598920)
    [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-indexing-and-ranking-in-graph-search/10151361720763920)
    [facebook.com](https://www.facebook.com/notes/facebook-engineering/under-the-hood-the-natural-language-interface-of-graph-search/10151432733048920) | | 设计类似 CloudFlare 的内容传递网络 | [cmu.edu](http://repository.cmu.edu/cgi/viewcontent.cgi?article=2112&context=compsci) | | 设计类似 Twitter 的热门话题系统 | [michael-noll.com](http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/)
    [snikolov .wordpress.com](http://snikolov.wordpress.com/2012/11/14/early-detection-of-twitter-trends/) | | 设计一个随机 ID 生成系统 | [blog.twitter.com](https://blog.twitter.com/2010/announcing-snowflake)
    [github.com](https://github.com/twitter/snowflake/) | | 返回一定时间段内次数前 k 高的请求 | [ucsb.edu](https://icmi.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf)
    [wpi.edu](http://davis.wpi.edu/xmdv/docs/EDBT11-diyang.pdf) | | 设计一个数据源于多个数据中心的服务系统 | [highscalability.com](http://highscalability.com/blog/2009/8/24/how-google-serves-data-from-multiple-datacenters.html) | | 设计一个多人网络卡牌游戏 | [indieflashblog.com](http://www.indieflashblog.com/how-to-create-an-asynchronous-multiplayer-game.html)
    [buildnewgames.com](http://buildnewgames.com/real-time-multiplayer/) | | 设计一个垃圾回收系统 | [stuffwithstuff.com](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/)
    [washington.edu](http://courses.cs.washington.edu/courses/csep521/07wi/prj/rick.pdf) | | 添加更多的系统设计问题 | [贡献](#贡献) | ### 真实架构 > 关于现实中真实的系统是怎么设计的文章。

    TcUo2fw.png
    Source: Twitter timelines at scale

    不要专注于以下文章的细节,专注于以下方面:

    • 发现这些文章中的共同的原则、技术和模式。
    • 学习每个组件解决哪些问题,什么情况下使用,什么情况下不适用
    • 复习学过的文章
    类型 系统 引用
    Data processing MapReduce - Google的分布式数据处理 research.google.com
    Data processing Spark - Databricks 的分布式数据处理 slideshare.net
    Data processing Storm - Twitter 的分布式数据处理 slideshare.net
    Data store Bigtable - Google 的列式数据库 harvard.edu
    Data store HBase - Bigtable 的开源实现 slideshare.net
    Data store Cassandra - Facebook 的列式数据库 slideshare.net
    Data store DynamoDB - Amazon 的文档数据库 harvard.edu
    Data store MongoDB - 文档数据库 slideshare.net
    Data store Spanner - Google 的全球分布数据库 research.google.com
    Data store Memcached - 分布式内存缓存系统 slideshare.net
    Data store Redis - 能够持久化及具有值类型的分布式内存缓存系统 slideshare.net
    File system Google File System (GFS) - 分布式文件系统 research.google.com
    File system Hadoop File System (HDFS) - GFS 的开源实现 apache.org
    Misc Chubby - Google 的分布式系统的低耦合锁服务 research.google.com
    Misc Dapper - 分布式系统跟踪基础设施 research.google.com
    Misc Kafka - LinkedIn 的发布订阅消息系统 slideshare.net
    Misc Zookeeper - 集中的基础架构和协调服务 slideshare.net
    添加更多 贡献

    公司的系统架构

    Company Reference(s)
    Amazon Amazon 的架构
    Cinchcast 每天产生 1500 小时的音频
    DataSift 每秒实时挖掘 120000 条 tweet
    DropBox 我们如何缩放 Dropbox
    ESPN 每秒操作 100000 次
    Google Google 的架构
    Instagram 1400 万用户,达到兆级别的照片存储
    是什么在驱动 Instagram
    Justin.tv Justin.Tv 的直播广播架构
    Facebook Facebook 的可扩展 memcached
    TAO: Facebook 社交图的分布式数据存储
    Facebook 的图片存储
    Flickr Flickr 的架构
    Mailbox 在 6 周内从 0 到 100 万用户
    Pinterest 从零到每月数十亿的浏览量
    1800 万访问用户,10 倍增长,12 名员工
    Playfish 月用户量 5000 万并在不断增长
    PlentyOfFish PlentyOfFish 的架构
    Salesforce 他们每天如何处理 13 亿笔交易
    Stack Overflow Stack Overflow 的架构
    TripAdvisor 40M 访问者,200M 页面浏览量,30TB 数据
    Tumblr 每月 150 亿的浏览量
    Twitter Making Twitter 10000 percent faster
    每天使用 MySQL 存储2.5亿条 tweet
    150M 活跃用户,300K QPS,22 MB/S 的防火墙
    可扩展时间表
    Twitter 的大小数据
    Twitter 的行为:规模超过 1 亿用户
    Uber Uber 如何扩展自己的实时化市场
    WhatsApp Facebook 用 190 亿美元购买 WhatsApp 的架构
    YouTube YouTube 的可扩展性
    YouTube 的架构

    公司工程博客

    你即将面试的公司的架构

    你面对的问题可能就来自于同样领域

    来源及延伸阅读

    正在完善中

    有兴趣加入添加一些部分或者帮助完善某些部分吗?加入进来吧

    • 使用 MapReduce 进行分布式计算
    • 一致性哈希
    • 直接存储器访问(DMA)控制器
    • 贡献

    致谢

    整个仓库都提供了证书和源

    特别鸣谢:

    联系方式

    欢迎联系我讨论本文的不足、问题或者意见。

    可以在我的 GitHub 主页上找到我的联系方式

    许可

    Creative Commons Attribution 4.0 International License (CC BY 4.0)
    
    http://creativecommons.org/licenses/by/4.0/
    
    展开全文
  • 如何进行系统分析与设计

    万次阅读 2018-08-02 00:05:06
    作者 | 章烨明杏仁医生CTO。中老年程序员,关注各种技术和团队管理。概述首先,系统是什么?根据《系统架构》一书的定义,系统是由一组实体和这些实体之间的关系所构成的集合,...
        

    作者 | 章烨明

    640?wx_fmt=jpeg

    杏仁医生CTO。中老年程序员,关注各种技术和团队管理。

    概述

    首先,系统是什么?根据《系统架构》一书的定义,系统是由一组实体和这些实体之间的关系所构成的集合,其功能要大于这些实体各自的功能之和。对于我们的场景,系统可能是 App、Web 应用、服务、批处理程序等,也可能是包括所有这些的一个大系统。

    随着互联网和传统企业的结合越来越深入,业务会越来越复杂。我们该如何设计我们的系统呢?

    从产品到研发

    从产品作出原型,到研发编程实现,中间有巨大的鸿沟。越复杂的业务需求,这条鸿沟就越大。一般而言,我们至少还要有两个步骤:业务分析与架构设计。

    640?wx_fmt=png

    业务分析,主要处理的是业务领域的建模。解决的问题是业务上如何实现。然后是技术与架构方面的设计,主要针对的是技术实现,解决的问题是技术上如何实现。这两个方面是会互相影响的,设计的时候往往需要来来回回的考虑这两个方面。甚至系统开发时也时常会需要调整模型或者架构,当然相应的也需要更新文档。

    640?wx_fmt=png

    基本原则

    设计与分析的过程就是不停的进行抽象和封装,并且确定各个系统实体的细节。抽象是指将业务抽象为软件领域的元素(系统、模块或类);封装则是指定义元素的边界,隐藏实现,开放接口。

    相应的,分析与设计时,最基本的原则就是抽象性和封装性。当然,我们有 SOLID、DRY、高内聚低耦合、设计模式等各种原则和方法,具体方式本文不详述了,但最终它们都可以归类到以上两点。

    业务分析

    分析方法

    业务分析是针对业务领域的建模,产出就是分析模型。分析模型描述系统的逻辑设计与结构,一般会包括需求用例、实体模型以及业务场景的交互流程、状态转换等。分析模型让非技术人员能够理解系统是如何构造的,让技术人员能够以此为基础搭建系统。

    分析的过程是不断迭代的。特别对于复杂的、涉及多个业务领域的需求,第一步往往需要在整体系统的层级进行分析,然后将模型划分到多个子系统,然后再在子系统的层级进行更细节的分析与建模。

    另一方面,分析过程中需要不断的优化和调整。例如在确定实体的行为细节时,发现两个实体的耦合很高,那么可能需要重新进行抽象,调整实体的功能范围。

    理清业务需求

    理清业务需求是所有分析与设计的前提:

    • 确定系统的利益相关者(Stakeholder)及他们的关注点。

    • 确定系统的业务需求,即「谁」使用该系统「做什么」。

    • 确定系统的功能范围,即该系统「包含什么」,不包含「什么」。

    系统需要满足利益相关者的关注点,所以要确保所有这些关注点都有涉及到。最重要的利益相关者当然就是用户(有时还会细分为不同类型的用户),此外还应该包括供应商、合作方、运营、销售、老板甚至政府等等,也同样包括研发测试和运维。

    具体到系统的用户,还需要细分到角色,即使有些角色实际可能是同一个人。比如对于门诊,可能有护士、顾问或系统管理员等等,可以进行不同的操作。需求范围简单话用一个列表即可,复杂的系统可以考虑使用用例图。

    例如,门诊预约系统的用例图可以这样画:

    • 角色有医生、患者和门诊员工。

    • 用例有设置排班、管理预约以及预约/取消医生。

    640?wx_fmt=png

    建立实体模型

    实体模型是确定系统包含的实体以及它们之间的关联的过程:

    • 理清业务概念,统一业务词汇。

    • 抽象业务实体,包括事件、人/角色、地点和事物等。

    • 识别实体关系:继承、聚合、关联等。

    实体模型也叫 ER(Entity-Relation)模型。可以考虑使用四色法建模,一般可以使用类图或组件图表示。需要注意的是一定要理清业务的概念,统一命名和定义业务相关词汇,这是进一步沟通的基础。

    例如,预约系统的实体关系图可以这样画:

    640?wx_fmt=png

    分析业务场景

    场景分析用于确定具体业务场景中,各个参与者的交互过程,从而进一步完善分析模型:

    • 分析具体业务场景,确定业务规则,梳理业务流程。

    • 如果涉及复杂的状态转换,需要确定状态转换逻辑。

    • 补充和完善实体模型的内容描述。

    对于一个业务场景,参与者可能包括人、内部模块、外部服务等,这一步需要理清楚整个业务过程和规则。需要注意的是,对于一些次要路径或者异常路径,也一定要考虑到。对于业务过程和规则,可以使用普通的流程图、泳道图,也可以考虑UML的活动图,状态转换过程则可以通过UML的状态图展示。

    对于场景分析中不太确定的需求,或者可能会有技术难点地方,可以记录下来,后面确认和验证。

    例如,下面是预约系统的预约状态图。

    640?wx_fmt=png

    例如,下面是我们和一家药品供应商对接的流程图。

    架构与技术设计

    架构方法

    架构设计不一定要深入到具体的实现细节,但是应该尽量全面的考虑系统的各个方面。关键是要对项目风险有比较大的把握,这样才能避免开发过程出现不可控的问题。具体设计需要多详细,是需要设计者自己去把握度的。

    对于暂时无法确定的内容,应该在文档中注明,在开发过程早期进行试验和验证。如果对项目比较关键,可以考虑先行开发原型来进行验证。

    架构设计常见的是4+1视图,即逻辑视图、开发视图、过程视图、物理视图,再加上场景。另外一种我更喜欢的是视点和视角的方法,如果再加上场景的话,可能会更全面。

    640?wx_fmt=png

    确定整体架构

    首先需要在整体上考虑系统的位置和职责:

    • 确定系统在整个上下文中的位置,与其他系统的关联。

    • 确定系统自身以及各个外部系统的职责。

    整体架构对应的就是情景视图。这一步将系统看作一个黑盒,确认系统自己的范围和职责,相关的外部系统的职责,以及他们之间的关联。

    例如,交易系统的整体架构大概是这样的:

    设计功能模块

    其次需要确定系统内部的功能模块及其职责:

    • 确定系统的模块划分。

    • 确定每个模块的职责以及模块间的关联。

    功能模块对应的就是功能视图。这一步需要明确系统的内部结构。内部模块划分主要有基于业务功能的划分,以及基于实现层次的划分,稍复杂的系统可能会两者都有。也有一些系统会采用CQRS等架构,那么模块划分可能会不一样。功能模块可以使用UML的组件图表示。

    例如,下图是一个系统模块示意图:

    明确架构关注点

    然后需要确定系统架构的理念:

    • 理清架构设计需要考虑的关注点。

    • 确定系统的架构设计上的取舍。

    这一步需要考虑各种架构视角,主要有(但不限于)以下关注点:

    • 安全性:身份验证、权限控制和授权、操作日志、安全审计、数据一致性等。

    • 性能:响应时间、吞吐量等。

    • 稳定性:停机时间、故障恢复、数据一致性、数据备份等。

    • 扩展性:未来可能的变更,以及如何应对变更。

    • 其他:国际化、易用性、合规性等。

    以上所有的关注点,和开发资源、时间、范围各个方面,往往很难同时满足,所以必须要明确哪些是关注的重点,哪些则可以有所妥协。例如,为了满足性能要求,可能需要降低数据的一致性;为了合规性,可能不得不花更多开发时间。

    对于未来可能的变更,也一定要考虑到。通常情况下,我们至少要考虑未来半年的架构,但可能只实现当前需要的版本,但是确保未来可以很容易的扩展。

    一旦确定了关注的重点,在设计和开发的每个过程中,我们都要把这个重点放在心上。

    例如,对于订单系统,因为涉及到钱和交易,数据的一致性和可追溯性极其重要。下单和支付的API都必须是幂等的,每一笔收入变动都必须记录日志,必须有严格的核对和对账。为了安全,每一次API调用都必须进行权限验证。

    例如,亚马逊有个知名的原则,所有的系统间调用都必须通过定义清楚的 API,不允许共享数据库。这也是一个架构原则。

    设计数据库模型

    如果分析时有了完善了实体模型,设计数据库模型就不是什么难事了。开发完成后,数据库模型应该以数据库为准,架构文档就不需要保留这一部分了。

    需要注意的是,数据库模型是实体模型在关系数据库的实现,但不一定是严格的映射。数据库可能会有范式、冗余、一致性、同步、分表分库方面的考虑,必要时可能会使用非关系型数据库如ElasticSearch、Cassandra等。

    有时候还会涉及到数据处理的流程。例如,一张图片提交后可能需要进行预处理,然后有运营人员进行审核和标记,最后进行发布。过程中数据的保存形式或者状态标记可能是不一样的。

    数据库设计的更多规范可以参考数据库规范。

    设计接口

    然后就需要确定 API 细节了。一般我们的服务的 API 是 JSON 格式 HTTP 形式的请求和回调。API 可能是接口定义,也可能会有其他接口形式,例如消息队列等。设计阶段,API 文档可以通过 Markdown 文档、RAP 等记录,开发完成后可以独立维护,或者使用 Swagger 和代码一起维护。

    接口设计需要注意几点:

    • 接口的设计应该以系统提供的领域资源或服务为基础,同时考虑调用方的需求。

    • 接口的粒度很重要,太细则调用方很不方便需要多次调用,太粗则无法灵活的满足各种需求,需要仔细权衡。

    • 接口的设计也需要从调用方的角度考虑如何进行调用。必要的话可以画流程图、时序图、状态图详细说明调用顺序即状态转换等。

    • 接口的文档一定要清楚的说明调用接口的方法、前置条件,参数作用、不同条件的处理、返回接口等。

    场景实现

    一般情况下,有了业务场景分析,有了数据库模型和 API,系统的实现一般是比较简单了。但可能还会有一些细节需要进一步考虑实现细节,以避免风险。可以考虑更细节的活动图、时序图甚至伪代码。例如:

    • 复杂业务场景的详细设计,或者复杂算法的实现描述。

    • 离线任务的执行方式、时间和步骤。

    • 非业务的一些场景,例如网络断开、缓存失效、第三方系统宕机等。

    例如,对于支付系统的微信 Web 支付过程,涉及系统较多,交互比较复杂,可以通过时序图来定义清楚:

    640?wx_fmt=png

    其他考虑

    对于我们的后台系统来说,基本的技术框架都已确定,可以解决很多基础的非业务需求。不过设计系统时,也还是需要考虑以下等方面:

    • 通用处理的方式,例如日志、错误处理、代码规范、单元测试等。

    • 数据迁移、同步和回滚方案:对于老系统的重构,需要仔细考虑并且提前演练。

    • 系统部署和发布:如果系统涉及多个子系统,需要考虑系统的部署架构。特别是同时涉及到数据迁移的,一定要仔细考虑发布的过程。

    • 系统监控和告警:除了常规的监控和告警,是否有特殊的指标需要监控?

    • 并发和数据量:如果系统可能面临对高并发和大数据量的问题, 需要设计对应的方案,以及相关的性能测试和压力测试。

    • 缓存设计:如果需要使用缓存,除了要考虑缓存的选型、方案,而且要把缓存放到整个系统中去进行设计。

    • 技术选型:涉及到新技术的引入时,则需要仔细分析备用技术的优缺点,选择最合适的方案。

    设计方法和工具

    • UML

    • 面向对象设计(OOAP)

    • 领域驱动设计(DDD)

    • CQRS & Event Sourcing

    参考

    • 分析模式:可复用的对象模型(https://book.douban.com/subject/4832380/)

    • 软件系统架构:使用视点和视角与利益相关者合作(https://book.douban.com/subject/24530471/)

    • UML和模式应用(https://book.douban.com/subject/1792387/)

    • 架构即未来:现代企业可扩展的Web架构、流程和组织(https://book.douban.com/subject/26765979/)

    文章


    • 从用例分析到方案评审,我们是如何进行业务系统设计的(http://mp.weixin.qq.com/s/qH3vpf5CRGJ4dVaKPOFFUg)

    • 互联网公司研发RD如何撰写总体设计与详细设计文档(http://www.10tiao.com/html/249/201412/201657741/1.html)

    • 用UML做好系统分析(http://www.infoq.com/cn/articles/use-uml-to-do-system-analysis)

    • 运用四色建模法进行领域分析(http://www.infoq.com/cn/articles/xh-four-color-modeling)

    • 从“四色建模法”到“限界纸笔建模法”(http://insights.thoughtworkers.org/paper-pen-modeling/)

    • 浅谈我对DDD领域驱动设计的理解(http://www.cnblogs.com/netfocus/p/5548025.html)

    • 领域驱动设计参考架构详解(http://blog.csdn.net/bluishglc/article/details/6681253)

    • 领域驱动设计和实践(http://www.infoq.com/cn/articles/cjq-ddd)

    • 我对CQRS/EventSourcing架构的思考(http://mp.weixin.qq.com/s?__biz=MzA5Nzc4OTA1Mw==&mid=2659598125&idx=1&sn=ca39d804aede5ee46988b6d635217027)

    • 架构设计基础知识整理(https://blog.dreamtobe.cn/2016/03/09/oo_architecture/)


    全文完



    以下文章您可能也会感兴趣:

    我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。


    640?wx_fmt=png


    杏仁技术站

    长按左侧二维码关注我们,这里有一群热血青年期待着与您相会。


    展开全文
  • 系统设计的全流程实例,借鉴一个公司的部分系统设计开发报告。
  • 系统设计:关于高可用系统的一些技术方案

    万次阅读 多人点赞 2019-11-09 17:19:22
    系统设计关于高可用系统的一些技术方案 高可用方法论 扩展 隔离 解耦 限流 分类 漏桶算法 令牌桶算法 滑动窗口计数法 动态限流 降级 熔断 发布相关 模块级自动化测试 灰度发布 回滚 其他 总结 参考资料 ...
  • 系统设计

    2019-10-13 15:16:50
    系统设计 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience/ 这个作业要求在哪里 https://www.cnblogs.com/harry240/p/11524148.html 团队的名称 C#软件造梦厂 ...
  • 系统设计总结

    2018-02-12 10:47:13
    不好的设计的几个特性: 僵化性:很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的改动。 脆弱性:对系统的改动会导致系统中和改动的地方在概念上无关的许多地方出现问题。 牢固性:很难解开系统的...
  • 系统设计问题

    2020-06-27 07:21:10
    1 题外话和系统设计无关的 内存映射问题 一个进程虚拟地址 2^64/2^32 (64和32取决于计算机多少位),虚拟地址里面分段,每段里面分页 每个进程都只知道自己存在,以为自己是计算机唯一存在的 逻辑地址 假设20 -> ...
  • 技术面试的系统设计题(一)

    万次阅读 2018-01-09 09:10:30
    技术面试的系统设计题(一) 本文为课程翻译和学习笔记,课程地址System Design for Tech Interviews。 关于课后题,这儿就不公布答案了。应该还是比较简单的。 什么是系统设计题 在面试的时候,面试官经常会...
  • 如何设计一个系统

    万次阅读 2017-12-06 21:08:40
    系统设计案例 Tomcat 设计目的 功能分解 总体架构 从设计角度查看上述结构现在软件变得越来越复杂,于是我们用“系统”这个词来形容现代的软件。正如生态系统、人的循环系统等一样复杂。 当事物复杂到一定程度的...
  • 系统总体结构设计

    万次阅读 2016-02-18 15:38:18
    系统总体结构设计   系统设计工作应该自顶向下地进行。首先设计总体结构,然后再逐层深入,直至进行每一个模块的设计。...系统设计又称为物理设计,是开发管理信息系统的第二阶段,系统设计通常
  • C语言图书管理系统设计报告

    万次阅读 多人点赞 2019-07-05 10:03:49
    源代码:https://blog.csdn.net/k_young1997/article/details/73480766 XXXX大学 C语言课程设计报告 ...题 目 图书管理系统设计 专业班级 XXXX级计算机科学与技术本科X班 组 别 计科第...
  • 在进行多旋翼无人机飞控系统设计之前,有必要列写一份详细的设计方案书;这是飞控系统设计的基石,并且在一定程度上指导了后续的研发工作。本篇博文列写了之前笔者在进行无人机飞控开发过程中所撰写的精简版本的设计...
  • 基于Java的物流公司管理系统设计与设计,该项目为本人的毕业设计,记录一下。 如有同课题的同学,只仅作参考! 博主联系方式:liumce1@163.com 一、报告目录(仅作参考) 二、项目简介 通过对该物流企业的结构...
  • 消息系统设计与实现

    万次阅读 2018-09-20 19:44:13
    欢迎关注公众号: ----------------------------------------------正文-------------...消息系统设计与实现 文/JC_Huang(简书作者) 原文链接:http://www.jianshu.com/p/f4d7827821f1 著作权归作者所有,转...
  • 通用数据权限管理系统设计

    千次阅读 2018-03-08 15:33:38
    通用数据权限管理系统设计(一) 作者:逸云 前言: 本文提供一种集成功能权限和数据权限的解决方法,以满足多层次组织中权限管理方面的集中控制。本方法是RBAC(基于角色的访问控制方法)的进一步扩展和延伸,即...
  • 图书管理系统设计总结与心得

    万次阅读 2018-06-30 22:14:01
    图书管理系统设计总结与心得设计思路:有日期类、记录类、图书类、用户类、管理类各个类之间的包含关系:管理类读取读者信息文件和图书信息文件,实现增删查改用户和图书。个体操作类登录,读取图书信息文件,实现...
  • 一、 操作系统设计 本操作系统命名为JIANG OS(本人姓江),操作系统的全部程序都放置在软盘,核心程序包括如下模块: 启动程序:启动程序扇区放置在软盘的第1扇区,以55AA为结束标记。 装载程序:从软盘引导...
  • 51单片机——基于单片机的智能报警系统设计

    千次阅读 热门讨论 2019-03-26 21:15:30
    基于单片机的智能报警系统设计 基于51单片机的报警系统实现 网上转载:本系统具备发送短信、接收短信,拨打电话、接听电话等功能。主控检测到有人入侵之后会立即产生高分贝的警报,吓退闯入者,与此同时通过GSM模块...
1 2 3 4 5 ... 20
收藏数 2,497,461
精华内容 998,984
关键字:

系统设计