第7章:随需应变:网站的可扩展架构

概述

网站的扩展性架构设计:对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力。

扩展性(Extensibiltiy) * 指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。它是系统架构设计层面的开闭原则:对扩展开放,对修改封闭。也就说,当系统新增一个功能时,不需要对现有系统的结构和代码进行修改。

伸缩性(Scalability) * 指系统能够通过增加(或减少)自身资源规模的方式增强(或减少)自己计算事务的能力。在网站架构中,通常是指利用集群的方式增加服务器数量,从而提高系统的整体事务吞吐能力。

构造可扩展的网站框架

设计网站可扩展架构的核心思想是:模块化,并在此基础之上降低模块间的耦合,提高模块的复用性。在大型网站中,这些模块通过分布式部署的方式,独立的模块部署在独立的服务器(集群)上,从物理上分离模块之间的耦合关系,进一步降低耦合性从而提高复用性。

软件架构师最大的价值:不在于掌握多少先进的技术,而在于具有将一个大系统切分成N个低耦合的子模块的能力(包括业务模块和基础技术模块)

利用分布式消息队列降低系统耦合性

如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块的影响最小,这样系统的可扩展性无疑会更好一些。

事件驱动架构

根据事件驱动架构(Event Driven Architecture)的定义:通过在低耦合的模块之间传输消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作。典型的EDA架构就是操作系统中常见的生产者消费者模式。在大型网站架构中,具体实现手段有很多,但是最常见的是分布式消息队列。

如上图所示,消息队列利用发布—订阅模式工作,消息发送者发布消息,一个或多个消息接受者订阅消息。消息发送者是消息源,在对消息进行处理后发送至分布式消息队列,消息接收者从分布式消息队列获取该消息后继续进行处理。可以明显看出,发送者与接受者之间没有直接耦合,消息发送者只需将消息发送给分布式消息队列即操作结束,而消息接受者也只需要从分布式消息队列获取消息后进行处理,不需要知道该消息从何而来。因此,对于新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展设计。

分布式消息队列

队列是一种先进先出的数据结构,分布式消息队列则看以看作是将这种数据结构部署到独立服务器上,应用程序看以通过远程访问接口使用分布式消息队列,进行消息存取操作,进而实现分布式的异步调用。

可以分为三个步骤:

  1. 消息生产者应用程序通过远程访问接口将消息推送给消息队列服务器,消息队列服务器将消息写入本地内存队列后马上返回成功响应给消息生产者。

  2. 消息队列服务器根据消息订阅列表查找订阅该消息的消费者应用程序,将消息队列中的消息按照先进先出的原则将消息通过远程通信接口发送给消费者应用程序;

  3. 消费者应用程序接收到推送过来的消息之后进行相关的一系列处理,过程终止;

为了避免消息队列服务器宕机后导致消息丢失,会将消息成功发送到消息队列的消息存储在消息生产者服务器,等消息真正被消息消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中其他的服务器发布消息。

利用分布式服务打造可复用的业务平台

如果说分布式消息队列通过消息对象分解系统耦合性,不同子系统处理同一个消息;那么分布式服务则通过接口分解系统耦合性,不同子系统通过相同的接口描述进行服务调用。

网址功能日益复杂,导致网页应用系统聚合了大量的应用和服务组件,难以继续进行开发、维护、部署以及升级。

巨无霸的应用系统带来的问题

  1. 编译、部署困难
  2. 代码分支管理困难
  3. 数据库连接耗尽
  4. 新增业务困难

解决方案:   解决方案还是拆分,将模块独立部署,降低系统耦合性。拆分又分为:横向拆分和纵向拆分。

纵向拆分:将一个大应用拆分为多个小应用,如果新增的业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统;

横向拆分:将可以复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务即可,不需要依赖于具体的模块代码。如果模块内业务逻辑发生变化时,只要接口保持一致就不会影响业务程序和其他模块。

Web Service 与企业级分布式服务

描述了服务提供者、服务代理、服务请求者之间的关系

大型网站分布式服务的需求与特点

  • 负载均衡
  • 失效转移
  • 高效的远程通信
  • 整合异构系统
  • 对应用最少侵入
  • 版本管理
  • 实时监控

分布式服务框架设计

以阿里巴巴开源的分布式框架Dubbo为例,分析其架构设计:

  1. 服务消费者 *通过服务接口使用服务,而服务接口通过代理加载具体服务,具体服务可以是本地的代码模块,也可以是远程的服务,因此对应用较少侵入;

  2. 应用程序

    • 只需要调用服务接口,服务框架根据配置自动调用本地或远程实现。
  3. 服务框架客户端模块 *通过服务注册中心加载服务提供者列表(服务提供者启动后自动向服务注册中心注册自己可提供的服务接口列表),查找需要的服务接口, 并根据配置的负载均衡策略将服务调用请求发送到某台服务提供者服务器。 *如果服务调用失败, 客户端模块会自动从服务提供者列表选择一个可提供同样服务的另一台服务器重新请求服务,实现服务的自动失效转移, 保证服务高可用。

可扩展的数据结构

传统的关系数据库为了保证关系运算(通过SQL语句)的正确性,在设计表结构的时候就需要制定表的Schema—字段名称、数据类型等,还要遵循制定的设计范式(例如:1NF、2NF、3NF等等)。这些规范带来的一个问题就是僵硬的数据结构难以面对需求变更带来的挑战,有些系统设计者通过预先设计一些冗余字段来应付,但这显然是一种糟糕的数据库设计。

有办法能够做到可扩展的数据结构设计呢?是否可以不需要修改表结构就可以新增字段呢? * 目前许多NoSQL数据库使用的ColumnFamily(列族)设计就是一个解决方案。

利用开放平台建设网站生态圈

网站的价值在于为他的用户创造价值,大型网站为了更好地服务自己的用户,会开发更多的增值服务,会把网站内部的服务封装一些调用接口开放出去,供外部的第三方开发者使用,这个提供开放接口的平台被称作开放平台。第三方开发者利用这些开放的接口开发应用程序(APP)或者网站,为更多的用户提供价值。这样一来,网站、用户、第三方开发者相互依赖,形成一个网站的生态圈,即为用户提供更多的价值,也提高了网站和第三方开发者的竞争能力和盈利能力。

目前BAT等国内互联网巨头都建设有自己的开放平台,力图利用自己庞大的用户群吸引第三方开发者,打造一个更加庞大的航母战斗群,在市场竞争中呼风唤雨,立于不败之地。

开放平台是网站内部和外部交互的接口,外部需要面对众多的第三方开发者,内部需要面对网站内诸多的业务服务。

  1. API接口:是开放平台暴露给开发者使用的一组API,其形式可以是RESTful、 WebService、 RPC等各种形式。
  2. 协议转换: 将各种API输入转换成内部服务可以识别的形式, 并将内部服务的返回封装成API的格式。
  3. 安全: 除了一般应用需要的身份识别、 权限控制等安全手段,开放平台还需要分级的访问带宽限制, 保证平台资源被第三方应用公平合理使用, 也保护网站内部服务不会被外部应用拖垮。
  4. 审计: 记录第三方应用的访问情况, 并进行监控、 计费等。
  5. 路由: 将开放平台的各种访问路由映射到具体的内部服务。
  6. 流程: 将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节, 提供统一接口供开发者调用。

文章来源

  • 作者:李智慧
  • 来源:《大型网站技术架构》