简介
实时汇总模块是monitor系统的至关重要的模块,这个模块做好了才能保证由上千台机器组成视图能够及时的计算出来。仔细分析一下就知道每计算一个视图的计算量其实是非常大的,如何能做到秒级完成汇总计算是这个模块的难点和亮点。问题简单的抽象和归纳如下:
- 输入数据:N台机器构成的视图,视图中绑定了M个属性,每个属性有K个数据点
- 输出数据:M个属性,每个属性K个数据点
- 汇总方式:支持累加、最大值、最小值和平均值等汇总方式
- 示意图:
探讨几种方案:
- 1.将所有数据拉取到一台/多台机器上,统一进行汇总计算(流计算模型)。因为数据是分布式存储的,所以数据没有存储到一台机器上,所以最简单的方案是将数据先拉回来,再进行计算。这种方案简单直观,但是最大的问题是,数据都通过网络收集到一起的代价是否能够承受?根据当前的视图统计,一个合计的假设是:某个视图汇总的机器数为1000,属性数据为400,每天有1440分钟个数据点,每个数据4字节存储。按照上述条件计算,先把数据通过网络收集到1台机器,那么网络穿越流量为10004001440*4,大约是2.3GB。看到这个数字就很惊讶了,计算一个视图需要这么大的流量穿越,那如何承受的了?!做个有意思的估算,假设我们不计成本的跑满带宽,带宽按照1024Mbit/s计算,那么每秒钟传输的字节为128MB,此时2.3GB需要传输18秒左右。所以跑的如此的带宽也无法满足“实时”计算的要求!既然把数据拉取回来已经完全无法实现我们设计的要求,那么是不是可以考虑数据做本地计算,把汇总好的结果再统一由一台服务器汇总,从而引入我们的改进方案。
- 采用Map-Reduce计算模型对数据进行快速汇总计算。Map-Reduce是google提出的分布式计算模型,其中介绍了如何把数据分而治之(Map),然后再合并成为最终结果(Reduce)的整个算法流程。这种算法框架并没有限制数据是以哪种方式存储,例如Hadoop中就是将数据存储到HDFS文件系统,然后下发jobs执行计算。前面介绍过我们系统中有2天的全内存数据,这些内存数据就是我们进行实时计算的数据基础。综合Map-Reduce思想,可以得出:
- Map过程:将视图中绑定的机器按照其存储的不同服务器分成不同的工作(jobs),然后将jobs下发到对应的服务器上分别进行汇总。汇总的时候会并发多个线程,每个线程对应一个任务(tasks)并发的进行计算,充分利用每个服务器多核的优势并发计算,从而保证数据可以在秒级在各个处理机上汇总完成。
- Reduce过程:数据已经在不同的服务器上汇总完成,如果想得到最终结果,还需要将每台机器上的汇总数据收集到一起进行整合。
- - 图中最左边是存放数据的datanode,在各个datanode上会启动多个task来并发执行Map操作,Map操作之后在datanode上产生多份中间数据,最后将这些中间数据汇总到一台或多台服务器上执行Reduce操作从而形成最终结果。按照这个思路这里给出实时汇总计算模块的架构,如下:
- 计算过程如下:
- proxy接收到从client发送的汇总数据的请求包,其中包括两个集合:SET(server_id)和SET(attr_id)。
- proxy负责将SET(server_id)按照其存储后端处理机(一致性hash算法)划分为SET_1、SET_2、…、SET_N(其中SET(server_id)=SET_1+SET_2+…+SET_N)。
- proxy按照server_id划分的N个SET,重新组装成N个请求包(全量的属性),发送到对应的后端处理机。
- 处理机proc接收到拆分后的请求包,包含两个集合:SET_X(server_id)和SET(attr_id)。其中SET_X(server_id)是由proxy拆分和分发的集合,所以仅包含在本地内存中存在的server_id。
- 处理机proc中有多个并发的线程。按照SET(attr_id)划分为SET_1、SET_2、…、SET_M,分别交给不同的线程并发计算(支持累加、最大值、最小值和平均值操作)。
- 处理机proc等待各个线程执行完毕之后,将数据进行一次汇总(将不同SET的数据合并到一起),最后统一回包给proxy。
- 7)proxy接收各个proc的回包,最终执行Reduce操作,按照server_id再做一次汇总操作(支持累加、最大值、最小值和平均值操作)
- proxy将Reduce之后的数据拼成返回包最终返回给client。
- 下面对穿越流量和计算时间进行一个简单的评估(假设某个视图汇总的机器数为1000,属性数据为400,每天有1440分钟个数据点,每个数据4字节存储)
- 流量评估:
- 1)接收到的请求包的字节数:10004+4004 = 5.6kB
- 每个proc处理机接收到的请求包字节数为proxy的1/3(后端3台处理机存储数据),所以为1.87kB
- 每个proc处理机计算之后产生的数据大小为:40014404=2.3MB
- proxy接收后端处理机的回包数据大小为:2.3*3=6.9MB
- 综上所述:
- proxy:in流量为 6.9MB,out流量为 5.6kB
- proc:in流量为1.87kB,out流量为 2.3MB
- 相比于之前的2.3GB的网络穿越而言,优化了太多,从而为秒级汇总奠定了流量基础。
- 计算时间评估:
- 对于千兆网卡和带宽而言,网络传输可以保证在百毫秒级别完成;
- 前面介绍过,采用3台B6的机器内存化存储数据,每台机器有16个核和64GB的内存。
- a) Cpu方面:每个核需要承载的计算次数为1000/34001440/16=12000000,就是 1.2kw(12M)次计算。对于主频在1GHz的核而言,简直可以轻而易举的在毫秒级别完成计算。
- b) 内存方面:每台机器需要访问的内存字节为1000 /34001440*4= 768MB,而内存的理论带宽一般为10GB的级别,考虑到hash结构访问内存会有一定的冲突几率(平均1次成功查找需要尝试3、4次左右),所以勉强在1s内能够完成访问。(实际测试大约需要0.8s~1s左右)
- 综合考虑网络带宽、cpu和内存等多方面的因素,可以保证处理1000台服务器、400个属性和1440分钟个数据点的视图是可以在1s左右完成计算的。
- 视图计算的总体架构:
- 视图计算的总体架构如上图所示,流程如下:
- 1)view_data_write_proxy按照数据库中存储的视图配置信息拼装成的汇总请求包,发送给实时汇总模块进行计算;
- 实时汇总模块在毫秒级或秒级时间内将计算结果返回给view_data_write_proxy;
- view_data_write_proxy拿到汇总好的结果之后,再将数据转发给视图存储服务器(view_storage),会同时转发两份给主备服务器;
- 最后由视图存储服务器上的view_data_write_proc进程将汇总数据写入到共享内存中,从而完成视图数据的存储。
- 看到这里,对于秒级汇总视图的原理应该清楚了,但是可能还有个疑问没有解释:前面介绍我们有将近5k个视图,如果每个视图的计算都需要将近1s的时间,那计算完这些视图岂不是要花费超过1个小时的时间才能计算一遍?针对这个问题,需要澄清两点:
- 第一,不是每个视图都绑定这么多机器和这么多属性的(平均每个视图也就绑定了50个属性);
- 第二,每次计算不需要重新计算1440分钟,那么最简单的情况就是每分钟计算1次,每次只计算1分钟的数据,这样就会节省很多资源(实际上为了保险,每分钟计算1次,每次重复计算15分钟的汇总数据)。
- 所以目前后台实际统计的数据显示:将近5k个视图总共计算一轮需要的时间大约为15s,还是远小于1分钟的。
- 流量评估: