今天的线上分享,我们来说说容器和应用这亲密的哥俩。

  你对应用系统好,那么应用系统就对你好。

  你对应用系统说,hi,上container吧! 一切问题都解决,那么就等着应用系统忽悠你。

  应该说container比起VM更贴近应用,可以理解为应用的"虚拟机",对应着VM是OS的虚拟机。

  我们上container的目的是为了应用,因此问题的本源是应用而非container,一个应用系统本身设计的好坏决定了最终应用的效果, 因此说设计好应用,才能用container的手段更好地支撑它。

  从应用的性能和稳定性说起,有如下五点:

  容器的启动时间和应用模块的初始化时间共同决定了应用的准备时间

  容器和节点的关系的选择影响着性能和稳定性

  应用的数据结构影响着容器应用的性能

  应用采用的中间件影响着容器伸缩的形式

  应用的结构设计影响着使用容器的方式

  1、容器的启动时间和应用模块的初始化时间共同决定了应用的准备时间

  容器的启动时间为秒级,但这只是OS上启动一个进程的时间而已,并不是一个应用启动的时间时间,一个应用加载后会有个初始化的时间,对一些应用的不同环节,会有不同的考虑,比如需要数据缓冲服务的进程,在加载的时候就需要把数据读入到内存中来,这类我们可以称之为有数据服务。当这个加载服务还未完成时,是不能对外提供服务的,因此实际的时间应该是启动开始到能实际提供服务的时间,而非容器本身的启动时间。

  这类的问题可以通过容器的提前启动来解决。

  2、容器和节点的关系的选择影响着性能和稳定性

  (1) 如下这个图,容器a在节点node1上,容器b在节点node2上,这两个容器通过网络进行数据和信息的传递

  

容器代替驱动_容器代替驱动

  再看一下另一种形式:

  (2) 如下图,容器a和b都运行在同一个节点node1上,容器之间通过内存或非物理网络进行数据和信息的传递

  

容器代替驱动_中间件_02

  (1)和(2)比,a拥有node1的计算能力,b拥有node2的计算能力,整体而言计算能力强过(2),但这是以a,b都是密集型计算任务为前提的,对于普通的处理,a,b对node1和node2的资源占用远未带到满负荷的程度,那么这个比较没有实际意义。

  而(2)的好处是相对于(1)容器a,b之间的数据交换不通过物理网络,可以以非常高的效率进行。

  考虑到实际的场景,我们可以归纳如下:

  

容器代替驱动_中间件_03

  从上图比较,我们很难区别出哪个方式更好,只能说按场景进行不同的侧重选择,比如(1)可以减少网络的占用,这里我们再考虑再具体一点的场景,比如容器a跑的是应用,而容器b跑的是数据库,那么比较就更加具体了,我们知道数据的HA比普通的应用得HA麻烦一些,这时候我们就只能判断出从稳定性上而言(1)会好过(2),因为这时候(1)的好处是应用出问题时不会引起数据库的切换,数据库的切换与app server不同,有数据完整性等的要求,而且切换时间一般比较长,因此对于数据的HA建议如下:

  

容器代替驱动_制造_04

  也就是说数据的HA尽量不要跟其他环节的HA混在一起。

  3、应用的数据结构影响着容器应用的性能

  大家都在说微服务,实际上微服务本身跟容器没有关系,但容器可以使微服务更好地发挥作用,微服务的划分有个粒度的问题,而这个粒度很多时候是跟数据结构相关的。

  对于一个乐队,每人一件乐器,也就是乐队的乐器是按人为粒度设计的,恰到好处,如果设计成一个笛子两个人共同吹可能就会有些问题,参考如下建议原则:

  对于要处理的数据列比较少,并且来源于同一个表,那么对这个的数据处理单元就不要按列再去拆分成更小的微服务。

  对于要处理的数据记录比较大,那么这时候按也业务区间进行更小的服务拆分是可以的。

  对于大量的数据分析查询,数据的读取也会使一个时间成本,这时候采用列式数据存储可以大大缩短数据读取的时间。

  4、应用采用的中间件影响着容器伸缩的形式

  说到容器的伸缩,我们自然想到是在空闲的节点上启动容器,这里我们再具体一些,比如用了中间件,这时候情况就有些具体的不一样了,我们知道中间件有:

  可伸缩性

  高可用

  应用程序故障转移

  管理据库连接池

  以weblogic 为例,可以理解为下图:

  

容器代替驱动_中间件_05

  weblogic有自己的一套集群管理和应用负责调度机制和规则,相对于容器,weblogic更接近应用和数据库,还有在一个weblogic节点里会有多个用户并发访问并调度到不同节点的EJB里,原因是基于中间件开发的应用系统是安装中间件的一套规范来进行的,因此中间件直接感知的就是应用的流程和状态。在这个场景下,用户请求在不同中间件的调度管理就交给中间件本身。 而容器平台所做的就是将每个中间封装在容器镜像里,根据实际的部署需求在不同的节点上运行起中间件容器即可,并且外部访问入口的负载分发也可以交给容器平台来调度。 因此总结建议如下:

  

容器代替驱动_中间件_06

  如果要上更好地上容器,那么可以考虑变成如下形式:

  

容器代替驱动_中间件_07

  由于Servlet和EJB属于同一个节点,Servlet和EJB之间不存在负载偏转调度的问题,那么全靠容器平台伸缩了,对容器而言可控性更强。

  5、应用的架构设计影响着使用容器的方式

  不同的业务场景和性能会要求应用系统和容器平台系统有不同的侧重点,比如业务计算并不复杂,而且负载主要来自用户并发的压力,和业务本身就比较需要计算量,在小并发时就有着负载的要求的侧重就会不同,前者要求依据好的规则将入口的请求分发到不同节点,后面服务端根据负载的并发变化而伸缩。 后者则需要设计好后端的逻辑流程,数据结构和存储等环节来更好地适应容器特性,如果是两者的特性都具备,那么就入口分发规则和后端规则需要一并考虑。

  对于一个业务应用系统,数据是核心,因此这里从数据开始展开,我们知道一个业务系统会有很多种不同的查询工作,也就是对数据库而言是一些数据的读取和运算过程,这里就会有两个选择:

  (1)数据的运算放在存储过程里,外面的容器通过接口只取到最终结果即可

  (2)数据的运算放在跟数据库相连的分布处理容器里,数据库只负责存储管理数据和一些基本的简单查询,就算有存储过程也是简单的存储过程,太复杂或耗时的运算放在应用容器里。

  对于(1),当同时的写请求比较多或数据更新比较频繁的时候,数据存储过程的执行本身会成为一个瓶颈,而这时容器里的应用只在等待数据返回的结果,在数据处理计算上无法帮助数据库,因此在数据库服务器不是高性能节点时不推荐这这种方式上容器,因为设计上无法让应用容器进行数据计算负载的伸缩。我们归纳为下表:

  

容器代替驱动_制造_08

  通过如上表格可以看到,用好容器,可以使性能更高,更加容易部署和维护数据库相关的计算。

  我们把方案(2)用图表示出来:

  

容器代替驱动_容器代替驱动_09

  容器虽说是生命周期应该短,用时启动即可,用完销毁,但为实际的应用考虑,可以预先启一些容器,可以成为某个服务的container pools,并对这些container定时作服务路径完成性检查,以确保服务的性能和稳定性。所以上述图中举了两个容器服务池:

  buffer pools:数据库缓冲服务池,池里的容器分担数据库的读负载,读的越多越频繁时,缓冲池的效果越明显。

  job pools:作业任务池,这个池里是提交和预先准备的需要进行计算的程序逻辑,有了容器后,这个提交工作变得简单了,这个简单是对增加了新的类型任务逻辑而言的,只需要提交测试过的容器镜像即可,job manger会根据任务的类型需要启动哪个类型的任务。