Flume数据采集结合etcd作为配置中心在爬虫数据采集处理中的架构实践。
Apache Flume是一个分布式的、可靠的、可用的系统,用于有效地收集、 聚合和将大量日志数据从许多不同的源移动到一个集中的数据存储,但是其本身是以本地properties作为配置的,配置无法做到动态监听和更新。
一、Flume和ETCD的结合,使用ETCD作为flume 数据采集的配置中心。
那么如何做出一个flume的动态配置中心呢,etcd 可以是一个很好的选择。etcd的API版本有v2和v3两个,这里选择v3版本。在flume启动的时候,可以启动etcd的监听。
...
@Override
public void start() {
//初始化监听
EtcdUtil.initListen(etcdConfig);
sinkCounter.start();
sinkCounter.incrementConnectionCreatedCount();
super.start();
}
...
/**
* etcd的监听,监听指定的key,当key 发生变化后,监听自动感知到变化。 key发生变化后,会更新本地缓存数据
*
* @param key 指定需要监听的key
*/
public static void initListen(String key) {
try { //加载配置
loadProperties(getConfig(EtcdUtil.getEtclClient().getKVClient().get(ByteSequence.fromString(key)).get().getKvs()));
new Thread(() -> {
Watch.Watcher watcher = EtcdUtil.getEtclClient().getWatchClient().watch(ByteSequence.fromString(key));
try {
while (true) {
watcher.listen().getEvents().stream().forEach(watchEvent -> {
KeyValue kv = watchEvent.getKeyValue();
log.info("etcd event:{} ,change key is:{},afterChangeValue:{}", watchEvent.getEventType(), kv.getKey().toStringUtf8(), kv.getValue().toStringUtf8());
loadProperties(kv.getValue().toStringUtf8());
});
}
} catch (InterruptedException e) {
log.error("etcd listen start cause Exception:{}", e);
}
}).start();
} catch (Exception e) {
log.error("etcd listen start cause Exception:{}", e);
}
}
备注:完整的代码可以参考笔者博客:https://www.cnblogs.com/laoqing/p/8967549.html
监听完配置后,就可以在etcd 的配置中心中管理配置了

然后就可以通过如下代码获取配置了
....
EtcdUtil.getLocalPropertie("xxxxx")
....
二、Flume 日志采集中的流水线架构设计
flume 中数据采集是通过source->Sink的方式进行数据采集入库的,但是有一个缺点就是数据中如果需要做一些ETL的业务处理,比如简单的数据加工,或者增加一些业务逻辑处理等然后再入库,无法满足。而是我们就可以对flume原有的架构进行拓展。
拓展后的架构图如下所示。

- 1、用户可以自定义process,继承统一的process接口,用户的process自己打成jar包。放到flume的lib目录中。
public interface Processor<T> {
T process(T log);
}
- 2、etcd动态配置中,配置需要使用哪些process,在多个process的时候,在etcd动态配置中配置顺序。
- processors=[{"processor":"com.xxx.flume.tax.processor.TaxCrawlerDataCommonProcessor","logType":"5"}] # logType代表日志类型
public class ProcessorBean {
private String processor;
private String logType;
private Processor processorInstance; public Processor getProcessorInstance() {
return processorInstance;
} public void setProcessorInstance(Processor processorInstance) {
this.processorInstance = processorInstance;
} public String getProcessor() {
return processor;
} public void setProcessor(String processor) {
this.processor = processor;
} public String getLogType() {
return logType;
} public void setLogType(String logType) {
this.logType = logType;
} @Override
public String toString() {
return "ProcessorBean{" +
"processor='" + processor + '\'' +
", logType='" + logType + '\'' +
", processorInstance=" + processorInstance +
'}';
}
}...
processorBeanList = GsonUtil.gson.fromJson(EtcdUtil.getLocalPropertie("processors"), new TypeToken<List<ProcessorBean>>() {
}.getType());
processorBeanList.forEach(processorBean -> {
try {
Processor<?> processor = (Processor<?>) Class.forName(processorBean.getProcessor()).newInstance();
processorBean.setProcessorInstance(processor);
} catch (Throwable e) {
e.printStackTrace();
}
});
...
- 3、process 为动态装载形式,可以随时开启和关闭。Process中业务自己处理自己的业务逻辑。
- 4、source负责数据采集
- 5、sink负责数据入库到目标端,并且负责通知(可以在动态配置中配置是否开启通知功能)
- isNotice=1#1代表打开通知
public interface Notice {
void noticePostLog(String logType);
void noticePostLog(List<Map<String,Object>> noticeMsg);
}public void noticePostLog(String logType) {
if (null != EtcdUtil.getLocalPropertie("isNotice") && "1".equals(EtcdUtil.getLocalPropertie("isNotice"))) {
List<Map<String, Object>> callList = new ArrayList<>();
................
if (null != callList && callList.size() > 0) {
noticePostLog(callList);
}
}
}if (null != processorBeanList && processorBeanList.size() > 0) {
for (ProcessorBean processorBean : processorBeanList) {
try {
if (logType.equals(processorBean.getLogType())) {
if ("2".equals(logType)) {
log = (BusinessLog) processorBean.getProcessorInstance().process(log);
} else if ("5".equals(logType)) {
log = (CrawlerLog) processorBean.getProcessorInstance().process(log);
}
}
} catch (Throwable e) {
logger.error("exec process cause Exception", e);
}
}
}
- 6、通知为一个通用的json字段。
- 7、后续所有的应用服务器都在装机时,统一预先把flume包放入进去。用户在使用flume时,只需要做配置以及上传自己的process包。
- 8、除了process不能复用外,其他的部分都通用组件复用。
- 9、process就类似流水线作业的一样。
本文作者:张永清 连接:https://www.cnblogs.com/laoqing/p/12620747.html
三、Flume 日志采集中的流水线架构设计在爬虫中的架构实践
这里以税务数据爬虫为例,仔细看如下的架构设计

- 1、税务的爬虫数据采用flume进行采集入库
- 2、由于各个省的税务网站欠差万别,数据在爬虫下来后,需要按照不同的省份进行进行(html页面数据解析,由于每个省的税务网站不同,html不一样)。解析时,就采用了process处理。
- 3、每个省份有一套解析的代码,每个省份实现同一个底层的解析接口,解析时,通过http接口从业务系统中获取配置的解析规则。
public interface TaxCrawlerAnalysis {
TaxTable analysisTaxTable(TaxHtmlTable taxHtmlTable,String taxTableType);
}
- 4、每个省份的解析类同样采用动态加载的方式,在解析处理时通过省份编码的形式进行匹配。
taxCrawlerAnalysises=[{"taxCrawlerAnalysis":"com.xxx.bigdata.crawler.tax.common.analysis.TaxCrawlerPdfTableAnalysis","provinceCity":"320000"}]
四、总结
作者的原创文章,转载须注明出处。原创文章归作者所有,欢迎转载,但是保留版权。对于转载了博主的原创文章,不标注出处的,作者将依法追究版权,请尊重作者的成果。本文作者:张永清 连接:https://www.cnblogs.com/laoqing/p/12620747.html
1、流水线的处理,让flume可以动态的扩展,可以支持自定义的业务处理。业务处理的代码可以作为单独的项目即插即用的集成到flume中。
2、etcd作为动态配置中心后,配置可以做到动态的更新,而不需要配置变更后,对jvm进程进行重启。
3、对flume进行改造和扩展的代码,后续都会放入个人github中。
Flume数据采集结合etcd作为配置中心在爬虫数据采集处理中的架构实践。的更多相关文章
- Etcd安全配置之Basic Auth认证
<中小团队落地配置中心详解>文章中我们介绍了如何基于Etcd+Confd构建配置中心,最后提到Etcd的安全问题时说了可以使用账号密码认证以达到安全访问的目的,究竟该如何开启认证以及怎么设 ...
- springcloud(九):配置中心和消息总线(配置中心终结版)
我们在springcloud(七):配置中心svn示例和refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端 ...
- spring-cloud-config-server分布式配置中心
spring cloud config是一个基于http协议的远程配置实现方式.通过统一的配置管理服务器进行配置管理,客户端通过https协议主动的拉取服务的的配置信息,完成配置获取. spring ...
- [转]springcloud(九):配置中心和消息总线(配置中心终结版)
https://www.cnblogs.com/ityouknow/p/6931958.html springcloud(九):配置中心和消息总线(配置中心终结版) 我们在springcloud(七) ...
- Spring Cloud(九):分布式配置中心和消息总线
我们在Spring Cloud(七):使用SVN存储分布式配置中心文件和实现refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码 ...
- SpringCloud04 服务配置中心、消息总线、远程配置动态刷新
1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...
- SpringCloud-分布式配置中心【加密-对称加密】
前面我们介绍了SpringCloud的分布式配置中心,我们将项目中的配置信息保存在git或者码云的仓库中,但是这样一些敏感信息就暴露出来了,比如数据库连接的账号密码等信息,这时我们最好能够对这些信 ...
- Nacos(四):SpringCloud项目中接入Nacos作为配置中心
前言 通过前两篇文章: Nacos(二):Nacos与OpenFeign的对接使用 Nacos(三):SpringCloud项目中接入Nacos作为注册中心 相信大家已经对Nacos作为注册中心的基本 ...
- SpringCloud分布式配置中心
一.什么是配置中心 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件.在Spring Cloud中,有分布式配置中心组件spring cloud c ...
随机推荐
- C++走向远洋——49(项目一2、复数类中的运算符重载、类的友元函数)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- python爬虫之数据加密解密
一.什么叫数据加密 数据加密是指利用加密算法和秘钥将明文转变为密文的过程. 二.数据加密的方式 1.单向加密 指只能加密数据而不能解密数据,这种加密方式主要是为了保证数据的完整性,常见的加密算法有MD ...
- 利用动态资源分配优化Spark应用资源利用率
背景 在某地市开展项目的时候,发现数据采集,数据探索,预处理,数据统计,训练预测都需要很多资源,现场资源不够用. 目前该项目的资源3台旧的服务器,每台的资源 内存为128G,cores 为24 (co ...
- SpringBoot图文教程11—从此不写mapper文件「SpringBoot集成MybatisPlus」
有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...
- CSS Sprite雪碧图的应用
CSS雪碧图,即CSS Sprite,也有人叫它CSS精灵图,是一种图像拼合技术.该方法是将多个小图标和背景图像合并到一张图片上,然后利用CSS的背景定位来显示需要显示的图片部分. 雪碧图的使用场景 ...
- 纯CSS实现带返回顶部右侧悬浮菜单
这是我做个人网页的时候加上的带返回顶部右侧悬浮菜单效果,如下图, 使用工具是Hbuilder. 代码如下: <!DOCTYPE html> <html> <head> ...
- 从0开始搭建kafka客户端
上一节,我们实现了搭建kafka集群.本节我们将从0开始,使用Java,搭建kafka客户端生产消费模型. 1.创建maven项目2.kafka producer3.kafka consumer4.结 ...
- 外部配置属性值是如何被绑定到XxxProperties类属性上的?--SpringBoot源码(五)
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 SpringBoot是如何实现自动配置的?--SpringBoot源码(四) 温故而知新,我们来简单回顾一下上 ...
- React-redux: React.js 和 Redux 架构的结合
通过Redux 架构理解我们了解到 Redux 架构的 store.action.reducers 这些基本概念和工作流程.我们也知道了 Redux 这种架构模式可以和其他的前端库组合使用,而 Rea ...
- openstack的yum源出错,配置openstack-ocata版的在线yum源,openstack的yum源配置
真的是几经周折,终于配置好了!我做好了一键配置yum的代码,地址:https://www.cnblogs.com/guarding/p/12321702.html 首先看一下配置前的报错信息把: 需要 ...