应用实时监控

1.  需求分析

互联网程序开发中,有两个步骤不可或缺:

1、  code review

2、  试错

但是由于人员限制和功能抢占时间限制,做这两个工作的人和时间极其有限,那么如何能自动完成这两项任务呢?

我们需要一套监控系统,这套系统不和我们的业务关联,并且是容错性高、兼容性强、独立部署与运维的通用架构,用来监控我们的程序。达到两个目的:

1、  统计每个接口的平均调用时间。

2、  统计接口的调用次数。

如何做这套系统呢?

2.  技术调研

现在互联网技术层面上,做流式监控的技术组合很多,但有一套技术架构被很多公司应用,就是flume+kafka+storm。

flume:负责监控日志,无论日志的格式是什么,也无论是什么日志,与其他系统耦合性相当低。

kafka:分布式消息系统,通过分布式的方式将flume传进来的消息保存,供消费者消费,集群稳定性极高。所以即使生产者和消费者挂掉,只要重启,可以继续生产消息。

storm:流式计算框架,可以实时的从kafka中读取数据,实时统计结果存储到数据底层。

redis:高速缓存工具,并发性好,查询速度块。

3.  技术分析

这套监控系统,由于组件过多,容易导致数据丢失的情况,这种情况会不会影响我们的结果?

在海量数据的流式监控过程中,不会产生用户级别的交互行为,数据仅供我们分析使用,数据的精度和准度由海量数据分析得来,少量数据的丢失不会影响结果。

4.  技术点

1、  flume环境搭建

2、  kafka集群搭建

3、  storm集群搭建

4、  flume的agent配置

5、  storm相关api使用

6、  flume-kafka插件使用

7、  kafka-storm插件使用

8、  集群部署

5.  项目架构图

见架构文档

6.  开发流程

6.1.  搭建集群环境

1、  搭建flume环境

2、  搭建zookeeper环境

3、  搭建kafka环境

4、  搭建storm环境

6.2.  启动集群

依次启动:zookeeper、kafka、storm

6.3.  开发web应用,并在方法中添加日志

用monitor应用

6.4.  修改web项目中的log4j配置

# Rules reminder:

# DEBUG < INFO < WARN < ERROR < FATAL

# Global logging configuration

log4j.rootLogger=INFO,R,stdout

## File output...

log4j.appender.R=org.apache.log4j.RollingFileAppender

log4j.appender.R.File=/home/hadoop/flume/logs/test.log

log4j.appender.R.MaxFileSize=100MB

log4j.appender.R.MaxBackupIndex=7

log4j.appender.R.layout=org.apache.log4j.PatternLayout

log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n

#log4j.logger.org.apache.catalina=INFO,R,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p%l method\:%M %m%n

#%d:显示日志记录时间

#[%t]:输出产生该日志事件的线程名

#%-5p:显示该条日志的优先级

#%l:输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数

#%M:方法名

#%m:显示输出消息

#%n:当前平台下的换行符

6.5.  部署web服务

在client机器部署tomcat,将应用打成war包放到tomcat中,启动tomcat即可

6.6.  开发flume,监控tomcat日志

6.6.1.  配置

log4j_agent.conf:

 

a1.sources = r1

a1.sinks = k1 k2

a1.channels = c1 c2

 

# Describe/configure the source

a1.sources.r1.type = exec

a1.sources.r1.command = tail -F /home/hadoop/flume/logs/test.log

 

# Describe the sink

a1.sinks.k1.type = logger

a1.sinks.k2.type = org.apache.flume.plugins.KafkaSink

a1.sinks.k2.metadata.broker.list=master:9092,slave1:9092,slave2:9092,slave3:9092

a1.sinks.k2.sink.directory = /home/hadoop/flume/logs

a1.sinks.k2.partitioner.class=org.apache.flume.plugins.SinglePartition

a1.sinks.k2.serializer.class=kafka.serializer.StringEncoder

a1.sinks.k2.request.required.acks=0

a1.sinks.k2.max.message.size=1000000

a1.sinks.k2.producer.type=sync

a1.sinks.k2.encoding=UTF-8

a1.sinks.k2.topic.name=testTopic

a1.sinks.k2.channel = c2

 

# Use a channel which buffers events in memory

a1.channels.c1.type = memory

a1.channels.c1.capacity = 10000

a1.channels.c1.transactionCapacity = 1000

a1.channels.c2.type = memory

a1.channels.c2.capacity = 1000

a1.channels.c2.transactionCapacity = 100

 

# Bind the source and sink to the channel

a1.sources.r1.channels = c1 c2

a1.sources.r1.selector.type = replicating

a1.sinks.k1.channel = c1

a1.sinks.k2.channel = c2

6.6.2.  启动脚本

因为是监控tomcat,所以flume需要在tomcat的机器上部署一个,并在此机器启动flume的agent:
命令:

flume-ng agent -c /home/hadoop/flume/conf/-f /home/hadoop/flume/conf/log4j_agent.conf -n a1-Dflume.root.logger=INFO,console

6.7.  中间件kafka

flume读取的日志会被存储在kafka中,而这些数据又会被后面的storm用到,所以kafka作为消息中间件使用,应用到两个kafka的插件,不需要写代码。

6.8.  开发storm程序,读取kafka,写向redis

6.8.1.  开发main启动类

package com.itcast.monitor.main;

import java.util.ArrayList;

 

import storm.kafka.BrokerHosts;

import storm.kafka.KafkaSpout;

import storm.kafka.SpoutConfig;

import storm.kafka.StringScheme;

import storm.kafka.ZkHosts;

import backtype.storm.Config;

import backtype.storm.StormSubmitter;

import backtype.storm.generated.AlreadyAliveException;

import backtype.storm.generated.InvalidTopologyException;

import backtype.storm.spout.SchemeAsMultiScheme;

import backtype.storm.topology.TopologyBuilder;

 

import com.itcast.monitor.bolts.HandlerBolt;

 

 

public class KafkaStormMain {

        

         public static void main(String[] args) throws InterruptedException, AlreadyAliveException, InvalidTopologyException {

                   //设置所有的broker

                   BrokerHosts brokerHosts = new ZkHosts("master,slave1,slave2,slave3");

                   //创建SpoutConfig,用来封装brokerHosts、topic、zookeeper节点、id

                   //topic是当前向消费的topic

                   ///storm-test随便写

                   //monitor_local:随便写

                   SpoutConfig kafkaConfig = new SpoutConfig(brokerHosts, "monitorTopic", "/storm-monitor", "monitor_local5");

                   //序列化

                   kafkaConfig.scheme = new SchemeAsMultiScheme(new StringScheme());//序列化工具

                   //配置zookeeper地址和port

                   kafkaConfig.zkServers = new ArrayList<String>() {

                            {

                                     add("slave1");

                                     add("slave2");

                                     add("slave3");

                            }

                   };

                   kafkaConfig.zkPort = 2181;//zookeeper端口

                   /**

         * 创建topologyBuilder

         */

                   TopologyBuilder builder = new TopologyBuilder();

        builder.setSpout("readlog", new KafkaSpout(kafkaConfig));

        builder.setBolt("handlerbolt", new HandlerBolt()).shuffleGrouping("readlog");

        Config config = new Config();

        config.setDebug(false);

        /**

         * 本地模式

         */

        //LocalCluster cluster = new LocalCluster(); 

        //cluster.submitTopology("DubboService-Test", config, builder.createTopology()); 

       // Thread.sleep(2000);//睡一会

        /**

                    * 线上运行

                    * 命令:storm jar Getting-Started-0.0.1-SNAPSHOT.jar countword.WordMain arg0

                    */

                   StormSubmitter.submitTopology("flume-kafka-storm", config, builder.createTopology());

         }

}

6.8.2.  开发bolt

package com.itcast.monitor.bolts;

 

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

import redis.clients.jedis.Jedis;

import backtype.storm.task.TopologyContext;

import backtype.storm.topology.BasicOutputCollector;

import backtype.storm.topology.OutputFieldsDeclarer;

import backtype.storm.topology.base.BaseBasicBolt;

import backtype.storm.tuple.Tuple;

 

public class HandlerBolt extends BaseBasicBolt {

   public Jedis jedis = null;

  

   @Override

   public void prepare(Map stormConf, TopologyContext context) {

      jedis = new Jedis("192.168.56.204",6379);

   }

   public void execute(Tuple tuple, BasicOutputCollector collector) {

      System.out.println(tuple.getString(0)+"============================================");

      String value = tuple.getString(0);

      if (value.contains("method")&&value.contains("com.itcast.tsc")&&!value.contains("springframework")) {

         String[] split = value.split(" ");

         String methodName = split[5].split(":")[1];

         String time = split[6];

         List<String> lrange = jedis.lrange("monitor_"+methodName, 0, -1);

         if (lrange==null||lrange.size()==0) {

            jedis.rpush("monitor_"+methodName, time);

            jedis.rpush("monitor_"+methodName, "1");

            jedis.rpush("monitor_"+methodName, time);

         }else{

            int lastTotleTime = Integer.parseInt(lrange.get(0));

            int thisTime = Integer.parseInt(time);

            int lastTotleCount = Integer.parseInt(lrange.get(1));

            int TotleCount = Integer.parseInt(lrange.get(1))+1;

            int avgTime = (lastTotleTime+thisTime)/TotleCount;

            jedis.del("monitor_"+methodName);

            jedis.rpush("monitor_"+methodName, lastTotleTime+thisTime+"");

            jedis.rpush("monitor_"+methodName, TotleCount+"");

            jedis.rpush("monitor_"+methodName, avgTime+"");

         }

      }

   }

 

   public void declareOutputFields(OutputFieldsDeclarer declarer) {

     

   }

 

}

6.9.  开发监控项目

演示使用,无需掌握。

6.10.    测试程序

6.10.1.          测试flume-kafka

1、  启动tomcat

2、  启动flume的agent

3、  此套应用会向kafka中写数据。用kafka的consumer例子读取数据,并验证。

6.10.2.          测试kafka-storm

1、  用kafka的producer例子向kafka中写数据

2、  用storm的程序做本地测试启动,打印日志

6.10.3.          测试flume+kafka+storm线上版

1、  启动tomcat

2、  启动flume的agent,向kafka写数据

3、  启动storm集群模式,读取数据,写入redis

a)      将storm程序改成集群模式,打成jar包

b)      在storm集群机器上运行,

c)      命令:storm jar Storm-Test_jiqun.jarcom.itcast.monitor.main.KafkaStormMain

4、  用测试应用查看redis中的数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值