Storm项目:流数据监控2《代码详解…

博客公告:

 (1)本博客所有博客文章搬迁至《博客虫http://blogchong.com/

                     (2)文章对应的源码下载链接参考博客虫网站首页的“代码GIT”;

                      (3)更多的相关文章更新,以及代码等,请关注博客虫网站,网站中有技术Q群,以及代码共享链接。

                 (4)该博客内容还会继续更新,不过会慢一些。

 


 该文档为实实在在的原创文档,转载请注明:

http://blog.sina.com.cn/s/blog_8c243ea30101ir4t.html

 

类型

详细

备注

该文档为原创模拟项目:流数据监控<2>文档《流数据监控代码详解》,相流数据监控其他文档。该文档附有源代码。

 

 

相关描述

²  其他相关文档请参考新浪博客http://blog.sina.com.cn/huangchongyuan

²  

²  部分文档涉及到源码,有需要的博客留言

² 欢迎加入storm-分布式-IT技术交流群(191321336,群中有详细的资料),一起讨论技术,一起分享代码,一起分享设计。

 


 

目录

Storm项目:流数据监控 <2>. 1

---流数据监控代码详解... 1

1 项目概述... 2

1.1 数据流向... 2

1.2 代码树... 2

2 代码详解... 3

2.1 Package storm.. 3

2.2 Package storm.xml 3

2.3 Package storm.spout. 4

2.4 Package storm.base. 4

2.5 Package storm.bolt. 6

3 文档总结... 11

 

1 项目概述

 

1.1 数据流向

 

流数据监控为storm模拟项目,模拟数据源从log文件中读取数据,并逐条发射到监控Bolt中,MonitorsBolt读取配置文件MonitorBolt.xml中的匹配规则,包括正则匹配、范围匹配、常规模糊匹配及常规完全匹配,多个条件可以组合多种匹配方式,多个条件字段可以有两种不同的逻辑关系。MonitorBolt在处理数据之后(过滤出符合匹配规则的数据),发射到数据持久化Bolt中,MysqlBolt读取配置文件MysqlBolt.xml中mysql相关信息,包括mysql的host及端口,username及password,database及from,最后将数据插入mysql中。

 

1.2 代码树

Storm项目:流数据监控2《代码详解》

 

图1.2 代码树

源码简单说明:

Storm包中为总体运行的Topology,Storm.base目前只有myslq预处理的一个类,storm.bolt为bolt处理类,包括monitorbolt及printbolt,storm.spout包中为spout源数据接口,storm.source为构造源数据的一个类(这个可以忽略),storm.xml为配置文件读取类,domain.log为源数据,MonitorBolt.xml及MyslqBolt.xml分别为配置文件。

 

2 代码详解

2.1 Package storm

 

Toplology.java:

// 设置喷发节点并分配并发数,该并发数将会控制该对象在集群中的线程数。

builder.setSpout("readlog", new ReadLogSpout(),1);

//创建monitor监控过滤节点,指定该节点接收喷发节点的策略为随机方式。

builder.setBolt("monitor", newMonitorBolt("MonitorBolt.xml"), 3)

        .shuffleGrouping("readlog");

//创建mysql数据存储节点,并传入配置文件

builder.setBolt("mysql", newMysqlBolt("MysqlBolt.xml"), 3)

                  .shuffleGrouping("monitor");

注:该部分代码显示了整个topology的结构,每个节点与节点之间的关系(发布与订阅),并且指明了每个节点的喷发方式。

 

2.2 Package storm.xml

 

MonitorXml.java:

import java.io.File;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.DocumentBuilder;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;

File file = new File(fd);

//创建xml文件模板

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();

DocumentBuilder db = dbf.newDocumentBuilder();

Document doc = db.parse(file);

//将Parameter里的项存入list中

NodeList nl = doc.getElementsByTagName("Parameter");

//从list的item中获取参数值

Element e = (Element) nl.item(0);

MatchLogic =e.getElementsByTagName_r("MatchLogic").item(0)

                  .getFirstChild().getNodeValue();

MatchType =e.getElementsByTagName_r("MatchType").item(0)

                  .getFirstChild().getNodeValue();

MatchField =e.getElementsByTagName_r("MatchField").item(0)

                  .getFirstChild().getNodeValue();

FieldValue =e.getElementsByTagName_r("FieldValue").item(0)

                  .getFirstChild().getNodeValue();

注:MyslqXml.java与MonitorXml.java核心代码相似,主要是调用java中解析xml的类,主要类见如上import。

 

2.3 Package storm.spout

 

ReadLogSpout.java:

public void open(Map conf, TopologyContextcontext,SpoutOutputCollector collector) {

                  this.collector = collector;

                  try {

                           this.fis = new FileInputStream("domain.log");

                           this.isr = new InputStreamReader(fis, "UTF-8");

                           this.br = new BufferedReader(isr);

                  } catch (Exception e) {

                           e.printStackTrace();

                  }

}

public void nextTuple() {

                  String str = "";

                  try {

                           //逐行读取发射,直到末尾

                           while ((str = this.br.readLine()) != null){

                                    this.collector.emit(new Values(str));

                                    Thread.sleep(100);

                           }

                  } catch (Exception e) {

                           // TODO Auto-generated catch block

                           e.printStackTrace();

                  }

        }

注:该类为产生源数据的类,该类逐行读取log文件中的数据,发射到下一级处理Bolt中,读取文件时注意编码转换。

 

2.4 Package storm.base

 

MysqlOpt.java

import java.io.Serializable;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

public class MysqlOpt implementsSerializable {

        public Connection conn = null;

        PreparedStatement statement = null;

        // 连接数据库

        public boolean connSQL(String host_p, Stringdatabase, String username,

                           String password) {

                  String url = "jdbc:mysql://" + host_p + "/" + database

                                    + "?characterEncoding=UTF-8";

                  try {

                           //使用jdbc驱动

                           Class.forName("com.mysql.jdbc.Driver");

                           conn = DriverManager.getConnection(url, username,password);

                           return true;

                  } catch (ClassNotFoundException cnfex) {

                           System.out

                                              .println("MysqlBolt-- Error: Loading JDBC/ODBC dirverfailed!");

                           cnfex.printStackTrace();

                  } catch (SQLException sqlex) {

                           System.out.println("MysqlBolt-- Error: Connect databasefailed!");

                           sqlex.printStackTrace();

                  }

                  return false;

        }

        // 插入数据

        public boolean insertSQL(String sql) {

                  try {

                           statement = conn.prepareStatement(sql);

                           statement.executeUpdate();

                           return true;

                  } catch (SQLException e) {

                           System.out.println("MysqlBolt-- Error: Insert databasefailed!");

                           e.printStackTrace();

                  } catch (Exception e) {

                           System.out.println("MysqlBolt-- Error: Insert failed!");

                           e.printStackTrace();

                  }

                  return false;

        }

        // 关闭连接

        public void deconnSQL() {

                  try {

                           if (conn != null)

                                    conn.close();

                  } catch (Exception e) {

                           System.out.println("MysqlBolt-- Error: Deconnect databasefailed!");

                           e.printStackTrace();

                  }

        }

}

注:该类是mysql的操作类,包括mysql的链接、数据插入及数据库关闭等操作,供Mysqlbolt调用。

 

2.5 Package storm.bolt

 

Monitorbolt.java:

        public void prepare(Map stormConf,TopologyContext context,

                           OutputCollector collector) {

                  System.out.println("MonitorBolt  --      Start!");

                  this.collector = collector;

                  // 从conf中获取参数

                  new MonitorXml(this.monitorXml).read();

                  this.MatchLogic = MonitorXml.MatchLogic;

                  this.MatchType = MonitorXml.MatchType;

                  this.MatchField = MonitorXml.MatchField;

                  this.FieldValue = MonitorXml.FieldValue;

        }

        public void execute(Tuple input) {

                  //订阅str

                  String str = input.getString(0);

                  if (this.flag_par == false) {

                           System.out

                                              .println("MonitorBolt-- Erre: can't get the path ofMonitor.xml!");

                  } else {

                           //调用Monitor进行条件判断,除了str,其他参数为配置文件中读取的列表

                           boolean moni = Monitor(str, this.MatchLogic,this.MatchType,

                                              this.MatchField, this.FieldValue);

                           if (moni == true) {

                                    // System.out.println("Monitor!!!");

                                    this.collector.emit(new Values(str));

                           }

                  }

        }

        private boolean Monitor(String str, String logic,String type,

                           String field, String value) {

                  //将列表拆分

                  String[] types = type.split("::");

                  String[] fields = field.split("::");

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

                  int flag_init = types.length;

                  int flag = 0;//判断标志

                  if (logic.equals("AND")) {//逻辑AND

                           for (int i = 0; i < flag_init; i++){

                                    if (types[i].equals("regular")) {

                                              //调用正则匹配方法regular

                                              boolean regu = regular(str, fields[i], values[i]);

                                              if (regu == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("range")) {

                                              //调用范围匹配方法range

                                              boolean ran = range(str, fields[i], values[i]);

                                              if (ran == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("routine0")) {

                                              //调用常规模糊匹配方法routine0

                                              boolean rou0 = routine0(str, fields[i], values[i]);

                                              if (rou0 == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("routine1")) {

                                              //调用常规完全匹配方法routine1

                                              boolean rou1 = routine1(str, fields[i], values[i]);

                                              if (rou1 == true) {

                                                       flag++;

                                              }

                                    }

                           }

                           if (flag == flag_init) {

                                    //所有条件都满足时

                                    return true;

                           } else {

                                    return false;

                           }

                  } else if (logic.equals("OR")) {//逻辑OR

                           for (int i = 0; i < flag_init; i++){

                                    if (types[i].equals("regular")) {

                                              boolean regu = regular(str, fields[i], values[i]);

                                              if (regu == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("range")) {

                                              boolean ran = range(str, fields[i], values[i]);

                                              if (ran == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("routine0")) {

                                              boolean rou0 = routine0(str, fields[i], values[i]);

                                              if (rou0 == true) {

                                                       flag++;

                                              }

                                    } else if (types[i].equals("routine1")) {

                                              boolean rou1 = routine1(str, fields[i], values[i]);

                                              if (rou1 == true) {

                                                       flag++;

                                              }

                                    }

                           }

                           if (flag != 0) {

                                    return true;

                           } else {

                                    return false;

                           }

                  }

                  return false;

        }

        // 正则匹配判断

        private boolean regular(String str, String field,String value) {

                  String[] strs = str.split("\t");

                  Pattern p = Pattern.compile(value);

                  Matcher m = p.matcher(strs[Integer.parseInt(field) -1]);

                  boolean result = m.matches();

                  if (result == true) {

                           return true;

                  } else {

                           return false;

                  }

        }

        // 范围匹配

        private boolean range(String str, String field,String value) {

                  String[] strs = str.split("\t");

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

                  int strss =Integer.parseInt(strs[Integer.parseInt(field) -1]);

                  if (values.length == 1) {

                           if (strss >Integer.parseInt(values[0])) {

                                    return true;

                           } else {

                                    return false;

                           }

                  } else if (values.length == 2&& values[0].length() == 0) {

                           if (strss <Integer.parseInt(values[1])) {

                                    return true;

                           } else {

                                    return false;

                           }

                  } else if (values.length == 2&& values[0].length() != 0) {

                           if (strss >Integer.parseInt(values[0])

                                              && strss <Integer.parseInt(values[1])) {

                                    return true;

                           } else {

                                    return false;

                           }

                  } else {

                           return false;

                  }

        }

        // 常规模糊匹配

        private boolean routine0(String str, String field,String value) {

                  String[] strs = str.split("\t");

                  String strss = strs[Integer.parseInt(field) - 1];

 

                  if (strss.contains(value) &&!strss.equals(value)) {

                           return true;

                  } else {

                           return false;

                  }

        }

        // 常规完全匹配

        private boolean routine1(String str, String field,String value) {

                  String[] strs = str.split("\t");

                  String strss = strs[Integer.parseInt(field) - 1];

 

                  if (strss.equals(value)) {

                           return true;

                  } else {

                           return false;

                  }

        }

注1:该类主要设计了匹配规则,支持多种匹配方式,包括正则、范围、常规模糊及完全匹配,且支持两种逻辑判断关系。

MyslqBolt.java:

        public void prepare(Map stormConf,TopologyContext context,

                           OutputCollector collector) {

                  System.out.println("MysqlBolt      --      Start!");

                  this.collector = collector;

                  // 初始化mysql

                  Loading();

        }

        // 参数初始化

        public void Loading() {

                  new MysqlXml(this.mysqlXml).read();

                  String host_port = MysqlXml.Host_port; //mysql地址及端口

                  String database = MysqlXml.Database; // 数据库名

                  String username = MysqlXml.Username; // 用户名

                  String password = MysqlXml.Password; // 密码

                  this.from = MysqlXml.From; // 表名

                  if (this.mysql.connSQL(host_port, database, username,password) == false) {

                           System.out

                                              .println("MysqlBolt--Config errer, Please check Mysql-conf: "

                                                                + this.mysqlXml);

                           flag_xml = false;

                  } else {

                           System.out.println("MysqlBolt-- Conf Loaded: " +this.mysqlXml);

                  }

        }

        public void execute(Tuple input) {

                  String str = input.getString(0);

                  if (this.flag_par == false) {

                           System.out

                                              .println("MysqlBolt-- Erre: can't get the path of Mysql.xml!");

                  } else {

                           if (this.flag_xml == true) {

                                    String insert = send_str(str);

                                    if (this.mysql.insertSQL(insert) == false){

                                              System.out

                                                                .println("MysqlBolt-- Erre: can't insert tuple intodatabase!");

                                              System.out.println("MysqlBolt-- Error Tuple: " + str);

                                    }

                           }

                  }

        }

        //插入mysql语句构造方法

        public String send_str(String str) {

                  String send_tmp = null;

                  String field[] = str.split("\t");

                  for (int i = 0; i < field.length; i++){

                           if (i == 0) {

                                    send_tmp = "'" + field[0] + "', '";

                           } else if (i == (field.length - 1)) {

                                    send_tmp = send_tmp + field[i] + "'";

                           } else {

                                    send_tmp = send_tmp + field[i] + "', '";

                           }

                  }

                  String send = "insert into " + this.from + " values (" +send_tmp

                                    + ");";

                  return send;

        }

注2:该类主要用于数据存储,调用了base包中的mysqlOpt类中的多个方法,对mysql进行连接,数据插入及数据库关闭等等。

 

3 文档总结

 

该文档为流数据监控模拟项目的代码解析部分,鉴于篇幅只解析部分核心代码,如果需要完整源代码可以到博客http://blog.sina.com.cn/huangchongyuan中留言,或者加入qq群191321336。有什么疑问,欢迎留言,一起讨论,一起学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值