实时数仓链路分享:kafka =SparkStreaming=kudu集成kerberos

本文主要是介绍实时数仓链路分享:kafka =SparkStreaming=kudu集成kerberos,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击上方蓝色字体,选择“设为星标

回复”资源“获取更多资源

大数据技术与架构

点击右侧关注,大数据开发领域最强公众号!

暴走大数据

点击右侧关注,暴走大数据!

本文档主要介绍在cdh集成kerberos情况下,sparkstreaming怎么消费kafka数据,并存储在kudu里面
  • 假设kafka集成kerberos

  • 假设kudu集成kerberos

  • 假设用非root用户操作

  • spark基于yarn-cluster模式

代码编写,这里只介绍关键代码
  • 主类,以下代码仅供参考

package deng.yb.sparkStreaming;import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kudu.spark.kudu.KuduContext;
import org.apache.log4j.Logger;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.StreamingContext;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka010.ConsumerStrategies;
import org.apache.spark.streaming.kafka010.KafkaUtils;
import org.apache.spark.streaming.kafka010.LocationStrategies;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;import deng.yb.sparkStreaming.kafka.KafkaTools;
import deng.yb.sparkStreaming.utils.NginxInfo;
import deng.yb.sparkStreaming.utils.SpringContextUtil;/*** Hello world!**/
@SuppressWarnings("unchecked")
public class EApp {private static final Logger logger = Logger.getLogger(App.class);private static final String BEAN_CONF = "classpath:spring/spring-bean.xml";private static Map<String, String> conf = new HashMap<String, String>();/*** epp接口-request*/private static final String EPP_REQUEST = "POST /api/sky_server_data_app/track/user_time HTTP/1.1";/*** app接口-request*/private static final String APP_REQUEST = "POST /api/sky_server_data_app/code/app_code HTTP/1.1";/*** 在spring 配置的参数id*/private static final String CONFIG = "commonConfig";/*** 以下配置参数皆为配置key spark模式*/private static final String MASTER = "master";/*** spark-appName*/private static final String APP_NAME = "appName";/*** 自定义字段*/private static final String COLUMNS = "columns";/*** topic*/private static final String TOPIC = "topic";/*** 表名*/private static final String TABLE = "tables";static {String[] confs = new String[] { BEAN_CONF };// 把actx设置进去,后续可以共用SpringContextUtil.setApplicationContext(new ClassPathXmlApplicationContext(confs));conf = (Map<String, String>) SpringContextUtil.getBean(CONFIG);}public static void main(String args[]) {try {SparkSession spark = SparkSession.builder().appName(conf.get(APP_NAME)).master(conf.get(MASTER)).getOrCreate();Map<String, Object> confMap = KafkaTools.kafkaConf(conf);String[] topicArr = conf.get(TOPIC).split(",");Collection<String> topics = Arrays.asList(topicArr);StreamingContext sc = new StreamingContext(spark.sparkContext(),Durations.milliseconds(5000));JavaStreamingContext jssc = new JavaStreamingContext(sc);JavaInputDStream<ConsumerRecord<String, String>> stream = KafkaUtils.createDirectStream(jssc, LocationStrategies.PreferConsistent(), ConsumerStrategies.<String, String> Subscribe(topics, confMap));jssc.sparkContext().setLogLevel("ERROR");stream.context().sparkContext().setLogLevel("ERROR");// nginx日志对应字段String[] columns = conf.get(COLUMNS).split(",");Map<String, String> colimnsMap = new LinkedHashMap<String, String>();// 把字段和类型映射String[] temp;for (String column : columns) {temp = column.split(":");colimnsMap.put(temp[0], temp[1]);}// 表名String[] tables = conf.get(TABLE).split(",");// epp表额外的字段String[] eppExtColumns = { "app_name", "end", "portal_user_id","resource", "start", "username", "app_id" };KuduContext kudu = new KuduContext(conf.get("kudu.instances"),sc.sparkContext());// dstream transform// 第一层封装// 第二层切分// 第三层转换JavaDStream<LinkedHashMap<String,String>> linkMap = stream.map(record -> {logger.info("消息进来:" + record.value());LinkedHashMap<String,String> json = new LinkedHashMap<String, String>();String[] messages = record.value().split(",");int length = colimnsMap.size();int i = 0;for (Map.Entry<String, String> entry : colimnsMap.entrySet()) {if (i < length) {json.put(entry.getKey(), messages[i]);}i += 1;}// 处理http_version字段String httpVersion;if (json.containsKey("http_version")&& (httpVersion = json.get("http_version")) != null) {String[] httpVersionArry = httpVersion.split("_");if (httpVersionArry != null&& httpVersionArry.length > 1) {json.put("portal_name", httpVersionArry[0]);json.put("channel", httpVersionArry[1]);json.put("version", httpVersionArry[2]);}}logger.info("封装完数据格式:"+json.toString());return json;}).cache();//EPP表linkMap.flatMap(new FlatMapFunction<LinkedHashMap<String,String>, JSONObject>(){@Overridepublic Iterator<JSONObject> call(LinkedHashMap<String,String> json) throws Exception {// TODO Auto-generated method stubArrayList<JSONObject> jsonArray = new ArrayList<JSONObject>();String request = json.get("request");if (request.indexOf(EPP_REQUEST) > -1) {logger.info("消息拆分:" + json.toString());// 这个进epp表String requestBody = URLDecoder.decode(json.get("app_id"), "utf-8");String[] strArr;JSONArray array = JSONObject.parseArray((strArr = requestBody.split("=")).length > 1 ? strArr[1]: strArr[0]);// 根据appid拆分for (int j = 0; j < array.size(); j++) {JSONObject obj = array.getJSONObject(j);JSONObject newJson = new JSONObject(new LinkedHashMap<String,Object>());// 把原来的属性加上for (String oldColumn : json.keySet()) {newJson.put(oldColumn,json.get(oldColumn));}for (String extColumn : eppExtColumns) {newJson.put(extColumn,obj.get(extColumn));}// kudu表一定要有主键newJson.put("id", UUID.randomUUID().toString().replace("-", ""));logger.info("生成EPP主键:"+newJson.getString("id"));jsonArray.add(newJson);}return jsonArray.iterator();}return new ArrayList().iterator();}}).map(eppRowMap -> {logger.info("消息转换为epprow:" + eppRowMap.toString());List<Object> objArry = new ArrayList<Object>();eppRowMap.forEach((key, value) -> {objArry.add(NginxInfo.valueTranForm(key, value));});return RowFactory.create(objArry.toArray());}).foreachRDD(eppRdd -> {Dataset<Row> rows = spark.createDataFrame(eppRdd,DataTypes.createStructType(NginxInfo.getStructFieldList("EPP")));kudu.insertRows(rows,tables[0]);});jssc.start();jssc.awaitTermination();logger.info("完成!");} catch (Exception e) {logger.error("处理消息错误2!", e);}}private StructType contructStructType() {List<StructField> structFields = new ArrayList<StructField>();return null;}
}
  • KafkaTools类,主要获取kafka配置,代码仅供参考

public static Map<String, Object> kafkaConf(Map<String, String> conf) {if (conf == null) {return null;}// kafka配置Map<String, Object> kafkaParams = new HashMap<>();kafkaParams.put(ConsumerConfig.GROUP_ID_CONFIG, "DemoConsumer");kafkaParams.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");kafkaParams.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");kafkaParams.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");kafkaParams.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "5000");//kafka集成kerberos后的security.inter.broker.protocolkafkaParams.put("security.protocol", "SASL_PLAINTEXT");kafkaParams.put("sasl.kerberos.service.name", "kafka");kafkaParams.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,conf.get("bootStrapServers"));return kafkaParams;}
注意到,集成kerberos后,身份验证的代码并没有在项目写太多,只有kafka客户端配置加上kafkaParams.put("security.protocol", "SASL_PLAINTEXT")而已
  • 身份验证的操作分别交给spark-submit处理和调度器linux crontab 处理

  • 假设我用的是wms这个账号去跑任务

  • 新建kafka_client_jaas.conf文件

cd /usr/wms/sparkstreaming/#该文件给kafka身份验证用
[wms@node1 sparkstreaming]$ vi kafka_client_jaas.conf
KafkaClient {com.sun.security.auth.module.Krb5LoginModule requireduseKeyTab=truestoreKey=trueuseTicketCache=falseserviceName="kafka"keyTab="./wms.keytab"principal="wms@W.COM";
};#把wms.keytab也放在相应目录下,此时目录机构应该是如此
-rwxr-xr-x 1 root root 352 Jul 16 09:48 wms.keytab
[wms@node1 sparkstreaming]$ ll
总用量 114172
#conf.properties文件是spark应用的配置文件
-rwxr-xr-x 1 wms wms       897 7月  16 09:45 conf.properties
-rwxr-xr-x 1 wms wms       221 7月  16 09:45 kafka_client_jaas.conf
-rwxr-xr-x 1 wms wms       352 7月  16 09:45 wms.keytab#scp到其他目录
scp /usr/wms/sparkstreaming/* root@bi-slave1:/usr/wms/sparkstreaming/
scp /usr/wms/sparkstreaming/* root@bi-slave2:/usr/wms/sparkstreaming/
scp /usr/wms/sparkstreaming/* root@bi-slave3:/usr/wms/sparkstreaming/
  • spark启动前,先初始化driver和executor是节点票据

#该操作主要是为了保证executor节点执行kudu操作前有权限
#这里我们写了一个批处理脚本,能在所有节点执行某个命令
#我们用linux调度工具,到点初始化wms用户票据,防止票据失效
#在root权限下操作
exit
[root@node1 sparkstreaming]# crontab -e
#每五分钟,在每台机器初始化wms用户票据,防止失效
*/5 * * * * ./doCommand.sh "su wms -c 'kinit -kt /usr/wms/sparkstreaming/wms.keytab wms@W.COM'" > /usr/wms/sparkstreaming/lastupdate
  • spark-submit

# 注意需要在配置文件目录下执行spark2-submit命令
# driver节点需要配置kafka的security.auth.login.config信息
# executor节点需要配置kafka的security.auth.login.config信息
# driver根据绝对路径读取配置
# executor根据相对路径读取配置
# 通过files配置把kafka_client_jaas.conf,wms.keytab发到executor节点spark2-submit  --driver-java-options=-Djava.security.auth.login.config=/etc/wonhighconf/bi/bi-sparkstreaming/kafka_client_jaas.conf  --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./kafka_client_jaas.conf" --files kafka_client_jaas.conf,wms.keytab --master yarn --deploy-mode cluster  --class deng.yb.sparkStreaming.App /usr/wms/sparkstreaming/sparkStreaming-0.0.1-SNAPSHOT.jar
  • spark启动后,进入yarn查看spark日志

欢迎点赞+收藏+转发朋友圈素质三连

文章不错?点个【在看】吧! ????

这篇关于实时数仓链路分享:kafka =SparkStreaming=kudu集成kerberos的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1143061

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Kafka拦截器的神奇操作方法

《Kafka拦截器的神奇操作方法》Kafka拦截器是一种强大的机制,用于在消息发送和接收过程中插入自定义逻辑,它们可以用于消息定制、日志记录、监控、业务逻辑集成、性能统计和异常处理等,本文介绍Kafk... 目录前言拦截器的基本概念Kafka 拦截器的定义和基本原理:拦截器是 Kafka 消息传递的不可或缺

SpringBoot如何使用TraceId日志链路追踪

《SpringBoot如何使用TraceId日志链路追踪》文章介绍了如何使用TraceId进行日志链路追踪,通过在日志中添加TraceId关键字,可以将同一次业务调用链上的日志串起来,本文通过实例代码... 目录项目场景:实现步骤1、pom.XML 依赖2、整合logback,打印日志,logback-sp

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

如何在一台服务器上使用docker运行kafka集群

《如何在一台服务器上使用docker运行kafka集群》文章详细介绍了如何在一台服务器上使用Docker运行Kafka集群,包括拉取镜像、创建网络、启动Kafka容器、检查运行状态、编写启动和关闭脚本... 目录1.拉取镜像2.创建集群之间通信的网络3.将zookeeper加入到网络中4.启动kafka集群