架构复杂度中的性能

2017, Nov 29    

性能带来的复杂度主要体现在两方面:

  • 单台计算机内部为了获得高性能而带来的复杂度。
  • 另一方面是多台计算机集群为了获得高性能而带来的复杂度。

此处的单台计算机并非都可以用集群中的单节点来涵盖。

伸缩性和高性能息息相关的

单机

计算机内部复杂度最关键的地方就是操作系统,是作为将硬件性能充分发挥出来的关键。

操作系统作为软件的运行环境,其复杂度直接决定了软件系统的复杂度。

操作系统和性能最相关的就是进程和线程。

在早期,计算机一次只能执行一个任务,如果某个任务需要从 I/O 设备(例如磁带)读取大量的数据,在 I/O 操作的过程中,CPU 其实是空闲的,而这个空闲时间本来是可以进行其他计算的。

为了进一步提升CPU利用效率,发明了”进程”,它们之间互相独立,各自拥有独立的内存空间。并且为CPU加入了”时间片”功能,让CPU可以用非常快的切换速度去执行多个任务,快到用户是感知不到的。

但如果只是完全独立,而不允许它们之间沟通协作的话,会使得某些场景下的任务执行起来效率低下且设计复杂度上升。所以,就产生了诸多进程间通讯的方式,例如:管道通信(管道文件)、消息通讯(消息队列)、信号量等。

多进程可以让多任务并行处理。但每个进程内部依然是串行处理,而很多实际场景中内部会有很多子任务需要并行处理。例如:我们去餐馆吃饭,我们不可能等到上一个人吃完,我们才能就餐。 所以这时候,又发明了线程,这些线程都共享一份进程资源。为了保证资源的正确性,又发明了互斥锁机制。

有了多线程后,操作系统调度的最小单位就变成了线程,而进程变成了操作系统分配资源的最小单位。

虽然有了CPU的分时,但本质上只是切换的快而已,不是真正意义的并行。那怎么办?那就再来一个 CPU !单核变多核。

综合上面说的,要提升单机的性能需要考虑操作系统、进程通讯、多线程并发等多个技术点。并且要充分结合客观情况及业务,这个过程本身也是非常复杂的。

集群

在17年随着双十一的来到,第一个百亿交易额数据节点定格在 0 点的 3 分 01 秒,而在去年,天猫双 11 成交超百亿用时 6 分 58 秒。 而新的支付峰值在开场 5 分 22 秒就冲到了 25.6 万笔/秒,比去年增长超 1.1 倍,再次刷新全球纪录。同时诞生的还有数据库处理峰值,4200 万次/秒。

听过一个事情,淘宝每笔成交所产生的硬件热量,可以煮熟一个鸡蛋。

要支持像淘宝这样的体量的支付,单个计算机是怎么也做不到的。必须采用集群的方式来做。

集群并不是简简单单的多个计算机放在一起工作这么简单,就像CPU从单核变多核一样,这一个复杂的设计。

任务分配

将不同的任务分配给不同的机器。例如:原来待洗的碗筷只有一个人在洗,现在变成两人在洗了。 会有以下需要考量的:

  • 新增任务分配器(洗碗工的管理者)。这个分配器可能是硬件网络设备(交换机),也可能是软件网络设备(LVS),也可能是负载均衡软件(nginx)。

  • 任务分配器和真正的业务服务器之间有连接和交互,需要选择合适的连接方式,并且对连接进行管理。 例如,连接建立、连接检测、连接中断后如何处理等

  • 任务分配器需要增加分配算法。例如,是采用轮询算法,还是按权重分配,又或者按照负载进行分配。 如果按照服务器的负载进行分配,则业务服务器还要能够上报自己的状态给任务分配器。

当要处理的任务增加到一定的量级。简单的为餐厅增加洗碗工而管理者不增加,就会有很大的风险。例如:管理者生病了不能工作了,那洗碗工就没法工作了。 而且当收到大量的任务超过管理者的处理能力时。管理员就成为了性能的瓶颈。那怎么办?加管理者!

那当前的架构(多个管理者)多对多,较于上面说的1对多架构有什么区别和新挑战?

  • 需要将不同的任务分给不同的管理者,常见的方法包括 DNS 轮询、智能 DNS、CDN(内容分发网络)、GSLB 设备(Global Server Load Balance,全局负载均衡)等。
  • 加入多个管理者后,原来的管理者的分配算法是否合适等等
  • 上面涉及的方面,都需要再次考量

任务分解

通过任务分配的方式,我们能够突破单台机器处理性能的瓶颈,通过增加更多的机器来满足业务的性能需求, 但如果业务本身也越来越复杂,单纯只通过任务分配的方式来扩展性能,收益会越来越低。

例如:原来洗碗工什么餐具都洗,但新规定,某些餐具必须分门别类好交给外部保洁公司进行处理。 这个时候单纯的增加洗碗工,已然提升效率不大。这个时候可以将洗碗工细化,分为自用清洗员工、归纳工、派送工等等。 将原来洗碗的业务进行细化。

从业务的角度来看,任务分解既不会减少功能,也不会减少代码量 (事实上代码量可能还会增加,因为从代码内部调用改为通过服务器之间的接口调用),那为何通过任务分解就能够提升性能呢?

  • 简单的系统更加容易做到高性能

    系统的功能越简单,影响性能的点就越少,就更加容易进行有针对性的优化。复杂的系统有可能牵一发而动全身。 例如:因为动脉硬化问题,而通过食醋,来增加血管软化度,但有会导致钙大量流失。

  • 可以针对单个任务进行扩展

    例如:可根据外部清洗的碗筷实际情况,对归纳工进行增减,而无需对清洁工及派送工改动。

当然凡事都有过而不及。如果分解的过细,性能也有可能会不升反降。从调用角度来说,子任务越多,调用的次数就越多。 大多子任务的通讯都是基于网络,而网络通讯性能远比系统内函数调用的性能低得多,而且网络通讯是有延迟,再少的延迟,在这种细分结构下,都会有不好的表现。

虽然系统拆分可能在某种程度上能提升业务处理性能,但提升性能也是有限的,例如:原来请求延迟是200ms,拆分可以达到100ms,但是想要进10ms内,怕单从拆分的角度来说是不大可能的。 因为最终决定业务处理性能的还是业务逻辑本身,业务逻辑本身没有发生大的变化下,理论上的性能是有一个上限的,系统拆分能够让性能逼近这个极限,但无法突破这个极限。

凡事适度,所以对于这个拆分的粒度来说就是一个非常重要的关键。


总体来说,性能要根据当前业务阶段来看,不能只看眼前,也不要看的太远,因为很多时候,也许业务就撑不到那个时候 : )