架构设计复杂度来源
极客时间《从零开始学架构》学习笔记
04 | 复杂度来源:高性能
首先把系统跑起来,然后尽可能的做单机性能优化,在单机成为瓶颈时,考虑集群的任务分配和任务分解。
一般人可能并没有机会去接触类似于淘宝或者微信这样量级的架构,从个人而言,我更关注单机性能优化。
除了传统意义上的单机优化,如果把应用部署阿里云这样的云平台上,单机性能优化是否有不同?
开辟新领域的技术,增加了选择或组合的可能,给软件系统带来复杂度。
高性能可以带来良好的用户体验(快),满足业务增长的需要(Google、淘宝、微信)
高性能带来的复杂度分为单机内部和多机集群两方面。
从没有操作系统的简单输入、计算、输出,到批处理,再到由操作系统调度的分时的进程,然后发展出进程间通信(管道、消息队列、信号量、共享存储),接下来进程内部又分出了线程,再加上互斥锁机制,操作系统调度的最小单位变成了线程,而进程是操作系统分配资源的最小单位。
多进程多线程其实仍然是分时的,为了让多个 CPU 同时工作,又有了三种方案 SMP(Symmetric Multi-Processor,对称多处理器结构)、NUMA(Non-Uniform Memory Access,非一致存储访问结构)、MPP(Massive Parallel Processing,海量并行结构)——不明觉厉
其实操作系统帮助我们屏蔽的很多复杂性。
Nginx 可以用多进程或者多线程,JBoss 多线程,Redis 单进程,Memcache 多线程……都是高性能,但是差别很大。
当单机性能无法支撑业务复杂度时,就要采用集群的方式,从任务分配到任务分解,尽可能提高整体性能。
现在比较流行的微服务有点类似于任务分解?
最终决定业务处理性能的还是业务逻辑本身,性能在理论上有一个上限。高性能并没有绝对标准,要从业务出发,结合行业经验判断。
05 | 复杂度来源:高可用
High availability (HA) is a characteristic of a system, which aims to ensure an agreed level of operational performance, usually uptime, for a higher than normal period.
高可用意味着无中断,系统高可用方案本质上都是通过“冗余”实现。
高性能增加机器的目的在于“扩展”处理性能;高可用增加机器的目的在于“冗余”处理单元。
有没有可能增加机器同时满足高性能和高可用?感觉上高性能和高可用是不同的两个衡量维度,有可能在降低性能指标的情况下保证高可用?
计算高可用将计算分配到不同主机,有双机(主备:冷备、热备、温备;主主)和集群,ZooKeeper 采用 1 主多备,Memcached 全主 0 备。
存储高可用将存储冗余到不同主机,与计算高可用不同,数据转移需要经过线路传输,有物理上的传输速度限制,同时传输线路本身也可能有问题(中断、拥塞、异常),从而造成延时。存储高可用的难点不在于如何备份数据,而在于如何减少或者规避桑树不一致对业务造成的影响。
分布式领域的 CAP 定义,从理论上论证了存储高可用的复杂度。存储高可用不可能同时满足“一致性、可用性、分区容错性”,最多满足其中两个。
计算高可用和存储高可用都建立在状态决策的基础上,与此同时,通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确。无论是独裁式、协商式或者民主式,状态决策都可能出现问题(这个和人类社会很像),需要结合业务,进行分析、判断和选择。
通常情况下,高可用要比高性能复杂一些,需要考虑的场景更多(如果不可用了,自然也就没有性能)。4 个 9 的可用性(99.99%)意味着系统全年宕机时间不超过 53 分钟。
Zookeeper 使用 ZAB 算法实现选举。
高可用是指正常提供服务的概率,主要和故障恢复时间有关;高可靠是指出问题的概率,主要和故障次数有关。
06 | 复杂度来源:可扩展性
Scalability is the property of a system to handle a growing amount of work by adding resources to the system. … In computing, scalability is characteristic of computers, networks, algorithms, networking protocols, programs and application.
面向对象和设计模式都试图解决扩展性带来的问题,但是想要做到“正确预测变化、完美封装变化”难度非常大。
不能每个设计点都考虑可扩展性,也不能完全不考虑;与此同时,所有的预测都有出错的可能。
即使预测正确,那么采用合适的解决方案,也很重要。一种是将变化封装在一个变化层,难点在于拆分变化层和稳定层,并且设计两层之间的借口;另一种是提炼出稳定的抽象层。然后根据具体业务需要定制开发抽象层。
装饰者模式的经典例子 TextView,其实只要能看懂那张类关系图,那么也就明白了什么是装饰者模式。我觉的难点在于 Decorator 类继承并且聚合了 Commponent 类,并且有多个 ConcreteDecorator 类继承 Decorator 类并实现 Operatorion() 方法。
老师在留言里面提到,“设计的时候考虑可扩展性,但是如果代价比较大,就展示不做,有需要时再重构”,这个比较实用。
之前做过的系统对于可扩展没有什么要求,实在不行的时候,就会考虑推到重来。
可扩展性并不想前面提到的高性能和高可用那么容易衡量,因为扩展的可能性还是要小一些,或者说可扩展性并不是特别的明显。
按照专栏里面的说法,设计模式好像更多的是考虑可扩展性,感觉上似乎对于高性能和高可用意义不大。但是反过来,对于普通的应用开发者来说,是不是遇到扩展性问题(或者需求变化)的可能性要远大于高性能或者高可用?
07 | 复杂度来源:低成本、安全、规模
以前其实是没有成本意识的。
低成本与高性能和高可用在本质上是有冲突的,低成本一般不会成为架构设计的首要目标,但是成本往往会成为架构设计的制约。
我自己的目标是成为“经济适用型”的架构师,那么就需要用合适的技术和合理的创新来实现性价比,进而需要了解业界已有的成熟架构,从中选择适用的设计。
相比创造新技术来说,引入新技术并且将新技术与已有技术结合,相对来说还是要容易一些。
惭愧的说,也没有想过架构安全的事。
因为以前的开发环境基本上是在一个封闭的内网环境,面对的也大多是“小白”用户(现在可能有一些高手了),所以不需要在安全上考虑太多,最多是使用框架自带的一些功能安全选项,比如避免 SQL 注入。
架构安全以前是由专人负责,其实就是网络以及防火墙的配置。
从专栏文章来看,我觉得架构师需要有安全意识(作为程序员也一样),但是安全的事情可能还是需要专业的人去处理。
我以前面对的系统可能勉强可以算的上是中等规模,功能比较多,数据量中等,应该还没有到“量变引起质变”的时候,但是应对起来似乎也比较勉强。
顺便回答思考题,这个系统的复杂度主要来源在于高可靠,一般是要求 24 × 7 不停机的,但是实际上估计达不到 4 个 9 的可靠性。
看到留言里面提到了“可伸缩性”,如果是租用数据中心的存储和计算资源,那么可伸缩性可以省钱,是有意义的;如果是自建系统,那么“可伸”类似于“可扩展”,“可缩”的意义就不大了,很难在自建环境中调配使用。
这四篇专栏文章讲述了架构设计复杂度的来源,相对重要的高性能、高可用和可扩展,也是后面整个课程的脉络,以及进行架构设计的考量维度。
参考资料:架构设计复杂度的 6 个来源
版权声明: 本文为 InfoQ 作者【escray】的原创文章。
原文链接:【http://xie.infoq.cn/article/8979628ccba8e621811b049fb】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论