2019独角兽企业重金招聘Python工程师标准>>>
一、Avro Souce介绍
- Flume主要的RPC Source是Avro Source
- Avro Source被设计为高扩展的RPC服务器端,能从其他的Flume Agent的Avro Sink或者使用Flume的SDK发送数据的客户端应用,接受数据到一个Flume Agent中。
- Avro Source的可扩展性结合Channel担当了缓冲器的角色,使得Flume Agent能够处理重要的负载峰值。
- Flume的Avro Source使用Netty-Avro inter-process的值通信(IPC)协议来通信,因此可以用Java或JVM语言发送数据到Avro Source。
如果想从应用使用Avro Source发送事件给一个Agent,你可以利用Flume SDK,或者嵌入式Agent来完成。
- Avro Source可以配置用来从配置好输出压缩事件的Avro Sink中接收压缩的事件。也可以配置来确保接收任何客户端或Sink发送的使用SSL加密的数据。
二、Avro Source参数说明
配置参数 |
默认值 | 描述 |
type |
|
Avro Source的别名是avro,也可以使用完整类别名称org.apache.flume.source.AvroSource |
bind |
|
绑定的ip地址或主机名。使用0.0.0.0表示绑定机器所有的接口 |
port | |
绑定的端口 |
threads |
infinity |
接收从客户端或Avro Sink传入的数据的最大工作线程的数量,默认无穷大 |
ssl | false |
设置为true时表示,所有连接到Source的客户端都需要使用SSL,如果使用了SSL,则keystore和keystore-password参数是必须的。 |
keystore | |
使用SSL的keystore的路径 |
keystore-password |
|
打开keystore使用的密码 |
keystore-type |
JKS | 正在使用的keystore的类型 |
compression-type | |
用于解压缩传入数据的压缩格式。唯一支持的压缩格式是zlib。如果要接收zlib压缩的数据,设置该参数为deflate。 |
ipFilter |
false | 设置为true启用ip过滤 |
ipFilter.rules |
|
通过此配置,定义ip过滤的表达式规则 |
- Avro Source使用Netty服务器来处理传入的请求。Netty服务器使用Java的非阻塞I/O(NIO),这保证了当Netty服务器使用了相对较少的线程来处理请求的高性能。
Avro Source允许用户配置线程的最大数量,但实际线程受JVM、操作系统、硬件等的限制。
- Keystore是用Java标准定义的加密密钥和证书的集合,每隔keystore受可以用来加载keystore的密码保护。 在Flume实例中,密码以纯文本存储在Flume配置文件中,配置文件必须以恰当的权限来保护,以避免密码落入他人手中。
- 使用的加密算法通过Java安全属性文件里的ssl.KeyManagerFactory.algorithm定义,如果Java文件中这个参数没有设置,就会使用SunX509算法。【Java安全指南】
- Avro Sink和Flume RPC客户端可以配置用于发送数据给Avro Source之前压缩数据,如果数据在广域网或数据中心之间的传输时,这个非常有用的,能够减少使用的宽带。
目前Avro Source仅对RPC支持zlib压缩,为了使Avro Source能以压缩的形式接收数据,需要将compression-type参数设置为deflate。
如果这个参数没有设置或者设置为none,Flume将不会解压数据,这可能导致事件积压在前一阶段(因为Source讲不能解析压缩数据,会给前一段返回错误,将导致该阶段一直重试)
- 如果compression-type参数设置为deflate,那么传入的数据必须被压缩,否则Source不能解析传入的数据。所以,Sink或Flume客户端必须配置为压缩将要发送的数据。
因此,如果压缩和为压缩的数据被传输到相同的Flume Agent时,agent应该能运行两种Avro Source:一种用来接收压缩的数据,另一种用来接收未压缩的数据。
- 当Avro Sink或Flume RPC客户端发送数据到Avro Source时,数据是分批被压缩的,而不是按照每个事件,因此这可能会提供更好的压缩率,减少压缩内存的使用情况。
- ipFilter.rules定义格式如下 :
: :
或
allow/deny:ip/name:pattern
例如:
a1.sources.r1.ipFilter = true
a1.sources.r1.ipFilter.rules = allow:ip:127.*,allow:name:localhost,deny:ip:*
三、Avro 配置实例
1.一个单点avro例子
- 配置文件 testAvro.conf
#test avro sources a1.sources=r1 a1.channels=c1 a1.sinks=k1 a1.sources.r1.type = avro a1.sources.r1.channels=c1 a1.sources.r1.bind=192.168.1.102 a1.sources.r1.port=55555 #Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity=1000 a1.channels.c1.transactionCapacity = 100 #sink配置 a1.sinks.k1.type=logger a1.sinks.k1.channel=c1
- 启动flume服务
$ bin/flume-ng agent -c conf -f conf/testAvro.conf -n a1 -Dflume.root.logger=INFO,console
- 测试
$ bin/flume-ng avro-client -c conf -H 192.168.1.102 -p 55555 -F /app/logs/test.log
2. avro source ssl例子
- 使用keytool工具创建keystore.jks和truststore.jks文件
- 在conf下新建serverSSL.conf文件
#server a2.sources=avroSrc a2.channels=memChannel a2.sinks=loggerSink a2.sources.avroSrc.type=avro a2.sources.avroSrc.channels=memChannel #Bind to all Interface a2.sources.avroSrc.bind=192.168.1.102 a2.sources.avroSrc.port=4353 #开启SSL a2.sources.avroSrc.ssl=true a2.sources.avroSrc.keystore=/Users/pengqiang/Program/keystore.jks a2.sources.avroSrc.keystore-password=******* a2.sources.avroSrc.keystore-type=JKS #开启压缩 a2.sources.avroSrc.compression-type=deflate a2.channels.memChannel.type=memory a2.channels.memChannel.capacity=1000 a2.channels.memChannel.transactionCapacity = 100 #Describe the sink a2.sinks.loggerSink.type = logger a2.sinks.loggerSink.channel=memChannel
启动命令:$ bin/flume-ng agent -c conf -f conf/serverSSL.conf -n a2 -Dflume.root.logger=INFO,console
- 在conf下新建clientSSL.conf文件
a1.sinks=avroSink a1.channels=c1 a1.sources.r1.type = exec a1.sources.r1.command=tail -F /app/logs/test.log a1.sources.r1.channels=c1 #Use a channel which buffers events in memory a1.channels.c1.type = memory a1.channels.c1.capacity=1000 a1.channels.c1.transactionCapacity = 100 #sink配置 a1.sinks.avroSink.type=avro a1.sinks.avroSink.channel=c1 a1.sinks.avroSink.hostname=192.168.1.102 a1.sinks.avroSink.port=4353 a1.sinks.avroSink.ssl=true a1.sinks.avroSink.trust-all-certs=true a1.sinks.avroSink.truststore=/Users/pengqiang/Program/truststore.jks a1.sinks.avroSink.truststore-type=JKS a1.sinks.avroSink.truststore-password=***** a1.sinks.avroSink.compression-type=deflate
启动命令: $ bin/flume-ng agent -c conf -f conf/clientSSL.conf -n a1 -Dflume.root.logger=INFO,console
- 测试验证
$ vim /app/logs/test.log
四、Avro Sink介绍
- Avro Sink使用Avro的Netty-based RPC协议发送数据到Avro Source。它被实现为一个感知事务的Flume NettyAvroRpcClient的包装器。
- Avro Sink可以批量发送事件到Avro Source.
五、Avro Sink参数
- 表格说明
参数 默认值 描述 type Avro Sink别名为avro,也可以使用FQCN(org.apache.flume.sink.AvroSink) hostname 托管Agent机器的主机名,Sink应该连接的Source在该Agent上
port Sink连接的Source的监听端口 batch-size 100 每个RPC调用发送的事件数量。也是在单次事务中Sink从Channel中读取的事件数量 compression-type 用来压缩传入数据的压缩格式。Flume1.5只支持zlib的压缩格式,如果要接收zlib压缩的
数据,需要叫compression-type设置为deflatecompression-level 6 压缩级别,有效值1~9,数值越高,压缩的越好 connect-timeout 20000 最初的连接和握手协议完成的超时,单位:毫秒 request-timeout 20000 整个RPC调用成功完成超时 ssl false 加密套接字协议层(一种加密的通讯协定,用在使用者与网服器之间) trust-all-certs false 如果设置为true,则Sink接受所有的SSL truststore 使用的truststore文件的路径 truststore-password 用来打开trust store的密码 truststore-type JKS java trust store类型 reset-connection-interval Sink从Source断开连接并重新连接之后的间隔
- Avro Sink在通过线路发送数据之前可以压缩数据。压缩级别1~9,虽然9代表最好的压缩,但是在Sink压缩和Source解压缩所花费的时间也越多。
- Avro Sink支持使用SSL进行加密通信。Source接收数据也必须配置为从Avro Sink接收加密数据。除非指定,Flume将使用Java默认的JSSE证书授权文件,jssecacerts/cacerts,来判断Avro Source的SSL证书是否可信。
- trust-all-certs为true时,表示Sink发送数据时不需要检查Source的SSL证书
- 大多数情况下,Agent之间在中间利用负载均衡器相互通信。
六、Avro Source源码
1.configure
@Override
public void configure(Context context) {
Configurables.ensureRequiredNonNull(context, PORT_KEY, BIND_KEY);
port = context.getInteger(PORT_KEY);
bindAddress = context.getString(BIND_KEY);
compressionType = context.getString(COMPRESSION_TYPE, "none");
try {
maxThreads = context.getInteger(THREADS, 0);
} catch (NumberFormatException e) {
logger.warn("AVRO source\'s \"threads\" property must specify an integer value.",
context.getString(THREADS));
}
enableSsl = context.getBoolean(SSL_KEY, false);
keystore = context.getString(KEYSTORE_KEY);
keystorePassword = context.getString(KEYSTORE_PASSWORD_KEY);
keystoreType = context.getString(KEYSTORE_TYPE_KEY, "JKS");
String excludeProtocolsStr = context.getString(EXCLUDE_PROTOCOLS);
if (excludeProtocolsStr == null) {
excludeProtocols.add("SSLv3");
} else {
excludeProtocols.addAll(Arrays.asList(excludeProtocolsStr.split(" ")));
if (!excludeProtocols.contains("SSLv3")) {
excludeProtocols.add("SSLv3");
}
}
if (enableSsl) {
Preconditions.checkNotNull(keystore,
KEYSTORE_KEY + " must be specified when SSL is enabled");
Preconditions.checkNotNull(keystorePassword,
KEYSTORE_PASSWORD_KEY + " must be specified when SSL is enabled");
try {
KeyStore ks = KeyStore.getInstance(keystoreType);
ks.load(new FileInputStream(keystore), keystorePassword.toCharArray());
} catch (Exception ex) {
throw new FlumeException(
"Avro source configured with invalid keystore: " + keystore, ex);
}
}
enableIpFilter = context.getBoolean(IP_FILTER_KEY, false);
if (enableIpFilter) {
patternRuleConfigDefinition = context.getString(IP_FILTER_RULES_KEY);
if (patternRuleConfigDefinition == null ||
patternRuleConfigDefinition.trim().isEmpty()) {
throw new FlumeException(
"ipFilter is configured with true but ipFilterRules is not defined:" +
" ");
}
String[] patternRuleDefinitions = patternRuleConfigDefinition.split(
",");
rules = new ArrayList(patternRuleDefinitions.length);
for (String patternRuleDefinition : patternRuleDefinitions) {
rules.add(generateRule(patternRuleDefinition));
}
}
if (sourceCounter == null) {
sourceCounter = new SourceCounter(getName());
}
}
2.start
lifecycleAware 会调用start方法启动avroSource。avroSource主要启动了一个NettyServer用于接收数据,然后交由avroSource处理。
@Override
public void start() {
logger.info("Starting {}...", this);
Responder responder = new SpecificResponder(AvroSourceProtocol.class, this);
NioServerSocketChannelFactory socketChannelFactory = initSocketChannelFactory();
ChannelPipelineFactory pipelineFactory = initChannelPipelineFactory();
server = new NettyServer(responder, new InetSocketAddress(bindAddress, port),
socketChannelFactory, pipelineFactory, null);
connectionCountUpdater = Executors.newSingleThreadScheduledExecutor();
server.start();
sourceCounter.start();
super.start();
final NettyServer srv = (NettyServer)server;
connectionCountUpdater.scheduleWithFixedDelay(new Runnable(){
@Override
public void run() {
sourceCounter.setOpenConnectionCount(
Long.valueOf(srv.getNumActiveConnections()));
}
}, 0, 60, TimeUnit.SECONDS);
logger.info("Avro source {} started.", getName());
}
3.当AvroSource接收到数据时,会调用append函数,append函数会调用getChannelProcessor().processEvent处理接收的event
@Override
public Status append(AvroFlumeEvent avroEvent) {
logger.debug("Avro source {}: Received avro event: {}", getName(),
avroEvent);
sourceCounter.incrementAppendReceivedCount();
sourceCounter.incrementEventReceivedCount();
Event event = EventBuilder.withBody(avroEvent.getBody().array(),
toStringMap(avroEvent.getHeaders()));
try {
getChannelProcessor().processEvent(event);
} catch (ChannelException ex) {
logger.warn("Avro source " + getName() + ": Unable to process event. " +
"Exception follows.", ex);
return Status.FAILED;
}
sourceCounter.incrementAppendAcceptedCount();
sourceCounter.incrementEventAcceptedCount();
return Status.OK;
}