日志采集项目——整合Flume+Kafka案例

日志采集项目——整合Flume+Kafka案例

创建模拟日志数据源项目

打开IDEA创建一个新的Maven项目(File -> New -> Project)

image-20251117195309289

image-20251117195156550

打开项目的pom.xml文件,在文件的指定位置添加如下内容

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Vfrti</groupId>
  <artifactId>artifactdata</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>artifactdata Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>artifactdata</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.14.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.0</version>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>org.my.logs.LoggerProducer</mainClass>
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
  </build>
</project>

在项目中创建OrdersInfo和LoggerProducer两个Java类,以及log4j.properties

# 1. 定义日志输出器:控制台 + 文件(每天生成一个新文件,避免单个文件过大)
log4j.rootLogger=INFO, CONSOLE, FILE

# 2. 控制台输出配置(保留原来的,方便调试)
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# 3. 文件输出配置(核心:写入 orderLogs 目录)
# 3.1 每天生成一个新日志文件(例如:order-2025-11-18.log)
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# 3.2 日志文件路径:指向 orderLogs 目录(注意:Linux 路径用 /,不是 \)
#     ${user.dir} 表示“当前程序运行的目录”,即 /usr/test/flume-test/flume-kafka
log4j.appender.FILE.File=${user.dir}/orderLogs/order.log
# 3.3 日志滚动规则:每天凌晨生成新文件
log4j.appender.FILE.DatePattern='.'yyyy-MM-dd
# 3.4 日志格式(和控制台一致,方便查看)
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# 3.5 日志文件编码(避免中文乱码)
log4j.appender.FILE.Encoding=UTF-8
package org.my.logs;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import com.alibaba.fastjson.JSONObject;

// 创建订单实体类
public class OrdersInfo {
    // 店铺名组
    private final String[] ShopNames = new String[] { "Moda", "ZARA", "乐町", "蒂妮佳", "太平鸟", "三彩", "茵曼", "伊芙丽", "秋水伊人", "Lily", "Mongyi", "玖姿", "红袖", "老思", "衣香丽影", "森马", "蜜仙娜" };
    // 商品名组
    private final String[] GoodsNames = new String[] { "连衣裙", "半身裙", "旗袍", "T恤", "衬衫", "毛衣", "雪纺衫", "卫衣", "马甲", "牛仔裤", "短外套", "西装", "风衣", "毛呢大衣", "羽绒服", "皮衣", "棉衣" };
    // 商品价格组
    private final float[] GoodsPrices = new float[] { 500.0f, 280.0f, 570.0f, 120.0f, 310.0f, 600.0f, 420.0f, 180.0f, 240.0f, 380.0f, 480.0f, 1300.0f, 1100.0f, 2600.0f, 1500.0f, 1800.0f, 580.0f };
    // 价格折扣组
    private final float[] PromotionRates = new float[] { 0.8f, 0.7f, 0.65f, 0.95f, 0.85f, 0.5f, 0.75f, 0.9f, 0.75f, 0.55f, 0.9f, 0.8f, 0.85f, 0.65f, 0.7f, 0.75f, 0.6f };

    private String orderId; // 订单ID
    private long createOrderTime; // 下单时间
    private String paymentId; // 支付编号
    private Date paymentTime; // 支付时间
    private String goodsId; // 商品ID
    private String goodsName; // 商品名
    private float goodsPrice; // 价格
    private float promotionRate; // 价格折扣
    private String shopId; // 店铺ID
    private String shopName; // 店铺名
    private String shopMobile; // 店铺电话
    private float payPrice; // 单笔订单支付总价
    private int num; // 单价/单数量
    private String province; // 省
    private String city; // 市
    private String county; // 县
    private String categorys; // 类别

    // 定义类属性orderId的get方法和set方法
    public String getOrderId() {
        return orderId;
    }
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    // 其他类属性的get方法和set方法可通过菜单自动生成,限于篇幅,省略了其他类属性的get方法和set方法的描述,请读者自行补充完整
    // ...

    @Override
    public String toString() {
        return "PaymentInfo{" + "orderId=" + this.orderId + "\", \"createOrderTime=" + this.createOrderTime + ", \"paymentId=" + this.paymentId + "\", \"paymentTime=" + this.paymentTime + ", \"goodsId=" + this.goodsId + "\", \"goodsName=" + this.goodsName + "\", \"goodsPrice=" + this.goodsPrice + ", \"promotionRate=" + this.promotionRate + ", \"shopId=" + this.shopId + "\", \"shopName=" + this.shopName + "\", \"shopMobile=" + this.shopMobile + "\", \"payPrice=" + this.payPrice + ", \"num=" + this.num + "}";
    }

    // 生产订单模拟数据
    public String random() throws ParseException {
        this.orderId = UUID.randomUUID().toString().replaceAll("-", "");
        this.paymentId = UUID.randomUUID().toString().replaceAll("-", "");
        this.shopId = new Random().nextInt(200) * 1000 + "";
        this.num = new Random().nextInt(10) + 1;

        int index = new Random().nextInt(ShopNames.length);
        this.shopName = ShopNames[index];
        this.goodsName = GoodsNames[index];
        this.goodsPrice = GoodsPrices[index];
        this.promotionRate = PromotionRates[index];

        this.payPrice = this.goodsPrice * this.promotionRate * this.num;

        this.categorys = new Random().nextInt(100) * 100 + "," + new Random().nextInt(100) * 100 + "," + new Random().nextInt(100) * 100;
        this.province = new Random().nextInt(23) + "";
        this.city = new Random().nextInt(265) + "";
        this.county = new Random().nextInt(1489) + "";

        String s_basedate = "2020-12-12 00:00:00";
        SimpleDateFormat sFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date base_date = sFormat.parse(s_basedate);
            this.createOrderTime = base_date.getTime() + new Random().nextInt(100) * 1000;
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return JSONObject.toJSONString(this);
    }
}
# 1. 定义日志输出器:控制台 + 文件(每天生成一个新文件,避免单个文件过大)
log4j.rootLogger=INFO, CONSOLE, FILE

# 2. 控制台输出配置(保留原来的,方便调试)
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# 3. 文件输出配置(核心:写入 orderLogs 目录)
# 3.1 每天生成一个新日志文件(例如:order-2025-11-18.log)
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# 3.2 日志文件路径:指向 orderLogs 目录(注意:Linux 路径用 /,不是 \)
#     ${user.dir} 表示“当前程序运行的目录”,即 /usr/test/flume-test/flume-kafka
log4j.appender.FILE.File=${user.dir}/orderLogs/order.log
# 3.3 日志滚动规则:每天凌晨生成新文件
log4j.appender.FILE.DatePattern='.'yyyy-MM-dd
# 3.4 日志格式(和控制台一致,方便查看)
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# 3.5 日志文件编码(避免中文乱码)
log4j.appender.FILE.Encoding=UTF-8

双击pakage运行,生成.jar文件

image-20251118143711519

创建两级新目录

mkdir -p /usr/test/flume-test/flume-kafka/orderLogs

将.jar文件上传到主节点上

cd /usr/test/flume-test/flume-kafka/orderLogs

执行 rz 后,会自动弹出一个 Windows 文件选择窗口。在窗口中,找到你本地电脑上的 JAR 文件然后点击 “打开” 或 “确定”。

rz

运行jar文件

java -jar artifacdata-1.0-SNAPSHOT-shaded.jar

image-20251118144342399

查看模拟日志生成情况

ll orderLogs/

image-20251118144457195

创建Kafka的消息topic

在每个节点开启zookeeper、kafka

zkServer.sh start
start-kafka.sh

在主节点hadoop01上为Kafka集群创建一个名称为kafka_test用于接收数据的topic

kafka-topics.sh --create --zookeeper hadoop01:2181,hadoop02:2181,hadoop03:2181 --replication-factor 2 --partitions 2 --topic kafka_test

执行成功后会反馈如下信息

image-20251118145905521

编写采集方案,实现Flume+Kafka整合

在flume_kafa目录下,执行以下命令创建Flume采集文案

vi flume-kafka.conf

在文件中按以下格式写入代码

# 设置 source channel sink
a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.channels = c1 # 指定 source 的管道
a1.sources.r1.type = TAILDIR # 指定 source 类型
a1.sources.r1.positionFile = /usr/test/flume-test/flume-kafka/record/taildir_position.json
a1.sources.r1.filegroups = f1
# 指定被监视的文件
a1.sources.r1.filegroups.f1 = /usr/test/flume-test/flume-kafka/orderLogs/order.log

a1.channels.c1.type = memory # 指定 channel 为 memory 类型

a1.sinks.k1.channel = c1 # 指定 sink 的管道
# 指定 sink 类型为 kafka,注意 KafkaSink 字母的大小,第一个“K”大写,第一个“S”大写
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
# 将 topic 的值指定为前面创建好的 kafka 中的 topic 名称
a1.sinks.k1.kafka.topic = kafka_test
a1.sinks.k1.kafka.bootstrap.servers = node1 主机名:9092,node2 主机名:9092,node3 主机名:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1

测试整合效果

在主节点hadoop01的flume-kafka目录下启动flume采集方案

flume-ng agent -c conf/ -f flume-kafka.conf -n a1 -Dflume.root.logger=INFO.console

开启另一个主节点hadoop01的终端窗口,在flume-kafka目录下执行以下命令,启动模拟日志生成程序

java -jar artifactdata-1.0-SNAPSHOT-shaded.jar

image-20251118162401059

在集群中的任意一个从节点上,以节点hadoop02为例,执行以下命令为前面已创建好的kafka-testTopic启动Condumer

kafka-console-consumer.sh --bootstrap-server hadoop02:9092,hadoop03:9092 --topic kafka_test --from-beginning

image-20251118162331644

posted @ 2025-12-15 11:22  酱焖热带鱼  阅读(44)  评论(0)    收藏  举报