flume之Avro Source和Avro Sink

2019独角兽企业重金招聘Python工程师标准>>> hot3.png


一、Avro Souce介绍


  1. Flume主要的RPC Source是Avro Source

  2. Avro Source被设计为高扩展的RPC服务器端,能从其他的Flume Agent的Avro Sink或者使用Flume的SDK发送数据的客户端应用,接受数据到一个Flume Agent中。

  3. Avro Source的可扩展性结合Channel担当了缓冲器的角色,使得Flume Agent能够处理重要的负载峰值。

  4. Flume的Avro Source使用Netty-Avro inter-process的值通信(IPC)协议来通信,因此可以用Java或JVM语言发送数据到Avro Source。

     如果想从应用使用Avro Source发送事件给一个Agent,你可以利用Flume SDK,或者嵌入式Agent来完成。

  5. 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过滤的表达式规则


  1. Avro Source使用Netty服务器来处理传入的请求。Netty服务器使用Java的非阻塞I/O(NIO),这保证了当Netty服务器使用了相对较少的线程来处理请求的高性能。
    Avro Source允许用户配置线程的最大数量,但实际线程受JVM、操作系统、硬件等的限制。

  2. Keystore是用Java标准定义的加密密钥和证书的集合,每隔keystore受可以用来加载keystore的密码保护。  在Flume实例中,密码以纯文本存储在Flume配置文件中,配置文件必须以恰当的权限来保护,以避免密码落入他人手中。

  3. 使用的加密算法通过Java安全属性文件里的ssl.KeyManagerFactory.algorithm定义,如果Java文件中这个参数没有设置,就会使用SunX509算法。【Java安全指南】

  4. Avro Sink和Flume RPC客户端可以配置用于发送数据给Avro Source之前压缩数据,如果数据在广域网或数据中心之间的传输时,这个非常有用的,能够减少使用的宽带。
        目前Avro Source仅对RPC支持zlib压缩,为了使Avro Source能以压缩的形式接收数据,需要将compression-type参数设置为deflate。
         如果这个参数没有设置或者设置为none,Flume将不会解压数据,这可能导致事件积压在前一阶段(因为Source讲不能解析压缩数据,会给前一段返回错误,将导致该阶段一直重试)

  5. 如果compression-type参数设置为deflate,那么传入的数据必须被压缩,否则Source不能解析传入的数据。所以,Sink或Flume客户端必须配置为压缩将要发送的数据。

    因此,如果压缩和为压缩的数据被传输到相同的Flume Agent时,agent应该能运行两种Avro Source:一种用来接收压缩的数据,另一种用来接收未压缩的数据。

  6. 当Avro Sink或Flume RPC客户端发送数据到Avro Source时,数据是分批被压缩的,而不是按照每个事件,因此这可能会提供更好的压缩率,减少压缩内存的使用情况。

  7. 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介绍

  1. Avro Sink使用Avro的Netty-based RPC协议发送数据到Avro Source。它被实现为一个感知事务的Flume NettyAvroRpcClient的包装器。

  2. Avro Sink可以批量发送事件到Avro Source.

五、Avro Sink参数


  1. 表格说明
    参数 默认值             描述
    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设置为deflate

    compression-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断开连接并重新连接之后的间隔


  2. Avro Sink在通过线路发送数据之前可以压缩数据。压缩级别1~9,虽然9代表最好的压缩,但是在Sink压缩和Source解压缩所花费的时间也越多。

  3. Avro Sink支持使用SSL进行加密通信。Source接收数据也必须配置为从Avro Sink接收加密数据。除非指定,Flume将使用Java默认的JSSE证书授权文件,jssecacerts/cacerts,来判断Avro Source的SSL证书是否可信。

  4. trust-all-certs为true时,表示Sink发送数据时不需要检查Source的SSL证书

  5. 大多数情况下,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;
  }






转载于:https://my.oschina.net/pengqiang/blog/535365

你可能感兴趣的:(flume之Avro Source和Avro Sink)