96SEO 2026-02-19 17:23 11
将“变化”封装在一个“变化层”将不变的部分封装在一个独立的“稳定层”。

2.2
关联系统是由一群有关联的个体组成的没有关联的个体堆在一起不能成为一个系统。
规则系统内的个体需要按照指定的规则运作而不是单个个体各自为政。
规则规定了系统内个体分工和协作的方式。
能力系统能力与个体能力有本质的差别系统能力不是个体能力之和而是产生了新的能力。
子系统的定义和系统定义是一样的只是观察的角度有差异一个系统可能是另外一个更大系统的子系统。
从逻辑的角度来拆分系统后得到的单元就是“模块”从物理的角度来拆分系统后得到的单元就是“组件”。
划分模块的主要目的是职责分离划分组件的主要目的是单元复用。
其实“组件”的英文component也可翻译成中文的“零件”一词“零件”更容易理解一些“零件”是一个物理的概念并且具备“独立且可替换”的特点。
framework通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范也指为了实现某个软件组件规范时提供规范所要求之基础功能的软件产品。
框架是组件规范例如MVC就是一种最常见的开发规范类似的还有MVP、MVVM、J2EE等框架。
框架提供基础功能的产品例如Spring
MVC是MVC的开发框架除了满足MVC的规范Spring提供了很多基础功能来帮助我们实现功能包括注解Controller等、Spring
软件架构指软件系统的“基础结构”创造这些基础结构的准则以及对这些结构的描述。
框架关注的是“规范”架构关注的是“结构”。
框架的英文是Framework架构的英文是Architecture。
首先“系统是一群关联个体组成”这些“个体”可以是“子系统”“模块”“组件”等架构需要明确系统包含哪些“个体”。
其次系统中的个体需要“根据某种规则”运作架构需要明确个体运作和协作的规则。
第三维基百科定义的架构用到了“基础结构”这个说法我改为“顶层结构”可以更好地区分系统和子系统避免将系统架构和子系统架构混淆在一起导致架构层次混乱。
一方面是单台计算机内部为了高性能带来的复杂度另一方面是多台计算机集群为了高性能带来的复杂度。
操作系统是软件系统的运行环境操作系统的复杂度直接决定了软件系统的复杂度。
操作系统和性能最相关的就是进程和线程。
操作系统发展到现在如果我们要完成一个高性能的软件系统需要考虑如多进程、多线程、进程间通信、多线程并发等技术点而且这些技术并不是最新的就是最好的也不是非此即彼的选择。
在做架构设计的时候需要花费很大的精力来结合业务进行分析、判断、选择、组合这个过程同样很复杂。
举一个最简单的例子Nginx可以用多进程也可以用多线程JBoss采用的是多线程Redis采用的是单进程Memcache采用的是多线程这些系统都实现了高性能但内部实现差异却很大。
“任务”涵盖的范围很广可以指完整的业务处理也可以单指某个具体的任务。
例如“存储”“运算”“缓存”等都可以作为一项任务因此存储系统、运算系统、缓存系统都可以按照任务分配的方式来搭建架构。
此外“任务分配器”也并不一定只能是物理上存在的机器或者一个独立运行的程序也可以是嵌入在其他程序中的算法例如Memcache的集群架构。
通过这种任务分解的方式能够把原来大一统但复杂的业务系统拆分成小而简单但需要多个系统配合的业务系统。
从业务的角度来看任务分解既不会减少功能也不会减少代码量事实上代码量可能还会增加因为从代码内部调用改为通过服务器之间的接口调用那为何通过任务分解就能够提升性能呢
虽然系统拆分可能在某种程度上能提升业务处理性能但提升性能也是有限的因为最终决定业务处理性能的还是业务逻辑本身业务逻辑本身没有发生大的变化下理论上的性能是有一个上限的系统拆分能够让性能逼近这个极限但无法突破这个极限。
因此任务分解带来的性能收益是有一个度的并不是任务分解越细越好而对于架构设计来说如何把握这个粒度就非常关键了。
系统无中断地执行其功能的能力代表系统的可用性程度是进行系统设计时的准则之一。
系统的高可用方案五花八门但万变不离其宗本质上都是通过“冗余”来实现高可用。
通俗点来讲就是一台机器不够就两台两台不够就四台一个机房可能断电那就部署两个机房一条通道可能故障那就用两条两条不够那就用三条移动、电信、联通一起上。
高可用的“冗余”解决方案单纯从形式上来看和之前讲的高性能是一样的都是通过增加更多机器来达到目的但其实本质上是有根本区别的高性能增加机器目的在于“扩展”处理性能高可用增加机器目的在于“冗余”处理单元。
这里的“计算”指的是业务的逻辑处理。
计算有一个特点就是无论在哪台机器上进行计算同样的算法和输入数据产出的结果都是一样的。
高可用集群具体应该采用哪种分配方式需要结合实际业务需求来分析和判断并不存在某种算法就一定优于另外的算法。
例如ZooKeeper采用的就是1主多备而Memcached采用的就是全主0备。
存储与计算相比有一个本质上的区别将数据从一台机器搬到到另一台机器需要经过线路进行传输。
线路传输的速度是毫秒级别同一机房内部能够做到几毫秒分布在不同地方的机房传输耗时需要几十甚至上百毫秒。
对于高可用系统来说这意味着整个系统在某个时间点上数据肯定是不一致的。
除了物理上的传输速度限制传输线路本身也存在可用性问题传输线路可能中断、可能拥塞、可能异常错包、丢包并且传输线路的故障时间一般都特别长短的十几分钟长的几个小时都是可能的。
综合分析无论是正常情况下的传输延迟还是异常情况下的传输中断都会导致系统的数据在某个时间点或者时间段是不一致的而数据的不一致又会导致业务问题但如果完全不做冗余系统的整体高可用又无法保证所以存储高可用的难点不在于如何备份数据而在于如何减少或者规避数据不一致对业务造成的影响。
分布式领域里面著名的CAP定理从理论上论证了存储高可用的复杂度。
也就是说存储高可用不可能同时满足“一致性、可用性、分区容错性”最多满足其中两个这就要求我们在做架构设计时结合业务进行取舍。
无论是计算高可用还是存储高可用其基础都是“状态决策”即系统需要能够判断当前的状态是正常还是异常如果出现了异常就要采取行动来保证高可用。
如果状态决策本身都是有错误或者有偏差的那么后续的任何行动和处理无论多么完美也都没有意义和价值。
但在具体实践的过程中恰好存在一个本质的矛盾通过冗余来实现的高可用系统状态决策本质上就不可能做到完全正确。
下面基于几种常见的决策方式进行详细分析。
独裁式决策指的是存在一个独立的决策主体称为“决策者”负责收集信息然后进行决策所有冗余的个体称为“上报者”都将状态信息发送给决策者。
当决策者本身故障时整个系统就无法实现准确的状态决策。
如果决策者本身又做一套状态决策那就陷入一个递归的死循环了。
协商式决策指的是两个独立的个体通过交流信息然后根据规则进行决策最常用的协商式决策就是主备决策。
2台服务器启动时都是备机。
2台服务器建立连接。
2台服务器交换状态信息。
某1台服务器做出决策成为主机另一台服务器继续保持备机身份。
如果两者的信息交换出现问题比如主备连接中断此时状态决策应该怎么做。
如果备机在连接中断的情况下认为主机故障那么备机需要升级为主机但实际上此时主机并没有故障那么系统就出现了两个主机这与设计初衷1主1备是不符合的如果备机在连接中断的情况下不认为主机故障则此时如果主机真的发生故障那么系统就没有主机了这同样与设计初衷1主1备是不符合的如果为了规避连接中断对状态决策带来的影响可以增加更多的连接。
例如双连接、三连接。
这样虽然能够降低连接中断对状态带来的影响注意只能降低不能彻底解决但同时又引入了这几条连接之间信息取舍的问题即如果不同连接传递的信息不同应该以哪个连接为准实际上这也是一个无解的答案无论以哪个连接为准在特定场景下都可能存在问题。
民主式决策指的是多个独立的个体通过投票的方式来进行状态决策。
例如ZooKeeper集群在选举leader时就是采用这种方式。
民主式决策和协商式决策比较类似其基础都是独立的个体之间交换信息每个个体做出自己的决策然后按照“多数取胜”的规则来确定最终的状态。
不同点在于民主式决策比协商式决策要复杂得多。
除了算法复杂民主式决策还有一个固有的缺陷脑裂。
脑裂的根本原因是原来统一的集群因为连接中断造成了两个独立分隔的子集群每个子集群单独进行选举于是选出了2个主机相当于人体有两个大脑了。
为了解决脑裂问题民主式决策的系统一般都采用“投票节点数必须超过系统总节点数一半”规则来处理。
如图中那种情况节点4和节点5形成的子集群总节点数只有2个没有达到总节点数5个的一半因此这个子集群不会进行选举。
这种方式虽然解决了脑裂问题但同时降低了系统整体的可用性即如果系统不是因为脑裂问题导致投票节点数过少而真的是因为节点故障例如节点1、节点2、节点3真的发生了故障此时系统也不会选出主节点整个系统就相当于宕机了尽管此时还有节点4和节点5是正常的。
设计具备良好可扩展性的系统有两个基本条件正确预测变化、完美封装变化。
不能每个设计点都考虑可扩展性。
不能完全不考虑可扩展性。
所有的预测都存在出错的可能性。
对于架构师来说如何把握预测的程度和提升预测结果的准确性是一件很复杂的事情而且没有通用的标准可以简单套上去更多是靠自己的经验、直觉所以架构设计评审的时候经常会出现两个设计师对某个判断争得面红耳赤的情况原因就在于没有明确标准不同的人理解和判断有偏差而最终又只能选择一个判断。
将“变化”封装在一个“变化层”将不变的部分封装在一个独立的“稳定层”。
无论是变化层依赖稳定层还是稳定层依赖变化层都是可以的需要根据具体业务情况来设计。
例如如果系统需要支持XML、JSON、ProtocolBuffer三种接入方式那么最终的架构就是上面图中的“形式1”架构也就是下面这样。
如果系统需要支持MySQL、Oracle、DB2数据库存储那么最终的架构就变成了“形式2”的架构了可以看下面这张图。
通过剥离变化层和稳定层的方式应对变化都会带来两个主要的复杂性相关的问题。
对于哪些属于变化层哪些属于稳定层很多时候并不是像前面的示例不同接口协议或者不同数据库那样明确不同的人有不同的理解导致架构设计评审的时候可能吵翻天。
需要设计变化层和稳定层之间的接口
接口设计同样至关重要对于稳定层来说接口肯定是越稳定越好但对于变化层来说在有差异的多个实现方式中找出共同点并且还要保证当加入新的功能时原有的接口设计不需要太大修改这是一件很复杂的事情。
抽象层是稳定的实现层可以根据具体业务需要定制开发当加入新的功能时只需要增加新的实现无须修改抽象层。
这种方案典型的实践就是设计模式和规则引擎。
低成本本质上是与高性能和高可用冲突的所以低成本很多时候不会是架构设计的首要目标而是架构设计的附加约束。
也就是说我们首先设定一个成本目标当我们根据高性能、高可用的要求设计出方案时评估一下方案是否能满足成本目标如果不行就需要重新设计架构如果无论如何都无法设计出满足成本要求的方案那就只能找老板调整成本目标了。
低成本给架构设计带来的主要复杂度体现在往往只有“创新”才能达到低成本目标。
这里的“创新”既包括开创一个全新的技术领域这个要求对绝大部分公司太高也包括引入新技术如果没有找到能够解决自己问题的新技术那么就真的需要自己创造新技术了。
相比来说创造新技术复杂度更高因此一般中小公司基本都是靠引入新技术来达到低成本的目标而大公司更有可能自己去创造新的技术来达到低成本的目标因为大公司才有足够的资源、技术和时间去创造新技术。
从技术的角度来讲安全可以分为两类一类是功能上的安全一类是架构上的安全。
例如常见的XSS攻击、CSRF攻击、SQL注入、Windows漏洞、密码破解等本质上是因为系统实现有漏洞黑客有了可乘之机。
黑客会利用各种漏洞潜入系统这种行为就像小偷一样黑客和小偷的手法都是利用系统或家中不完善的地方潜入并进行破坏或者盗取。
因此形象地说功能安全其实就是“防小偷”。
从实现的角度来看功能安全更多地是和具体的编码相关与架构关系不大。
现在很多开发框架都内嵌了常见的安全功能能够大大减少安全相关功能的重复开发但框架只能预防常见的安全漏洞和风险常见的XSS攻击、CSRF攻击、SQL注入等无法预知新的安全问题而且框架本身很多时候也存在漏洞例如流行的Apache
Struts2就多次爆出了调用远程代码执行的高危漏洞给整个互联网都造成了一定的恐慌。
所以功能安全是一个逐步完善的过程而且往往都是在问题出现后才能有针对性的提出解决方案我们永远无法预测系统下一个漏洞在哪里也不敢说自己的系统肯定没有任何问题。
换句话讲功能安全其实也是一个“攻”与“防”的矛盾只能在这种攻防大战中逐步完善不可能在系统架构设计的时候一劳永逸地解决。
架构安全就是“防强盗”强盗会直接用大锤将门砸开或者用炸药将围墙炸倒小偷是偷东西而强盗很多时候就是故意搞破坏对系统的影响也大得多。
因此架构设计时需要特别关注架构安全尤其是互联网时代理论上来说系统部署在互联网上时全球任何地方都可以发起攻击。
传统的架构安全主要依靠防火墙防火墙最基本的功能就是隔离网络通过将网络划分成不同的区域制定出不同区域之间的访问控制策略来控制不同信任程度区域间传送的数据流。
防火墙的功能虽然强大但性能一般所以在传统的银行和企业应用领域应用较多。
但在互联网领域防火墙的应用场景并不多。
因为互联网的业务具有海量用户访问和高并发的特点防火墙的性能不足以支撑尤其是互联网领域的DDoS攻击轻则几GB重则几十GB。
公司一般不会堆防火墙来防DDoS攻击因为DDoS攻击最大的影响是大量消耗机房的出口总带宽。
不管防火墙处理能力有多强当出口带宽被耗尽时整个业务在用户看来就是不可用的因为用户的正常请求已经无法到达系统了。
防火墙能够保证内部系统不受冲击但用户也是进不来的。
对于用户来说业务都已经受到影响了至于是因为用户自己进不去还是因为系统出故障用户其实根本不会关心。
基于上述原因互联网系统的架构安全目前并没有太好的设计手段来实现更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力较少自己来设计和实现。
规模带来复杂度的主要原因就是“量变引起质变”当数量超过一定的阈值后复杂度会发生质的变化。
常见的规模带来的复杂度有
随着系统功能数量增多功能之间的连接呈指数级增长。
下图形象地展示了功能数量的增多带来了复杂度。
数据太多以后传统的数据收集、加工、存储、分析的手段和工具已经无法适应必须应用新的技术才能解决。
目前的大数据理论基础是Google发表的三篇大数据相关论文其中Google
MapReduce是大数据运算的技术理论这三篇技术论文各自开创了一个新的技术领域。
即使数据没有达到大数据规模数据的增长也可能给系统带来复杂性。
最典型的例子莫过于使用关系数据库存储数据以MySQL为例MySQL单表的数据因不同的业务和应用场景会有不同的最优值但不管怎样都肯定是有一定的限度的一般推荐在5000万行左右。
如果因为业务的发展单表数据达到了10亿行就会产生很多问题例如
添加索引会很慢可能需要几个小时这几个小时内数据库表是无法插入数据的相当于业务停机了。
修改表结构和添加索引存在类似的问题耗时可能会很长。
即使有索引索引的性能也可能会很低因为数据量太大。
数据库备份耗时很长。
……
因此当MySQL单表数据量太大时我们必须考虑将单表拆分为多表这个拆分过程也会引入更多复杂性例如
以用户表为例是按照用户id拆分表还是按照用户注册时间拆表拆完表后查询如何处理
以用户表为例假设按照用户id拆表当业务需要查询学历为“本科”以上的用户时要去很多表查询才能得到最终结果怎么保证性能…
优秀程序员和架构师之间还有一个明显的鸿沟需要跨越这个鸿沟就是“不确定性”。
对于编程来说本质上是不能存在不确定的。
而对于架构设计来说本质上是不确定的。
相比编程来说架构设计并没有像编程语言那样的语法来进行约束更多的时候是面对多种可能性时进行选择。
这个问题的关键原因在于架构设计领域并没有一套通用的规范来指导架构师进行架构设计更多是依赖架构师的经验和直觉因此架构设计有时候也会被看作一项比较神秘的工作。
业务千变万化技术层出不穷设计理念也是百花齐放看起来似乎很难有一套通用的规范来适用所有的架构设计场景。
但是有几个共性的原则隐含其中这就是合适原则、简单原则、演化原则架构设计时遵循这几个原则有助于做出最好的选择。
面对“不确定性”时架构设计的三原则分别是合适优于业界领先、简单优于复杂、演化优于一步到位。
再好的梦想也需要脚踏实地实现这里的“脚踏实地”主要体现在下面几个方面。
将军难打无兵之仗没那么多人却想干那么多活是失败的第一个主要原因。
罗马不是一天建成的没有那么多积累却想一步登天是失败的第二个主要原因。
冰山下面才是关键没有那么卓越的业务场景却幻想灵光一闪成为天才是失败的第三个主要原因。
真正优秀的架构都是在企业当前人力、条件、业务等各种约束下设计出来的能够合理地将资源整合在一起并发挥出最大功效并且能够快速落地。
这也是很多BAT出来的架构师到了小公司或者创业团队反而做不出成绩的原因因为没有了大公司的平台、资源、积累只是生搬硬套大公司的做法失败的概率非常高。
“复杂”在制造领域代表先进在建筑领域代表领先但在软件领域却恰恰相反代表的是“问题”。
软件领域的复杂性体现在两个方面
结构上的复杂性存在的第一个问题是组件越多就越有可能其中某个组件出现故障从而导致系统故障。
结构上的复杂性存在的第二个问题是某个组件改动会影响关联的所有组件这些被影响的组件同样会继续递归影响更多的组件。
这个问题会影响整个系统的开发效率因为一旦变更涉及外部系统需要协调各方统一进行方案评估、资源协调、上线配合。
结构上的复杂性存在的第三个问题是定位一个复杂系统中的问题总是比简单系统更加困难。
首先是组件多每个组件都有嫌疑因此要逐一排查其次组件间的关系复杂有可能表现故障的组件并不是真正问题的根源。
意识到结构的复杂性后我们的第一反应可能就是“降低组件数量”毕竟组件数量越少系统结构越简单。
最简单的结构就是整个系统只有一个组件即系统本身所有的功能和逻辑都在这一个组件中实现。
不过这样做是行不通的原因在于除了结构的复杂性还有逻辑的复杂性即如果某个组件的逻辑太复杂一样会带来各种问题。
逻辑复杂几乎会导致软件工程的每个环节都有问题。
功能复杂的组件另外一个典型特征就是采用了复杂的算法。
复杂算法导致的问题主要是难以理解进而导致难以实现、难以修改并且出了问题难以快速解决。
综合来看无论是结构的复杂性还是逻辑的复杂性都会存在各种问题所以架构设计时如果简单的方案和复杂的方案都可以满足需求最好选择简单的方案。
《UNIX编程艺术》总结的KISSKeep
对于建筑来说永恒是主题而对于软件来说变化才是主题。
软件架构需要根据业务的发展而不断变化。
如果没有把握“软件架构需要根据业务发展不断变化”这个本质在做架构设计的时候就很容易陷入一个误区试图一步到位设计一个软件架构期望不管业务如何变化架构都稳如磐石。
考虑到软件架构需要根据业务发展不断变化这个本质特点软件架构设计其实更加类似于大自然“设计”一个生物通过演化让生物适应环境逐步变得更加强大软件架构设计同样是类似的过程
首先设计出来的架构要满足当时的业务需要。
其次架构要不断地在实际应用过程中迭代保留优秀的设计修复有缺陷的设计改正错误的设计去掉无用的设计使得架构逐渐完善。
第三当业务发生变化时架构要扩展、重构甚至重写代码也许会重写但有价值的经验、教训、逻辑、设计等类似生物体内的基因却可以在新架构中延续。
架构师在进行架构设计时需要牢记这个原则时刻提醒自己不要贪大求全或者盲目照搬大公司的做法。
应该认真分析当前业务的特点明确业务面临的主要问题设计合理的架构快速落地以满足业务需要然后在运行过程中不断完善架构不断随着业务演化架构。
即使是大公司的团队在设计一个新系统的架构时也需要遵循演化的原则而不应该认为团队人员多、资源多不管什么系统上来就要一步到位因为业务的发展和变化是很快的不管多牛的团队也不可能完美预测所有的业务发展和变化路径。
即使是现在非常复杂、非常强大的架构也并不是一开始就进行了复杂设计而是首先采取了简单的方式简单原则满足了当时的业务需要合适原则随着业务的发展逐步演化而来的演化原则。
淘宝技术发展主要经历了“个人网站”→“Oracle/支付宝/旺旺”→“Java时代1.0”→“Java时代2.0”→“Java时代3.0”→“分布式时代”。
买一个系统是为了“快速可用”而买一个轻量级的系统是为了“快速开发”。
因为系统上线后肯定有大量的需求需要做这时能够快速开发就非常重要。
从这个实例我们可以看到淘宝最开始的时候业务要求就是“快”因此反过来要求技术同样要“快”业务决定技术这里架构设计和选择主要遵循的是“合适原则”和“简单原则”。
技术的替代方案非常简单就是换成Oracle。
换Oracle的原因除了它容量大、稳定、安全、性能高还有人才方面的原因。
此时离刚上线才半年不到业务飞速发展最快的方式支撑业务的发展还是去买。
如果说第一阶段买的是“方案”这个阶段买的就是“性能”这里架构设计和选择主要遵循的还是“合适原则”和“简单原则”。
淘宝切换到Java的原因很有趣主要因为找了一个PHP的开源连接池SQL
Relay连接到Oracle而这个代理经常死锁死锁了就必须重启而数据库又必须用Oracle于是决定换个开发语言。
这次切换的最主要原因是因为技术影响了业务的发展频繁的死锁和重启对用户业务产生了严重的影响从业务的角度来看这是不得不解决的技术问题。
而且Java是当时最成熟的网站开发语言它有比较良好的企业开发框架被世界上主流的大规模网站普遍采用另外有Java开发经验的人才也比较多后续维护成本会比较低。
综合来看这次架构的变化没有再简单通过“买”来解决而是通过重构来解决架构设计和选择遵循了“演化原则”。
随着数据量的继续增长采取“买”的方式已无法解决容量、性能、成本问题。
另外随着规模的增大纯粹靠买的一个典型问题开始成为重要的考虑因素那就是成本。
这就是“量变带来质变”的一个典型案例业务和系统发生质变后架构设计遵循“演化原则”的思想需要再一次重构甚至重写。
到了这个阶段业务规模急剧上升后原来并不是主要复杂度的IOE成本开始成为了主要的问题因此通过自研系统来降低IOE的成本去IOE也是系统架构的再一次演化。
手机QQ的发展历程按照用户规模可以粗略划分为4个阶段十万级、百万级、千万级、亿级不同的用户规模IM后台的架构也不同而且基本上都是用户规模先上去然后产生各种问题倒逼技术架构升级。
按照“演化原则”的指导进行了重构重构的方案相比现在来说也还是简单得多因此当时做架构设计时也遵循了“合适原则”和“简单原则”。
架构需要继续改造升级再一次“演化”。
可以看到这次的方案相比之前的方案来说并不简单了这是业务特性决定的。
IM后台从1.0到3.5都是在原来基础上做改造升级的但是持续打补丁已经难以支撑亿级在线IM后台4.0必须从头开始重新设计实现这里再次遵循了“演化原则”。
4.0架构如图所示和之前的架构相比架构本身都拆分为两个主要的架构存储架构和通信架构。
在设计架构时首先就要分析系统的复杂性。
只有正确分析出了系统的复杂性后续的架构设计方案才不会偏离方向否则如果对系统的复杂性判断错误即使后续的架构设计方案再完美再先进都是南辕北辙做的越好错的越多、越离谱。
架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面但架构师在具体判断复杂性的时候不能生搬硬套认为任何时候架构都必须同时满足这三方面的要求。
实际上大部分场景下复杂度只是其中的某一个少数情况下包含其中两个如果真的出现同时需要解决三个或者三个以上的复杂度要么说明这个系统之前设计的有问题要么可能就是架构师的判断出现了失误即使真的认为要同时满足这三方面的要求也必须要进行优先级排序。
如果运气真的不好接手了一个每个复杂度都存在问题的系统也要一个个来解决问题不要幻想一次架构重构解决所有问题。
如果同时要解决这些问题就可能会面临这些困境
要做的事情太多反而感觉无从下手。
设计方案本身太复杂落地时间遥遥无期。
同一个方案要解决不同的复杂性有的设计点是互相矛盾的。
例如要提升系统可用性就需要将数据及时存储到硬盘上而硬盘刷盘反过来又会影响系统性能。
因此正确的做法是将主要的复杂度问题列出来然后根据业务、技术、团队等综合情况进行排序优先解决当前面临的最主要的复杂度问题。
对于按照复杂度优先级解决的方式存在一个普遍的担忧如果按照优先级来解决复杂度可能会出现解决了优先级排在前面的复杂度后解决后续复杂度的方案需要将已经落地的方案推倒重来。
这个担忧理论上是可能的但现实中几乎是不可能出现的原因在于软件系统的可塑性和易变性。
对于同一个复杂度问题软件系统的方案可以有多个总是可以挑出综合来看性价比最高的方案。
即使架构师决定要推倒重来这个新的方案也必须能够同时解决已经被解决的复杂度问题一般来说能够达到这种理想状态的方案基本都是依靠新技术的引入。
例如Hadoop能够将高可用、高性能、大容量三个大数据处理的复杂度问题同时解决。
识别复杂度对架构师来说是一项挑战因为原始的需求中并没有哪个地方会明确地说明复杂度在哪里需要架构师在理解需求的基础上进行分析。
有经验的架构师可能一看需求就知道复杂度大概在哪里如果经验不足那只能采取“排查法”从不同的角度逐一进行分析。
架构师的工作并不神秘成熟的架构师需要对已经存在的技术非常熟悉对已经经过验证的架构模式烂熟于心然后根据自己对业务的理解挑选合适的架构模式进行组合再对组合后的方案进行修改和调整。
虽说基于已有的技术或者架构模式进行组合然后调整大部分情况下就能够得到我们需要的方案但并不意味着架构设计是一件很简单的事情。
因为可选的模式有很多组合的方案更多往往一个问题的解决方案有很多个如果再在组合的方案上进行一些创新解决方案会更多。
因此如何设计最终的方案并不是一件容易的事情这个阶段也是很多架构师容易犯错的地方。
根据架构设计原则中“合适原则”和“简单原则“的要求挑选合适自己业务、团队、技术能力的方案才是好方案否则要么浪费大量资源开发了无用的系统例如之前提过的“亿级用户平台”的案例设计了TPS
50000的系统实际TPS只有500要么根本无法实现例如10个人的团队要开发现在的整个淘宝系统。
心里评估过于简单可能没有想得全面只是因为某一个缺点就把某个方案给否决了而实际上没有哪个方案是完美的某个地方有缺点的方案可能是综合来看最好的方案。
架构师再怎么牛经验知识和技能也有局限有可能某个评估的标准或者经验是不正确的或者是老的经验不适合新的情况甚至有的评估标准是架构师自己原来就理解错了。
单一方案设计会出现过度辩护的情况即架构评审时针对方案存在的问题和疑问架构师会竭尽全力去为自己的设计进行辩护经验不足的设计人员可能会强词夺理。
5个为最佳。
少于3个方案可能是因为思维狭隘考虑不周全多于5个则需要耗费大量的精力和时间并且方案之间的差别可能不明显。
备选方案的差异要比较明显。
例如主备方案和集群方案差异就很明显或者同样是主备方案用ZooKeeper做主备决策和用Keepalived做主备决策的差异也很明显。
但是都用ZooKeeper做主备决策一个检测周期是1分钟一个检测周期是5分钟这就不是架构上的差异而是细节上的差异了不适合做成两个方案。
备选方案的技术不要只局限于已经熟悉的技术。
设计架构时架构师需要将视野放宽考虑更多可能性。
很多架构师或者设计师积累了一些成功的经验出于快速完成任务和降低风险的目的可能自觉或者不自觉地倾向于使用自己已经熟悉的技术对于新的技术有一种不放心的感觉。
就像那句俗语说的“如果你手里有一把锤子所有的问题在你看来都是钉子”。
例如架构师对MySQL很熟悉因此不管什么存储都基于MySQL去设计方案系统性能不够了首先考虑的就是MySQL分库分表而事实上也许引入一个Memcache缓存就能够解决问题。
有的架构师或者设计师在写备选方案时错误地将备选方案等同于最终的方案每个备选方案都写得很细。
这样做的弊端显而易见
耗费了大量的时间和精力。
将注意力集中到细节中忽略了整体的技术设计导致备选方案数量不够或者差异不大。
评审的时候其他人会被很多细节给绕进去评审效果很差。
例如评审的时候针对某个定时器应该是1分钟还是30秒争论得不可开交。
正确的做法是备选阶段关注的是技术选型而不是技术细节技术选型的差异要比较明显。
在完成备选方案设计后如何挑选出最终的方案也是一个很大的挑战主要原因有
每个方案都是可行的如果方案不可行就根本不应该作为备选方案。
没有哪个方案是完美的。
例如A方案有性能的缺点B方案有成本的缺点C方案有新技术不成熟的风险。
评价标准主观性比较强比如设计师说A方案比B方案复杂但另外一个设计师可能会认为差不多因为比较难将“复杂”一词进行量化。
因此方案评审的时候我们经常会遇到几个设计师针对某个方案或者某个技术点争论得面红耳赤。
设计师挑选一个看起来最简单的方案。
例如我们要做全文搜索功能方案1基于MySQL方案2基于Elasticsearch。
MySQL的查询功能比较简单而Elasticsearch的倒排索引设计要复杂得多写入数据到Elasticsearch要设计Elasticsearch的索引要设计Elasticsearch的分布式……全套下来复杂度很高所以干脆就挑选MySQL来做吧。
最牛派
最牛派的做法和最简派正好相反设计师会倾向于挑选技术上看起来最牛的方案。
例如性能最高的、可用性最好的、功能最强大的或者淘宝用的、微信开源的、Google出品的等。
我们以缓存方案中的Memcache和Redis为例假如我们要挑选一个搭配MySQL使用的缓存Memcache是纯内存缓存支持基于一致性hash的集群而Redis同时支持持久化、支持数据字典、支持主备、支持集群看起来比Memcache好很多啊所以就选Redis好了。
最熟派
设计师基于自己的过往经验挑选自己最熟悉的方案。
我以编程语言为例假如设计师曾经是一个C经验丰富的开发人员现在要设计一个运维管理系统由于对Python或者Ruby
领导派就更加聪明了列出备选方案设计师自己拿捏不定然后就让领导来定夺反正最后方案选的对那是领导厉害方案选的不对怎么办那也是领导“背锅”。
其实这些不同的做法本身并不存在绝对的正确或者绝对的错误关键是不同的场景应该采取不同的方式。
也就是说有时候我们要挑选最简单的方案有时候要挑选最优秀的方案有时候要挑选最熟悉的方案甚至有时候真的要领导拍板。
应该选择哪种方法来评估和选择备选方案呢答案就是“360度环评”具体的操作方式为列出我们需要关注的质量属性点然后分别从这些质量属性的维度去评估每个方案再综合挑选适合当时情况的最优方案。
常见的方案质量属性点有性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等。
在评估这些质量属性时需要遵循架构设计原则1“合适原则”和原则2“简单原则”避免贪大求全基本上某个质量属性能够满足一定时期内业务发展就可以了。
有的设计师会有这样的担心如果我们运气真的很好业务直接一年翻了10倍之前的方案不合适了又要重新做方案这种情况确实有可能存在但概率很小如果每次做方案都考虑这种小概率事件我们的方案会出现过度设计导致投入浪费。
考虑这个问题的时候需要遵循架构设计原则3“演化原则”避免过度设计、一步到位的想法。
按照原则3的思想即使真的出现这种情况那就算是重新做方案代价也是可以接受的因为业务如此迅猛发展钱和人都不是问题。
通常情况下如果某个质量属性评估和业务发展有关系例如性能、硬件成本等需要评估未来业务发展的规模时一种简单的方式是将当前的业务规模乘以2
~4即可如果现在的基数较低可以乘以4如果现在基数较高可以乘以2。
最理想的情况是设计一个方案能够简单地扩容就能够跟上业务的发展。
但现实往往没那么理想因为量变会引起质变具体哪些地方质变是很难提前很长时间能预判到的。
完成方案的360度环评后可以基于评估结果整理出360度环评表一目了然地看到各个方案的优劣点。
但是360度环评表也只能帮助我们分析各个备选方案还是没有告诉我们具体选哪个方案原因就在于没有哪个方案是完美的极少出现某个方案在所有对比维度上都是最优的。
数量对比法简单地看哪个方案的优点多就选哪个。
例如总共5个质量属性的对比其中A方案占优的有3个B方案占优的有2个所以就挑选A方案。
这种方案主要的问题在于把所有质量属性的重要性等同而没有考虑质量属性的优先级。
其次有时候会出现两个方案的优点数量是一样的情况。
如果为了数量上的不对称强行再增加一个质量属性进行对比这个最后增加的不重要的属性反而成了影响方案选择的关键因素这又犯了没有区分质量属性的优先级的问题。
加权法每个质量属性给一个权重。
例如性能的权重高中低分别得10分、5分、3分成本权重高中低分别是5分、3分、1分然后将每个方案的权重得分加起来最后看哪个方案的权重得分最高就选哪个。
这种方案主要的问题是无法客观地给出每个质量属性的权重得分。
这个分数是很难确定的没有明确的标准甚至会出现为了选某个方案设计师故意将某些权重分值调高而降低另外一些权重分值最后方案的选择就变成了一个数字游戏了。
正确的做法是按优先级选择即架构师综合当前的业务发展情况、团队人员规模和技能、业务发展预测等因素将质量属性按照优先级排序首先挑选满足第一优先级的如果方案都满足那就再看第二优先级……以此类推。
那会不会出现两个或者多个方案每个质量属性的优缺点都一样的情况呢理论上是可能的但实际上是不可能的。
前面提到在做备选方案设计时不同的备选方案之间的差异要比较明显差异明显的备选方案不可能所有的优缺点都是一样的。
备选方案的选择和很多因素相关并不单单考虑性能高低、技术是否优越这些纯技术因素。
业务的需求特点、运维团队的经验、已有的技术体系、团队人员的技术水平都会影响备选方案的选择。
假如我们确定使用Elasticsearch来做全文搜索那么就需要确定Elasticsearch的索引是按照业务划分还是一个大索引就可以了副本数量是2个、3个还是4个集群节点数量是3个还是6个等。
假如我们确定使用MySQL分库分表那么就需要确定哪些表要分库分表按照什么维度来分库分表分库分表后联合查询怎么处理等。
假如我们确定引入Nginx来做负载均衡那么Nginx的主备怎么做Nginx的负载均衡策略用哪个权重分配轮询ip_hash等。
可以看到详细设计方案里面其实也有一些技术点和备选方案类似。
例如Nginx的负载均衡策略备选有轮询、权重分配、ip_hash、fair、url_hash五个具体选哪个呢看起来和备选方案阶段面临的问题类似但实际上这里的技术方案选择是很轻量级的我们无须像备选方案阶段那样操作而只需要简单根据这些技术的适用场景选择就可以了。
详细设计方案阶段可能遇到的一种极端情况就是在详细设计阶段发现备选方案不可行一般情况下主要的原因是备选方案设计时遗漏了某个关键技术点或者关键的质量属性。
架构师不但要进行备选方案设计和选型还需要对备选方案的关键细节有较深入的理解。
例如架构师选择了Elasticsearch作为全文搜索解决方案前提必须是架构师自己对Elasticsearch的设计原理有深入的理解比如索引、副本、集群等技术点而不能道听途说Elasticsearch很牛所以选择它更不能成为把“细节我们不讨论”这句话挂在嘴边的“PPT架构师”。
通过分步骤、分阶段、分系统等方式尽量降低方案复杂度方案本身的复杂度越高某个细节推翻整个方案的可能性就越高适当降低复杂性可以减少这种风险。
如果方案本身就很复杂那就采取设计团队的方式来进行设计博采众长汇集大家的智慧和经验防止只有1~2个架构师可能出现的思维盲点或者经验盲区。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback