用于测试应用程序的两台服务器(4core + 16GRAM)
我的想法是从kafka获取数据,使用多线程处理,并保存在Elasticsearch
spark-submit --class com.yizhisec.bigdata.TrafficEs
--master yarn
--deploy-mode cluster
--executor-memory 512M
--executor-cores 2
--conf spark.streaming.concurrentJobs=5
--num-executors 5
--supervise bigdata-1.0.jar
代码
我已经使用numPartitions
来获取数据
spark.readStream().format("kafka")
.option("kafka.bootstrap.servers", prop.getProperty("kafka.broker.list"))
.option("kafka.ssl.truststore.location", prop.getProperty("kafka.jks.path"))
.option("kafka.ssl.truststore.password", prop.getProperty("kafka.jks.passwd"))
.option("kafka.security.protocol", "SSL")
.option("kafka.ssl.endpoint.identification.algorithm", "")
.option("startingOffsets", "earliest")
.option("numPartitions", prop.getProperty("kafka.partition"))
.option("subscribe", topic)
.load()
.selectExpr("CAST(topic AS STRING)", "CAST(value AS STRING)");
流程代码
Dataset<Traffic> df = StreamSparkUtils.steamToTraffic(rawDf);
String[] appProtoFilter = properties.getProperty("appproto").split(",");
Dataset<TrafficNode> nodeDataset = df
.filter(df.col("appproto").isin(appProtoFilter))
.map(new MapFunction<Traffic, TrafficNode>() {
@Override
public TrafficNode call(Traffic traffic) throws Exception {
TrafficNode n = new TrafficNode();
n.setDestport(traffic.getDestport());
n.setSrcip(traffic.getSrcip());
n.setDestip(traffic.getDestip());
n.setAppproto(traffic.getAppproto());
n.setEndtime(traffic.getEnd_time());
return n;
}
}, Encoders.bean(TrafficNode.class));
StreamingQuery query = null;
try {
query = StreamSparkUtils.streamSinkEs(nodeDataset, "loh_traffic");
query.awaitTermination();
} catch (IOException | StreamingQueryException e) {
e.printStackTrace();
}
如何优化它。
保存到es
public static StreamingQuery streamSinkEs(Dataset<?> dataSet, String index) throws IOException {
Properties properties = readProp();
return dataSet.writeStream()
.option("es.nodes", properties.getProperty("es.nodes"))
.option("es.port", properties.getProperty("es.port"))
.option("checkpointLocation", properties.getProperty("es.checkpoint"))
.format("es")
.start(index);
}
streamtoTraffic
public static Dataset<Traffic> steamToTraffic(Dataset<Row> df) {
if (df == null) {
return null;
}
StructType trafficSchema = new StructType()
.add("guid", DataTypes.LongType)
...
.add("downsize", DataTypes.LongType);
Dataset<Row> ds = df.select(functions.from_json(df.col("value").cast(DataTypes.StringType), trafficSchema).as("data")).select("data.*");
return ds.as(ExpressionEncoder.javaBean(Traffic.class));
}
答案 0 :(得分:0)
从Kafka读取的应用程序会按主题中分区的数量进行扩展。只要您将数据存储在一个分区中,您的应用程序就只能使用一个使用者来获取数据。
在您的情况下,Spark应用程序中有多少执行程序无关紧要,因为只有一个执行程序可以从一个分区读取。这是因为在Kafka中,我们具有消费者组的概念。如果要提高性能,则应在Kafka主题中增加分区数。
以下是Kafa documentation的摘录,描述了消费者组和分区之间的交互:
通过在主题内具有并行性(即分区)的概念,Kafka能够在用户进程池中提供顺序保证和负载均衡。这是通过将主题中的分区分配给消费者组中的消费者来实现的,以便每个分区都由组中的一个消费者完全消费。通过这样做,我们确保使用者是该分区的唯一读取器,并按顺序使用数据。由于存在许多分区,因此仍然可以平衡许多使用者实例上的负载。但是请注意,使用者组中的使用者实例不能超过分区。