storm_入门02学习笔记----【storm原理、storm整个hdfs和mysql、storm定时器使用、日志监控告警项目的流程和业务处理逻辑】

Storm-日志监控告警系统 1、背景知识 一款优秀的软件需要具备的特点 软件的实用性。 所谓有的放矢,软件的诞生是为了解决特定的问题,比如现在流行的MVC 框架,早期的没有MVC 开发的时候,耦合度很大,后期维护更新成本高,难度大,这样MVC 框架就孕育而生;比如陌陌这种社交软件,是为了解决陌生人之间交流的问题;比如疼醒这种软件是为了解决人们远程沟通的问题;比如OA系统为了解决公司协同流程、项目管理、知识管理等问题……所以一款优秀的软件必须能够解决一个领域内的问题。 软件的稳定性。 软件的实用性问题解决之后,急需要解决的问题就是 阅读详情

storm_入门02学习笔记

1、目标
  • 1、掌握storm任务提交和执行过程
  • 2、掌握storm整合hdfs和mysql
  • 3、掌握storm定时器使用
  • 4、掌握日志监控告警项目的流程和业务处理逻辑
2、storm内部原理和任务提交

在这里插入图片描述

(1)客户端提交topology到nimbus主节点
(2)nimbus主节点接受到客户端的任务信息,然后保存到本地目录,后期把任务的分配信息写入到zk集群中
(3)zk保存任务的划分信息,包括后期再哪些supervisor节点启动对应的worker进程来运行对应的task
(4)supervisor定时向zk进行通信,获取得到属于自己的任务信息
(5)supervisor找到活着的nimbus老大,然后把对应的task涉及到的jar包和代码拷贝到自己的机器,然后运行

在这里插入图片描述

  • storm的本地目录树

在这里插入图片描述

  • zk本地目录树

在这里插入图片描述

3、storm整合hdfs

在这里插入图片描述

  • 数据处理流程:

    (1)通过RandomSpout实时产生一些订单数据,发送给下游的bolt进行处理
    (2)通过构建一个CountMoneyBolt实时统计所有订单数据的总金额,最后把订单数据发送下游的其他的bolt
    (3)构建HdfsBolt把实时流入的订单数据写入到hdfs上
    (4)基于hive构建外部分区表,关联订单数据,后期对于这些订单数据进行离线分析处理

  • 代码开发

    • 1、引入依赖

      <dependency>
          <groupId>org.apache.storm</groupId>
          <artifactId>storm-hdfs</artifactId>
          <version>1.1.1</version>
      </dependency>
      
    • 2、RandomOrderSpout

      package cn.itcast.hdfs;
      
      import cn.itcast.realBoard.domain.PaymentInfo;
      import org.apache.storm.spout.SpoutOutputCollector;
      import org.apache.storm.task.TopologyContext;
      import org.apache.storm.topology.OutputFieldsDeclarer;
      import org.apache.storm.topology.base.BaseRichSpout;
      import org.apache.storm.tuple.Fields;
      import org.apache.storm.tuple.Values;
      
      import java.util.Map;
      import java.util.Random;
      
      //todo:随机产生大量的订单数据,然后发送给下游bolt去处理
      public class RandomOrderSpout extends BaseRichSpout {
            private SpoutOutputCollector collector;
            private PaymentInfo paymentInfo;
      
          /**
           * 初始化方法,只会被调用一次
           * @param conf
           * @param context
           * @param collector
           */
          @Override
          public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
                this.collector=collector;
                this.paymentInfo=new PaymentInfo();
          }
      
          @Override
          public void nextTuple() {
               //随机产生一个订单
              String order = paymentInfo.random();
              collector.emit(new Values(order));
      
          }
      
          @Override
          public void declareOutputFields(OutputFieldsDeclarer declarer) {
             declarer.declare(new Fields("order"));
          }
      }
      
      
    • 3、CountMoenyBolt

      package cn.itcast.hdfs;
      
      import cn.itcast.realBoard.domain.PaymentInfo;
      import com.alibaba.fastjson.JSONObject;
      import org.apache.storm.topology.BasicOutputCollector;
      import org.apache.storm.topology.OutputFieldsDeclarer;
      import org.apache.storm.topology.base.BaseBasicBolt;
      import org.apache.storm.tuple.Fields;
      import org.apache.storm.tuple.Tuple;
      import org.apache.storm.tuple.Values;
      
      import java.util.HashMap;
      
      //todo:接受spout发送的订单数据。实时订单金额的实时统计,把订单数据发送给下游的bolt
      public class CountMoneyBolt extends BaseBasicBolt {
          private HashMap<String,Long> map=new HashMap<String,Long>();
      
          @Override
          public void execute(Tuple input, BasicOutputCollector collector) {
              String orderJson = input.getStringByField("order");
              JSONObject jsonObject = new JSONObject();
              PaymentInfo paymentInfo = jsonObject.parseObject(orderJson, PaymentInfo.class);
              long price = paymentInfo.getPayPrice();
      
              if(!map.containsKey("totalPrice")){
                   map.put("totalPrice",price);
              }else{
                  map.put("totalPrice",price+map.get("totalPrice"));
              }
              System.out.println(map);
      
              collector.emit(new Values(orderJson));
      
          }
      
          @Override
          public void declareOutputFields(OutputFieldsDeclarer declarer) {
              declarer.declare(new Fields("orderJson"));
          }
      }
      
      
    • 4、StormHdfsTopology

      package cn.itcast.hdfs;
      
      import org.apache.storm.Config;
      import org.apache.storm.LocalCluster;
      import org.apache.storm.StormSubmitter;
      import org.apache.storm.generated.AlreadyAliveException;
      import org.apache.storm.generated.AuthorizationException;
      import org.apache.storm.generated.InvalidTopologyException;
      import org.apache.storm.hdfs.bolt.HdfsBolt;
      import org.apache.storm.hdfs.bolt.format.DefaultFileNameFormat;
      import org.apache.storm.hdfs.bolt.format.DelimitedRecordFormat;
      import org.apache.storm.hdfs.bolt.format.FileNameFormat;
      import org.apache.storm.hdfs.bolt.format.RecordFormat;
      import org.apache.storm.hdfs.bolt.rotation.FileRotationPolicy;
      import org.apache.storm.hdfs.bolt.rotation.FileSizeRotationPolicy;
      import org.apache.storm.hdfs.bolt.sync.CountSyncPolicy;
      import org.apache.storm.hdfs.bolt.sync.SyncPolicy;
      import org.apache.storm.topology.TopologyBuilder;
      
      public class StormHdfsTopology {
          public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException {
              TopologyBuilder topologyBuilder = new TopologyBuilder();
              topologyBuilder.setSpout("randomOrderSpout",new RandomOrderSpout());
              topologyBuilder.setBolt("countMoneyBolt",new CountMoneyBolt()).shuffleGrouping("randomOrderSpout");
      
              // use "|" instead of "," for field delimiter
              //指定字段的分割符是|
              RecordFormat format = new DelimitedRecordFormat()
                      .withFieldDelimiter("|");
      
      // sync the filesystem after every 1k tuples
              //数据量条数到达1千条批量写入
              SyncPolicy syncPolicy = new CountSyncPolicy(1000);
      
      // rotate files when they reach 5MB
              //数据量大小到达5m批量写入
              FileRotationPolicy rotationPolicy = new FileSizeRotationPolicy(5.0f, FileSizeRotationPolicy.Units.MB);
      
              //指定数据保存在hdfs上的目录名称
              FileNameFormat fileNameFormat = new DefaultFileNameFormat()
                      .withPath("/storm-data/");
      
              // 构建hdfsBolt,指定namenode地址和策略
              HdfsBolt hdfsBolt = new HdfsBolt()
                      .withFsUrl("hdfs://node1:9000")
                      .withFileNameFormat(fileNameFormat)
                      .withRecordFormat(format)
                      .withRotationPolicy(rotationPolicy)
                      .withSyncPolicy(syncPolicy);
      
      
              topologyBuilder.setBolt("hdfsBolt",hdfsBolt).shuffleGrouping("countMoneyBolt");
      
              Config config = new Config();
              if(args !=null && args.length>0){
                  //集群提交
                  StormSubmitter.submitTopology(args[0],config,topologyBuilder.createTopology());
              }else {
                  //本地运行
                  LocalCluster localCluster = new LocalCluster();
                  localCluster.submitTopology("storm-hdfs",config,topologyBuilder.createTopology());
      
              }
      
      
          }
      }
      
4、storm的ack机制
4.1 storm的ack机制是什么

​ storm是一个实时处理的框架,后期需要对数据的处理,处理的时候需要保证数据不丢失,或者是说数据需要把完全处理成功,以及数据处理失败之后,有对应的处理策略。
​ ack机制可以保证数据被处理成功或者是数据处理失败之后有对应的策略,比如说,某一条数据处理失败了,这个时候把处理失败的数据重新发送下,再次处理。

4.2 ack机制的原理

在这里插入图片描述

每一次数据发送和接受都会把一个成功的标识写入到某一个内存区域,然后后期再这块内存区域中就有大量的标识,

最后使用一个算法: 异或算法
相同为0
不同为1
0|0=0
0|1=1
1|0=1
1|1=0

最后异或的结果如果为0,就表示该数据在每一个阶段都是处理成功的,如果后期结果不为0 就是表示处理失败。

4.3 如何开启ack机制
  • 1、在spout中处理逻辑

    //在发送数据的时候需要指定一个messageId,后期可以通过这个messageId来定位到那条数据处理成功或者是那条数据处理失败。
                 //这里为了后期定位到失败的数据是什么,可以简单处理,就把数据看成是messageId
                collector.emit(new Values(line),line);
    
    数据处理成功之后会调用ack方法:
        public void ack(Object msgId) {
            //该方法会在数据处理成功之后被调用
            System.out.println("哪一条数据处理成功:"+msgId);
    
        }
        
        
    数据处理失败之后会调用fail方法:
        public void fail(Object msgId) {
            //该方法会在数据处理失败之后被调用
            System.out.println("处理失败的数据:"+msgId);
    
            //把失败的数据重新发送
            collector.emit(new Values(msgId),msgId);
        }
    
    
    
  • 2、在bolt中的逻辑

    • BaseBasicBolt

      它会把我们每一数据处理成功之后,它会自己去调用ack方法 或者数据处理失败会调用fail方法

      后期就不需要自己去实现ack或者是fail方法

    • BaseRichBolt

      需要自己实现成功后调用ack方法
      collector.ack(input)

      失败后调用fail方法
      collector.fail(input)

    • 另外需要注意的,当spout 触发fail 动作时,不会自动重发失败的tuple,需要 spout 自己重新获取数据,手动重新再发送一次

  • 3 ack 机制即 spout 发送的每一条消息

    • 在规定的时间内,spout 收到 Acker 的 ack 响应,即认为该tuple 被后续 bolt 成功处理
    • 在规定的时间内,没有收到Acker的ack响应 tuple,就触发fail动作,即认为该tuple处理失败
    • 或者收到Acker发送的fail响应tuple,也认为失败,触发fail动作
4.4 关闭ack机制

(1)在spout中发送数据的时候,不指定messageId
(2)可以设置ack线程数为0
config.setNumAckers(0);

5、storm的定时器和mysql整合
  • 1、引入依赖

           <dependency>
                <groupId>org.apache.storm</groupId>
                <artifactId>storm-jdbc</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.38</version>
            </dependency>
            <dependency>
                <groupId>com.google.collections</groupId>
                <artifactId>google-collections</artifactId>
                <version>1.0</version>
            </dependency>
    
  • 2、代码开发

    • 1、RandomSpout

      package cn.itcast.tickAndMysql;
      
      import org.apache.storm.spout.SpoutOutputCollector;
      import org.apache.storm.task.TopologyContext;
      import org.apache.storm.topology.OutputFieldsDeclarer;
      import org.apache.storm.topology.base.BaseRichSpout;
      import org.apache.storm.tuple.Fields;
      import org.apache.storm.tuple.Values;
      
      import java.util.Map;
      import java.util.Random;
      
      //todo:随机产生数据,发送给下游
      public class RandomSpout extends BaseRichSpout {
          private SpoutOutputCollector collector;
          private Random random;
          private String[] user;
      
          @Override
          public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
              this.collector=collector;
              this.random=new Random();
              this.user=new String[]{"1 zhangsan 30","2 lisi 40"};
          }
      
          @Override
          public void nextTuple() {
              try {
                  //随机产生数据
                  int index = random.nextInt(user.length);
                  String line = user[index];
                  collector.emit(new Values(line));
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          @Override
          public void declareOutputFields(OutputFieldsDeclarer declarer) {
              declarer.declare(new Fields("line"));
          }
      }
      
      
    • 2、TickBolt

      package cn.itcast.tickAndMysql;
      
      import org.apache.storm.Config;
      import org.apache.storm.Constants;
      import org.apache.storm.topology.BasicOutputCollector;
      import org.apache.storm.topology.OutputFieldsDeclarer;
      import org.apache.storm.topology.base.BaseBasicBolt;
      import org.apache.storm.tuple.Fields;
      import org.apache.storm.tuple.Tuple;
      import org.apache.storm.tuple.Values;
      
      import java.text.SimpleDateFormat;
      import java.util.Date;
      import java.util.Map;
      
      //todo:接受spout的数据,定时每隔5s打印系统的时间,同时把解析数据,最后把结果数据传递给下游bolt
      public class TickBolt  extends BaseBasicBolt{
      
          @Override
          public Map<String, Object> getComponentConfiguration() {
              //可以实现发送系统级别的tuple
              Config config = new Config();
                  //每隔5s发送一个系统级别的tuple
               config.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS,5);
      
              return config;
          }
      
          @Override
          public void execute(Tuple input, BasicOutputCollector collector) {
               //判断一下数据到底是来自于spout或者是系统
              if(input.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID) && input.getSourceStreamId().equals(Constants.SYSTEM_TICK_STREAM_ID)){
      
                  //实现每隔5s打印下系统时间
                  Date date = new Date();
                  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                  String dateFormat = format.format(date);
                  System.out.println(dateFormat);
      
              }else{
                  String user = input.getStringByField("line");
                  String[] split = user.split(" ");
                  String id = split[0];
                  String name = split[1];
                  String age = split[2];
      
                  //发送数据的时候,需要跟表中的字段的结果类型一致
                  collector.emit(new Values(id,name,age));
              }
      
          }
      
          @Override
          public void declareOutputFields(OutputFieldsDeclarer declarer) {
      
              //声明字段的时候,需要跟mysql表中的字段名称一致
              declarer.declare(new Fields("id","name","age"));
          }
      }
      
      
    • 3、驱动主类代码开发

      package cn.itcast.tickAndMysql;
      
      import com.google.common.collect.Maps;
      import com.sun.org.apache.xpath.internal.operations.Or;
      import org.apache.storm.Config;
      import org.apache.storm.LocalCluster;
      import org.apache.storm.StormSubmitter;
      import org.apache.storm.generated.AlreadyAliveException;
      import org.apache.storm.generated.AuthorizationException;
      import org.apache.storm.generated.InvalidTopologyException;
      import org.apache.storm.generated.StormTopology;
      import org.apache.storm.jdbc.bolt.JdbcInsertBolt;
      import org.apache.storm.jdbc.common.ConnectionProvider;
      import org.apache.storm.jdbc.common.HikariCPConnectionProvider;
      import org.apache.storm.jdbc.mapper.JdbcMapper;
      import org.apache.storm.jdbc.mapper.SimpleJdbcMapper;
      import org.apache.storm.topology.TopologyBuilder;
      
      import java.util.Map;
      
      public class TickMysqlTopology {
          public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException {
              TopologyBuilder topologyBuilder = new TopologyBuilder();
              topologyBuilder.setSpout("randomSpout",new RandomSpout());
              topologyBuilder.setBolt("tickBolt",new TickBolt()).shuffleGrouping("randomSpout");
      
              //构建mysqlBolt
              Map hikariConfigMap = Maps.newHashMap();
              hikariConfigMap.put("dataSourceClassName","com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
              hikariConfigMap.put("dataSource.url", "jdbc:mysql://node-1/test");
              hikariConfigMap.put("dataSource.user","root");
              hikariConfigMap.put("dataSource.password","123");
              ConnectionProvider connectionProvider = new HikariCPConnectionProvider(hikariConfigMap);
      
              String tableName = "person";
              JdbcMapper simpleJdbcMapper = new SimpleJdbcMapper(tableName, connectionProvider);
      
              JdbcInsertBolt mysqlBolt = new JdbcInsertBolt(connectionProvider, simpleJdbcMapper)
                      .withTableName("person")
                      .withQueryTimeoutSecs(90);
      //        Or
      //        JdbcInsertBolt userPersistanceBolt = new JdbcInsertBolt(connectionProvider, simpleJdbcMapper)
      //                .withInsertQuery("insert into user values (?,?)")
      //                .withQueryTimeoutSecs(30);
      
              topologyBuilder.setBolt("mysqlBolt",mysqlBolt).shuffleGrouping("tickBolt");
              Config config = new Config();
              StormTopology stormTopology = topologyBuilder.createTopology();
      
              if(args!=null && args.length>0){
                  StormSubmitter.submitTopology(args[0],config,stormTopology);
              }else{
                  LocalCluster localCluster = new LocalCluster();
                  localCluster.submitTopology("storm-mysql",config,stormTopology);
              }
      
          }
      }
      
      

tips : 首先需要创建好库和表 , 且表的字段类型要与传进去的保持一致

6、日志监控告警系统

在这里插入图片描述

6.1 flume自定义拦截器开发
package cn.itcast.flume;

import org.apache.commons.lang.StringUtils;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

//todo:功能需求:实现在每条日志前面加上一个appId来做唯一标识
public class FlumeInterceptorApp implements Interceptor {
    //属性
    private String appId;

    public FlumeInterceptorApp(String appId){
        this.appId = appId;
    }

    public Event intercept(Event event){
        String message = null;
        try {
            message = new String(event.getBody(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            message = new String(event.getBody());
        }

          // error java.lang.TypeNotPresentException    ---> 1\001error java.lang.TypeNotPresentException 
        if (StringUtils.isNotBlank(message)) {
            message =  this.appId + "\001" + message;
            event.setBody(message.getBytes());
            return event;
        }

        return event;
    }

    public List<Event> intercept(List<Event> list){
        List resultList = new ArrayList();
        for (Event event : list) {
            Event r = intercept(event);
            if (r != null) {
                resultList.add(r);
            }
        }
        return resultList;
    }

    public void close()
    {
    }

    public void initialize(){

    }

    public static class AppInterceptorBuilder implements Interceptor.Builder{

        private String appId;

        public Interceptor build() {
            return new FlumeInterceptorApp(this.appId);
        }

        public void configure(Context context)
        {
            this.appId = context.getString("appId", "default");
            System.out.println("appId:" + this.appId);
        }

        /**
         a1.sources = r1
         a1.channels = c1
         a1.sinks = k1

         a1.sources.r1.type = exec
         a1.sources.r1.command = tail -F /export/data/flume/click_log/error.log
         a1.sources.r1.channels = c1
         a1.sources.r1.interceptors = i1
         a1.sources.r1.interceptors.i1.type = cn.itcast.realtime.flume.AppInterceptor$AppInterceptorBuilder
         a1.sources.r1.interceptors.i1.appId = 1

         a1.channels.c1.type=memory
         a1.channels.c1.capacity=10000
         a1.channels.c1.transactionCapacity=100

         a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
         a1.sinks.k1.topic = log_monitor
         a1.sinks.k1.brokerList = kafka01:9092
         a1.sinks.k1.requiredAcks = 1
         a1.sinks.k1.batchSize = 20
         a1.sinks.k1.channel = c1


         */
    }
}

6.2 flume的配置和运行
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /export/data/flume/click_log/error.log
a1.sources.r1.channels = c1
a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = cn.itcast.flume.FlumeInterceptorApp$AppInterceptorBuilder
a1.sources.r1.interceptors.i1.appId = 1

a1.channels.c1.type=memory
a1.channels.c1.capacity=10000
a1.channels.c1.transactionCapacity=100

a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.topic = log_monitor
a1.sinks.k1.brokerList = node-1:9092,node-2:9092,node-3:9092
a1.sinks.k1.requiredAcks = 1
a1.sinks.k1.batchSize = 20
6.3 代码开发
  • 1、LogMonitorTopology

    package cn.itcast.logMonitor;
    
    import org.apache.storm.Config;
    import org.apache.storm.LocalCluster;
    import org.apache.storm.StormSubmitter;
    import org.apache.storm.generated.AlreadyAliveException;
    import org.apache.storm.generated.AuthorizationException;
    import org.apache.storm.generated.InvalidTopologyException;
    import org.apache.storm.generated.StormTopology;
    import org.apache.storm.kafka.spout.KafkaSpout;
    import org.apache.storm.kafka.spout.KafkaSpoutConfig;
    import org.apache.storm.topology.TopologyBuilder;
    
    public class LogMonitorTopology {
        public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException {
            TopologyBuilder topologyBuilder = new TopologyBuilder();
    
            KafkaSpoutConfig.Builder<String, String> builder = KafkaSpoutConfig.builder("node-1:9092,node-2:9092,node-3:9092", "log_monitor");
            builder.setGroupId("logMonitor");
            builder.setFirstPollOffsetStrategy(KafkaSpoutConfig.FirstPollOffsetStrategy.UNCOMMITTED_LATEST);
            KafkaSpoutConfig<String, String> kafkaSpoutConfig = builder.build();
    
            KafkaSpout<String, String> kafkaSpout = new KafkaSpout<String, String>(kafkaSpoutConfig);
            //组织kafkaSpout
            topologyBuilder.setSpout("kafkaSpout",kafkaSpout);
            topologyBuilder.setBolt("monitorMysqlBolt",new MonitorMysqlBolt()).shuffleGrouping("kafkaSpout");
            topologyBuilder.setBolt("processDataBolt",new ProcessDataBolt()).shuffleGrouping("monitorMysqlBolt");
            topologyBuilder.setBolt("notifyPeopleBolt",new NotifyPeopleBolt()).shuffleGrouping("processDataBolt");
            topologyBuilder.setBolt("saveDataBolt",new SaveDataBolt()).shuffleGrouping("notifyPeopleBolt");
    
            Config config = new Config();
            StormTopology stormTopology = topologyBuilder.createTopology();
    
            if(args!=null && args.length>0){
                StormSubmitter.submitTopology(args[0],config,stormTopology);
            }else{
                LocalCluster localCluster = new LocalCluster();
                localCluster.submitTopology("logMonitor",config,stormTopology);
            }
    
        }
    }
    
    
  • 2、MonitorMysqlBolt

    package cn.itcast.logMonitor;
    
    import cn.itcast.logMonitor.utils.CommonUtils;
    import org.apache.storm.Config;
    import org.apache.storm.Constants;
    import org.apache.storm.task.TopologyContext;
    import org.apache.storm.topology.BasicOutputCollector;
    import org.apache.storm.topology.OutputFieldsDeclarer;
    import org.apache.storm.topology.base.BaseBasicBolt;
    import org.apache.storm.tuple.Fields;
    import org.apache.storm.tuple.Tuple;
    import org.apache.storm.tuple.Values;
    
    import java.util.Map;
    
    //todo:需要接受kafkaSpout的数据,然后定时的从mysql表中把对应的数据库中规则进行同步
    public class MonitorMysqlBolt extends BaseBasicBolt{
           private CommonUtils commonUtils;
        /**
         * 初始化的方法
         * @param stormConf
         * @param context
         */
        @Override
        public void prepare(Map stormConf, TopologyContext context) {
            this.commonUtils=new CommonUtils();
        }
    
        @Override
        public Map<String, Object> getComponentConfiguration() {
            Config config = new Config();
            config.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS,5);
            return config;
        }
    
        public void execute(Tuple input, BasicOutputCollector collector) {
            if(input.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID) && input.getSourceStreamId().equals(Constants.SYSTEM_TICK_STREAM_ID)){
                //系统发送的数据
                //需要把mysql表中的数据进行同步
                //同步数据库中业务系统信息    把数据库中app表中的数据加载进来,最后把结果保存在一个map集合
                commonUtils.monitorApp();
                //同步数据库中的业务系统对应的规则
                commonUtils.monitorRule();
                //同步数据库中的用户信息
                commonUtils.monitorUser();
    
            }else{
                //kafkaSpout发送的数据
                String logs = input.getString(4);
                //把数据发送给下游
                collector.emit(new Values(logs));
    
            }
    
        }
    
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
           declarer.declare(new Fields("logs"));
        }
    }
    
    
  • 3、ProcessDataBolt

    package cn.itcast.logMonitor;
    
    import cn.itcast.logMonitor.utils.CommonUtils;
    import org.apache.storm.topology.BasicOutputCollector;
    import org.apache.storm.topology.OutputFieldsDeclarer;
    import org.apache.storm.topology.base.BaseBasicBolt;
    import org.apache.storm.tuple.Fields;
    import org.apache.storm.tuple.Tuple;
    import org.apache.storm.tuple.Values;
    
    //todo:接受上游的数据,然后解析,最后进行匹配,看看是否满足了对应的规则,后面把满足规则的数据发送
    public class ProcessDataBolt extends BaseBasicBolt{
        public void execute(Tuple input, BasicOutputCollector collector) {
            //1\001error:Java.lang.NegativeArraySizeException
            String logs = input.getStringByField("logs");
            String[] split = logs.split("\001");
            String appId = split[0];
            String error = split[1];
    
            //获取得到数据,然后通过规则库进行匹配
            String rules = CommonUtils.checkRules(appId, error);
    
            if(!"".equals(rules)) {
                //把错误数据和匹配的规则信息发送给下游
                collector.emit(new Values(logs, rules));
    
            }
        }
    
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
           declarer.declare(new Fields("errorLogs","rules"));
        }
    }
    
    
  • 4、NotifyPeopleBolt

    package cn.itcast.logMonitor;
    
    import cn.itcast.logMonitor.utils.CommonUtils;
    import org.apache.storm.topology.BasicOutputCollector;
    import org.apache.storm.topology.OutputFieldsDeclarer;
    import org.apache.storm.topology.base.BaseBasicBolt;
    import org.apache.storm.tuple.Fields;
    import org.apache.storm.tuple.Tuple;
    import org.apache.storm.tuple.Values;
    
    //todo:找到该业务系统的负责人,给他们以短信或者是邮件的方式进行告警
    public class NotifyPeopleBolt  extends BaseBasicBolt{
        public void execute(Tuple input, BasicOutputCollector collector) {
            String errorLogs = input.getStringByField("errorLogs");
            String rules = input.getStringByField("rules");
    
            //需要找到业务系统的负责人,然后向他们发送信息
            CommonUtils.notifyPeople(rules,errorLogs);
    
            //保存异常信息
            collector.emit(new Values(rules,errorLogs));
    
        }
    
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
           declarer.declare(new Fields("appRules","errorLogs"));
        }
    }
    
    
  • 4、SaveDataBolt

    package cn.itcast.logMonitor;
    
    import cn.itcast.logMonitor.utils.CommonUtils;
    import org.apache.storm.topology.BasicOutputCollector;
    import org.apache.storm.topology.OutputFieldsDeclarer;
    import org.apache.storm.topology.base.BaseBasicBolt;
    import org.apache.storm.tuple.Tuple;
    
    //todo:接受上游的数据。最后把异常信息进行保存
    public class SaveDataBolt  extends BaseBasicBolt{
        public void execute(Tuple input, BasicOutputCollector collector) {
            String appRules = input.getStringByField("appRules");
            String errorLogs = input.getStringByField("errorLogs");
    
            //保存异常信息到mysql表中
            CommonUtils.insertToDb(appRules,errorLogs);
        }
    
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
    
        }
    }
    
    

kafkaSpout 的更多说明:
https://github.com/apache/storm/blob/caeaf255b7c20009d36c39bc2999c205082c63aa/docs/storm-kafka-client.md

流式计算实战避坑指南:状态一致性、实时性与背压治理 流式计算是处理持续数据流的核心范式,其本质在于对时间语义、有状态计算和容错恢复的协同控制。理解EventTime与Watermark机制,是保障实时分析准确性的前提;合理选型状态后端(如RocksDBStateBackend)并配置TTL,直接决定系统稳定性与一致性能力;而背压并非性能瓶颈的表象,而是数据生产、处理与消费速率失衡的预警信号。本文聚焦真实生产环境中的高频痛点,覆盖电商大屏、用户漏斗、金融风控、IoT入湖四大典型场景,结合Flink SQL与DataStream实践,深入解析状态管理、Check 阅读详情

相关推荐

大数据实时案例--实时日志监控告警系统

本次介绍使用Flume+kafka+storm+mysql的实时日志监控告警系统,代码部分比较多,会放在一个下载的连接里面,可以免费下载。 需求 在软件开发中国,上线运行时经常会出现一些报错,但是我们如果不能进行有效的实时监控,及时的处理,经常会带来巨大损失。为了保证异常的即使处理,我们设计一套系统,对产生的日志进行实时的监控,放出现异常或者指定的信息的时候,给我们的对应工作人员发送邮件和短信提...

weixin_42229056的博客 2万+

日志监控告警系统

课程介绍 课程名称: 日志监控告警系统 基于的日志进行监控,监控需要一定规则,对触发监控规则的日志信息进行告警,告警的方式,是短信和邮件。 log4j---->error,info,debug 应用程序程序的日志 error级别 TimeOutException 角标越界IndexXXXException ......Error com.alibaba.jstorm.dae...

weixin_30642869的博客 2349

推荐系统-经典协同过滤算法【基于记忆的协同过滤算法、基于模型的协同过滤算法】

推荐系统-经典协同过滤理论基础实践 1.协同过滤推荐方法CF简介 协同过滤CF 基于记忆的协同过滤 ---- 用户和物品的相似度矩阵 用户相似度的推荐 物品相似度推荐 UserCF用户协同过滤算法 ItemCF物品的协同过滤推荐算法 基于模型的协同过滤 ---- 隐因子 LFM(latent fator machine)隐藏因子的分解模型-----矩阵分解(将一个矩阵分解成连个矩阵的乘...

CoderBoom的博客 9689

Strom运行监控

总所周知,storm提供的UI界面进行查看运行情况,但是在storm的运行过程中,无法时刻进行观察storm UI界面是否有失败或者处理延时等情况,根据STORM提供的API进行抓取storm运行情况并输出log文件,进行文件监控,若发生失败场景进行报警处理。由于使用log日志监控,使用python进行编写此案例,示例代码如下:#!/usr/bin/python # -*- coding:UTF-...

文学超的博客 1889

【信息科学与工程学】计算机科学与自动化-——第十五篇云计算 12 公有云里的“多Region + 多AZ“ 02 运营算法01

算法逐步思考推理思考(含数学方程式、对象、资源、任务、进程/协程/线程及对应的代数、约束、目标函数/传递函数/依赖函数、参数及参数的数值范围及边界条件、逐步推理的数学方程式列表、上下文切换、并发/串行/随机/乱序/顺序)算法逐步思考推理思考(含数学方程式、对象、资源、任务、进程/协程/线程及对应的代数、约束、目标函数/传递函数/依赖函数、参数及参数的数值范围及边界条件、逐步推理的数学方程式列表、上下文切换、并发/串行/随机/乱序/顺序)云厂商提高闲置资源利用率。算法复杂度为O(N),N为实例数量。

weixin_49199313的博客 282

【信息科学与工程学】计算机科学与自动化——第八十一篇 Java分布式软件高并发/高可用算法01

4. 消息队列(如Kafka的Topic分区,本质是范围)。3. 若是ACCEPT事件,bossGroup线程接受连接,创建SocketChannel,并将其注册到workerGroup的一个EventLoop的Selector上,关注READ事件。1. 分布式缓存分片(如Redis Cluster)。4. 分布式文件存储(如Ceph CRUSH)。6. 调用栈的模拟(如协程)。3. 服务网格(如Istio)的基础。2. 本地缓存与集中式缓存(如Redis)的一致性维护。3. 静态数据(如配置)缓存。

weixin_49199313的博客 1231

日志监控告警系统的设计与实现

日志监控告警系统 基于的日志进行监控,监控需要一定规则,对触发监控规则的日志信息进行告警,告警的方式,是短信和邮件。 log4j---->error,info,debug 应用程序程序的日志 error级别 TimeOutException 角标越界IndexXXXException ......Error com.alibaba.jstorm.daemon.worker.Wo...

朱培(知浅_ZLH) 5万+

【信息科学与工程学】计算机科学与自动化 第二百三十三篇 凤凰架构01

编号类型领域系统软件/硬件或系统集成方案及系统架构模块子模块函数名称/算法名称算法的数学分析及计算机体系架构及数据结构与算法详细设计及参数列表及数值范围设计关联知识1共识算法分布式基石状态机复制架构:Proposer/Acceptor/Learner 多节点角色模型,基于操作转移(Operation Transfer)分布式共识PaxosPaxos 协议(Prepare/Promise/Accept/Accepted 两阶段)数学基础:多数派(Quorum)投票,基于鸽巢原理保证 W+R>N 时读写集合必有

weixin_49199313的博客 265

用一条河讲透Flink实时数据处理:从概念到实战排查

流式计算与批处理不同,它面向无界数据流,要求数据到达即处理,并支持毫秒级延迟与状态容错。Flink 作为业内主流的实时计算框架,其核心设计包括 DataStream API、Table API/SQL、事件时间与水位线、窗口计算、状态后端及 Checkpoint 容错机制,同时通过连接器无缝对接 Kafka、JDBC、文件系统等外部存储。理解这些概念,是构建实时数仓、实时风控、实时大屏等应用的基础。本文从一条“数据河”的比喻切入,用工程化视角拆解 Flink 的核心抽象与运行原理,梳理流批一体、时间语义与状

weixin_33787529的博客 513

【信息科学与工程学】计算机科学与自动化——第三百零四篇 高性能系统开发指南01

高并发:限流、熔断、降级高性能:红包拆分、多级缓存、大Key/热Key拆分、Pipeline、线程池、RocketMQ零丢失、幂等、分布式锁、集群缩容、分批入库海量数据处理:日志分表分片、跨表查询、冷热分层、大数据引擎服务器选型系统安全:网关安全、服务器安全、云存储安全、风控、监控、测试数据一致性:缓存与数据库一致性、大厂方案、蓝绿回滚、流量一致性、流程一致性项目与团队管理:流程问题、管理问题(风险、成本、人员、文档、培训)稳定性建设:上线三板斧、线上五步闭环、混沌工程、容量规划。

weixin_49199313的博客 249

日志监控系统源码

日志监控告警系统的设计与实现,基于的日志进行监控,监控需要一定规则,对触发监控规则的日志信息进行告警,告警的方式,是短信和邮件。

数据实时分析:日志监控告警系统(一)

1、背景知识 一个优秀的软件需要具备的特点: 1: 软件的实用性 软件的诞生就是为了解决特定的问题,比如现在流行的 MVC 框架,早期没有 MVC 开发的时候,耦合度很大,后期维护更新成本搞,难度大,这样 MVC 框架就孕育而生;比如 OA 系统为了解决公司协同的问题 ;比如 微信 QQ 等,即时聊天 为了解决人们远程沟通的问题。 2:软件的稳定性 软件的实用性问题解决后,急需要解决的...

WandaZw的博客 3187

基于Storm的日志收集系统

基于Storm平台开发的日志处理系统 使用Netty,Mongo,等技术 请勿商用

第1节 storm日志告警:1、 - 5、日志监控告警业务需求、代码、集群运行、总结...

如何解决短信或者邮件频繁发送的问题:每次发送的时候都先查询数据库记录,看一下有没有给这个人发送消息,上一次发送消息的时间是什么时候,如果发送时间间隔小于半个小时,就不要再发了 ========================================== 6、日志监控告警系统 6.1需求分析: 实现项目中日志监控的功能,需要做到日志监控实时告警,例如系...

dengmanzhou3124的博客 329

从零理解Brep:用Python玩转3D建模的边界表示法(附OpenCASCADE示例)

本文深入解析了边界表示法(Brep)在3D建模中的应用,通过Python和OpenCASCADE的实战示例,详细介绍了Brep的核心数据结构、布尔运算、网格转换及3D打印优化技巧。适合CAD设计、3D打印和计算机图形学领域的开发者学习与实践。

n4o5p6q7r的博客 427

本地部署大模型 vs 网页版大模型区别

fill:#333;color:#333;color:#333;fill:none;本地服务器/工作站硬件资源私有化部署GPU集群高速存储模型文件训练框架推理引擎。

Ds-Rag的博 1712

用Storm处理实时日志

之前写过一篇用MapReduce清洗数据,比起MR,在工作中更早使用了Storm进行实时的日志清理 Storm的输入和输出相当灵活,我处理的主要输入流都是Kafka,输出流有Kafka和Scribe

Copperfield的技术成长专栏 3223

简单搭建 可视化日志+链路追踪

JAVA 可视化日志、链路追踪、plumeLog、Tlog、Logback

qq_39535439的博客 1204

[Storm]Storm流控制

一个流分流到多个流在storm中,将一个流分流到多个不同的流中。 参考代码: main部分// tracker解析器 topologyBuilder.setBolt( "TrackerBolt", new TrackerBolt(), 2).shuffleGrouping("KafkaFilterBolt"); // 点击数统计 topolog

个人技术博客 4079

Matlab实现POD本征正交分解数据降维模型

近年来,随着大数据时代的到来,各种复杂的工程问题产生了海量的高维数据,如何有效降维、提取数据中的关键信息成为了众多领域中的重要问题。在传统的数据降维方法中,PCTFA(主成分分析)是一种典型的统计方法,然而对于流体动力学等非线性问题,PCTFA在处理时可能失去部分物理意义,难以捕捉到系统的复杂性。在降维过程中,POD提取的主要特征通常是一组复杂的正交基函数,如何将这些结果有效地转化为直观且易于理解的物理意义,特别是在实际应用中,对该特征的理解和分析,依然是一个重要的课题。本项目的扩展性也得到了有效体现。

优质创作者: 人工智能技术领域 对于有一定基础的 MATLAB和Python带具体需求都可以详谈 MATLAB和Python可以提供代码调试服务加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢 1216

TL431过压保护电路实战:5.5V阈值设计全流程(附MOSFET选型建议)

本文详细介绍了基于TL431和MOSFET构建5.5V阈值过压保护电路的完整设计流程。内容涵盖核心原理、阈值计算、驱动电路设计,并重点针对大电流应用场景,提供了MOSFET选型与散热处理的实战建议,帮助工程师打造可靠高效的电源保护方案。

weixin_28327051的博客 536

告警日志介绍

内容转载自:https://www.cnblogs.com/kerrycode/p/3899558.html 告警日志位置 在ORACLE 10g中,BACKGROUND_DUMP_DEST参数确定了告警日志的位置,但是告警日志的文件名无法修改,告警日志的名称为:alert_&lt;SID&gt;.log ,其中&lt;SID&gt;是实例的名称。BACKGROUND_DUMP_DEST参数是...

m0_37564426的博客 3172

保姆级教程:手把手配置AutoSar诊断复位(Dcm 0x11服务联动BswM/EcuM)

本文提供AutoSar诊断复位(Dcm 0x11服务联动BswM/EcuM)的保姆级配置教程,详细讲解从诊断服务基础配置到BswM规则引擎搭建、服务端口映射及EcuM复位执行的完整流程。通过Vector配置工具的实际截图和代码片段,帮助开发者高效实现远程复位功能,并分享调试技巧与性能优化实践。

weixin_30756499的博客 544
上一篇: storm_入门01学习笔记----【storm集群搭建、一键脚本启动关闭storm、storm与kafka整合】
下一篇: 推荐系统-机器学习理论基础详解01
CoderBoom
博客等级 码龄8年 62粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值