【Kafka+Flume+Mysql+Spark】实现新闻话题实时统计分析系统(附源码)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【Kafka+Flume+Mysql+Spark】实现新闻话题实时统计分析系统(附源码)

需要源码请点赞关注收藏后评论区留言私信~~~

系统简介

新闻话题实时统计分析系统以搜狗实验室的用户查询日志为基础,模拟生成用户查询日志,通过Flume将日志进行实时采集、汇集,分析并进行存储。利用Spark Streaming实时统计分析前20名流量最高的新闻话题,并在前端页面实时显示结果。

系统总体架构

1:利用搜狗实验室的用户查询日志模拟日志生成程序生成用户查询日志,供Flume采集

2:日志采集端Flume采集数据发送给Flume日志汇聚节点,并进行预处理

3:Flume将预处理的数据进行数据存储,存储到HBase数据库中,并发送消息给Kafka的Topic

4:Spark Streaming接收Kafka的Topic实时消息并计算实时话题的数量,并将计算结构保存到mysql数据库中

5:前端页面通过建立WebSocket通道读取Mysql数据库中的数据,实时展示话题的动态变化

表结构设计

(1)MySQL的表结构设计

webCount(新闻话题数量表)

(2)HBase表结构设计

weblogs(日志表)

系统实现

模拟日志生成程序

(1)在IntelliJ IDEA构建Java项目weblogs。编写数据生成模拟类,主要功能是读取搜狗用户日志文件,并构建新的格式写入一个新文件供Flume采集

(2)生成 JAR包,并将JAR包上传到生成日志服务器

(3)编写weblog.sh,调用模拟日志生成JAR包,并将weblog.sh上传到生成日志服务器

代码如下

#/bin/bashecho "start log......"java -jar /opt/jars/weblog.jar /opt/datas/weblog.log /opt/datas/weblog-flume.log

Flume配置

(1)配置日志采集端的Flume服务

(2)配置日志汇聚端的Flume服务

(3)自定义SinkHBase程序设计与开发

(4)修改SimpleRowKeyGenerator类,根据具体业务自定义Rowkey生成方法

(5)生成JAR包

(6) JAR上传,将打包名字替换为Flume默认包名flume-ng-hbase-sink-1.7.0.jar ,然后上传至日志汇聚服务器上的flume/lib目录下,覆盖原有的JAR包

Spark Streaming开发

(1)新建一个MAVEN工程,添加依赖包

(2)编写Scala类StructuredStreamingKafka ,实现从Kafka中读取数据存储到关系型数据库MySQL

Websocket和前端界面开发

(1)新建pom.xml文件,内容如下

(2)编写Java类WeblogService,实现功能为连接MySQL数据库

(3)编写Java类WeblogSocket,实现功能建立WebSocket通讯,取统计数据供前端调用。

(4)建立大屏显示页面index.html,实时进行大屏显示

效果展示

在日志采集端运行模拟日志生成程序

发布Web应用 访问大屏显示页面如下

代码

部分代码如下

package main.java;
import java.io.*;
public class ReadWrite {
      static String readFileName;
      static String writeFileName;
      public static void main(String args[]){
           readFileName = args[0];
           writeFileName = args[1];
          try {
             // readInput();
            readFileByLines(readFileName);
          }catch(Exception e){
          }
      }
    public static void readFileByLines(String fileName) {
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        String tempString = null;
        try {
            System.out.println("以行为单位读取文件内容,一次读一整行:");
            fis = new FileInputStream(fileName);// FileInputStream
            // 从文件系统中的某个文件中获取字节
            isr = new InputStreamReader(fis,"GBK");
            br = new BufferedReader(isr);
            int count=0;
            while ((tempString = br.readLine()) != null) {
                count++;
                // 显示行号
                Thread.sleep(300);
                String str = new String(tempString.getBytes("UTF8"),"GBK");
                System.out.println("row:"+count+">>>>>>>>"+tempString);
                method1(writeFileName,tempString);
                //appendMethodA(writeFileName,tempString);
            }
            isr.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e1) {
                }
            }
        }
    }
//    public static void appendMethodA(String fileName, String content) {
//        try {
//            // 打开一个随机访问文件流,按读写方式
//            //logger.info("file line >>>>>>>>>>>>>>>>>>>>>>>>>:"+content);
//            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
//
//            // 文件长度,字节数
//            long fileLength = randomFile.length();
//            //将写文件指针移到文件尾。
//            randomFile.seek(fileLength);
//            //randomFile.writeUTF(content);
//            randomFile.writeUTF(content);
//            randomFile.writeUTF("\n");
//           // randomFile.wri;
//
//            randomFile.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
    public static void method1(String file, String conent) {
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(file, true)));
            out.write("\n");
            out.write(conent);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Hbase数据库类代码

package org.apache.flume.sink.hbase;
import com.google.common.base.Charsets;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.FlumeException;
import org.apache.flume.conf.ComponentConfiguration;
import org.apache.flume.sink.hbase.SimpleHbaseEventSerializer.KeyType;
import org.hbase.async.AtomicIncrementRequest;
import org.hbase.async.PutRequest;
import java.util.ArrayList;
import java.util.List;
public class KfkAsyncHbaseEventSerializer implements AsyncHbaseEventSerializer {
    private byte[] table;
    private byte[] cf;
    private byte[] payload;
    private byte[] payloadColumn;
    private byte[] incrementColumn;
    private String rowPrefix;
    private byte[] incrementRow;
    private KeyType keyType;
    @Override
    public void initialize(byte[] table, byte[] cf) {
        this.table = table;
        this.cf = cf;
    }
    @Override
    public List<PutRequest> getActions() {
        List<PutRequest> actions = new ArrayList<PutRequest>();
        if (payloadColumn != null) {
            byte[] rowKey;
            try {
                String[] columns = new String(this.payloadColumn).split(",");
                String[] values = new String(this.payload).split(",");
                for (int i=0; i < columns.length; i++) {
                    byte[] colColumn = columns[i].getBytes();
                    byte[] colValue = values[i].getBytes(Charsets.UTF_8);
                    String datetime = values[0].toString();
                    String userid =  values[1].toString();
                    rowKey = SimpleRowKeyGenerator.getKfkRowKey(userid, datetime);
                    PutRequest putRequest =  new PutRequest(table, rowKey, cf,
                            colColumn, colValue);
                    actions.add(putRequest);
                }
            } catch (Exception e) {
                throw new FlumeException("Could not get row key!", e);
            }
        }
        return actions;
    }
    public List<AtomicIncrementRequest> getIncrements() {
        List<AtomicIncrementRequest> actions = new ArrayList<AtomicIncrementRequest>();
        if (incrementColumn != null) {
            AtomicIncrementRequest inc = new AtomicIncrementRequest(table,
                    incrementRow, cf, incrementColumn);
            actions.add(inc);
        }
        return actions;
    }
    @Override
    public void cleanUp() {
        // TODO Auto-generated method stub
    }
    @Override
    public void configure(Context context) {
        String pCol = context.getString("payloadColumn", "pCol");
        String iCol = context.getString("incrementColumn", "iCol");
        rowPrefix = context.getString("rowPrefix", "default");
        String suffix = context.getString("suffix", "uuid");
        if (pCol != null && !pCol.isEmpty()) {
            if (suffix.equals("timestamp")) {
                keyType = KeyType.TS;
            } else if (suffix.equals("random")) {
                keyType = KeyType.RANDOM;
            } else if (suffix.equals("nano")) {
                keyType = KeyType.TSNANO;
            } else {
                keyType = KeyType.UUID;
            }
            payloadColumn = pCol.getBytes(Charsets.UTF_8);
        }
        if (iCol != null && !iCol.isEmpty()) {
            incrementColumn = iCol.getBytes(Charsets.UTF_8);
        }
        incrementRow = context.getString("incrementRow", "incRow").getBytes(Charsets.UTF_8);
    }
    @Override
    public void setEvent(Event event) {
        this.payload = event.getBody();
    }
    @Override
    public void configure(ComponentConfiguration conf) {
        // TODO Auto-generated method stub
    }
}

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
1656 0
|
1月前
|
Ubuntu 关系型数据库 MySQL
MySQL源码编译安装
本文详细介绍了MySQL 8.0及8.4版本的源码编译安装全过程,涵盖用户创建、依赖安装、cmake配置、编译优化等步骤,并提供支持多Linux发行版的一键安装脚本,适用于定制化数据库部署需求。
175 4
MySQL源码编译安装
|
7月前
|
消息中间件 缓存 弹性计算
纯PHP+MySQL手搓高性能论坛系统!代码精简,拒绝臃肿
本内容分享了一套经实战验证的社交系统架构设计,支撑从1到100万用户的发展,并历经6次流量洪峰考验。架构涵盖客户端层(App、小程序、公众号)、接入层(API网关、负载均衡、CDN)、业务服务层(用户、内容、关系、消息等服务)、数据层(MySQL、Redis、MongoDB等)及运维监控层(日志、监控、告警)。核心设计包括数据库分库分表、多级缓存体系、消息队列削峰填谷、CQRS模式与热点数据动态缓存。同时提供应对流量洪峰的弹性伸缩方案及降级熔断机制,并通过Prometheus实现全链路监控。开源建议结构清晰,适合大型社交平台构建与优化。
272 11
|
3月前
|
NoSQL 关系型数据库 MySQL
在Visual Studio Code中设置MySQL源码调试环境
以上步骤涵盖了在VS Code中设置MySQL源码调试环境的主要过程,是一个相对高级的任务,旨在为希望建立强大开发和调试环境的开发者提供指引。遵循这些步骤,将可以利用VS Code强大的编辑和调试功能来深入理解和改进MySQL数据库的底层实现。
317 0
|
6月前
|
开发框架 Java 关系型数据库
在Linux系统中安装JDK、Tomcat、MySQL以及部署J2EE后端接口
校验时,浏览器输入:http://[your_server_IP]:8080/myapp。如果你看到你的应用的欢迎页面,恭喜你,一切都已就绪。
494 17
|
7月前
|
关系型数据库 MySQL Linux
CentOS 7系统下详细安装MySQL 5.7的步骤:包括密码配置、字符集配置、远程连接配置
以上就是在CentOS 7系统下安装MySQL 5.7的详细步骤。希望这个指南能帮助你顺利完成安装。
1692 26
|
7月前
|
Ubuntu 关系型数据库 MySQL
在Ubuntu系统的Docker上安装MySQL的方法
以上的步骤就是在Ubuntu系统的Docker上安装MySQL的详细方法,希望对你有所帮助!
772 12
|
8月前
|
关系型数据库 MySQL PHP
源码编译安装LAMP(HTTP服务,MYSQL ,PHP,以及bbs论坛)
通过以上步骤,你可以成功地在一台Linux服务器上从源码编译并安装LAMP环境,并配置一个BBS论坛(Discuz!)。这些步骤涵盖了从安装依赖、下载源代码、配置编译到安装完成的所有细节。每个命令的解释确保了过程的透明度,使即使是非专业人士也能够理解整个流程。
204 18
|
9月前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
322 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战

推荐镜像

更多