1.3.4 低成本
在设计高性能、高可用的架构方案时,如果涉及到数百、数千甚至数万台服务器,成本就会成为一个非常重要的考虑点。为了控制成本,需要减少服务器的数量,这与增加更多服务器来提升性能和可用性的通用做法相冲突。因此,低成本往往不是架构设计的首要目标,而是一个附加约束。为了解决这个问题,需要先设定一个成本目标,然后根据高性能和高可用的要求设计方案,并评估是否能够满足成本目标。如果不能,就需要重新设计架构;如果无论如何都无法设计出满足成本要求的方案,那只能找老板调整成本目标了。低成本给架构设计带来的主要复杂度体现在,往往只有"创新"才能达到低成本目标。"创新"的含义是开创一个全新的技术领域,或者引入新技术来解决问题。如果没有找到能够解决自己问题的新技术,那么就需要自己创造新技术了。例如,NoSQL(如Memcache、Redis等)是为了解决关系型数据库无法应对高并发访问带来的访问压力;全文搜索引擎(如Sphinx、Elasticsearch、Solr)是为了解决关系型数据库like搜索的低效问题;Hadoop则是为了解决传统文件系统无法应对海量数据存储和计算的问题。创造新技术的主要复杂度在于需要创造全新的理念和技术,并且新技术需要与旧技术相比有质的飞跃。
1.3.5 安全
从技术的角度来讲,安全可以分为两类:
- 一类是功能上的安全,
- 一类是架构上的安全。
1.3.5.1 功能安全
常见的 XSS 攻击、CSRF 攻击、SQL 注入、Windows 漏洞、密码破解等,本质上是因为系统实现有漏洞,黑客有了可乘之机,功能安全其实就是“防小偷”。
从实现的角度来看,功能安全更多地是和具体的编码相关,与架构关系不大。开发框架会内嵌常见的安全功能,但是开发框架本身也可能存在安全漏洞和风险。
所以功能安全是一个逐步完善的过程,而且往往都是在问题出现后才能有针对性的提出解决方案,我们永远无法预测系统下一个漏洞在哪里,也不敢说自己的系统肯定没有任何问题。
换句话讲,功能安全其实也是一个“攻”与“防”的矛盾,只能在这种攻防大战中逐步完善,不可能在系统架构设计的时候一劳永逸地解决。
1.3.5.2 架构安全
如果说功能安全是“防小偷”,那么架构安全就是“防强盗”。
架构设计时需要特别关注架构安全,尤其是互联网时代,理论上来说系统部署在互联网上时,全球任何地方都可以发起攻击。
传统的架构安全主要依靠防火墙,防火墙最基本的功能就是隔离网络,通过将网络划分成不同的区域,制定出不同区域之间的访问控制策略来控制不同信任程度区域间传送的数据流。
防火墙的功能虽然强大,但性能一般,所以在传统的银行和企业应用领域应用较多。但在互联网领域,防火墙的应用场景并不多。
互联网系统的架构安全目前并没有太好的设计手段来实现,更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现。
1.3.6 规模
规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。常见的规模带来的复杂度有:
1.功能越来越多,系统复杂度指数级上升
2.数据越来越多,系统复杂度发生质变
1.3.6.1 功能越来越多,系统复杂度指数级上升
例如,某个系统开始只有 3 大功能,后来不断增加到 8 大功能,虽然还是同一个系统,但复杂度已经相差很大了,具体相差多大呢?我以一个简单的抽象模型来计算一下,假设系统间的功能都是两两相关的,系统的复杂度 = 功能数量 + 功能之间的连接数量,通过计算我们可以看出:3个功能的系统复杂度为3+3=6
8个功能的系统复杂度为8+(7+0)*8/2=36 可以看出,具备8个功能的系统的复杂度不是比具备 3 个功能的系统的复杂度多5,而是多了30,基本是指数级增长的,主要原因在于随着系统功能数量增多,功能之间的连接呈指数级增长。下图形象地展示了功能数量的增多带来了复杂度。
1.3.6.2 数据越来越多,系统复杂度发生质变
随着数据量的不断增长,传统的数据处理和管理方式已经无法适应,因此“大数据”这一概念应运而生。大数据的诞生主要是为了解决数据规模变得越来越大时,传统的数据收集、存储、分析等方式无法胜任的问题。Google的三篇技术论文,即Google File System、Google Bigtable和Google MapReduce则分别开创了大数据文件存储、列式数据存储和大数据运算的技术领域。即便数据规模没有达到大数据的水平,数据增长仍然可能会给系统带来复杂性。例如,在使用关系数据库存储数据时,当单表数据达到一定规模时,就会导致添加索引、修改表结构等操作变得很慢,可能需要几个小时,这就会对业务造成不良影响。因此,必须考虑将单表拆分为多表来解决这个问题,但这个过程也会引入更多的复杂性。
1.4 简单的复杂度分析案例
我们来分析一个简单的案例,一起来看看如何将“架构设计的真正目的是为了解决软件系统复杂度带来的问题”这个指导思想应用到实践中。
当我们设计一个大学的学生管理系统时,我们需要考虑该系统的复杂度以及如何解决这些复杂度带来的问题。首先,我们可以将该系统的复杂度分为以下几个方面:
性能 该系统的访问频率并不高,因此性能并不是一个很大的问题。我们可以使用MySQL作为存储,Nginx作为Web服务器,无需考虑缓存。
可扩展性 该系统的功能比较稳定,可扩展的空间并不大,因此可扩展性方面也不是一个很大的问题。
高可用 数据丢失是不可接受的,故该系统的高可用性方面需要考虑多种异常情况,如机器故障、机房故障等。为此,我们需要设计MySQL同机房主备方案和MySQL跨机房同步方案。
安全性 该系统存储的信息涉及到学生的隐私,因此需要考虑安全性。我们可以使用Nginx提供的ACL控制、用户账号密码管理和数据库访问权限控制来保证系统的安全性。
成本 由于该系统比较简单,基本上几台服务器就可以搞定,因此成本方面并不需要太多关注。
规模 同上,规模复杂度无需过度关注。
总体来说,我们需要在架构设计中充分考虑系统的复杂度,同时根据不同问题选择合适的解决方案,以提高系统的可靠性和安全性。
1.5 总结
第一章提出了架构的根本目是解决系统复杂度,并简要说明系统复杂度的六个来源及通用解法,为我们设计架构提供了清晰可执行的操作思路。
二、微服务架构解决了高可用、可扩展问题,但性能下降、
成本&规模复杂度暴增
我们知道,这些年来随着设备和新技术的发展,软件的架构模式发生了很大的变化。软件架构模式大体来说经历了从单机、集中式到分布式微服务架构三个阶段的演进 。随着分布式技术的快速兴起,我们已经进入到了微服务架构时代。
2.1 微服务架构的优点
与传统单体应用架构相比,微服务架构有很多优点,具体表现如下:
2.1.1 高可用
当架构中的某一组件发生故障时,在单一进程的传统架构下,故障很有可能在进程内扩散,导致整个应用不可用。在微服务架构下,故障会被隔离在单个服务中。若设计良好,其他服务可通过重试、平稳退化等机制实现应用层面的容错。
2.1.4 可扩展
单个服务应用也可以实现横向扩展,这种扩展可以通过将整个应用完整的复制到不同的节点中实现。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务可以根据实际需求独立进行扩展。
2.2 微服务的缺点
2.2.1 复杂度高
与单体式架构相比,微服务会导致复杂性上升,因为多个团队会在更多地方创建更多服务。若管理不当,则会导致开发速度和效率降低。
2.2.2 基础设施成本呈指数级增长
每个新的微服务都有自己的成本,例如测试工具、托管基础架构和监控工具等方面。
2.2.3 性能下降
微服务之间通过REST、RPC等形式进行交互,通信的时延会受到较大的影响。