周四,我为你讲了架构设计的主要目的是为了解决软件系统复杂度带来的问题。那么从今天开始,我将为你深入分析复杂度的 6 个来源,先来聊聊复杂度的来源之一高性能。
对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机,从电子管计算机到晶体管计算机再到集成电路计算机,运算性能从每秒几次提升到每秒几亿次。但伴随性能越来越高,相应的方法和系统复杂度也是越来越高。现代的计算机 CPU 集成了几亿颗晶体管,逻辑复杂度和制造复杂度相比最初的晶体管计算机,根本不可同日而语。
软件系统也存在同样的现象。最近几十年软件系统性能飞速发展,从最初的计算机只能进行简单的科学计算,到现在 Google 能够支撑每秒几万次的搜索。与此同时,软件系统规模也从单台计算机扩展到上万台计算机;从最初的单用户单工的字符界面 Dos 操作系统,到现在的多用户多工的 Windows 10 图形操作系统。
当然,技术发展带来了性能上的提升,不一定带来复杂度的提升。例如,硬件存储从纸带→磁带→磁盘→SSD,并没有显著带来系统复杂度的增加。因为新技术会逐步淘汰旧技术,这种情况下我们直接用新技术即可,不用担心系统复杂度会随之提升。只有那些并不是用来取代旧技术,而是开辟了一个全新领域的技术,才会给软件系统带来复杂度,因为软件系统在设计的时候就需要在这些技术之间进行判断选择或者组合。就像汽车的发明无法取代火车,飞机的出现也并不能完全取代火车,所以我们在出行的时候,需要考虑选择汽车、火车还是飞机,这个选择的过程就比较复杂了,要考虑价格、时间、速度、舒适度等各种因素。
软件系统中高性能带来的复杂度主要体现在两方面,一方面是单台计算机内部为了高性能带来的复杂度;另一方面是多台计算机集群为了高性能带来的复杂度。
单机复杂度
计算机内部复杂度最关键的地方就是操作系统。计算机性能的发展本质上是由硬件发展驱动的,尤其是 CPU 的性能发展。著名的“摩尔定律”表明了 CPU 的处理能力每隔 18 个月就翻一番;而将硬件性能充分发挥出来的关键就是操作系统,所以操作系统本身其实也是跟随硬件的发展而发展的,操作系统是软件系统的运行环境,操作系统的复杂度直接决定了软件系统的复杂度。
操作系统和性能最相关的就是进程和线程。最早的计算机其实是没有操作系统的,只有输入、计算和输出功能,用户输入一个指令,计算机完成操作,大部分时候计算机都在等待用户输入指令,这样的处理性能很显然是很低效的,因为人的输入速度是远远比不上计算机的运算速度的。
为了解决手工操作带来的低效,批处理操作系统应运而生。批处理简单来说就是先把要执行的指令预先写下来(写到纸带、磁带、磁盘等),形成一个指令清单,这个指令清单就是我们常说的“任务”,然后将任务交给计算机去执行,批处理操作系统负责读取“任务”中的指令清单并进行处理,计算机执行的过程中无须等待人工手工操作,这样性能就有了很大的提升。
批处理程序大大提升了处理性能,但有一个很明显的缺点:计算机一次只能执行一个任务,如果某个任务需要从 I/O 设备(例如磁带)读取大量的数据,在 I/O 操作的过程中,CPU 其实是空闲的,而这个空闲时间本来是可以进行其他计算的。
为了进一步提升性能,人们发明了“进程”,用进程来对应一个任务,每个任务都有自己独立的内存空间,进程间互不相关,由操作系统来进行调度。此时的 CPU 还没有多核和多线程的概念,为了达到多进程并行运行的目的,采取了分时的方式,即把 CPU 的时间分成很多片段,每个片段只能执行某个进程中的指令。虽然从操作系统和 CPU 的角度来说还是串行处理的,但是由于 CPU 的处理速度很快,从用户的角度来看,感觉是多进程在并行处理。
多进程虽然要求每个任务都有独立的内存空间,进程间互不相关,但从用户的角度来看,两个任务之间能够在运行过程中就进行通信,会让任务设计变得更加灵活高效。否则如果两个任务运行过程中不能通信,只能是 A 任务将结果写到存储,B 任务再从存储读取进行处理,不仅效率低,而且任务设计更加复杂。为了解决这个问题,进程间通信的各种方式被设计出来了,包括管道、消息队列、信号量、共享存储等。
多进程让多任务能够并行处理任务,但本身还有缺点,单个进程内部只能串行处理,而实际上很多进程内部的子任务并不要求是严格按照时间顺序来执行的,也需要并行处理。例如,一个餐馆管理进程,排位、点菜、买单、服务员调度等子任务必须能够并行处理,否则就会出现某个客人买单时间比较长(比如说信用卡刷不出来),其他客人都不能点菜的情况。为了解决这个问题,人们又发明了线程,线程是进程内部的子任务,但这些子任务都共享同一份进程数据。为了保证数据的正确性,又发明了互斥锁机制。有了多线程后,操作系统调度的最小单位就变成了线程,而进程变成了操作系统分配资源的最小单位。
多进程多线程虽然让多任务并行处理的性能大大提升,但本质上还是分时系统,并不能做到时间上真正的并行。解决这个问题的方式显而易见,就是让多个 CPU 能够同时执行计算任务,从而实现真正意义上的多任务并行。目前这样的解决方案有 3 种:SMP(Symmetric Multi-Processor,对称多处理器结构)、NUMA(Non-Uniform Memory Access,非一致存储访问结构)、MPP(Massive Parallel Processing,海量并行处理结构)。其中 SMP 是我们最常见的,目前流行的多核处理器就是 SMP 方案。
操作系统发展到现在,如果我们要完成一个高性能的软件系统,需要考虑如多进程、多线程、进程间通信、多线程并发等技术点,而且这些技术并不是最新的就是最好的,也不是非此即彼的选择。在做架构设计的时候,需要花费很大的精力来结合业务进行分析、判断、选择、组合,这个过程同样很复杂。举一个最简单的例子:Nginx 可以用多进程也可以用多线程,JBoss 采用的是多线程;Redis 采用的是单进程,Memcache 采用的是多线程,这些系统都实现了高性能,但内部实现差异却很大。
集群的复杂度
虽然计算机硬件的性能快速发展,但和业务的发展速度相比,还是小巫见大巫了,尤其是进入互联网时代后,业务的发展速度远远超过了硬件的发展速度。例如:
2016 年“双 11”支付宝每秒峰值达 12 万笔支付。
2017 年春节微信红包收发红包每秒达到 76 万个。
要支持支付和红包这种复杂的业务,单机的性能无论如何是无法支撑的,必须采用机器集群的方式来达到高性能。例如,支付宝和微信这种规模的业务系统,后台系统的机器数量都是万台级别的。
通过大量机器来提升性能,并不仅仅是增加机器这么简单,让多台机器配合起来达到高性能的目的,是一个复杂的任务,我针对常见的几种方式简单分析一下。
1. 任务分配
任务分配的意思是指每台机器都可以处理完整的业务任务,不同的任务分配到不同的机器上执行。
我从最简单的一台服务器变两台服务器开始,来讲任务分配带来的复杂性,整体架构示意图如下。

从图中可以看到,1 台服务器演变为 2 台服务器后,架构上明显要复杂多了,主要体现在:
需要增加一个任务分配器,这个分配器可能是硬件网络设备(例如,F5、交换机等),可能是软件网络设备(例如,LVS),也可能是负载均衡软件(例如,Nginx、HAProxy),还可能是自己开发的系统。选择合适的任务分配器也是一件复杂的事情,需要综合考虑性能、成本、可维护性、可用性等各方面的因素。
任务分配器和真正的业务服务器之间有连接和交互(即图中任务分配器到业务服务器的连接线),需要选择合适的连接方式,并且对连接进行管理。例如,连接建立、连接检测、连接中断后如何处理等。
任务分配器需要增加分配算法。例如,是采用轮询算法,还是按权重分配,又或者按照负载进行分配。如果按照服务器的负载进行分配,则业务服务器还要能够上报自己的状态给任务分配器。
这一大段描述,即使你可能还看不懂,但也应该感受到其中的复杂度了,更何况还要真正去实践和实现。
上面这个架构只是最简单地增加 1 台业务机器,我们假设单台业务服务器每秒能够处理 5000 次业务请求,那么这个架构理论上能够支撑 10000 次请求,实际上的性能一般按照 8 折计算,大约是 8000 次左右。
如果我们的性能要求继续提高,假设要求每秒提升到 10 万次,上面这个架构会出现什么问题呢?是不是将业务服务器增加到 25 台就可以了呢?显然不是,因为随着性能的增加,任务分配器本身又会成为性能瓶颈,当业务请求达到每秒 10 万次的时候,单台任务分配器也不够用了,任务分配器本身也需要扩展为多台机器,这时的架构又会演变成这个样子。
这个架构比 2 台业务服务器的架构要复杂,主要体现在:
任务分配器从 1 台变成了多台(对应图中的任务分配器 1 到任务分配器 M),这个变化带来的复杂度就是需要将不同的用户分配到不同的任务分配器上(即图中的虚线“用户分配”部分),常见的方法包括 DNS 轮询、智能 DNS、CDN(Content Delivery Network,内容分发网络)、GSLB 设备(Global Server Load Balance,全局负载均衡)等。
任务分配器和业务服务器的连接从简单的“1 对多”(1 台任务分配器连接多台业务服务器)变成了“多对多”(多台任务分配器连接多台业务服务器)的网状结构。
机器数量从 3 台扩展到 30 台(一般任务分配器数量比业务服务器要少,这里我们假设业务服务器为 25 台,任务分配器为 5 台),状态管理、故障处理复杂度也大大增加。
上面这两个例子都是以业务处理为例,实际上“任务”涵盖的范围很广,可以指完整的业务处理,也可以单指某个具体的任务。例如,“存储”“运算”“缓存”等都可以作为一项任务,因此存储系统、运算系统、缓存系统都可以按照任务分配的方式来搭建架构。此外,“任务分配器”也并不一定只能是物理上存在的机器或者一个独立运行的程序,也可以是嵌入在其他程序中的算法,例如 Memcache 的集群架构。
(http://my.oschina.net/uploads/space/2010/1015/163250_g2tS_98095.png)
2. 任务分解
通过任务分配的方式,我们能够突破单台机器处理性能的瓶颈,通过增加更多的机器来满足业务的性能需求,但如果业务本身也越来越复杂,单纯只通过任务分配的方式来扩展性能,收益会越来越低。例如,业务简单的时候 1 台机器扩展到 10 台机器,性能能够提升 8 倍(需要扣除机器群带来的部分性能损耗,因此无法达到理论上的 10 倍那么高),但如果业务越来越复杂,1 台机器扩展到 10 台,性能可能只能提升 5 倍。造成这种现象的主要原因是业务越来越复杂,单台机器处理的性能会越来越低。为了能够继续提升性能,我们需要采取第二种方式:任务分解。
继续以上面“任务分配”中的架构为例,“业务服务器”如果越来越复杂,我们可以将其拆分为更多的组成部分,我以微信的后台架构为例。
(http://image.jiagoushuo.com/2016/qAnayi.jpg)
通过上面的架构示意图可以看出,微信后台架构从逻辑上将各个子业务进行了拆分,包括:接入、注册登录、消息、LBS、摇一摇、漂流瓶、其他业务(聊天、视频、朋友圈等)。
通过这种任务分解的方式,能够把原来大一统但复杂的业务系统,拆分成小而简单但需要多个系统配合的业务系统。从业务的角度来看,任务分解既不会减少功能,也不会减少代码量(事实上代码量可能还会增加,因为从代码内部调用改为通过服务器之间的接口调用),那为何通过任务分解就能够提升性能呢?
主要有几方面的因素:
- 简单的系统更加容易做到高性能
系统的功能越简单,影响性能的点就越少,就更加容易进行有针对性的优化。而系统很复杂的情况下,首先是比较难以找到关键性能点,因为需要考虑和验证的点太多;其次是即使花费很大力气找到了,修改起来也不容易,因为可能将 A 关键性能点提升了,但却无意中将 B 点的性能降低了,整个系统的性能不但没有提升,还有可能会下降。
- 可以针对单个任务进行扩展
当各个逻辑任务分解到独立的子系统后,整个系统的性能瓶颈更加容易发现,而且发现后只需要针对有瓶颈的子系统进行性能优化或者提升,不需要改动整个系统,风险会小很多。以微信的后台架构为例,如果用户数增长太快,注册登录子系统性能出现瓶颈的时候,只需要优化登录注册子系统的性能(可以是代码优化,也可以简单粗暴地加机器),消息逻辑、LBS 逻辑等其他子系统完全不需要改动。
既然将一个大一统的系统分解为多个子系统能够提升性能,那是不是划分得越细越好呢?例如,上面的微信后台目前是 7 个逻辑子系统,如果我们把这 7 个逻辑子系统再细分,划分为 100 个逻辑子系统,性能是不是会更高呢?
其实不然,这样做性能不仅不会提升,反而还会下降,最主要的原因是如果系统拆分得太细,为了完成某个业务,系统间的调用次数会呈指数级别上升,而系统间的调用通道目前都是通过网络传输的方式,性能远比系统内的函数调用要低得多。我以一个简单的图示来说明。

从图中可以看到,当系统拆分 2 个子系统的时候,用户访问需要 1 次系统间的请求和 1 次响应;当系统拆分为 4 个子系统的时候,系统间的请求次数从 1 次增长到 3 次;假如继续拆分下去为 100 个子系统,为了完成某次用户访问,系统间的请求次数变成了 99 次。
为了描述简单,我抽象出来一个最简单的模型:假设这些系统采用 IP 网络连接,理想情况下一次请求和响应在网络上耗费为 1ms,业务处理本身耗时为 50ms。我们也假设系统拆分对单个业务请求性能没有影响,那么系统拆分为 2 个子系统的时候,处理一次用户访问耗时为 51ms;而系统拆分为 100 个子系统的时候,处理一次用户访问耗时竟然达到了 149ms。
虽然系统拆分可能在某种程度上能提升业务处理性能,但提升性能也是有限的,不可能系统不拆分的时候业务处理耗时为 50ms,系统拆分后业务处理耗时只要 1ms,因为最终决定业务处理性能的还是业务逻辑本身,业务逻辑本身没有发生大的变化下,理论上的性能是有一个上限的,系统拆分能够让性能逼近这个极限,但无法突破这个极限。因此,任务分解带来的性能收益是有一个度的,并不是任务分解越细越好,而对于架构设计来说,如何把握这个粒度就非常关键了。
小结
今天我给你讲了软件系统中高性能带来的复杂度主要体现的两方面,一是单台计算机内部为了高性能带来的复杂度;二是是多台计算机集群为了高性能带来的复杂度,希望对你有所帮助。
这就是今天的全部内容,留一道思考题给你吧。你所在的业务体系中,高性能的系统采用的是哪种方式?目前是否有改进和提升的空间?
欢迎你把答案写到留言区,和我一起讨论。相信经过深度思考的回答,也会让你对知识的理解更加深刻。(编辑乱入:精彩的留言有机会获得丰厚福利哦!)

版权归极客邦科技所有,未经许可不得转载
精选留言
1 WHAT 对高性能的理解?
性能是软件的一个重要质量属性。衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标,也可以是用户的主观感受(从程序员、业务用户、终端用户/客户不同的视角,可能会得出不同的结论)。
在说性能的时候,有一个概念与之紧密相关—伸缩性,这是两个有区别的概念。性能更多的是衡量软件系统处理一个请求或执行一个任务需要耗费的时间长短;而伸缩性则更加关注软件系统在不影响用户体验的前提下,能够随着请求数量或执行任务数量的增加(减少)而相应地拥有相适应的处理能力。
但是,什么是“高”性能?这可能是一个动态概念,与当前的技术发展状况与业务所处的阶段紧密相关。比如,现在在行业/企业内部认为的高性能,站在5年后来看,未必是高性能。因此,站在架构师、设计师的角度,高性能需要和业务所处的阶段来衡量。高到什么程度才能与当前或可预见的未来业务增长相匹配。一味去追求绝对意义上的高,没有太大的实际意义。因为,伴随性能越来越高,相应的方法和系统复杂度也是越来越高,而这可能会与当前团队的人力、技术、资源等不相匹配。但是什么才合适的高性能了?这可能需要从国、内外的同行业规模相当、比自己强的竞争者、终端用户使用反馈中获取答案并不断迭代发展。
软件系统中高性能带来的复杂度主要体现在两方面,一方面是单台计算机内部为了高性能带来的复杂度;另一方面是多台计算机集群为了高性能带来的复杂度。
2 WHY 为什么需要高性能?
追求良好的用户体验;
满足业务增长的需要。
3 HOW 如何做好高性能?
可以从垂直与水平两个维度来考虑。垂直维度主要是针对单台计算机,通过升级软、硬件能力实现性能提升;水平维度则主要针对集群系统,利用合理的任务分配与任务分解实现性能的提升。
垂直维度可包括以下措施:
增大内存减少I/O操作
更换为固态硬盘(SSD)提升I/O访问速度
使用RAID增加I/O吞吐能力
置换服务器获得更多的处理器或分配更多的虚拟核
升级网络接口或增加网络接口
水平维度可包括以下措施:
功能分解:基于功能将系统分解为更小的子系统
多实例副本:同一组件重复部署到多台不同的服务器
数据分割:在每台机器上都只部署一部分数据
垂直维度方案比较适合业务阶段早期和成本可接受的阶段,该方案是提升性能最简单直接的方式,但是受成本与硬件能力天花板的限制。
水平维度方案所带来的好处要在业务发展的后期才能体现出来。起初,该方案会花费更多的硬件成本,另外一方面对技术团队也提出了更高的要求;但是,没有垂直方案的天花板问题。一旦达到一定的业务阶段,水平维度是技术发展的必由之路。因此,作为技术部门,需要提前布局 ,未雨绸缪,不要被业务抛的太远。
我:
1, 早期的计算机是没有操作系统的,只有输入,计算,输出。手工输入速度远低于计算机的计算速度。
2, 于是出现了批处理操作系统,通过纸带,磁带等工具预先写入指令,形成一个指令清单(即任务)交给计算机处理。但批处理系统的缺点是只能有一个任务,而且当计算机在进行I/O处理时,CPU是空闲的。
3, 世人发明了进程,一个进程就代表一个任务,多个进程通过分时操作能让用户认为并行操作多任务,进程间的资源是独立单元,但是可以通过介质进行通信。缺点:进程内只进行串行处理,无法很好地分工合作提高处理效率。
4, 于是就有了操作系统调度的最小单元-线程,线程能够使进程内的子任务能够共享进程内的资源,并并行工作,大大提高操作系统的性能。
区别:
线程是任务调度的最小单元,共用进程内的资源。
进程是资源分配的最小单元,与其他进程资源互相独立。
于是我们将系统进行了拆分,起初是按照业务拆分成几个核心系统,同时针对不同业务的负载情况进行了合理的水平扩展,整个系统的性能得到了提升,扩展性得到了保证,并且开发部署效率也得到了极大的提高。
但是随着业务的发展,之前的系统拆分不能满足现有业务,同时随着公司很多老员工的离开,之前的架构设计思路没有人清楚,于是就变成了走一步看一步的推进模式,衍生出了各种独立的服务达40个左右,这样系统之间的边界越来越模糊,甚至出现了服务间的循环调用,白白浪费时间。而且一次调用链路过长,发生问题很难定位。
所以我觉得我们的系统就是一个活生生的,没有搞好架构设计的例子,前期是没有设计导致性能瓶颈,后期是过度设计导致系统复杂。
(1)单机的高性能主要在于多任务处理,让不同或相同的任务能够同时处理。
(2)集群的高性能主要在于任务(业务模块,组件,资源)的拆分和利用,一是分配,二是分解,大规模分配的前提是要合理的分解系统,合理的分解也是为了更好的聚合任务。
二、其实现在针对网络访问,dns,反向代理,web服务,应用服务,缓存,数据库,分布式文件等都有很多的解决方案,但如何把这些方案和当前你的业务结合起来,并且你的业务如何进行设计,如何拆分功能和组件来满足不同时期的业务性能变化。
三、其实老师今天提供了一个渐进性的方案,也是业务性能变化的应对方法论,先单机,再集群,然后拆分再集群,不管什么样的性能问题都能用这个方法论来解决。具体如何集群相应开源的解决方案很多,但是业务系统如何拆分,拆分的粒度,我觉得老师也应该有相应的方法论,期待...
具体到我们公司,涉及到性能要改的地方很多了,包括静态资源处理,业务消息队列多线程处理,数据库现在是单库,如何进行读写分离。。。
对于任务分解,我认为不但没有性能上的收益,反而有性能上的损耗,本来可以在一个进程内部完成的交互,分解后却需要进行服务器间的网络交互。(分解前后业务逻辑不变的情况下)
不知道我这么理解对不对,但是与楼主说的任务分解一定程度上可以提高性能有些矛盾,求楼主指点迷津😊
我在做系统的时候,应用层的扩展和优化相对持久化层的架构设计来说要容易一些。请问老师如何针对应用层和持久化层来做设计,有什么好的策略可以分享。
谢谢
分为一个任务分解器(服务端):仅仅实现调度和任务分配(轮询)
前期由平台抽象的任务,即各种采集项目封装为一个任务。
采集机集群,可以处理各种采集任务。
后期采集任务之间互相之间有逻辑和顺序越来越复杂,
然后任务分解器没有逻辑处理模块,导致现在只能尽量将任务封装成一个。
考虑需要在任务分解器集成逻辑模块。
普通的快餐厅,比如**缘,就是单线程,所有必须排队进行,最原始的系统架构。所以你会发现效率低,通常会拍队列,体验就不好。
而去**王吃饭,进去就有一个引导员(负载均衡),提前帮你分配座位,发点餐单,而且有多个引导员同时工作(负载均衡集群),而且各种菜系可以同时进行(并行)。另外一些需要等待的菜,会让你边吃边等(异步)。所以看上去人好多,很少有在排队的现象。可见,这位老板也是位不错的架构师。
单机阶段:一开始是手动输入,但cpu处理速度比人工快,就将输入记录在媒介上,然后批量输入。此时cpu还是单个任务串行处理,于是就出现了多进程的概念,多个任务并行执行。但是任务内部还是串行执行,因此就采用多线程,同时执行任务内的不同模块。
多台计算机:由于单机的性能达到瓶颈,因此就采用多台计算机处理任务,采用任务分配器进行分配。当单个任务分配器性能达到上限时,就采用多台任务分配器。随着业务的增多,系统越来越复杂,性能也越来越差,于是就将任务细化,但是粒度并不是越细越好,因为网络通信需要耗费一定的时间,就想缓存无底洞那样,所以要把握好粒度。
优化的空间在于单台机器的性能,并没有对进程,线程,高并发有深入地思考。
1、协程和纤程没有讲,golang还是升的比较快的;
2、系统不卡的情况下,分模块后的总体处理时间会更长。不卡的时候为方便业务扩展或业务域清晰,按业务拆分。如果服务卡或不可用的时候兼顾业务针对性能瓶颈分拆。
2.根据模块的特性采用不同的机器,集群
3.加缓存,将延迟保证在可接受的范围
4.对于用户无感知的接口,采用mq,并行结果直接返回,后台串行或并行计算
5.主从+分表
据我了解系统的用户主要分为两类,一类是运行商高层,CTO,CTO什么的,这些人会关注系统小时,天,周,月几个粒度的关键KPI报告,了解网络运行情况;另一类为网优人员,这些可能需要每天,或者每周,通过系统报表关联分析,定位分析已知网络问题,并给出优化解决方案。从用户特点可知,系统偶尔宕机,不会对这些客户工作造成大的影响,只要保证做好客户安抚,在尽可能短的时间恢复系统,并将丢失实际补齐即可,所以高可用计算不是系统架构设计的关键复杂度所在。安全性架构也不是关键复杂度所在,因为性能管理系统中包含的敏感数据不多,也不是黑客的主要攻击点,但对于特定几个国家,根据国家安全要求,安全性是首要要求。可扩展性架构我理解不论在哪个阶段都是应该考虑的,方便后期新功能加入和考虑系统容量变大时,无缝切换到其他架构,这一块我们当前系统仅在系统接入侧做了可扩展设计,但是系统内部就相当凌乱不堪了。最关键还是如何保障数据尽可能高的实时性。
我们的系统从大的方向上分为前端和后端。前端的功能主要是报表,Dashboard,告警等可视化模块,我们通常都把这些叫Web,被部署在web容器中,例如jboss,并在仅有的一台web服务器运行,这不是系统能关键性能瓶颈所在;后端功能主要包括数据采集解析和汇总计算,这两个模块是目前系统关键性能瓶颈点所在,并分别采用了分布式的架构设计。数据采集解析按照分布式设计分别被部署在多台服务器上,这些服务器被命名为EAM服务器,包含一台Master和多台Slave,Master机器主要负责任务生成和下发,不具备任务分配功能,任务该在哪台机器上运行,其实是认为划分好的,不用通过负载来自动分配,Slave负责执行实际的采集解析工作。数据汇总计算类似采集解析也被部署在多台服务器上,这些服务器被命名为APP服务器,包含一台Master和多台Slave,Master负责任务决策和任务分配,Slave负责任务执行。数据汇总计算子系统使用了Hadoop大数据生态圈技术,汇总计算本身使用Storm流式处理机制,不同任务被分配到不用worker中来执行,执行完数据存入Hbase,不同类型任务之间通过Kafka消息进行驱动。另外还有汇总计算过程中使用到的模型数据被缓存到Redis中,方便获取。
写到这里系统结构已经非常清晰,根据老师讲解,我来谈谈对这个架构的评价以及存在的问题。这个系统对复杂度判断正确,高性能架构方案也很优秀,但是即使这样在现场使用中还是被各种性能问题所困扰。我理解问题在于公司没有一套标准的编码规范,和代码审查机制,开发人员对编程语言特性,设计模式,内存管理,业务流程理解不够透彻,仅以完成功能开发为目的。导致一线客户在使用过程出现KPI计算不准确,为空等情况,开发人员定位后是由于代码不满足某些特性场景导致,然后又由另外不熟悉业务的开发人员修改代码,导致代码本身攀枝末节,错综复杂,这也是系统内部功能不具备可扩展性的原因。再写一个典型性能问题的发生场景,以某个汇总计算任务为例,第一步收到Kafka消息,第二步根据Kafka消息里的条件字段到oracle中查询Hbase文件key,第三步使用文件key到Hbase读取指定文件,文件中包含网元,时间,指标三部分。第四部,使用for循环读取文件每一样,每个单元格进行求和或平均。最后把汇总结果生成文件存入Hbase,并把Key存入Oracle。这样当客户现网网元数量增加,开启指标增加,for循环次数也跟着增加,性能问题就产生了。或者下层网管系统数据延迟,上个周期,或者上几个周期数据没来,在某一个时刻统一上来了,导致系统在某段时间负荷就会加大,接下来几个周期数据实时性都没发得到比较好的保障。
单机的高性能,更多的落脚点是机器本身的性能,以及处理具体任务的方式,多进程或多线程,更合理的应用单机的性能;
集群的高性能,即任务的分配和分解。分配是物理层面的,即哪些机器处理用户的请求;分解是业务层面的,即单个请求哪些业务子系统来处理。分配的难点:分配机器的性能,分配算法,与业务系统的连接,失败重试机制等等。分解难点在于业务切分的粒度把握,只能对业务与机器这两块理解恰到好处,才能做较好的切分。
因此集群的高性能的基础是把握好单机器性能。
我反复咀嚼了3遍!
、业务拆分等方式在提升系统容量的同时请求的耗时其实是变长了。
高性能带来的是业务复杂性的提升
业务复杂提升,可将业务进行拆分达到简单的目的
拆分不可过细,带来的影响是各个系统之间调研过多导致性能下降。
业务模块拆分,各模块按业务量大小决定单机/集群部署,各模块之间通过dubbo调度。目前也是感觉模块分得太细,调用复杂
二、我接触过的系统中,在高性能方面:1、数据库采用集群设计,也有的时候使用读写分离;2、缓存服务器单独部署;3、应用服务器分层开发和部署,并使用集群;4、负载均衡采用过F5、Weblogic等。
我的意思是说,在这个语言环境下,强调redis采用的是单线程的模式是不是好一些
1,任务分配主要是集群,通过多台主机处理业务。这里的任务分配可以理解为,所有的业务在一台主机,把这样的主机复制多台。2,任务分解,任务分解指的是业务拆分,业务拆分可以更好的找到系统瓶颈,可以更有利于代码优化。
以上,就是我学到的,谢谢作者,谢谢。
1.为了实现高性能需要进行任务分解(不同应用服务器,文件服务器,数据库)
2.为了实现各个服务器的独立弹性扩展,可用性,应用服务器不能保存数据,这个我理解不太好。
用户通过反向代理把请求输入,应用服务器一般都做哪些工作,帮忙举几个例子
X系统为企业系统,根据业务拆分出以下两个系统。
A系统为人事系统
B系统为绩效系统(考勤,项目,积分等等)
B系统的人事数据以及考勤等部分数据都是来自于拆分后的A系统,这些时候是不是不太合理呢?拆出来后系统的耦合度还是挺好的,但是根据业务情况,好像也没有错。不知华哥你怎么看?
2. 性能优化点思路总结起来还是两步走:先单机后集群,如多线程、协程等编程模型的使用,缓存的使用,最终都是为了更快完成一次请求服务
3. 运华兄,点赞,加油,希望突破千万订阅者!
一般人可能并没有机会去接触类似于淘宝或者微信这样量级的架构,从个人而言,我更关注单机性能优化。
除了传统意义上的单机优化,如果把应用部署阿里云这样的云平台上,单机性能优化是否有不同?