# 解决方案架构的设计原则

# 了解工作负载的伸缩

在多数情况下,如果了解工作负载的规律,那么其伸缩是可预测的,但是当工作负载突然出现或者出现以前从未处理过的高负载事件时,我们只能被动应对。

可预测伸缩是组织希望采用的理想方案,可以通过监控工具来监听用户流量数据,然后基于数据对伸缩情况进行预测。可能的伸缩情况包括在工作负载增加时,自动规划更多的服务器,或者添加额外的缓存。

有时意料之外的流量高峰会使工作负载突然增加,所以也可能需要进行被动伸缩。为了规划用于处理流量的服务器资源伸缩,需要确定以下模式:

  • 明确哪些web页面是只读并且可缓存的。
  • 确定哪些用户查询只需要读取数据,不需要写入或更新数据库的内容。
  • 确认某个用户查询是否反复的请求相同或重复的数据。

一旦了解了这些模式,就可以从架构上减轻负担,使其可以处理更多的过载流量,要减轻web层的流量负担,可以将静态内容从web服务器转移到CDN,服务器集群,可以使用负载均衡器来分配流量,并且通过自动伸缩机制来进行水平伸缩,自动的增加或缩减服务器。降低数据库的负载,需要根据需求选择合适的数据库,例如使用NoSQL数据库来存储用户会话,使用关系型数据库来存储事务数据,并对频繁的查询进行缓存。

# 构建有韧性的架构

有韧性的架构意味着当发生故障时,应用程序仍然可以供用户使用,并能从故障中恢复。架构的各层都需要设计韧性,包括基础设施、应用程序、数据库、安全和网络层。

需要在影响应用程序可用性的所有关键层中构建韧性,以实现容错设计:

  • 使用DNS服务器将流量路由到不同物理区域,以便当整个区域出现故障时应用程序仍可以运行。
  • 使用CDN在靠近用户位置分发和缓存静态内容,这样发生DDoS攻击或本地网点故障时,应用程序仍可使用。
  • 一旦流量达到某个区域,使用负载均衡器将流量路由到服务器集群,这样区域内某个位置出现故障,应用程序仍然可以运行。
  • 使用自动伸缩,根据用户需求添加或删除服务器,这样应用程序不会受到服务器单点故障影响。
  • 创建备用数据库来保障数据库的高可用性,当数据库发生故障时应用程序仍然可以使用。

# 进行性能设计

需要在架构设计的每一层中都考虑性能,更好的性能意味着能够提高用户体验和投资回报率。要获得出色的性能,在架构设计中每一层都可以使用缓存。缓存可以将数据保留在用户本地存储,或将数据保存在内存中,以提供更快的响应:

  • 通过浏览器缓存来价值频繁请求的网页。
  • 通过DNS缓存快速查询网站地址。
  • 通过CDN在用户位置附近缓存静态资源。
  • 服务器层面,最大限度的利用内存缓存来服务用户请求。
  • 使用Redis之类的缓存引擎来处理缓存层的频繁查询。
  • 使用数据库缓存来处理内存中的频繁查询。
  • 要注意每一层缓存过期和缓存逐出的情况。

# 使用可替换资源

很多组织会在硬件上投入大量资金,随着时间的流逝,最终不同的服务器可能会以不同的配置运行,这种情况下进行故障排查是一项非常繁琐的任务。

由于无法替换服务器,因此很难再服务器集群中部署和测试任何更新,为了更快的适应变化,在架构师设计时应该考虑不可变基础设施。“不可变”意味着在应用程序升级期间,不仅需要替换软件,还需要替换硬件。要创建可替换的服务器,确保应用程序是无状态的,避免对任何服务器的IP或数据库的DNS名称进行硬编码

本质上来说,就是要将基础设施视为软件而非硬件,不仅要对运行中的系统进行更新,还要始终从黄金镜像启动新的服务器实例,在该镜像中,所有必要的安全性配置和软件都应就绪。

我们可以创建虚拟机的黄金镜像,并使用它来部署新版本,这种部署策略便于故障排查,我们可以关闭有问题的服务器并从黄金镜像启动新的服务器,如果所有的环境都是通过相同的基准镜像创建的,那么就可以确保整个环境的一致性。

在使用不可变基础设施进行滚动部署时,可以使用金丝雀测试,将软件更新部署在新服务器上,并将少量流量路由到新服务器,如果一切顺利,可以添加更多新服务器并将更多的流量路由过来,同时关闭旧服务器。金丝雀部署为生产环境的实时部署更新提供了一种安全的方式,即便出现问题,也只会影响少量用户,并且可以通过流量路由回旧的服务器进行即时恢复。

# 考虑松耦合

传统的应用程序通常会搭建一个紧密集成的服务器集群,其中每台机器各司其职,应用程序依赖其他服务器来实现功能的完整性,这种架构,如果一台应用服务器出现故障,那么所有web服务器都会接收到错误,请求也会被路由到出问题的应用服务器,最终导致整个系统故障。

在松耦合的架构下,可以添加负载均衡器或者队列作为中间层,利用中间层自动处理了故障或伸缩,队列可以通过在系统之间传递消息来实现松耦合。

基于队列的解耦方式实现了系统的异步联接,服务器不需要等待另一台服务器的响应,而是独立工作。可以随时增加虚拟服务器的数量,并行的接收和护理x消息。

# 考虑微服务

微服务可以独立伸缩,这是应用程序中的单个组件可以不影响其他组件的情况下更容易扩展或收缩,单体架构的所有组件都构建在同一台服务器中,并与统一数据库绑定在一起这将导致所有组件会有很强的依赖性。在微服务架构中,每个组件都具备独立的框架和数据库,这使它们可以独立伸缩。

微服务的优势需要维护的代码面较小,并且服务是独立的,所有依赖都被包含在服务的内部,这样就能实现松耦合及可伸缩性功能。

# 选择合适的存储

很多组织一直在使用传统的关系型数据库,并试图将所有内容都放入其中,事实上,关系型的数据库更适用于事务性数据,在做解决方案架构时的数据存储选型,应该考虑如下因素:

  • 耐久性要求:如何存储数据防止数据损坏?
  • 数据可用性:那个数据存储系统可以被用来传递数据?
  • 延时要求:数据应该在多短的时间内返回?
  • 数据吞吐量:数据读写的需求是什么?
  • 数据规模:数据存储的大小预估有多少?
  • 数据负载:需要支持多少并发用户?
  • 数据完整性:如何保持数据的准确性和一致性?
  • 数据查询:数据查询的特征是什么?

在选存储时,还要考虑数据的温度:

  • 热数据,类似股票交易或产品推荐数据,必须使用缓存做数据存储。
  • 温数据,类似财务报表数据,可以承受一定的延迟,可以使用数据仓库或关系型数据库存储。
  • 冷数据,类似审计数据,可以以时间单位规划延迟,并将其存储至硬盘中。

# 克服约束

一个项目主要的约束包括成本、时间、预算、范围和资源等等,如何克服越是是设计解决方案时需要考虑的重要因素。我们在设计解决方案时,要将客户放在第一位,同时还要兼顾其他限制,我们可以通过聚焦优先级来克服约束。

MoSCoW是一种比较流行的优先级排序方法,它将用户的需求分为如下几类:

  • Mo(must have,必须具备):对客户来说至关重要,没有将无法发布产品
  • S(should have,应该具备):客户使用该产品后,他们最想要的功能
  • Co(cloud have,可以具备):锦上添花的需求
  • W(won’t have,不需要具备):即便没有也不会引起用户关注的需求

我们可以聚焦最有价值的需求,构建一个MVP版本的产品来验证产品,从而减少浪费。

# 注意安全

安全是解决方案设计最重要的方面之一,在开始设计应用程序之前,需要充分了解安全方面的需求,以下是设计阶段需要考虑的安全因素:

  • 数据中心的物理安全
  • 网络安全
  • 身份和访问权限安全
  • 数据传输安全
  • 数据安全
  • 安全监控

# 自动化一切

我们遇到的大部分事故都是由于人为失误而导致的,其实可以通过自动化来规避这些错误,任何可重复执行的任务都应该被自动化,以释放人力资源。可以考虑一下组件的自动化:

  • 应用程序测试:应用程序的每次更新都需要测试,以确保没有任何功能被破坏,人工测试非常耗时,而且需要大量资源,可重复的测试用例进行自动化,可以加快产品部署和发布速度。
  • IT基础设施:可以通过脚本(Ansible、Terraform)来实现基础设施的自动化,采用基础设施自动化能够快速的完成环境搭建的同时避免配置错误。
  • 日志、监控和告警:可以通过日志、监控和告警来实现其他自动化措施,以确保应用程序能够平稳工作。
  • 部署:部署是一项很耗时的重复工作,也通过CI/CD搭建自动化部署流水线,通过频繁的自动部署来快速迭代产品。