分布式领域架构师要掌握的技术

分布式系统无疑是持久的热门话题,但其实如果不是一定有必要,强烈建议不要进入分布式领域,在集中式的情况下很多问题都会简单不少,技术人员千万不要因为外界火热的例如微服务,就把自己的产品的也去做改造,一定要仔细判断是否有必要,不要为了技术而技术,那么在必须分布式的情况下(访问量、存储量或开发人数),一个分布式领域的合格的架构师要掌握哪些技术呢,这篇文章就聊聊这个话题。

简单重复下我对架构师的标准,一个架构师最重要的不是画几个框,连几条线(这是基本要求),而是控制技术风险,要控制技术风险显然不是看几个结构性的ppt就能学会的。

通信
既然是分布式系统,系统间通信的技术就不可避免的要掌握。
首先要掌握一些基础知识,例如网络通信协议(诸如TCP/UDP等等)、网络IO(Blocking-IO,NonBlocking-IO、Asyn-IO)、网卡(多队列等);更偏应用的层面,需要了解例如连接复用、序列化/反序列化、RPC、负载均衡等。
学了这些基本知识后,基本上可以写一个简单的分布式系统里的通信模块,但这其实远远不够,既然进入了分布式领域,对规模其实就已经有了不低的要求,通常也就意味着需要的是能支持大量连接、高并发、低资源消耗的通信程序。

大量的连接通常会有两种方式:
1. 大量client连一个server
在现如今NonBlocking-IO这么成熟的情况下,一个支持大量client的server已经不那么难写了,但在大规模,并且通常长连接的情况下,有一个点要特别注意,就是当server挂掉的时候,不能出现所有client都在一个时间点发起重连,那样基本就是灾难,在没有经验的情况下我看过好几起类似的case,到client规模上去后,server一重启基本就直接被冲进来的大量建连冲垮了(当然,server的backlog队列首先应该稍微设置大一些),通常可以采用的方法是client重连前都做随机时间的sleep,另外就是重连的间隔采取避让算法。

2. 一个client连大量的server
有些场景也会出现需要连大量server的现象,在这种情况下,同样要注意的也是不要并发同时去建所有的连接,而是在能力范围内分批去建。
除了建连接外,另外还要注意的地方是并发发送请求也同样,一定要做好限流,否则很容易会因为一些点慢导致内存爆掉。

这些问题在技术风险上得考虑进去,并在设计和代码实现上体现,否则一旦随着规模上去了,问题一时半会还真不太好解。

高并发这个点需要掌握CAS、常见的lock-free算法、读写锁、线程相关知识(例如线程交互、线程池)等,通信层面的高并发在NonBlocking-IO的情况下,最重要的是要注意在整体设计和代码实现上尽量减少对io线程池的时间占用。

低资源消耗这点的话NonBlocking-IO本身基本已经做到。

伸缩性
分布式系统基本就意味着规模不小了,对于这类系统在设计的时候必须考虑伸缩性问题,架构图上画的任何一个点,如果请求量或者是数据量不断增大,怎么做到可以通过加机器的方式来解决,当然,这个过程也不用考虑无限大的场景,如果经历过从比较小到非常大规模的架构师,显然优势是不小的,同样也会是越来越稀缺的。

伸缩性的问题围绕着以下两种场景在解决:
1. 无状态场景
对于无状态场景,要实现随量增长而加机器支撑会比较简单,这种情况下只用解决节点发现的问题,通常只要基于负载均衡就可以搞定,硬件或软件方式都有;
无状态场景通常会把很多状态放在db,当量到一定阶段后会需要引入服务化,去缓解对db连接数太多的情况。
2. 有状态场景
所谓状态其实就是数据,通常采用Sharding来实现伸缩性,Sharding有多种的实现方式,常见的有这么一些:
2.1 规则Sharding
基于一定规则把状态数据进行Sharding,例如分库分表很多时候采用的就是这样的,这种方式支持了伸缩性,但通常也带来了很复杂的管理、状态数据搬迁,甚至业务功能很难实现的问题,例如全局join,跨表事务等。
2.2 一致性Hash
一致性Hash方案会使得加机器代价更低一些,另外就是压力可以更为均衡,例如分布式cache经常采用,和规则Sharding带来的问题基本一样。
2.3 Auto Sharding
Auto Sharding的好处是基本上不用管数据搬迁,而且随着量上涨加机器就OK,但通常Auto Sharding的情况下对如何使用会有比较高的要求,而这个通常也就会造成一些限制,这种方案例如HBase。
2.4 Copy
Copy这种常见于读远多于写的情况,实现起来又会有最终一致的方案和全局一致的方案,最终一致的多数可通过消息机制等,全局一致的例如zookeeper/etcd之类的,既要全局一致又要做到很高的写支撑能力就很难实现了。

即使发展到今天,Sharding方式下的伸缩性问题仍然是很大的挑战,非常不好做。

上面所写的基本都还只是解决的方向,到细节点基本就很容易判断是一个解决过多大规模场景问题的架构师,:)

稳定性
作为分布式系统,必须要考虑清楚整个系统中任何一个点挂掉应该怎么处理(到了一定机器规模,每天挂掉一些机器很正常),同样主要还是分成了无状态和有状态:
1. 无状态场景
对于无状态场景,通常好办,只用节点发现的机制上具备心跳等检测机制就OK,经验上来说无非就是纯粹靠4层的检测对业务不太够,通常得做成7层的,当然,做成7层的就得处理好规模大了后的问题。
2. 有状态场景
对于有状态场景,就比较麻烦了,对数据一致性要求不高的还OK,主备类型的方案基本也可以用,当然,主备方案要做的很好也非常不容易,有各种各样的方案,对于主备方案又觉得不太爽的情况下,例如HBase这样的,就意味着挂掉一台,另外一台接管的话是需要一定时间的,这个对可用性还是有一定影响的;
全局一致类型的场景中,如果一台挂了,就通常意味着得有选举机制来决定其他机器哪台成为主,常见的例如基于paxos的实现。

可维护性
维护性是很容易被遗漏的部分,但对分布式系统来说其实是很重要的部分,例如整个系统环境应该怎么搭建,部署,配套的维护工具、监控点、报警点、问题定位、问题处理策略等等。

从上面要掌握的这些技术,就可以知道为什么要找到一个合格的分布式领域的架构师那么的难,何况上面这些提到的还只是通用的分布式领域的技术点,但通常其实需要的都是特定分布式领域的架构师,例如分布式文件系统、分布式cache等,特定领域的架构师需要在具备上面的这些技术点的基础上还具备特定领域的知识技能,这就更不容易了。

随着互联网的发展,分布式领域的很多技术都在成熟化,想想在8年或9年前,一个大规模的网站的伸缩性是怎么设计的还是很热门的探讨话题,但是到了今天基本的结构大家其实都清楚,并且还有很多不错的系统开源出来,使得很多需要经验的东西也被沉淀下去了,在有了各种不错的开源产品的支撑下以后要做一个分布式系统的难度一定会越来越大幅降低,云更是会加速这个过程。

ps: 在写这篇文章的过程中,发现要判断一个技术人的功底有多厚,其实还真不难,就是请TA写或者讲自己觉得懂的所有技术,看看能写多厚或讲多久…要写厚或讲很久其实都不容易,尽管我也不否认要很简洁的写明白或讲清楚也不容易,但一定是先厚然后薄。

=============================
欢迎关注微信公众号:hellojavacases

公众号上发布的消息都存放在http://hellojava.info上。

我在系统设计上犯过的14个错

在上篇《架构师画像》的文章中提到了自己在系统设计上犯过的一些错,觉得还挺有意义的,这篇文章就来回顾下自己近八年来所做的一些系统设计,看看犯的一些比较大的血淋淋的错误(很多都是推倒重来),这八年来主要做了三个基础技术产品,三个横跨三年的大的技术项目(其中有两个还在进行中),发现大的错误基本集中在前面几年,从这个点看起来能比较自豪的说在最近的几年在系统设计的掌控上确实比以前成熟了很多。

第1个错
在设计服务框架时,我期望服务框架对使用者完全不侵入,于是做了一个在外部放一个.xml文件来描述spring里的哪些bean发布为服务的设计,这个版本发布后,第一个小白鼠的用户勉强在用,但觉得用的很别扭,不过还是忍着用下去了,到了发布的时候,发现出现了两个问题,一是这个xml文件研发也不知道放哪好,所以到了发布的时候都不知道去哪拿这个xml文件。
这个设计的关键错误就在于在设计时没考虑过这个设计方式对研发阶段、运维阶段的影响,后来纠正这个错误的方法是去掉了这个xml文件,改为写了一个Spring FactoryBean,用户在spring的bean配置文件中配置下就可以。
因此对于一个架构师来说,设计时在全面性上要充分考虑。

第2个错
服务框架在核心应用上线时,出现了前端web应用负载高,处理线程数不够用的现象,当时处理这个故障的方式是回滚了服务框架的上线,这个故障排查了比较长的时间后,查到的原因是服务框架用的JBoss Remoting在通信时默认时间是60s,导致一些处理速度慢的请求占据了前端web应用的处理线程池。
上面这里故障的原因简单来说是分布式调用中超时时间太长的问题,但更深层次来思考,问题是犯在了设计服务框架时的技术选型,在选择JBoss-Remoting时没有充分的掌握它的运行细节,这个设计的错误导致的是后来决定放弃JBoss-Remoting,改为基于Mina重写了服务框架的通信部分,这里造成了服务框架的可用版本发布推迟了两个多月。
因此对于一个架构师来说,在技术选型上对技术细节是要有很强的掌控力的。

第3个错
在服务框架大概演进到第4个版本时,通信协议上需要做一些改造,突然发现一个问题是以前的通信协议上是没有版本号的,于是悲催的只能在代码上做一个很龌蹉的处理来判断是新版本还是老版本。
这个设计的错误非常明显,这个其实只要在最早设计通信协议时参考下现有的很多的通信协议就可以避免了,因此这个错误纠正也非常简单,就是参考一些经典的协议重新设计了下。
因此对于一个架构师来说,知识面的广是非常重要的,或者是在设计时对未来有一定的考虑也是非常重要的。

说到协议,就顺带说下,当时在设计通信协议和选择序列化/反序列化上没充分考虑到将来多语言的问题,导致了后来在多语言场景非常的被动,这也是由于设计时前瞻性的缺失,所谓的前瞻性不是说一定要一开始就把未来可能会出现的问题就解掉,而是应该留下不需要整个改造就可以解掉的方法,这点对于架构师来说也是非常重要的。

第4个错
在服务框架切换为Mina的版本上线后,发布服务的应用重启时出现一个问题,就是发现重启后集群中的机器负载严重不均,排查发现是由于这个版本采用是服务的调用方会通过硬件负载均衡去建立到服务发布方的连接,而且是单个的长连接,由于是通过硬件负载均衡建连,意味着服务调用方其实看到的都是同一个地址,这也就导致了当服务发布方重启时,服务调用方重连就会集中的连到存活的机器上,连接还是长连,因此就导致了负载的不均衡现象。
这个设计的错误主要在于没有考虑生产环境中走硬件负载均衡后,这种单个长连接方式带来的问题,这个错误呢还真不太好纠正,当时临时用的一个方法是服务调用方的连接每发送了1w个请求后,就把连接自动断开重建,最终的解决方法是去掉了负载均衡设备这个中间点。
因此对于一个架构师来说,设计时的全面性要非常的好,我现在一般更多采用的方式是推演上线后的状况,一般来说在脑海里过一遍会比较容易考虑到这些问题。

第5个错
服务框架在做了一年多以后,某个版本中出现了一个严重bug,然后我们就希望能通知到用了这个版本的应用紧急升级,在这个时候悲催的发现一个问题是我们压根就不知道生产环境中哪些应用和机器部署了这个版本,当时只好用一个临时的扫全网机器的方法来解决。
这个问题后来纠正的方法是在服务发布和调用者在连接我们的一个点时,顺带把用的服务框架的版本号带上,于是就可以很简单的知道全网的服务框架目前在运行的版本号了。
因此对于一个架构师来说,设计时的全面性是非常重要的,推演能起到很大的帮助作用。

第6个错
服务框架这种基础类型的产品,在发布时会碰到个很大的问题,就是需要通知到使用者去发布,导致了整个发布周期会相当的长,当时做了一个决定,投入资源去实现完全动态化的发布,就是不需要重启,等到做的时候才发现这完全就是个超级大坑,最终这件事在投入两个人做了接近半年后,才终于决定放弃,而且最终来看其实升级的问题也没那么大。
这个问题最大的错误在于对细节把握不力,而且决策太慢。
因此对于一个架构师来说,技术细节的掌控非常重要,同时决策力也是非常重要的。

第7个错
服务发布方经常会碰到一个问题,就是一个服务里的某些方法是比较耗资源的,另外的一些可能是不太耗资源,但对业务非常重要的方法,有些场景下会出现由于耗资源的方法被请求的多了些导致不太耗资源的方法受影响,这种场景下如果要去拆成多个服务,会导致开发阶段还是挺痛苦的,因此服务框架这边决定提供一个按方法做七层路由的功能,服务的发布方可以在一个地方编写一个规则文件,这个规则文件允许按照方法将生产环境的机器划分为不同组,这样当服务调用方调用时就可以做到不同方法调用到不同的机器。
这个功能对有些场景来说用的很爽,但随着时间的演进和人员的更换,能维护那个文件的人越来越少了,也成为了问题。
这个功能到现在为止我自己其实觉得也是一直处于争议中,我也不知道到底是好还是不好…
因此对于一个架构师来说,设计时的全面性是非常重要的。

第8个错
服务框架在用的越来越广后,碰到了一个比较突出的问题,服务框架依赖的jar版本和应用依赖的jar版本冲突,服务框架作为一个通用技术产品,基本上没办法为了一个应用改变服务框架自己依赖的jar版本,这个问题到底怎么去解,当时思考了比较久。
可能是由于我以前OSGi这块背景的原因,在设计上我做了一个决定,引入OSGi,将服务框架的一堆jar处于一个独立的classloader,和应用本身的分开,这样就可以避免掉jar冲突的问题,在我做了引入OSGi这个决定后,团队的1个资深的同学就去做了,结果是折腾了近两个月整个匹配OSGi的maven开发环境都没完全搭好,后来我自己决定进去搞这件事,即使是我对OSGi比较熟,也折腾了差不多1个多月才把整个开发的环境,工程的结构,以及之前的代码基本迁移为OSGi结构,这件事当时折腾好上线后,效果看起来是不错的,达到了预期。
但这件事后来随着加入服务框架的新的研发人员越来越多,发现多数的新人都在学习OSGi模式的开发这件事上投入了不少的时间,就是比较难适应,所以后来有其他业务问是不是要引入OSGi的时候,我基本都会建议不要引入,主要的原因是OSGi模式对大家熟悉的开发模式、排查问题的冲击,除非是明确需要classloader隔离、动态化这两个点。
让我重新做一个决策的话,我会去掉对OSGi的引入,自己做一个简单的classloader隔离策略来解决jar版本冲突的问题,保持大家都很熟悉的开发模式。
因此对于一个架构师来说,设计时的全面性是非常重要的。

第9个错
服务框架在用的非常广了后,团队经常会被一个问题困扰和折腾,就是业务经常会碰到调用服务出错或超时的现象,这种情况通常会让服务框架这边的研发来帮助排查,这个现象之所以查起来会比较复杂,是因为服务调用通常是多层的关系,并不是简单的A–>B的问题,很多时候都会出现A–>B–>C–>D或者更多层的调用,超时或者出错都有可能是在其中某个环节,因此排查起来非常麻烦。
在这个问题越来越麻烦后,这个时候才想起在09年左右团队里有同学看过G家的一篇叫dapper的论文,并且做了一个类似的东西,只是当时上线后我们一直想不明白这东西拿来做什么,到了排查问题这个暴露的越来越严重后,终于逐渐想起这东西貌似可以对排查问题会产生很大的帮助。
到了这个阶段才开始做这件事后,碰到的主要不是技术问题,而是怎么把新版本升级上去的问题,这个折腾了挺长时间,然后上线后又发现了一个新的问题是,即使服务框架具备了Trace能力,但服务里又会调外部的例如数据库、缓存等,那些地方如果有问题也会看不到,排查起来还是麻烦,于是这件事要真正展现效果就必须让Trace完全贯穿所有系统,为了做成这件事,N个团队付出了好几年的代价。
因此对于一个架构师来说,设计时的全面性、前瞻性非常重要,例如Trace这个的重要性,如果在最初就考虑到,那么在一开始就可以留好口子埋好伏笔,后面再要做完整就不会太复杂。

第10个错
服务的发布方有些时候会碰到一个现象是,服务还没完全ready,就被调用了;还有第二个现象是服务发布方出现问题时,要保留现场排查问题,但服务又一直在被调用,这种情况下就没有办法很好的完全保留现场来慢慢排查问题了。
这两个现象会出现的原因是服务框架的设计是通过启动后和某个中心建立连接,心跳成功后其他调用方就可以调用到,心跳失败后就不会被调到,这样看起来很自动化,但事实上会导致的另外一个问题是外部控制上下线这件事的能力就很弱。
这个设计的错误主要还是在设计时考虑的不够全面。
因此对于一个架构师来说,设计时的全面性非常重要。

第11个错
在某年我和几个小伙伴决定改变当时用xen的模式,换成用一种轻量级的“虚拟机”方式来做,从而提升单机跑的应用数量的密度,在做这件事时,我们决定自己做一个轻量级的类虚拟机的方案,当时决定的做法是在一个机器上直接跑进程,然后碰到一堆的问题,例如从运维体系上来讲,希望ssh到“机器”、独立的ip、看到自己的系统指标等等,为了解决这些问题,用了N多的黑科技,搞得很悲催,更悲催的是当时觉得这个问题不多,于是用一些机器跑了这个模式,结果最后发现这里面要黑科技解决的问题实在太多了,后来突然有个小伙伴提出我们试用lxc吧,才发现我们之前用黑科技解的很多问题都没了,哎,然后就是决定切换到这个模式,结果就是线上的那堆机器重来。
这个设计的主要错误在于知识面不够广,导致做了个不正确的决定,而且推倒重来。
因此对于一个架构师来说,知识面的广非常重要,在技术选型这点上非常明显。

第12个错
还是上面这个技术产品,这个东西有一个需求是磁盘空间的限额,并且要支持磁盘空间一定程度的超卖,当时的做法是用image的方式来占磁盘空间限额,这个方式跑了一段时间觉得没什么问题,于是就更大程度的铺开了,但铺开跑了一段时间后,出现了一个问题,就是经常出现物理机磁盘空间不足的报警,而且删掉了lxc容器里的文件也还是不行,因为image方式只要占用了就会一直占着这个大小,只会扩大不会缩小。
当时对这个问题极度的头疼,只能是删掉文件后,重建image,但这个会有个要求是物理机上有足够的空间,即使有足够的空间,这个操作也是很折腾人的,因为得先停掉容器,cp文件到新创建的容器,这个如果东西多的话,还是要耗掉一定时间的。
后来觉得这个模式实在是没法玩,于是寻找新的解决方法,来满足磁盘空间限额,允许超卖的这两需求,最后我们也是折腾了比较长一段时间后终于找到了更靠谱的解决方案。
这个设计的主要错误还是在选择技术方案时没考虑清楚,对细节掌握不够,考虑的面不够全,导致了后面为了换掉image这个方案,用了极大的代价,我印象中是一堆的人熬了多次通宵来解决。
因此对于一个架构师来说,知识面的广、对技术细节的掌控和设计的全面性都非常重要。

第13个错
仍然是上面的这个技术产品,在运行的过程中,突然碰到了一个虚拟机中线程数创建太多,导致其他的虚拟机也创建不了线程的现象(不是因为物理资源不够的问题),排查发现是由于尽管lxc支持各个容器里跑相同名字的账号,但相同名字的账号的uid是相同的,而max processes是限制在UID上的,所以当一个虚拟机创建的线程数超过时,就同样影响到了其他相同账号的容器。
这个问题我觉得一定程度也可以算是设计问题,设计的时候确实由于对细节掌握的不够,考虑的不全导致忽略了这个点。
因此对于一个架构师来说,对技术细节的掌控和设计的全面性都非常重要。

第14个错
在三年前做一个非常大的项目时,项目即将到上线时间时,突然发现一个问题是,有一个关键的点遗漏掉了,只好赶紧临时讨论方案决定怎么做,这个的改动动作是非常大的,于是项目的上线时间只能推迟,我记得那个时候紧急周末加班等搞这件事,最后带着比较高的风险上了。
这个问题主要原因是在做整体设计时遗漏掉了这个关键点的考虑,当时倒不是完全忽略了这个点,而是在技术细节上判断错误,导致以为不太要做改动。
因此对于一个架构师来说,对技术细节的掌控是非常重要的,这里要注意的是,其实不代表架构师自己要完全什么都很懂,但架构师应该清楚在某个点上靠谱的人是谁。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

架构师画像

架构师,这个title就和总监之类的title一样,已经彻底被用烂了,但在一个软件产品的生命周期中,架构师是实实在在的一个极度重要的角色,这篇文章就来讲讲我觉得的架构师的画像,到底具备什么素质的同学是贴合架构师形象的,同时欢迎大家回复下在你心目中NB的架构师的画像是怎么样的呢。

业务理解和抽象能力
架构师的第一职责是理解业务,并转换为可被研发理解的实现方案,因此业务理解能力是架构师的必备技能,通常来说一个资深的业务架构师,对业务会有非常深的认识和积累,一个极好的业务架构师应该能大概预判业务未来的发展趋势,以便在系统的可扩展性上留好一定的空间,所以也会很自然的出现有些业务架构师做着做着就干脆转为PD类型的角色。
抽象能力是通过对业务的理解转换为系统实现的模型,这显然也是重要的能力,抽象很多时候也承担了分解清楚多个团队的职责,分工清晰化。

NB的代码能力
之所以现在很多的架构师都会被认为是大忽悠,就是有一堆顶着架构师头衔,又不干活的人(甚至会出现对技术几乎不太懂的人),光说不干,再加上说的不靠谱的话自然很容易被认为是大忽悠,就我自己而言,我一直认为架构师有个非常重要的职责是编写整个系统中核心部分的代码,这个部分并一定是技术挑战最高的,但对整个系统的质量/成败与否是具备非常关键的控制作用的,所以架构师必须是从写核心代码的人中诞生出来的。
在一个跨多领域的大型系统中,架构师不太可能什么都擅长,不可能写各个部分的核心代码,这种时候架构师一定要知道怎么判断非自己知识领域的部分实现是否OK,以确保各部分组合在一起的时候是符合架构设计预期的,通常这种确保各部分组织在一起work的机制部分的代码应该由架构师自己操刀。

全面
全面是一个架构师展现出来的最关键素质,全面会体现在三点上:
1. 在面对业务问题上,架构师脑海里是否会浮现出多种技术方案,这点其实挺重要的,否则可能就会出现明明有一个简单成熟的方案,但由于不知道而做了其他复杂不成熟的方案,所以广阔的技术视野是架构师的必备,另外架构师不可能全部擅长,在自己不擅长的点上,需要知道找哪个专业的人是靠谱的,这点也非常重要;

2. 在做系统设计时是否考虑到了足够多的方方面面:
例如很多系统设计容易遗漏上线环节的细节,导致在上线时发现漏掉了什么考虑,临时解决或只能重来,记得有一年我做的一个设计没有考虑到上线阶段的一个细节,导致上线的时候发现由于网段的问题完全不work,并且没有临时解决方案,只好重来,系统设计不仅仅指导研发同学怎么写代码,也包括指导其他所有相关技术同学的工作;
又例如我2008年在做服务框架设计的时候,集群和集群之间通过硬件负载均衡设备来访问的,连接的方式是单个长连接,这个设计导致了运行过程中如果要发布被调用的服务方,很容易出现压力都集中在前面重启的机器上,这也是典型的整个链路没有考虑清楚造成的设计问题;
再例如2013年我在做一个比较大范围的系统改造的设计时,由于对其中一部分的软件了解的不够,判断错误,导致后来这个改造在进行过程中才发现有些需要改造的关键软件的设计做的太粗糙,最后上线进度差不多推迟了一个多月,而且那些后来补的设计都是紧急做的,风险非常高;
回顾自己设计过的软件,发现在这个点上犯的错可以讲好几天,看来我应该整理另外一篇文档《我在系统设计上犯过的xxx个错误》,里面有些其实靠一份好的系统设计模板也许就能避免掉,一份好的系统设计模板是可以帮助架构师思考全面些的。

3. 在做系统设计时是否考虑到了未来的一些发展,尽可能不要出现未来的一点变化就导致现在白干或要花大量力气来改造的现象,想当年做服务框架的时候,后来就发现由于当年做设计的时候没有考虑到将来服务调用trace的问题,导致了后来为了弥补这点花了巨大的力气(不是技术上,而是实施上)。

全面需要架构师有足够广的技术领域知识和足够多的经验积累,从全面这点就可以看到架构师的工作绝不是画几个框,连几根线那么简单。

对架构师全面这点的挑战,会随着系统的范围越大(一个系统的设计,和100个系统组成的大系统的设计挑战是完全不同的)而变得越难,无论是知识的广度、考虑的点的覆盖度、还是未来趋势,更复杂的情况甚至会出现架构的调整对应着组织结构的调整,这种也要考虑到,例如服务化这种大的架构改造,就意味着专职的专业领域服务团队的成立。

全局
全局观通常是指在系统设计时是否考虑到了对上下游的系统的影响,毕竟通常所设计的系统不是一个孤立的系统,如果没有足够好的全局观,有可能会导致自己的系统做完上线,其他上下游系统(尤其有些连上下游是谁,怎么用的都不知道的情况下)出现问题,这种案例同样不少。

权衡
权衡同样也是架构师极度重要的能力,或者也可以认为是决策能力,技术方案的拍板是一个架构师最重要的职责。
上面说的全面是架构师在思考时开的过程,而权衡就是收的过程,收的过程结束基本就意味着技术方案的确定,同时也确定了节奏,权衡在两点上会体现的特别突出:
1. 技术方案决策原则
通常一个问题都会有多种可解决的技术方案,怎么来决策就至关重要了,而决策通常又和全面相关,大的来说通常决策的原则就是性价比和可持续发展。
性价比简单来说是方案的实现成本,这个成本要包括非常多的方面,例如有些场景可能会是用硬件解决看起来是花钱,但最终折算成本是最划算的,很多系统设计在决策性价比时都过于随意,例如一个另外常见的场景就是建设一套新系统替代旧系统,这个时候可能完全没考虑旧系统的迁移代价甚至超过了改造旧系统的代价;
可持续发展简单来说就是所选择的技术方案在公司是否可持续,例如简单的案例是公司主体的研发人员都是php,却搞一个其他语言,且只有极少人懂的(当然,这还是要看性价比,如果搞一个其他语言带来的效益超过了语言/人才体系的更换成本),又例如引入一个开源产品,有无专业团队维护这都是要考虑的关键因素。

2. 优先级和节奏控制
经常我会问做系统设计的同学一个问题:对于这个业务场景而言,在系统设计上最需要把握的一个点是什么;这是一个关键问题,全面意味着考虑到了很多地方的问题,但通常业务需求实现都是有很强的时间要求的,因此在这个时候必须考虑清楚不同点的优先级,同时也包括技术方案在决策时也要做出取舍,有可能选了一个不是那么好的技术方案,但通过留下一些可改造的空间,为以后的重构做好铺垫,那就是很不错的,尤其技术同学有些时候比较容易陷入解决技术问题的场景去,但那个问题其实有可能不是现阶段最重要的。

其实优先级和节奏控制是我认为一个最NB的架构师的最佳体现,优先级意味着把握住了重点,可以确保在所设计的架构指导下业务实现不会出现大问题,节奏控制则意味着全面,为将来做好了铺垫。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。