OnlineLogAnalysisScala

1.部分代码展示


import java.sql.Timestamp
import java.util
import java.util.regex.Pattern

import Streamning03.{InfluxDBUtils, ScalaBroadcastAlert, ScalaCDHRoleLog}
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.sql.{Dataset, Row, SparkSession}
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.KafkaUtils
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.{Duration, StreamingContext}
import org.influxdb.{InfluxDB, InfluxDBFactory}
import org.json.JSONObject


object ScalaOnLineLogAnalysis {
  System.setProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
  //没有这个序列化,后面运行的时候会报一个序列化错误的
  /**
    * Created by jpwu on 2017/2/14.
    *
    * 主要使用spark streaming and spark sql来实现:
    * 1.从kafka0.10 cluster读取json格式的log ,其格式: 机器名称 服务名称 时间 日志级别 日志信息
    * {"time":"2017-04-11 22:40:47,981","logtype":"INFO","loginfo":"org.apache.hadoop.hdfs.server.datanode.DataNode:PacketResponder: BP-469682100-172.16.101.55-1489763711932:blk_1073775313_34497, type=HAS_DOWNSTREAM_IN_PIPELINE terminating"}
    * {"time":"2017-04-11 22:40:48,120","logtype":"INFO","loginfo":"org.apache.hadoop.hdfs.server.datanode.DataNode:Receiving BP-469682100-172.16.101.55-1489763711932:blk_1073775314_34498 src: /172.16.101.59:49095 dest: /172.16.101.60:50010"}
    *
    * 2.每隔5秒统计最近15秒出现的机器,日志级别为info,debug,warn,error次数
    *
    * 3.每隔5秒统计最近15秒出现的机器,日志信息出现自定义alert词的次数
    *
    *  1.消费kafka json数据转换为DF,然后show()
    *  2.group by语句
    *  3.写入到InfluxDB
    *  4.广播变量+更新(自定义预警关键词)
    *
    */
  val slide_interval: Duration = new Duration(5 * 1000)
  //定义task滚动时间,Time interval after which the DStream generates a RDD (每隔一段时间返回一个RDD)
  val window_width: Duration = new Duration(5 * 1000)
//定义窗口的时间, of the window; must be a multiple of this DStream's interval(必须是这个DStream时间在倍数)

  val regexSpace: Pattern = Pattern.compile(" ")
//将给定的正则表达式编译成模式,当遇到需要匹配、查找、替换、判断字符串的情况发生,而这些情况有时又比较复杂
  //正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。
  // 正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
  val spiltstr: Array[String] = null
  var scalacdhRoleLog = new ScalaCDHRoleLog()
  //通过ScalaCDHRoleLog得到一个scalacdhRoleLog
  var sqlstr: String = null
  val recordTimestamp: Timestamp = null
  val key: String = null
  var value: String = null
  var host_service_logtype: String = null

  var influxDB:InfluxDB = null
  val   dbName: String = "online_log_analysis"
  var jsonlogline: JSONObject = null

  val alertList :util.ArrayList[String]= new util.ArrayList[String]
  var alertsql: String = ""
  def onlineLogsAnalysis(): Unit = {
    try { //定义连接influxdb
      influxDB = InfluxDBFactory.connect("http://" + InfluxDBUtils.getInfluxIP + ":" + InfluxDBUtils.getInfluxPORT(true), "admin", "admin")
      //通过InfluxDBUtils里面的方法得到influxDB的ip和port来创建连接
      val rp: String = InfluxDBUtils.defaultRetentionPolicy(influxDB.version)
      //1.使用 SparkSession,JavaSparkContext, JavaStreamingContext来定义 对象 jssc
      val ss: SparkSession = new SparkSession.Builder().master("local[2]")
        .appName("OnLineLogAnalysis")
        .config("spark.streaming.kafka.consumer.poll.ms", 150000)
        .getOrCreate
      //SparkSession 是Spark SQL 的入口。使用 Dataset 或者 Datafram 编写 Spark SQL 应用的时候,第一个要创建的对象就是 SparkSession。
      //Note:在 Spark 2.0 中, SparkSession 合并了 SQLContext 和 HiveContext。
     // SparkSession 的内部, 包含了SparkContext, SharedState,SessionState 几个对象
      val sc = ss.sparkContext
     /* SparkContext
      1,Spark程序在运行的时候分为Driver和Executors两部分;
      2,Spark的程序编写是基于SparkContext的,具体来说包含两方面:
      Spark编程的核心基础—RDD,是由SparkContext来最初创建(第一个RDD一定是由SparkContext来创建的);
      Spark程序的调度优化也是基于SparkContext;
      3,Spark程序的注册时通过SparkContext实例化时候生产的对象来完成的(其实是SchedulerBackend来注册程序)
      4,Spark程序运行的时候要通过Cluster Manager获得具体的计算资源,计算资源的获取也是通过SparkContext产生的对象来申请的(其实是SchedulerBackend来获取计算资源的);
      5,SparkContext崩溃或者结束的时候整个Spark程序也结束啦!*/

      val ssc = new StreamingContext(sc,slide_interval)
      /*StreamingContext
      1、通过创建输入DStream来创建输入数据源。
      2、通过对DStream定义transformation和output算子操作,来定义实时计算逻辑。
      3、调用StreamingContext的start()方法,来开始实时处理数据。
      4、调用StreamingContext的awaitTermination()方法,来等待应用程序的终止。可以使用CTRL+C手动停止,或者就是让它持续不断的运行进行计算。
      5、也可以通过调用StreamingContext的stop()方法,来停止应用程序。*/

      /* 2.开启checkpoint机制,把checkpoint中的数据目录设置为hdfs目录
                  hdfs dfs -mkdir -p hdfs://nameservice1/spark/checkpointdata
                  hdfs dfs -chmod -R 777 hdfs://nameservice1/spark/checkpointdata
                  hdfs dfs -ls hdfs://nameservice1/spark/checkpointdata
                   */
//      ssc.checkpoint(".")


      //3.设置kafka的map参数
      val kafkaParams = Map[String, Object](
        "bootstrap.servers" -> "192.168.137.251:9092" //这个只是连接kafka broker的一个接口
        ,"key.deserializer" -> classOf[StringDeserializer]   //key,value的俩个序列化类
        ,"value.deserializer" -> classOf[StringDeserializer]
        ,"group.id" -> "use_a_separate_group_id_for_each_stream"//这个属性是使用Subscribe必须的
        ,"auto.offset.reset" -> "latest" //自动将偏移量重置为最小的
        ,"enable.auto.commit" -> (false: java.lang.Boolean)//表示偏移量不后期提交时时更新
        ,"max.partition.fetch.bytes" -> (10485760 : java.lang.Integer)//配置每个分区的最大数据量
        ,"request.timeout.ms" -> (210000 : java.lang.Integer)//配置客户端请求响应的最长时间
        ,"session.timeout.ms" -> (180000 : java.lang.Integer) //用于检测消费者失败的超时,如果再这个时间内broker都没有收到心跳,broker将会将这个消费者移除出去,并且再启动一个再平衡
        ,"heartbeat.interval.ms" -> (30000 : java.lang.Integer) //心跳机制确保消费者的会话保持活跃,并在新消费者加入团队时促进再平衡,大小通常是流的1/3
        ,"receive.buffer.bytes" -> (10485760 : java.lang.Integer)//读取数据时,TCP接收缓冲区的大小
      )
      //3.创建要从kafka去读取的topic的集合对象
      //Collection<String> topics = Arrays.asList("online_log_analysis");
      val topics = "onlinelogs".split(",").toSet
      //4.输入流
      val lines = KafkaUtils.createDirectStream[String, String](
        ssc,
        PreferConsistent, //它将始终在所有executor之间分配分区,防止负载不均
        Subscribe[String, String](topics,kafkaParams)  //这个是10之后版本的方法,传入的是map和object,前面是主题,后面是相应的参数
      ) //返回一个DStream
      //5.将DS的RDD解析为JavaDStream<CDHRoleLog>     A DStream of RDD's that contain parsed CDH Role Logs.
      val cdhRoleLogFilterDStream = lines.map(x =>
      {
      //做一个map数据结构变成key,value类型
        if(x.value().contains("INFO")==true || x.value().contains("WARN")==true || x.value().contains("ERROR")==true || x.value().contains("DEBUG")==true|| x.value().contains("FATAL")==true)
        { //contains这个函数返回的序列是否包含这个关键字
          try{
            jsonlogline = new JSONObject(x.value()) //这是一个json格式的转换方法
            scalacdhRoleLog = new ScalaCDHRoleLog(jsonlogline.getString("hostname"),//获取与key相关联的字符串
              jsonlogline.getString("servicename"),
              jsonlogline.getString("time"),
              jsonlogline.getString("logtype"),
              jsonlogline.getString("loginfo"))
          }
          catch{
            case e:Exception => {
              println(e.toString())
              scalacdhRoleLog=null;}
          }
        }
        else {
          scalacdhRoleLog = null;
        }
        scalacdhRoleLog
      }).filter(_!= null)

      //7.Splits the cdhRoleLogFilterDStream into a dstream of time windowed rdd's.
      val windowDStream = cdhRoleLogFilterDStream.window(window_width, slide_interval)
      //8.使用foreachRDD
      windowDStream.foreachRDD(x => {
        if (x.count == 0) {
          println("No cdh role logs in this time interval")
          //用来判断是否有RDD进来
        }
        // 8.2从RDD创建Dataset
        val cdhRoleLogDR: Dataset[Row] = ss.createDataFrame(x, classOf[ScalaCDHRoleLog])
        //x是传进来的rdd,后面就是schema
        //8.3注册为临时表
        cdhRoleLogDR.createOrReplaceTempView("cdhrolelogs")
        //8.4调用自定义alert广播变量
        val alertInfoList = ScalaBroadcastAlert.updateAndGet(ss).value
        //8.5拼接SQL
        if (alertInfoList.size > 0)
        { //定义alertsql
          alertsql = ""
          for (alertInfo <- alertInfoList) {
            alertsql = alertsql + " logInfo like '%" + alertInfo + "%' "
          }
          alertsql = alertsql.substring(0, alertsql.length - 2)
          //定义sql
          sqlstr = "SELECT hostName,serviceName,logType,COUNT(logType) FROM cdhrolelogs GROUP BY hostName,serviceName,logType union  " +
            "SELECT t.hostName,t.serviceName,t.logType,COUNT(t.logType) FROM " +
            "(SELECT hostName,serviceName,'alert' as logType FROM cdhrolelogs where " + alertsql + ") t " +
            " GROUP BY t.hostName,t.serviceName,t.logType"
        }
        else {
          sqlstr = "SELECT hostName,serviceName,logType,COUNT(logType) FROM cdhrolelogs GROUP BY hostName,serviceName,logType"
        }
        //8.6计算结果为List<Row>
        val logtypecount = ss.sql(sqlstr).collectAsList
        value = ""
        //8.7循环处理
        import scala.collection.JavaConversions._
        for (rowlog <- logtypecount) {
          host_service_logtype = rowlog.get(0) + "_" + rowlog.get(1) + "_" + rowlog.get(2)
          value = value + "logtype_count,host_service_logtype=" + host_service_logtype + " count=" + rowlog.getLong(3).toString + "\n"
        }
        //8.8 存储至influxdb
        if (value.length > 0) {
          value = value.substring(0, value.length) //去除最后一个字符“,”

          //打印
          println(value)
          //保存
          influxDB.write(dbName, rp, InfluxDB.ConsistencyLevel.ONE, value)
        }
      })
      ssc.start() //启动流式计算
      ssc.awaitTermination() //等待中断
    } catch {
      case e: Exception =>
        e.printStackTrace()
    }
  }

  def main(args: Array[String]): Unit = {
    onlineLogsAnalysis
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值