Open AlexiaChen opened 4 years ago
Linux内核有架构,MySQL有架构,JVM有架构,微信有架构,支付宝有架构,我们平时所说的架构到底是谈什么类型的架构?
当然,从上面所说的提问,我们知道了,架构一般泛指软件系统更加高层的设计或者组织方式,是更加宏观的层面,而不是代码细节层面,比如类的关系组织。
架构也有很多层次:
系统(软件系统)一般是一堆有关联的实体组成,通过某种规则运行,完成单个实体不能单独完成工作的群体。当然,子系统也是一样的,也是一群有关联的实体组成的系统,一般是大系统的一部分,看角度了。大致是一个树形结构。
举个例子:
子系统追溯到叶子节点的时候,一般就是模块与组件了,因为工程量,规模或许是其他维度的原因,只能是组件,模块规模了。
模块是从逻辑角度拆分得到的软件单元,比如一个模块由很多Java package构成。再比如,MySQL模块负责存储数据,ES模块主要负责搜索数据。
组件是从物理角度拆分得到的系统单元,比如这个Web服务系统,从物理上看可以分为Nginx,Web服务器,MySQL数据库,这个可以称为组件。所以一般组件是与编程语言无关的,可复用,甚至可编程的软件产品。
框架与架构是非常相似的概念,是强关联关系。
框架一般是实现了某个软件组件的规范,比如MVC就是一种开发规范,MVP,MVVM,J2EE等。同时框架也是提供基础功能的产品,比如,Spring MVC是MVC开发框架,Spring提供了很多方便开发的东西。所以框架某种角度可以说是一种约束,约束开发人员在一定的范围内开发,尽量减少犯错。
架构一般是软件系统的基础结构,这个结构可以是物理上的,也可以是逻辑上的。
当然,很多网络上,框架和架构有些是混用的,这个视情况而定,它们不一定是错的,在特定的上下文里理解了就行。
Q: 不做架构就运行不起来吗?
A: 显然不是,创业公司初始产品一般是不太做架构设计的,基本是单体应用开始撸代码了,不一样跑的好好的?
Q: 做了架构设计就能提升开发效率?
A: 不是,架构设计是需要耗费时间和人力,这部分投入如果用来尽早编码,可能会更快。微服务架构适合创业公司吗? 显然不适合。
Q: 设计良好的架构能促进业务发展?
A: 貌似有一定道理,微信的架构好吗?照超过来能成功吗?显然不是。架构是从实际出发,分析问题本身而得到的结果。不然就是PPT架构师。
Q: 为高性能,高可用,高扩展,所以要做架构设计,是不是?
A: 恩,有一定工作经历了,确实互联网很多架构是奔着这几个目标设计的。但记住,这样的系统是慢慢根据实际情况迭代出来的,不是一开始架构设计出来的,一开始就奔着这个目标,是会给团队带来灾难的。
最终,软件架构。 也就是随着软件规模增加,计算相关的算法和数据结构不再构成主要的设计问题(数据结构和算法大部分已经固化到基础设施上,比如MySQL,Redis,基础库和框架等),当系统是由许多部分组成,整个系统的组织或架构,导致了一系列的新设计问题。比如,内部耦合严重,不好维护等。
所以,架构设计的主要目的是为了解决复杂度带来的问题。你也看出来了,后面文章所说的架构一般是业务系统的架构,不是基础设施实现的架构。虽然一些架构思想是一样的。当然,业务架构和可以简单理解为,把开源组件,通过物理+逻辑的组织方式调整布局,或进行二次开发,来达到你想要的目的。这么理解可能比较low,不过这就是大多数互联网的套路,比如大数据系统什么的。
打算从两方面来说,一个单机内部为了高性能带来的复杂度,另一个是集群为了高性能带来的。
单机的一些高性能,一个是操作系统相关的高性能API,另一个就是对多线程,多进程的模型做合理设计和取舍来适应多核CPU设计高性能,很繁琐。目前多核方案是SMP方案。Nginx是多进程,Redis单进程,memcached是多线程,这几个都单机都实现了高性能,但是内部实现差异巨大。所以复杂。吃力不讨好,一般做业务架构,不往这方面考虑。
通过大量机器提高性能,并不是增加机器这么简单,比较复杂,所以业务架构往往是优化集群复杂度,不知道大家能不能理解。支付宝等支持高并发的系统,后面可能是几万台机器。这么多的机器看起来貌似是堆机器堆上去的性能,但是如果是普通的人来做,可能十几万,几十万都达不到它们的性能。
所以,这节会着重围绕集群复杂度来讲。
从单个服务器,增加到多个时,就需要有个全局的分配器出现,来处理任务的分发,分配器可能是硬件设备(F5,交换机等),也可能是软件网络内核(LVS,就是章文崇博士写的这个,阿里P11,滴滴技术副总),也可能是负载均衡软件(Nginx,HAProxy)。
分配器的算法选择,轮询,权重分配还是服务器负载分配?如果是负载分配,业务服务器还要上报自己的负载状态给分配器。随着任务量的要求,业务服务器不断增加,但是始终会有瓶颈的,瓶颈就在分配器是单台,最后分配器也要弄一个集群。麻烦大了。架构突然复杂。
分配器变成集群以后,带来的问题就是要将不同的用户分配到不同的分配器上,常见的方法是DNS轮询,智能DNS,CDN,GSLB全局负载设备等。关系一旦变成多对多,那么状态管理,故障处理复杂度也会陡增。
之前的任务分发方式,能突破单台机器的极限,可以满足一定量的业务需求,但是,单纯通过这种扩展,收益会越来越低。主要原因是,你既然想通过加机器,那么就说明你的用户量多了,业务和需求越来越复杂,单体应用代码也越来越复杂,单台机器的性能会越来越低。
这时候需要用业务拆分的手段进行分解,就是以业务来拆分,从逻辑上把大业务拆分成子业务,比如微信中的子业务,朋友圈,漂流瓶,评论系统啥的。把业务拆分成小的来配合。走SOA的路线,子业务之间通过RPC来通信。
从业务角度看,业务拆分不会减少功能,也不会减少代码量(代码量可能还会增加,比如增加RPC模块啥的),但是为什么这样做就可以提高性能了呢?
业务简单的系统更容易做到高性能,功能简单,影响性能的点越少,有利于分析,优化。系统业务复杂,很难找到关键性能点,影响的地方太多,迁一发而动全身。
可以针对单个子业务进行扩展。改动粒度小,好Profile,好优化,好维护。
是不是拆分粒度越小越好?也不是。拆分的太小,表明子业务增加,子业务之间的通信RPC是走网络的,子业务太多的话,时间成本会加大。要适可而止。从实际业务考虑来拆分,把握一个粒度。
就是字面意思,很高的可用性,就是系统7×24小时不间断的运行,关键是“不间断”,怎么做呢?软件,硬件都会有BUG,故障。Google每天有会硬件故障,在那么大的集群下。
所以,高可用方案是五花八门,但是万变不离其宗的是,都是通过“冗余”来实现的,通俗点说就是加机器,把数据A,分别冗余备份在多台机器上。跟高性能的方案确实有点像,区别在于,高性能增加机器是增加处理器性能,高可用是增加机器为了“备份”冗余的数据或者计算资源。
这里主要是业务逻辑的处理,是CPU密集的。前面提到了,同样是增加机器,那么还会有一个机器作为一个任务分配的角色,这也是复杂度的体现,任务分配器需要增加分配算法,常见的双机算法有,主备,主主。主备又分为冷备,温备,热备。
双机是比较简单的,更复杂的还有高可用集群,分配算法更加复杂,有1主3备,2主2备,3主1备,4主0备,这几种方案没有最优,只有合适,需要结合业务。Zookeeper采用的就是1主多备,memcached就是全主0备。
存储与计算的高可用区别在于:它需要将数据从一台机器移动到另一台机器,需要经过线路传输。线路传输大概在毫秒级:同一个机房,在一台交换机上内部能够做到几毫秒。分布在不同地方的机房耗时大概是几十到上百毫秒。
看起来以上的数字还挺快的,其实对于高可用系统来说,意味着,在某一小段时间内,数据肯定是不一致的,数据不一致,就意味着业务表现不一样。而且线路也会出现故障。2015年支付宝因为光缆被挖断,业务就受到了巨大影响。所以无论如何,请把传输这个先当作是不太可靠的。
不做“冗余“,达不到高可用,数据做“冗余”,那么就肯定有传输的不可靠问题,传输不可靠带来的就是,某段时间内的数据不一致。所以存储高可用的难点就是,假设一定会存在数据不一致的前提下,怎样减少或者规避数据不一致对业务造成的影响。而不是数据怎样备份。
另外,存储高可用需要考虑CAP原理,强一致性,高可用性,强分区容错性,大概只能同时满足2个100%,最后一个可以尽量提高。但是达不到100%。
状态决策是啥?就是你的系统要能判断当前系统(一般是集群)的整个状态是异常还是正常,如果出现异常,就需要采取行动来保证高可用。看样子需要有一个元数据的管理决策者,类似于leader,聪明,这里确实开始涉及到了分布式系统的共识问题(非拜占庭网络)。下面列举几个方式:
只有一个决策者,结果是不会出现决策混乱,但是前面说了,网络,机器长期下来都有故障,这个方案单点故障问题出现就废了。
最常见的就是主备切换,这个比独裁好些,但是一旦网络出现问题,状态决策怎样做?哪个为主哪个为备?总会出现问题的。
当今你接触到的几个常见的共识算法都是民主的,比如Paxos,Raft,ZAB。就是通过多个独立的个体投票来选举leader进行状态决策。主要是多个独立个体,即使出现网络问题,一般也会出现大多数取胜,所以容错高了不少。民主的本质就是少数服从多数。
当然,民主决策有个问题就是脑裂。就是一个集群因为连接中断等原因,造成了两个独立分隔的子集群,每个子集群单独进行选举,于是选出了两个leader,相当于有了两个大脑,所以为了解决这个问题,民主决策的系统一般都采用”投票节点数必须超过总节点数一半“的规则来处理。
以上的方式虽然解决了脑裂问题,但是同时降低了系统整体的可用性,如果系统不是因为脑裂问题导致投票节点数过少,而真是因为节点故障,此时系统是不会进行选举的,整个系统相当于宕机了。
所以,无论采取什么方案,状态决策都不可能做到任何场景下都没有问题,但完全不做高可用方案又会有更大问题,所以要有trade-off。
这个主要是因为业务的变化了。大部分是靠自己的经验和直觉。
应对变化的方案就是拆分,分离出变化层和稳定层。然后两层之间需要设计一组接口,一般的实践就是《设计模式》将的那套东西了。这方面多套用,多思考别人的模式就可以了。
当我们设计”高性能“,”高可用“往往是通过加机器来实现的,但是低成本往往又是减少机器,它们本质上是冲突的。这个也需要权衡了。一般是设定一个成本目标,比如不能超过XX上限,花XX钱的前提下,设计”高性能“,”高可用“的方案,评估方案是否符合成本,不行就重新设计架构,如果实在不行,那就只能找老板沟通了。
低成本给架构设计带来的挑战主要是,往往只有”创新“才能达到低成本目标。这”创新“既包括了开创一个全新的技术领域(对于绝大部分公司要求过高),也包括引入新技术,找不到新技术,只有自己开创了。比如阿里巴巴去IOE,自研OceanBase,魔改InnoDB等等。
新技术的例子很多,大部分公司基本是用这样现成的,比如:
NoSQL(memcached,Redis)的出现为了解决关系型数据库无法应对的高并发访问带来的压力
ElasticSearch,Solr的出现是为了解决关系型数据库like搜索的低效问题
Hadoop(HDFS是GFS开原版,HBase是BigTable的开原版)的出现是为了解决传统文件系统无法应对海量数据存储和计算的问题。
自研创新的例子:
Linkedin为了处理每天5亿个事件,开发出了Kafka
FaceBook为了解决PHP的低效,搞出了HHVM。
引入新技术的复杂度主要是需要团队去熟悉新的技术栈,并跟已有的系统集成。创造新技术难度在于创造全新的理念和技术,与旧的相比需要有质的飞跃,比如Flink 超越了 Spark。
所以显然后者难,一般的小公司靠引入新技术来达到低成本,高开发效率的目标。不应该自己造轮子。
一旦说起架构,本质上就是不确定性的,这个人认为可以这样,另一个认为这样不行。一旦涉及”选择“,就可能会让人陷入两难,比如,后端数据库用MongoDB还是MySQL,前端用Vue还是React?
其实不用纠结,架构设计可以遵循以下原则。
合适优于业界领先。
如果不遵循这个原则,一般以失败告终,不外乎以下几个原因:
没那么多人,却想干那么多活。
没那么多技术和人才积累,却想一步登天。
业务量级没到那个程度,却幻想灵光一现成为天才。
简单优于复杂。
程序员毕竟是有些技术情怀的,追求业界先进,追求炫酷的新技术,所以如果你作为一个架构师,不要被你的队员带歪,不要被有意无意地带领团队走向复杂,你心中要有个指标,就是复杂性。复杂性尽量选择简单的,至少是你当前认为更简单的。设计一个主备方案,如果用心跳来实现互相报告状态,可能大家认为太简单了,引入ZooKeeper来做主备决策,大家可能认为才高大上些,你看ZAB共识协议,多么高大上,但是真正理解ZAB协议的普通程序员很少。
组成系统的组件更多意味着更复杂,同时它们的互交关系也更复杂。你可以想像一个图结构,一个节点的出度入度很多,脑袋开始理不清楚了。出问题太难排查了。
意思就是单个组件承担了太多的功能。单体应用。往往随着需求增加都会变成这样。
之前说的Zookeeper就挺复杂的,它的功能本身是分布式选举,采用ZAB协议,功能简单,但实现复杂,相比之下,etcd就更简单些,因为etcd采用的是Raft协议,Raft协议更加容易理解和实现。你看,PingCAP这家数据库公司选择的就是etcd翻译过来的Rust代码实现的Raft协议。如果好奇他们为什么这样,可以去他们网站上看他们写的博客。
KISS原则总是在哪里都有用的。
演进优于一步到位。
阿里巴巴有篇文章写的这样一句话:”好的系统架构是迭代出来的,不是设计出来的“。 请体会下,说的就是这个意思。主要因为,软件系统唯一的不变就是变化,拥抱变化,才能主宰未来。所以是好的软件是演进出来的。没见过世界上任何一个知名开源软件的仓库的第一个commit上去的代码,架构或技术上就很牛逼,有些质量可能真不敢恭维。
只要记住这几个原则就好,不要被炫酷的东西暂时迷惑住了双眼就好。
首先,从这里开始,普通程序员要明白,架构设计的思想无处不在,不要总觉得架构师很牛逼,可望不可及。我觉得架构师这个title,可能是国内互联网的流行(因为真的太火了),给各位造成了些误解。因为国内的架构师,一般是要应对所谓的”三高“ (高可用,高并发,高性能)。比如,XX架构师好牛逼,带团队实现了XX系统,双十一抗住了XX量级。这可能是阿里带出来的节奏。你看国外的Google,Microsoft等顶级公司,招聘的JD上就很少写架构师(Architector)这种岗位,David Culter老爷子是架构师吗? 他可不是。至少title不是。但是他不比国内互联网大厂的P8,P9什么的架构师牛逼多了?微软最高技术级别。阿里的多隆目前暂时比不过。有些人把多隆比作中国的Jeff Dean,我觉得就目前的展现出来的成果,多隆比Jeff Dean差得还是天远。Jeff Dean的技术栈,可能全世界也没几个达到,不是单纯个人技术比较。
所以说架构师是个很虚的概念,但是架构设计是个很真实的概念,软件系统哪里都需要架构,只是国外的一些大牛人家没天天说自己是架构师而已。
说了那么多,回归下正题。架构设计是有套路的(特别是互联网后端的业务架构,大数据架构,公众号文章推送的架构文章还不多吗?),按照百度或者Google出来的套路,参考别人的经验,即使没有丰富的架构实战经验,也可以做出基本可行的架构。
根据前面的原则设计适合当下的系统,千万不要过于复杂。给各个子系统,组件作复杂度排序,优先解决复杂度最高的问题。对于同一个复杂度的问题,软件系统的方案可以有多个,总是可以综合挑出个性价比最高的方案。
确定了系统面临的主要问题后,方案设计就有了明确目标,我们就可以开始真正进行架构设计了。绝大部分的架构设计不需要天才那样的创新,首先,对一存在的技术和开源工具组件非常熟悉,对已经验证过的架构模式烂熟于心,然后根据自己对业务的理解,挑选合适的架构模式进行组合,再对组合后的方案进行修改和调整。其实本质上跟电脑城配置组装电脑的没啥区别,你要根据当前的成本,了解各种CPU,内存,主板的性价比。
当然,架构设计需要有些创新,不过也就是微创新,大部分情况都是基于已有的成熟技术和架构。不过话说回来,也不要真把架构设计当成电脑城组装电脑的人员了。
根据这章节的标题,想说,架构设计的一个错误就是只做一个方案。
这样做有很多弊端,一个是万一经验不足,想的不够全面,架构评审的时候会出问题。
所以:
备选方案数量以3-5个为最佳
备选方案的差异在架构上要比较明显
备选方案的技术不要只局限于自己熟悉的技术
备选方案细节不要过于详细
备选方案都是可行的(不可行你还备选?)
正确的做法是,备选阶段关注的是技术选型,而不是技术细节,技术选型的差异要比较明显。比如Zookeeper和etcd这两种方案差异就非常大。
选择备选方案有点困难,不过有以下一些原则,这个得看场景,至于怎么选,凭借经验了:
最简单的方案。选择复杂度最简单的。
最牛的方案,选择业界评价牛逼的,性能,功能,可用性最好。
最熟悉的方案,选择自己和团队最熟悉的
让领导拍板选择,列出备选方案,和基本的优缺点。
怎样选择以上方案呢?大概套路是这样:
把备选方案列出一个二维表格,就是各个方案在各个质量维度(性能,复杂度,成本,可扩展,可用性)的对比。
按照当前团队的状况,在质量维度排优先级,看哪个方案首先满足你需要的质量维度。
确定方案选型
主要就是选择的方案的技术细节了,需要对最终选择的方案的关键细节有比较深入的理解,比如用ES做全文搜索方案,那么需要对ES的设计原理有深入的理解,比如索引,副本,集群等。不能道听途说,看几篇文章的出结论。当然,你要深入理解,肯定要查找比较多的文章资料的,这一步是必不可少的,还有自己亲手搭建方案环境验证一些原型设计。
创世记的宏观概念和基本法差不多就两篇文章说完了,可能之后的架构文章就是比较细节的技术方面的研究了,这样更有助于宏观的选型。
EOF
什么是架构?
Linux内核有架构,MySQL有架构,JVM有架构,微信有架构,支付宝有架构,我们平时所说的架构到底是谈什么类型的架构?
当然,从上面所说的提问,我们知道了,架构一般泛指软件系统更加高层的设计或者组织方式,是更加宏观的层面,而不是代码细节层面,比如类的关系组织。
架构也有很多层次:
系统与子系统
系统(软件系统)一般是一堆有关联的实体组成,通过某种规则运行,完成单个实体不能单独完成工作的群体。当然,子系统也是一样的,也是一群有关联的实体组成的系统,一般是大系统的一部分,看角度了。大致是一个树形结构。
举个例子:
子系统追溯到叶子节点的时候,一般就是模块与组件了,因为工程量,规模或许是其他维度的原因,只能是组件,模块规模了。
模块与组件
模块是从逻辑角度拆分得到的软件单元,比如一个模块由很多Java package构成。再比如,MySQL模块负责存储数据,ES模块主要负责搜索数据。
组件是从物理角度拆分得到的系统单元,比如这个Web服务系统,从物理上看可以分为Nginx,Web服务器,MySQL数据库,这个可以称为组件。所以一般组件是与编程语言无关的,可复用,甚至可编程的软件产品。
框架与架构
框架与架构是非常相似的概念,是强关联关系。
框架一般是实现了某个软件组件的规范,比如MVC就是一种开发规范,MVP,MVVM,J2EE等。同时框架也是提供基础功能的产品,比如,Spring MVC是MVC开发框架,Spring提供了很多方便开发的东西。所以框架某种角度可以说是一种约束,约束开发人员在一定的范围内开发,尽量减少犯错。
架构一般是软件系统的基础结构,这个结构可以是物理上的,也可以是逻辑上的。
当然,很多网络上,框架和架构有些是混用的,这个视情况而定,它们不一定是错的,在特定的上下文里理解了就行。
架构目的
架构设计误区
Q: 不做架构就运行不起来吗?
A: 显然不是,创业公司初始产品一般是不太做架构设计的,基本是单体应用开始撸代码了,不一样跑的好好的?
Q: 做了架构设计就能提升开发效率?
A: 不是,架构设计是需要耗费时间和人力,这部分投入如果用来尽早编码,可能会更快。微服务架构适合创业公司吗? 显然不适合。
Q: 设计良好的架构能促进业务发展?
A: 貌似有一定道理,微信的架构好吗?照超过来能成功吗?显然不是。架构是从实际出发,分析问题本身而得到的结果。不然就是PPT架构师。
Q: 为高性能,高可用,高扩展,所以要做架构设计,是不是?
A: 恩,有一定工作经历了,确实互联网很多架构是奔着这几个目标设计的。但记住,这样的系统是慢慢根据实际情况迭代出来的,不是一开始架构设计出来的,一开始就奔着这个目标,是会给团队带来灾难的。
历史的发展
最终,软件架构。 也就是随着软件规模增加,计算相关的算法和数据结构不再构成主要的设计问题(数据结构和算法大部分已经固化到基础设施上,比如MySQL,Redis,基础库和框架等),当系统是由许多部分组成,整个系统的组织或架构,导致了一系列的新设计问题。比如,内部耦合严重,不好维护等。
所以,架构设计的主要目的是为了解决复杂度带来的问题。你也看出来了,后面文章所说的架构一般是业务系统的架构,不是基础设施实现的架构。虽然一些架构思想是一样的。当然,业务架构和可以简单理解为,把开源组件,通过物理+逻辑的组织方式调整布局,或进行二次开发,来达到你想要的目的。这么理解可能比较low,不过这就是大多数互联网的套路,比如大数据系统什么的。
复杂度来源
高性能
打算从两方面来说,一个单机内部为了高性能带来的复杂度,另一个是集群为了高性能带来的。
单机复杂度
单机的一些高性能,一个是操作系统相关的高性能API,另一个就是对多线程,多进程的模型做合理设计和取舍来适应多核CPU设计高性能,很繁琐。目前多核方案是SMP方案。Nginx是多进程,Redis单进程,memcached是多线程,这几个都单机都实现了高性能,但是内部实现差异巨大。所以复杂。吃力不讨好,一般做业务架构,不往这方面考虑。
集群的复杂度
通过大量机器提高性能,并不是增加机器这么简单,比较复杂,所以业务架构往往是优化集群复杂度,不知道大家能不能理解。支付宝等支持高并发的系统,后面可能是几万台机器。这么多的机器看起来貌似是堆机器堆上去的性能,但是如果是普通的人来做,可能十几万,几十万都达不到它们的性能。
所以,这节会着重围绕集群复杂度来讲。
从单个服务器,增加到多个时,就需要有个全局的分配器出现,来处理任务的分发,分配器可能是硬件设备(F5,交换机等),也可能是软件网络内核(LVS,就是章文崇博士写的这个,阿里P11,滴滴技术副总),也可能是负载均衡软件(Nginx,HAProxy)。
分配器的算法选择,轮询,权重分配还是服务器负载分配?如果是负载分配,业务服务器还要上报自己的负载状态给分配器。随着任务量的要求,业务服务器不断增加,但是始终会有瓶颈的,瓶颈就在分配器是单台,最后分配器也要弄一个集群。麻烦大了。架构突然复杂。
分配器变成集群以后,带来的问题就是要将不同的用户分配到不同的分配器上,常见的方法是DNS轮询,智能DNS,CDN,GSLB全局负载设备等。关系一旦变成多对多,那么状态管理,故障处理复杂度也会陡增。
之前的任务分发方式,能突破单台机器的极限,可以满足一定量的业务需求,但是,单纯通过这种扩展,收益会越来越低。主要原因是,你既然想通过加机器,那么就说明你的用户量多了,业务和需求越来越复杂,单体应用代码也越来越复杂,单台机器的性能会越来越低。
这时候需要用业务拆分的手段进行分解,就是以业务来拆分,从逻辑上把大业务拆分成子业务,比如微信中的子业务,朋友圈,漂流瓶,评论系统啥的。把业务拆分成小的来配合。走SOA的路线,子业务之间通过RPC来通信。
从业务角度看,业务拆分不会减少功能,也不会减少代码量(代码量可能还会增加,比如增加RPC模块啥的),但是为什么这样做就可以提高性能了呢?
业务简单的系统更容易做到高性能,功能简单,影响性能的点越少,有利于分析,优化。系统业务复杂,很难找到关键性能点,影响的地方太多,迁一发而动全身。
可以针对单个子业务进行扩展。改动粒度小,好Profile,好优化,好维护。
是不是拆分粒度越小越好?也不是。拆分的太小,表明子业务增加,子业务之间的通信RPC是走网络的,子业务太多的话,时间成本会加大。要适可而止。从实际业务考虑来拆分,把握一个粒度。
高可用
就是字面意思,很高的可用性,就是系统7×24小时不间断的运行,关键是“不间断”,怎么做呢?软件,硬件都会有BUG,故障。Google每天有会硬件故障,在那么大的集群下。
所以,高可用方案是五花八门,但是万变不离其宗的是,都是通过“冗余”来实现的,通俗点说就是加机器,把数据A,分别冗余备份在多台机器上。跟高性能的方案确实有点像,区别在于,高性能增加机器是增加处理器性能,高可用是增加机器为了“备份”冗余的数据或者计算资源。
这里主要是业务逻辑的处理,是CPU密集的。前面提到了,同样是增加机器,那么还会有一个机器作为一个任务分配的角色,这也是复杂度的体现,任务分配器需要增加分配算法,常见的双机算法有,主备,主主。主备又分为冷备,温备,热备。
双机是比较简单的,更复杂的还有高可用集群,分配算法更加复杂,有1主3备,2主2备,3主1备,4主0备,这几种方案没有最优,只有合适,需要结合业务。Zookeeper采用的就是1主多备,memcached就是全主0备。
存储与计算的高可用区别在于:它需要将数据从一台机器移动到另一台机器,需要经过线路传输。线路传输大概在毫秒级:同一个机房,在一台交换机上内部能够做到几毫秒。分布在不同地方的机房耗时大概是几十到上百毫秒。
看起来以上的数字还挺快的,其实对于高可用系统来说,意味着,在某一小段时间内,数据肯定是不一致的,数据不一致,就意味着业务表现不一样。而且线路也会出现故障。2015年支付宝因为光缆被挖断,业务就受到了巨大影响。所以无论如何,请把传输这个先当作是不太可靠的。
不做“冗余“,达不到高可用,数据做“冗余”,那么就肯定有传输的不可靠问题,传输不可靠带来的就是,某段时间内的数据不一致。所以存储高可用的难点就是,假设一定会存在数据不一致的前提下,怎样减少或者规避数据不一致对业务造成的影响。而不是数据怎样备份。
另外,存储高可用需要考虑CAP原理,强一致性,高可用性,强分区容错性,大概只能同时满足2个100%,最后一个可以尽量提高。但是达不到100%。
状态决策是啥?就是你的系统要能判断当前系统(一般是集群)的整个状态是异常还是正常,如果出现异常,就需要采取行动来保证高可用。看样子需要有一个元数据的管理决策者,类似于leader,聪明,这里确实开始涉及到了分布式系统的共识问题(非拜占庭网络)。下面列举几个方式:
只有一个决策者,结果是不会出现决策混乱,但是前面说了,网络,机器长期下来都有故障,这个方案单点故障问题出现就废了。
最常见的就是主备切换,这个比独裁好些,但是一旦网络出现问题,状态决策怎样做?哪个为主哪个为备?总会出现问题的。
当今你接触到的几个常见的共识算法都是民主的,比如Paxos,Raft,ZAB。就是通过多个独立的个体投票来选举leader进行状态决策。主要是多个独立个体,即使出现网络问题,一般也会出现大多数取胜,所以容错高了不少。民主的本质就是少数服从多数。
当然,民主决策有个问题就是脑裂。就是一个集群因为连接中断等原因,造成了两个独立分隔的子集群,每个子集群单独进行选举,于是选出了两个leader,相当于有了两个大脑,所以为了解决这个问题,民主决策的系统一般都采用”投票节点数必须超过总节点数一半“的规则来处理。
以上的方式虽然解决了脑裂问题,但是同时降低了系统整体的可用性,如果系统不是因为脑裂问题导致投票节点数过少,而真是因为节点故障,此时系统是不会进行选举的,整个系统相当于宕机了。
所以,无论采取什么方案,状态决策都不可能做到任何场景下都没有问题,但完全不做高可用方案又会有更大问题,所以要有trade-off。
可扩展性
这个主要是因为业务的变化了。大部分是靠自己的经验和直觉。
应对变化的方案就是拆分,分离出变化层和稳定层。然后两层之间需要设计一组接口,一般的实践就是《设计模式》将的那套东西了。这方面多套用,多思考别人的模式就可以了。
低成本
当我们设计”高性能“,”高可用“往往是通过加机器来实现的,但是低成本往往又是减少机器,它们本质上是冲突的。这个也需要权衡了。一般是设定一个成本目标,比如不能超过XX上限,花XX钱的前提下,设计”高性能“,”高可用“的方案,评估方案是否符合成本,不行就重新设计架构,如果实在不行,那就只能找老板沟通了。
低成本给架构设计带来的挑战主要是,往往只有”创新“才能达到低成本目标。这”创新“既包括了开创一个全新的技术领域(对于绝大部分公司要求过高),也包括引入新技术,找不到新技术,只有自己开创了。比如阿里巴巴去IOE,自研OceanBase,魔改InnoDB等等。
新技术的例子很多,大部分公司基本是用这样现成的,比如:
NoSQL(memcached,Redis)的出现为了解决关系型数据库无法应对的高并发访问带来的压力
ElasticSearch,Solr的出现是为了解决关系型数据库like搜索的低效问题
Hadoop(HDFS是GFS开原版,HBase是BigTable的开原版)的出现是为了解决传统文件系统无法应对海量数据存储和计算的问题。
自研创新的例子:
Linkedin为了处理每天5亿个事件,开发出了Kafka
FaceBook为了解决PHP的低效,搞出了HHVM。
引入新技术的复杂度主要是需要团队去熟悉新的技术栈,并跟已有的系统集成。创造新技术难度在于创造全新的理念和技术,与旧的相比需要有质的飞跃,比如Flink 超越了 Spark。
所以显然后者难,一般的小公司靠引入新技术来达到低成本,高开发效率的目标。不应该自己造轮子。
架构设计原则
一旦说起架构,本质上就是不确定性的,这个人认为可以这样,另一个认为这样不行。一旦涉及”选择“,就可能会让人陷入两难,比如,后端数据库用MongoDB还是MySQL,前端用Vue还是React?
其实不用纠结,架构设计可以遵循以下原则。
合适原则
合适优于业界领先。
如果不遵循这个原则,一般以失败告终,不外乎以下几个原因:
没那么多人,却想干那么多活。
没那么多技术和人才积累,却想一步登天。
业务量级没到那个程度,却幻想灵光一现成为天才。
简单原则
简单优于复杂。
程序员毕竟是有些技术情怀的,追求业界先进,追求炫酷的新技术,所以如果你作为一个架构师,不要被你的队员带歪,不要被有意无意地带领团队走向复杂,你心中要有个指标,就是复杂性。复杂性尽量选择简单的,至少是你当前认为更简单的。设计一个主备方案,如果用心跳来实现互相报告状态,可能大家认为太简单了,引入ZooKeeper来做主备决策,大家可能认为才高大上些,你看ZAB共识协议,多么高大上,但是真正理解ZAB协议的普通程序员很少。
组成系统的组件更多意味着更复杂,同时它们的互交关系也更复杂。你可以想像一个图结构,一个节点的出度入度很多,脑袋开始理不清楚了。出问题太难排查了。
意思就是单个组件承担了太多的功能。单体应用。往往随着需求增加都会变成这样。
之前说的Zookeeper就挺复杂的,它的功能本身是分布式选举,采用ZAB协议,功能简单,但实现复杂,相比之下,etcd就更简单些,因为etcd采用的是Raft协议,Raft协议更加容易理解和实现。你看,PingCAP这家数据库公司选择的就是etcd翻译过来的Rust代码实现的Raft协议。如果好奇他们为什么这样,可以去他们网站上看他们写的博客。
KISS原则总是在哪里都有用的。
演进原则
演进优于一步到位。
阿里巴巴有篇文章写的这样一句话:”好的系统架构是迭代出来的,不是设计出来的“。 请体会下,说的就是这个意思。主要因为,软件系统唯一的不变就是变化,拥抱变化,才能主宰未来。所以是好的软件是演进出来的。没见过世界上任何一个知名开源软件的仓库的第一个commit上去的代码,架构或技术上就很牛逼,有些质量可能真不敢恭维。
只要记住这几个原则就好,不要被炫酷的东西暂时迷惑住了双眼就好。
架构设计流程
首先,从这里开始,普通程序员要明白,架构设计的思想无处不在,不要总觉得架构师很牛逼,可望不可及。我觉得架构师这个title,可能是国内互联网的流行(因为真的太火了),给各位造成了些误解。因为国内的架构师,一般是要应对所谓的”三高“ (高可用,高并发,高性能)。比如,XX架构师好牛逼,带团队实现了XX系统,双十一抗住了XX量级。这可能是阿里带出来的节奏。你看国外的Google,Microsoft等顶级公司,招聘的JD上就很少写架构师(Architector)这种岗位,David Culter老爷子是架构师吗? 他可不是。至少title不是。但是他不比国内互联网大厂的P8,P9什么的架构师牛逼多了?微软最高技术级别。阿里的多隆目前暂时比不过。有些人把多隆比作中国的Jeff Dean,我觉得就目前的展现出来的成果,多隆比Jeff Dean差得还是天远。Jeff Dean的技术栈,可能全世界也没几个达到,不是单纯个人技术比较。
所以说架构师是个很虚的概念,但是架构设计是个很真实的概念,软件系统哪里都需要架构,只是国外的一些大牛人家没天天说自己是架构师而已。
说了那么多,回归下正题。架构设计是有套路的(特别是互联网后端的业务架构,大数据架构,公众号文章推送的架构文章还不多吗?),按照百度或者Google出来的套路,参考别人的经验,即使没有丰富的架构实战经验,也可以做出基本可行的架构。
识别复杂度
根据前面的原则设计适合当下的系统,千万不要过于复杂。给各个子系统,组件作复杂度排序,优先解决复杂度最高的问题。对于同一个复杂度的问题,软件系统的方案可以有多个,总是可以综合挑出个性价比最高的方案。
设计备选方案
确定了系统面临的主要问题后,方案设计就有了明确目标,我们就可以开始真正进行架构设计了。绝大部分的架构设计不需要天才那样的创新,首先,对一存在的技术和开源工具组件非常熟悉,对已经验证过的架构模式烂熟于心,然后根据自己对业务的理解,挑选合适的架构模式进行组合,再对组合后的方案进行修改和调整。其实本质上跟电脑城配置组装电脑的没啥区别,你要根据当前的成本,了解各种CPU,内存,主板的性价比。
当然,架构设计需要有些创新,不过也就是微创新,大部分情况都是基于已有的成熟技术和架构。不过话说回来,也不要真把架构设计当成电脑城组装电脑的人员了。
根据这章节的标题,想说,架构设计的一个错误就是只做一个方案。
这样做有很多弊端,一个是万一经验不足,想的不够全面,架构评审的时候会出问题。
所以:
备选方案数量以3-5个为最佳
备选方案的差异在架构上要比较明显
备选方案的技术不要只局限于自己熟悉的技术
备选方案细节不要过于详细
备选方案都是可行的(不可行你还备选?)
正确的做法是,备选阶段关注的是技术选型,而不是技术细节,技术选型的差异要比较明显。比如Zookeeper和etcd这两种方案差异就非常大。
评估和选择备选方案
选择备选方案有点困难,不过有以下一些原则,这个得看场景,至于怎么选,凭借经验了:
最简单的方案。选择复杂度最简单的。
最牛的方案,选择业界评价牛逼的,性能,功能,可用性最好。
最熟悉的方案,选择自己和团队最熟悉的
让领导拍板选择,列出备选方案,和基本的优缺点。
怎样选择以上方案呢?大概套路是这样:
把备选方案列出一个二维表格,就是各个方案在各个质量维度(性能,复杂度,成本,可扩展,可用性)的对比。
按照当前团队的状况,在质量维度排优先级,看哪个方案首先满足你需要的质量维度。
确定方案选型
详细方案设计
主要就是选择的方案的技术细节了,需要对最终选择的方案的关键细节有比较深入的理解,比如用ES做全文搜索方案,那么需要对ES的设计原理有深入的理解,比如索引,副本,集群等。不能道听途说,看几篇文章的出结论。当然,你要深入理解,肯定要查找比较多的文章资料的,这一步是必不可少的,还有自己亲手搭建方案环境验证一些原型设计。
结语
创世记的宏观概念和基本法差不多就两篇文章说完了,可能之后的架构文章就是比较细节的技术方面的研究了,这样更有助于宏观的选型。
EOF