频道栏目
首页 > 系统 > 其他 > 正文

架构设计:系统间通信(40)——自己动手设计ESB(1)

2016-07-28 09:14:04         来源:JAVA入门中  
收藏   我要投稿

1、概述

在我开始构思这几篇关于“自己动手设计ESB中间件”的文章时,曾有好几次动过放弃的念头。原因倒不是因为对冗长的文章产生了惰性,而是ESB中所涉及到的技术知识和需要突破的设计难点实在是比较多,再冗长的几篇博文甚至无法对它们全部进行概述,另外如果在思路上稍微有一点差池就会误导读者。一个可以稳定使用的ESB中间件凝聚了一个团队很多参与者的心血,一个人肯定是无法完成这些工作的。但是笔者思索再三,还是下决心将这这即便文章完成,因为这是对本专题从第19篇文章到第39篇文章中所介绍的知识点的最好的总结。我们自己动手设计ESB中间件,不是为了让它商用,也不是为了让它可以比拟市面上某款ESB中间件,甚至不是为了把ESB中的技术难点的解决全部方案化。我们的目的是检验整个专题中所介绍的知识点是否能在读者自己消化后进行综合应用,是否能做到技术知识的活学活用、按需选型

2、ESB的顶层设计

这里写图片描述
(顶层设计图)

上图是我们要进行实现的ESB中间件的顶层设计。从上图中可以看到,整个ESB中间件分为以下几个模块:Client客户端、流程编排/注册工具、主控服务模块、服务状态协调组(模块)、服务运行组(模块)。首先我们大致描述一下这些模块的工作内容:<喎"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPkNsaWVudL/Nu6e2y8rH0OjSqr3TyOtFU0LW0LzkvP61xLj3uPbStc7xt/7O8c+1zbOho8D9yOfO78H3z7XNs6GiwarVy8+1zbOhokNSTc+1zbO1yLXIoaM8c3Ryb25nPtTa1eLQqb/Nu6e2y8+1zbO908jrRVNC1tC85Lz+yrGjrL2rvK+zyUVTQtbQvOS8/szhuam4+Mv7w8e1xLj31ta/qrei0+/R1LDmsb61xEVTQi1DbGllbnTX6bz+PC9zdHJvbmc+oaPI57n7yrnTw7XEysdDI9Pv0dTU8kVTQi1DbGllbnTX6bz+v8nE3NLURExMzsS8/rXEt73Kvczhuamju8jnufvKudPDtcTKx0pBVkHT79HU1PJFU0ItQ2xpZW501+m8/r/JxNzS1Ephcs7EvP61xLe9yr3M4bmpo7vI57n7yrnTw7XEysdOT0RFSlPU8r/JxNzKx9K7uPajqLvytuC49qOpSlPOxLz+JmhlbGxpcDsmaGVsbGlwOzwvcD4NCjxwPtXi0Km/zbuntsvPtc2ztcS/qreiyMvUsb2rv8nS1Mq508NFU0LW0LzkvP7M4bmptcTSu7j2tsDBorXEwfezzLHgxcUv16Ky4bmkvt+jrLrz1d/U2rrctuBFU0LW0LzkvP7Ptc2z1tDSu7DjsbvD/MP7zqombGRxdW87JmhlbGxpcDsmaGVsbGlwOyBTdHVkaW8mcmRxdW87o6yyosfS1eLQqcH3s8yx4MXFL9eisuG5pL7f0ruw49LUuPfW1klERbLlvP61xNDOyr3M4bmps/bAtKOswP3I59bG1/ezyUVjbGlwc2UtUGx1Z2luzOG5qbj4v6q3osjL1LGho9Xi0Km5pL7ftcTW99Kq1/fTw77NysfIw7/Nu6e2y8+1zbO1xL+qt6LIy9Sxo6i/qreizcW206Opvt+xuM/yRVNC1ve/2Lf+zvG9+NDQ1K3X07f+zvHXorLhtcTE3MGmo6zB7c3iu7m/ydLUyMO/qreiyMvUsbLp0a+1vcS/x7C3/s7xtsvL+dPQv8nTw7XExuTL/NSt19O3/s7xo6jAtNfU09rG5Mv80rXO8c+1zbO1xKOpo6zS1LHj1NrB97PMseDFxS/XorLhuaS+38nPzeqzydDCtcS3/s7xwfezzLHgxcW6zdLR09C3/s7xwfezzNDCsOaxvrXEt6KyvKGj1eK+zcrHyc/NvNbQserXos6qJmxkcXVvOzEmcmRxdW87tcSyvdbooaM8L3A+DQo8cD7B7c3iRVNC1tC85Lz+zqrBy7Gj1qTB97PMseDFxcv5yrnTw7XE1K3X07f+zvGyu7vh0vLOqszhuanV4rj21K3X07f+zvG1xNK1zvHPtc2ztcSx5Luvtviy+sn607DP7KOs0ruw48C0y7XU2r340NDStc7xz7XNs9eisuHUrdfTt/7O8cqxtry74da4tqjV4rj21K3X07f+zvG1xLDmsb66zbX308PIqM/eoaO199PDyKjP3tK7sOPT1rfWzqq62sP7taXIqM/eus2w18P7taXIqM/eoaPS1LDXw/u1pcioz97AtMu1o6zWu9PQsNfD+7Wl1tDL+cHQwdC+2bXE0rXO8c+1zbPT0Mioz96199PD1eK49tSt19O3/s7xoaO8tMq51eK49tSt19O3/s7xss7T68HLxLO49kVTQtbQtcTB97PMseDFxaOsyOe5+8frx/PV4rj2seDFxbrDtcTB97PMtcTStc7xz7XNs7K71NrV4rj2sNfD+7Wl1tCjrLX308PSsrvhyqew3KGjPC9wPg0KPHA+1ve/2Lf+zvHOqsH3s8yx4MXFL7eisry5pL7fzOG5qdDCtcTUrdfTt/7O8deisuHH68fzoaLQwrXEwfezzLeisrzH68fzoaLS0dPQwfezzLXE0MKw5rG+t6KyvMfrx/Oho9fu0MK1xNSt19O3/s7xoaLB97PMseDFxbXIyv2+3b2ru+Gxu9b3v9i3/s7xtOa0otTas9a+w7uvyN3G99bQo6jA/cjnudjPtdDNyv2+3b/io6mjrLKix9LP8iZsZHF1bzu3/s7x17TMrNCttffEo7/pJnJkcXVvO7eiy83X7tDCtcTK/b7dseS7r6GjPHN0cm9uZz7XotLio6zW97/Yt/7O8bKisru4utTw1rTQ0LHgxcW6w7XEwfezzKOs1rvKx9PD09q8x8K8yv2+3bHgxcW1xLHku6+6zc/yJmxkcXVvO8r9vt3QrbX3xKO/6SZyZHF1bzu3osvN1eLQqcr9vt2x5LuvPC9zdHJvbmc+o6zV4r7NysfJz8281tDL+bHqyr61xLK91ugyoaPW97/Yt/7O8bu509DB7c3iwb249tf308Ojuri61PDIqM/eudzA7brNt/7O8dTL0NDEo7/ptcTXtMysvOC/2KGjPC9wPg0KPHA+08nT2ri61PDX7tbVttTB97PMseDFxb340NDWtNDQtcQmbGRxdW87t/7O8dTL0NDEo7/pJnJkcXVvO7Tm1Nq63Lbgvdq146Ooz8LOxLPGzqpFU0ItQnJva2VyIFNlcnZlcr3ateOjqaOsx9I8c3Ryb25nPtXi0KlFU0ItQnJva2VyIFNlcnZlcr3ateO1xMr9wb/U2rf+zvG5/bPM1tC74bK7ts+x5Luvo6jQwtT2u/K89cnZo6mjrMv50tQmbGRxdW871ve/2Lf+zvEmcmRxdW87sqKyu9aqtcDT0MTE0KlCb2tlctTa1MvQ0Dwvc3Ryb25nPqGjzqrBy82o1qrV4tCp1NrUy9DQ17TMrLXEQnJva2Vy09DQwrXEt/7O8bHgxcWxu7eisryjqLvy1d/G5Mv8ysK8/tDFz6KjqaOsPHN0cm9uZz7V4tCptKbT2tTL0NDXtMystcRFU0ItQnJva2VyIFNlcnZlcr3ateO2vLvhway907W9JmxkcXVvO7f+zvHXtMys0K2198Sjv+kmcmRxdW87o6yyosfS08m689Xfzeqzycr9vt2x5LuvtcTKwrz+zajWqjwvc3Ryb25nPqGj1eK+zcrHJmxkcXVvO7f+zvHXtMys0K2198Sjv+kmcmRxdW87tcTW99KquabE3KOs0rLKx8nPzbzW0Mv5yr61xLK91ugzoaPU2s7Sw8fX1Ly6yei8xrXERVNC1tC85Lz+1tCjrCZsZHF1bzu3/s7x17TMrNCttffEo7/pJnJkcXVvO9PJ0rvX6Xpvb2tlZXBlcrf+zvG5ubPJo6jU2s7Swe3N4ry4xqqyqc7E1tDXqMPFvenJ3Hpvb2tlZXBlcqOs1eK49teozOK+zbK7ttR6b29rZWVwZXK1xLv5sb6y2df3vfjQ0L2yveLBy6Opo6zI57n7xPrU2sq1vMq1xLmk1/fW0NPQxuTL/LmmxNwvvLzK9dDox/OjrNKyv8nS1NfUvLrJ6LzGJmxkcXVvO7f+zvHXtMys0K2198Sjv+kmcmRxdW87oaM8L3A+DQo8cD7U2tK1zvHPtc2zvK+zybn9s8zW0KOsRVNC1tC85Lz+y/mw59HdtcS9x8mrvs3Kx9TauPe49tK1zvHPtc2zvOS9+NDQ1K3X07f+zvG199PDoaLXqru7yv2+3aGi1Nm9+NDQ1K3U8rf+zvG199PDoaLU2dequ7smaGVsbGlwOyZoZWxsaXA7LtfuuvPP8ta00NC3/s7xseDFxbXEx+vH89Xft7W72L3hufuhozxzdHJvbmc+y/nS1EVTQtbQvOS8/rf+zvHN+c3509C9z7jftcTQ1MTc0qrH8zwvc3Ryb25nPqGjyOe5+9a00NBFU0K3/s7xseDFxbXEvdq149a709DSu7j2o6zN+c35vs2077K7tb1FU0LW0LzkvP61xMnovMbSqsfzyfXWwbvhyrlFU0LW0LzkvP63/s7xs8nOqtX7uPbI7bz+vNy5ubXE0NTE3Ma/vrG146Gjy/nS1NTaztLDx8novMa1xEVTQtbQvOS8/tbQo6zV5tX91rTQ0EVTQrf+zvG1xL3ateO74dPQtuC49tXi1tZFU0ItQnJva2VyIFNlcnZlcr3ateOhozwvcD4NCjxwPtTaRVNC1MvQ0Lf+zvG1xLn9s8zW0Mq508O24Lj2QnJva2VyIFNlcnZlctPQuty24LrDtKajrMrXz8jAtMu1y/zDx7/J0tSxo9ak1NrV+7j2z7XNs7P2z9bH68fzuum35bXEx+m/9s/Co6zE3Lm7sNHV4tCpx+vH89G5wabGvb75t9bF5LW91eLQqUJyb2tlciBTZXJ2ZXK92rXjyc+jrNfu1tXKuUVTQrf+zvGyu7vhs8nOqtX7uPa2pbLjyei8xrXExr++saGjx+vH89G5waa1xLfWxeS5pNf3u+HTyXpvb2tlZXBlcryvyLrN6rPJoaPB7c3io6y24Lj2QnJva2VyIFNlcnZlcr/J0tSxo9akxLPSu7j2o6i78tXfvLi49qOpQnJva2VyIFNlcnZlcr3atePU2rP2z9bS7LOjsqLNy7P2t/7O8brzo6zV+7j2RVNC1tC85Lz+tcS3/s7xsru74c2j1rkmbWRhc2g7Jm1kYXNoO9XiysfSu7j2z9azybXEyN207be9sLiho7+qt6LIy9Sxv8nS1M2ouf3Ny7Hcy+O3qMC0vva2qEVTQi1DbGllbnTPwtK7tM7K1M28t8POyrP2z9a07c7ztcRCcm9rZXIgU2VydmVyvdq147XEyrG85KOs0rK/ydLUwaK8tM6qRVNCLWNsaWVudNbY0MK31sXk0ru49r2hv7W1xEJyb2tlciBTZXJ2ZXK92rXjoaPX7rrzo6zV4rj2veK+9re9sLi/ydLU1NpFU0K3/s7x1MvQ0LXEuf2zzNbQsaPWpMq1z9ZCcm9rZXIgU2VydmVytcS2r8ysuuHP8sCp1bmjurWxRVNC1ve/2Lf+zvHEo7/pt6LP1tX7uPZCcm9rZXIgU2VydmVyt/7O8dfptcTQ1MTctO+1vaOou/K/7NKqtO+1vaOpt+XWtcqxo6zUy86syMvUsb/J0tTC7cnPv6rG9NDCtcRCcm9rZXIgU2VydmVyvdq146Osem9va2VlcGVyvK/IurvhuLrU8L2rtqjWxrXEseDFxaGitqjWxrXEUHJvY2Vzc29ytKbA7cb3tcjK/b7d0MXPojxzdHJvbmc+tq/MrLzT1Ng8L3N0cm9uZz61vdDCtcRCcm9rZXIgU2VydmVyvdq149bQo6yyosjDuvPV38GivLS808jr1fu49rf+zvHX6b+qyry5pNf3oaM8L3A+DQo8cD7U2kVTQi1DbGllbnSjqMSzuPbStc7xz7XNs6Opx+vH89a00NDEs7j2t/7O8bHgxcXKsaOsytfPyLvhyrnTw9XiuPZFU0ItQ2xpZW50o6jEs7j20rXO8c+1zbOjqdLRvq28r7PJtcR6b29rZWVwZXK/zbuntsvH68fzRVNCtcR6b29rZWVwZXK8r8i6t/7O8aOstNPW0MihtcO1scew1f3U2tTL0NC1xEJyb2tlciBTZXJ2ZXK92rXj0MXPoqOssqLNqLn9xLPW1svjt6i+9rao19S8urfDzsrExNK7uPZCcm9rZXIgU2VydmVyvdq146Ooy+O3qLrctuCjusLW0a/L47eooaK808ioy+O3qKGi0rvWwtDUSGFzaMvjt6i1yLXIo6mjrMjnJmxkcXVvO7alsuPJ6LzGzbwmcmRxdW871tCyvdboNKGisr3W6DXL+cq+oaPOqsHLsaPWpMnPzsTW0Mzhtb21xNDCtcRCcm9rZXIgU2VydmVyvdq148Tcubu808jrt/7O8dfpsqLOqkNsaWVudEVTQi1DbGllbnS3/s7xo6yyvdboNLrNsr3W6DW1xLn9s8y/ydLU1tzG2tDUvfjQ0KOssqLK08fpv/bW2NDCzqpFU0ItQ2xpZW50t9bF5EJyb2tlciBTZXJ2ZXK92rXjoaM8L3A+DQo8cD61sUVTQi1DbGllbnTIt7aoxL+x6kJyb2tlciBTZXJ2ZXK92rXjuvOjrL2r1f3Kvc/y1eK49kJyb2tlciBTZXJ2ZXK3osbw1rTQ0MSzuPa3/s7xseDFxbXEx+vH86GjtbHNrNK7uPZFU0ItQ2xpZW50tdq2/rTOx+vH89a00NC3/s7xseDFxcqxo6y+zb/J0tTU2tK7tqjKsbzk1tzG2sTao6jT0NCnyrG85MTao6myu9TZ19+yvdboNKGiNcHLo6y2+L/J0tTWsb3Tt6LG8Mfrx/O1vc2s0ru49sS/sepCcm9rZXIgU2VydmVyvdq146Gj1rG1vdXiuPZCcm9rZXIgU2VydmVysrvU2cTcubvP7NOm1eLQqcfrx/POqta5o6i78tXf09DG5Mv80sC+3ci3tqjV4rj2QnJva2VyIFNlcnZlcr3atePS0b6tsrvE3Mzhuam3/s7xo6mjrEVTQi1DbGllbnS74dTZ1rTQ0LK91ug0oaI1o6zS1LHjyLe2qMHt0ru49tDCtcShotX9s6O5pNf3tcRCcm9rZXIgU2VydmVyvdq146Gj1NrPws7EscrV39Kyu+HW2LXjvenJ3Mjnus69+NDQQnJva2VyIFNlcnZlcr3ateO1xNGh1PGhozwvcD4NCjxoMSBpZD0="3主控服务的日志收集">3、主控服务的日志收集

上一节已经说到,在我们设计的ESB中间件中包括两个模块:主控服务模块和服务运行组(模块)。其中主控服务模块的其中一个作用,是对若干当前处于运行状态的服务运行组节点(Broker Server)进行性能状态监控。性能状态监控的目的是确保运维人员实时了解这些Broker Server的运行状态,并且能在整个服务运行组快要达到性能瓶颈时能够启动新的Broker Server分担压力或者在整个服务运行组没有什么请求负担时,停止一些Broker Server。

那么主控节点如何知道整个Broker Server组中多个服务节点的性能状态呢?要知道,Broker Server节点是可以动态扩展的。上文也已经说到:主控节点并不知道当前有哪些Broker Server节点处于运行状态。那么基于Kafka消息队列的日志收集就是一个解决方案,设计人员还可以使用Flume + Storm的解决方案进行日志自动收集和即时分析。下面我们对这两种日志收集方案进行介绍。注意,关于Kafka、Flume在这个专题之前的文章中已经做了详细介绍,所以本小节中涉及Kafka、Flume技术的部分就不再对设计方案的实施进行介绍了。

3-1、使用Kafka收集性能数据

Kafka Server的特点就是快,虽然在特定的情况下Kafka Server会出现消息丢失或重复发送的问题,但是这个问题针对日志数据收集场景来说不算大问题。使用消息队列收集各Broker Server节点的性能日志也是和ESB中各模块的依赖特性相适应的:由于在我们设计的ESB中间件中,主控服务模块并不知道有多少Broker Server节点处于运行状态,也不知道这些Broker Server节点的IP位置。也就是说主控服务模块无法主动去这些Broker Server节点上收集性能数据。最好的办法就是由这些活动的Broker Server节点主动发送日志数据。

3-1-1、设计思路

下图是使用Kafka组件收集Broker Server节点上性能数据并进行性能数据处理、结果存储的设计示例图:

这里写图片描述

上图中,每一个Broker Server节点上除了启动一个Camel Context实例以外(后文进行详细说明),还需要配置一个Kafka的Producer端用于发送数据。Kafka-Producer端收集的性能数据可能包括:CPU使用情况、内存使用情况、本地I/O速度、操作系统线程情况、Camel Context中的路由实例状态、Endpoint在Cache中的命中情况、客户端对Broker Server中以编排路由的调用情况等等——业务数据和非业务数据都可以通过这种方式进行监控,并且以业务数据为主。

Kafka Servers中部署了三个Kafka Broker Server节点(建议的值),用于接收若干ESB Broker Server节点上各个Kafka-Producer发送来的性能日志数据。为了保证整个Kafka集群的性能,每一个Kafka Broker Server都有至少两个分区(partition,还是建议值)。这里多说一句,为了节约服务资源您可以将Kafka Broker Server和Kafka-Consumer放在一台服务节点上,甚至可以将它们和主控服务节点放在一起。

Kafka-Consumer负责进行性能日志数据的处理。有的读者可能就要问了,既然Consumer接收到的都是可以独立存储性能日志数据,那么只需要将这些日志找到一个合适的存储方案(例如HBase)存放起来就可以了,还需要Consumer做什么处理呢?这是因为开发团队完成的Producer采样频率可能和运维团队要求的监控采用频率不一样。

为了保证性能监控数据的精准性,开发团队利用基于Kafka集群提供的吞吐量优势,可以在各个ESB Broker Server节点所集成的Kafka-Producer上设置一个较高的采样率(当然还是要顾忌节点本身的资源消耗),例如每秒对固定的业务指标和非业务指标完成10次采样。但是运维团队通过主控服务监控各个ESB Broker Server节点是,往往不需要这么高的采样率(这里可以提供一个设置选项供运维团队随时进行调整),大概也就是每秒更新1次的样子就差不多了。

这里写图片描述

那么Consumer如何处理每秒钟多出来的9次采样数据呢?可以明确想到的有两种处理方式:一种处理方式是无论主控服务的监控台上的性能指标以何种频率进行显示,Consumer都将收到的数据写出存储系统中;另一种处理方式是Consumer将收到的多余数据丢弃,只按照运维团队设置的采样频率将数据写入持久化存储系统。在第二中处理方式中有一个情况需要特别注意:如果将要被丢弃的性能数据达到了性能阀值(例如本次采集的内存使用率超多了2GB),则这条日志数据还是需要进行保留。第一种处理基本上没有什么需要介绍的,优点和缺点也是很明确的:优点是可以在后期进行完整的性能历史回溯,缺点就是会占用较大的存储空间——虽然目前可以使用的超大存储方案有很多而且都很成熟稳定,但它们都需要比较强大的资金预算支持。

3-1-2、Consumer的实现

这里笔者主要讨论一下Consumer的第二种处理方式:丢弃多余的数据。我们可以使用之前文章介绍过的ConcurrentLinkedHashMap作为Consumer中存储性能消息日志的Cache,Cache的固定大小设置为200(或者其它一个较大的值)。这个Cache结构可以帮助我们完成很多工作:首先它可靠的性能能够保证过个Consumer不会成为整个性能日志收集方案的瓶颈——虽然ConcurrentLinkedHashMap的性能并不是最快的;其次这个Cache结构能够帮助我们自动完成多余性能日志的清除工作,因为在第201条日志记录被推入Cache时,在LRU队列尾部的最初一条记录将自动被排除队列,最终被垃圾回收策略回收掉;最后,Consumer按照运维团队设置的采样周期,对Cache中的性能日志数据进行持久化保存时,始终只需要取出当前在Cache将被剔除的那条记录,这样就省掉了编写程序,在两个周期的时间差之间判断“要对哪条性能日志数据”进行持久化保存的定位工作。

顺便说一句,如果您需要在工程中使用Google提供的ConcurrentLinkedHashMap数据结构工具,那么您需要首先在pom文件中添加相应的组件依赖信息:


    com.googlecode.concurrentlinkedhashmap
    concurrentlinkedhashmap-lru
    1.4.2

以下是Consumer中用于处理LRU队列添加、LRU周期性读取、LRU删除事件的代码片段:

......
/**
 * 这就是性能数据的LRU队列
 */
private static final ConcurrentLinkedHashMap PERFORMANCE_CACHE = 
        new ConcurrentLinkedHashMap.Builder()
        .initialCapacity(200)
        .maximumWeightedCapacity(200)
        .listener(new EvictionListenerImpl())
        .build();
......

/**
 * 这个监听器用于在数据被从LRU队列剔除时

 * 按照功能需求检查这条记录是否需要被持久化存储起来。
 * @author yinwenjie
 */
public static class EvictionListenerImpl implements EvictionListener {

    // 上一次进行数据采集的时间,初始为-1
    private Long lastTime = -1l;

    // 这是由运维团队设置的数据采集周期,1000表示1000毫秒
    // 正式系统中,这个值将有外部读取
    private Long period = 1000l;

    @Override
    public void onEviction(Long key, String jsonValue) {
        /*
         * 以下条件任意成立时,就需要对这条数据进行采集了:
         * 1、lastTime为-1的情况(说明是程序第一次采集)
         * 
         * 2、当前事件 - lastTime >= period(采集周期)
         * 
         * 3、当监控数据大于设置的警告阀值,在这个示例代码中
         * 这个警告阀值为80,正式系统中,这个阀值应从外部读取
         * 以下的threshold变量就代表这个值
         * */
        Long threshold = 80L;
        Long nowtime = new Date().getTime();
        // 获取性能数据中的CPU使用率
        // 注意,正式系统 中最好不要传递json结构,文本结构的数据就好了
        JSONObject jsonData = JSONObject.fromObject(jsonValue);
        Long cpuRate = jsonData.getLong("cpu");
        boolean mustCollecting = false;
        if(this.lastTime == -1 || 
            nowtime - lastTime >= this.period ||
            cpuRate >= threshold) {
            mustCollecting = true;
            this.lastTime = nowtime;
        }
        // 如果不需要做数据的持久化存储,就终止本次监听的操作即可
        if(!mustCollecting) {
            return;
        }

        // ********************
        // 这里可以做持久化数据存储的操作了
        // ********************
        LRUConsumer.LOGGER.info(key + ":" + jsonValue + " 完成数据持久存储操作=======");
    }
}

......

// 以下代码就是当Kafka-Consumer收到性能日志数据的操作
// 将这个数据存放到PERFORMANCE_CACHE即可
Long key = new Date().getTime();
// 可使用时间的毫秒数作为key值(正式应用场景下,考虑多个consumer节点,Key的确定会有一个更规范的规则)
LRUConsumer.PERFORMANCE_CACHE.put(key, performanceData);
......

以上代码中,我们使用之前已经介绍过的LRU数据结构在Consumer端保存发送过来的数据。如果读者对LRU还不清楚可以查看我另外的一篇文章中的介绍(《架构设计:系统间通信(39)——Apache Camel快速入门(下2)》)。由Google提供的ConcurrentLinkedHashMap结构就可以向我们提供一个现成的LRU队列,这样一来当LRU队列存储满后,最先被接收到的性能日志数据就会从队列尾部被删除。最关键的处理工作都将在EvictionListener接口的实现类中完成,在实际应用中开发人员还可以在确定一条性能日志需要被持久化存储之后专门启动一个线程进行操作,例如使用一个专门的线程池(ThreadPoolExecutor)。这样一来LRU队列就真正不受持久化存储操作延迟时间的影响了。

3-2、使用Flume + Storm收集性能数据

以上使用Kafka收集Broker Server节点的性能数据的方案中,需要在每个编写的Broker Server节点上增加额外的代码向Kafka Broker Server发送数据。实际上这种功能需求情况使用Apache Flume收集数据会使技术方案更容易实现和维护,下面我们就大致介绍一下这个技术方案实现。由于在之前的文章中笔者已经较详细的介绍了如何使用Apache Flume进行基本配置了,所以这里我们重点讨论两个问题Apache Flume的数据来源和Storm Server在接收到Flume Server发送来的数据后如何进行处理。

3-2-1、设计思路

这里写图片描述

上图展示了整个功能需求的设计结构。安装在ESB Broker Server节点的Flume程序负责收集这个节点上的各种功能性指标和非功能性指标,这样避免了在ESC Broker Server服务上编写额外的代码采集非功能性指标,也减少了编写代码采集功能性指标的复杂度。然后将这些性能日志数据按照负载均衡模式传递到若干中继Flume Server节点上,后者专门用于承载/汇总多个ESB Broker Server节点传来的性能日志数据,并且最终将数据写入Storm Server。在Flume Server和Storm Server之间我们还是需要使用Kafka Server作为缓存,这是因为Apache Kafka通过Storm-Kafka组件和Storm Server实现无缝集成。

首先请注意安装在ESB Broker Server节点的Flume程序,在3-1小节中采集节点功能性指标和非功能性指标都是依靠开发人员编写程序完成,并发送给Kafka-Broker。但这样做却真的绕了很大一个弯路,因为Linux操作系统上已经提供了很多采集节点非功能性指标的方式(例如采集I/O信息、内存使用信息、内存分页信息、CPU使用信息、网络流量信息等),开发人员只需要一些脚本就可以完成采集工作。例如,我们采集CPU信息完全不需要我们在ESB-Broker Server中编写程序(采集CPU信息也不应该是ESB-Broker Server的一项工作任务),而采用如下的脚本即可:

top -d 0.1 | grep Cpu >> cpu.rel

#写法还有很多,还可以从/proc/stat文件中获取CPU状态

以上脚本可以按照100毫秒为周期,获取CPU的信息。并将这条信息作为一条新的记录存储到cpu.rel文件中。这样Apache Flume就可以读取cpu.rel文件中的变化,作为性能日志数据的来源:

#flume 配置文件中的片段
......
agent.sources.s1.type = exec
agent.sources.s1.channels = c1
agent.sources.s1.command = tail -f -n 0 /root/cpu.rel
......

在ESB-Broker Server节点中,我们可以使用这样的方式从不同文件中读取各种不同的日志信息,如下图所示:

这里写图片描述

=================================
(接下文)

相关TAG标签 架构 系统
上一篇:vagrant入门教程--管理虚拟机快照(7)
下一篇:架构设计:系统间通信(41)——自己动手设计ESB(2)
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站