新时代业务需求 高并发业务越来越多。随着互联网业务在各行各业的深入渗透,传统行业应用也逐步涉及海量并发业务,比如政府的健康码、核酸等抗疫类应用,对金融的监管,城市治理落地视频分析等应用。 业务敏捷性要求变高。世界变化越来越快,需要更敏捷的开发模式来满足不断变化的需求,现在社会是快鱼吃慢鱼,所以开发的敏捷性也越来越重要。 数据洞察。数据成为资源,数据驱动业务,发展成新的业务。现代化应用架构设计模式 应用采用N层架构。 在多层架构下,应用功能被划分为多个层,例如表示层、业务层、数据库层,这样每一层都可以独立地构建和弹性伸缩。 N层架构的优势: 分层后,每一层更易采用新技术;提升开发效率。 每一层相互独立,可以在不影响其他层的情况下,独立添加新功能; 安全上,每层相互隔离,即便某一层被破坏,也不影响其他层; 应用程序的故障排查和管理也更家可控,可快速定位问题来源。 创建基于SaaS的多租户架构 组织在推行数字化变革的同时想要保持较低的总体应用程序成本,因此多租户架构变得越来越流行。软件即服务(SaaS)模型构建于多租户架构之上,其中,一套软件及其配套基础设施可以为多个客户提供服务。在这种设计下,所有客户共享应用程序和数据库,每个租户通过其独有的配置、身份和数据进行隔离。它们在共享同一产品时仍然互不可见。 构建无状态和有状态的架构设计 在设计复杂应用程序(例如电子商务网站)时,需要处理用户状态以维持活动流(有状态),其中用户可能正在进行一系列的活动,例如添加购物车、下单、选择运送方式并付款。在这种情况下,系统需要在多个设备间保持用户活动并维持其状态,直到交易完成。 为了保持用户状态并使应用程序无状态,需要将用户会话信息存储在持久化数据库层(例如NoSQL数据库)。该状态可以在多个Web服务器或微服务之间共享。 传统单体应用程序使用有状态架构,其用户会话信息存储在服务器本地,而非外部持久化数据库。 有状态应用程序难以很好地支持水平伸缩,因为应用程序的状态存储在服务器中,无法替换。 采用SOA架构 在SOA模式中,不同的应用程序组件通过网络通信协议互相交互。每个服务都提供了端到端的功能,例如获取订单历史记录。并将其作为单独的解决方案。 采用SOA架构的好处是,SOA解耦了服务,使你可以单独优化和扩展每个服务。 构建无服务器架构 在传统情况下,如果想开发一个应用程序,你需要有一台服务器,并安装所需的操作系统和软件。在代码编写期间,需要确保服务器已启动并运行。在部署期间,需要添加更多的服务器以满足用户需求,还需要设置伸缩机制(例如自动伸缩功能),根据用户请求量管理所需服务器的数量。在整个过程中,基础设施的管理和维护将会消耗大量精力,而这些都与业务无关。 采用无服务器架构,团队可以专注于应用程序及功能特性开发,而不必担心底层基础设置的维护。 创建微服务架构 微服务是基于REST风格的Web服务来构建的,并且可以独立伸缩。这使你可以在保持其他组件不变的情况下,更加轻松地扩展或收缩系统中的相关组件。采用微服务的系统可以更加轻松和优雅地应对应用程序的可用性降级事件,避免其他级联故障。 构建基于队列的架构 RESTful架构使微服务能够被轻易发现,但是如果服务宕机,会发生什么呢?在RESTful架构中,客户端服务会等待主机服务的响应,这意味着HTTP请求会阻塞API。有时,由于下游服务不可用,信息可能会丢失。在这种情况下,必须实现一些重试逻辑才能保留信息。 基于队列的架构通过在服务之间添加消息队列来解决上述问题,由消息队列来为服务保留信息。基于队列的架构提供了完全异步的通信和松耦合的架构。在基于队列的架构中,信息被保留在消息中,所以仍然可以访问。 创建事件驱动架构 事件驱动架构可以帮助你将一系列事件衔接在一起,以完成完整的功能流程。例如,在网站上购买商品时,你期望在支付完成后自动生成订单的发票,并立即收到电子邮件。事件驱动架构有助于串联所有这些事件,因此付款后可以触发其他任务以完成整个订单流程。 构建基于缓存的架构 缓存是为了让后续的请求更快,并降低网络吞吐量,而将数据或文件临时性地存储在请求者与持久化存储之间中间位置的过程。缓存可以提高应用程序的运行速度并降低成本。它使你可以重用之前检索的数据。为了提高应用程序的性能,可以将缓存应用于架构的各个层(例如Web层、应用层、数据层和网络层)。 断路器模式 分布式系统通常会调用其他下游服务,而且可能会因为调用失败或挂起而导致没有响应。你可能经常看到一些代码对失败的调用进行多次重试。远程服务的问题是,可能需要花费数分钟甚至数小时来修复,立即重试可能会导致另一次失败。结果,当代码重试几次后,终端用户需要等待更长的时间才能得到错误响应。而且重试功能会消耗更多线程,甚至导致级联故障。断路器模式的目的是了解下游依赖项的运行状况。当它检测到依赖项的健康状态不正常时,就会通过其实现逻辑驳回请求,直到检测到依赖项恢复正常。通过使用持久层监控过去一段时间内的成功和失败请求数,可以实现断路器模式。 隔板模式 隔板用于在船舶内形成单独的水密舱室,以限制故障的影响范围,理想情况下可以防止船舶下沉。如果大水冲破了船体的一个舱室,隔板会阻止其流入其他舱室,从而限制了故障的范围。 同样的概念也可以用于限制大型系统架构中的故障范围,在大型系统中,系统会被分区以解耦服务间的依赖关系。其理念是,一个故障不应该导致整个系统崩溃.在隔板模式中,最好将应用程序高度依赖的元素隔离成多个服务池,这样,即使其中一个发生故障,其他池仍然可以为上游提供服务。 构建浮动IP模式 为了实现该目的,可以将网络接口从故障实例转移到新服务器。网络接口通常是一个网络接口卡(Network Interface Card,NIC),用于辅助服务器之间的网络通信。网络接口可以采用硬件的形式,也可以采用软件的形式。转移网络接口意味着新服务器现在承担了旧服务器的身份。这样一来,应用程序就可以继续使用相同的DNS和IP地址。你还可以通过将网络接口移至原始实例轻松地回滚。 采用容器部署应用程序 随着多种编程语言的发明和技术的发展,应用程序又将面临新的挑战。不同的应用程序栈需要不同的硬件和软件部署环境。通常,应用程序需要跨平台运行并能够从一个平台迁移到另一平台。解决方案需要可以在任何地方运行任何内容,并且保持一致性、轻量级且可移植。 就像航运集装箱标准化了货物的运输一样,软件容器为应用程序的运输制定了标准。Docker创建了一种容器,其中包含了运行软件应用程序所需的所有文件和内容,例如文件系统结构、守护程序、库和应用程序依赖项等。容器将软件与其周边的开发和预演(Staging)环境隔离开。这有助于减少在同一基础设施上运行不同软件的团队之间的冲突。 应用程序架构中的数据库处理 数据始终是应用程序开发的中心,并且数据的伸缩非常具有挑战性。高效的数据处理可以改善应用程序的延迟和性能。 在应用程序部署方面,随着应用程序用户群的增长,关系型数据库需要处理越来越多的数据。你需要添加更多的存储或通过增加内存和CPU的方式来垂直伸缩数据库服务器。在伸缩关系型数据库时,水平伸缩通常不那么容易。如果应用程序是读密集型的,那么可以通过创建数据库的只读副本来实现水平伸缩。将所有的读取请求路由到数据库只读副本,同时让数据库主节点来服务写入和更新请求。由于只读副本需要异步复制,因此可能会增加一些延迟时间。如果应用程序可以容忍几毫秒的延迟,那么应该选用只读副本的方案。 你也可以通过只读副本来降低报表查询的压力。你可以使用数据库分片技术为关系型数据库创建多个主库,并引入水平伸缩的概念。分片技术用于提高多数据库服务器的写入性能。从本质上来说,它采用一致的结构来创建和划分数据库,并使用恰当的表列作为键来分配写入处理。 避免解决方案架构中的反模式 反模式常见案例 伸缩是被动的,需要手动完成。 缺少自动化。当应用服务器崩溃时,管理员必须手动启动并配置新服务器,还需手动通知用户。应该将资源监控、替代资源的启动,甚至在资源更改时发出通知等整个过程全部自动化。 服务器长期使用硬编码的IP地址,这会降低灵活性。 以单体的方式构建应用程序,其中架构的所有层(包括Web层、应用层和数据层)都紧密耦合并依赖于服务器。 应用程序与服务器绑定,并且服务器之间直接进行通信,用户身份验证和会话信息存储在本地服务器中,所有静态文件均从本地服务器提供。 将一种类型的数据库应用于各种需求。 直接从服务器提供静态内容(例如高分辨率图像和视频),而没有进行任何缓存。 在没有精细安全策略的情况下开放服务器的访问权限,会导致安全漏洞。