大数据框架思维导图整理

bigdata
    采集层
        flume 采集
        flume 源码分析
    存储层
        存储层hbase 使用
        存储层hbase 源码分析
    分析层
        智能算法
         报表BI

----------------------------------------------------

flume 采集:

Flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。Flume可以采集文件,socket数据包、文件、文件夹、kafka等各种形式源数据,又可以将采集到的数据(下沉sink)输出到HDFShbasehivekafka等众多外部存储系统中。

单个agent采集数据

2.源码分析:

 testaccse1:

2.1 webserver to source

 ? 什么时候webserer 开始采集,有哪些主要的类作用?

按照kafka soure 为例:

Flume的数据流由事件(Event)贯穿始终。事件是Flume的基本数据单位,它携带日志数据(字节数组形式)并且携带有头信息,这些Event由Agent外部的Source生成,当Source捕获事件后会进行特定的格式化,然后Source会把事件推入(单个或多个)Channel中。你可以把Channel看作是一个缓冲区,它将保存事件直到Sink处理完该事件。Sink负责持久化日志或者把事件推向另一个Source。

source流程:Source–>Event–>processEvents–>InterceptorChain–>Channel s:

下面就NetcatSource 进行分析
NetcatSource.java中的start()方法

  @Override
  public void start() {

    logger.info("Source starting");

    counterGroup.incrementAndGet("open.attempts");

    handlerService = Executors.newCachedThreadPool(new ThreadFactoryBuilder()
        .setNameFormat("netcat-handler-%d").build());

    try {
      SocketAddress bindPoint = new InetSocketAddress(hostName, port);

      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().setReuseAddress(true);
      serverSocket.socket().bind(bindPoint);

      logger.info("Created serverSocket:{}", serverSocket);
    } catch (IOException e) {
      counterGroup.incrementAndGet("open.errors");
      logger.error("Unable to bind to socket. Exception follows.", e);
      throw new FlumeException(e);
    }

    AcceptHandler acceptRunnable = new AcceptHandler(maxLineLength);
    acceptThreadShouldStop.set(false);
    acceptRunnable.counterGroup = counterGroup;
    acceptRunnable.handlerService = handlerService;
    acceptRunnable.shouldStop = acceptThreadShouldStop;
    acceptRunnable.ackEveryEvent = ackEveryEvent;
    acceptRunnable.source = this;
    acceptRunnable.serverSocket = serverSocket;
    acceptRunnable.sourceEncoding = sourceEncoding;

    acceptThread = new Thread(acceptRunnable);

    acceptThread.start();

    logger.debug("Source started");
    super.start();
  }
  • 和客户端套接字连接,并启动一个线程,一旦线程启动就进入AcceptHandler中run方法
   @Override
    public void run() {
      logger.debug("Starting accept handler");

      while (!shouldStop.get()) {
        try {
          SocketChannel socketChannel = serverSocket.accept();

          NetcatSocketHandler request = new NetcatSocketHandler(maxLineLength);

          request.socketChannel = socketChannel;
          request.counterGroup = counterGroup;
          request.source = source;
          request.ackEveryEvent = ackEveryEvent;
          request.sourceEncoding = sourceEncoding;

          handlerService.submit(request);

          counterGroup.incrementAndGet("accept.succeeded");
        } catch (ClosedByInterruptException e) {
          // Parent is canceling us.
        } catch (IOException e) {
          logger.error("Unable to accept connection. Exception follows.", e);
          counterGroup.incrementAndGet("accept.failed");
        }
      }

      logger.debug("Accept handler exiting");
    }
  }
  • 一旦请求被submit,就进入NetcatSocketHandler 的run方法中
    @Override
    public void run() {
      logger.debug("Starting connection handler");
      Event event = null;

      try {
        Reader reader = Channels.newReader(socketChannel, sourceEncoding);
        Writer writer = Channels.newWriter(socketChannel, sourceEncoding);
        //字节缓冲区
        CharBuffer buffer = CharBuffer.allocate(maxLineLength);
        buffer.flip(); // flip() so fill() sees buffer as initially empty

        while (true) {
          // this method blocks until new data is available in the socket
          int charsRead = fill(buffer, reader);
          logger.debug("Chars read = {}", charsRead);

          // attempt to process all the events in the buffer
          //处理事件
          int eventsProcessed = processEvents(buffer, writer);
          logger.debug("Events processed = {}", eventsProcessed);

          if (charsRead == -1) {
            // if we received EOF before last event processing attempt, then we
            // have done everything we can
            break;
          } else if (charsRead == 0 && eventsProcessed == 0) {
            if (buffer.remaining() == buffer.capacity()) {
              // If we get here it means:
              // 1. Last time we called fill(), no new chars were buffered
              // 2. After that, we failed to process any events => no newlines
              // 3. The unread data in the buffer == the size of the buffer
              // Therefore, we are stuck because the client sent a line longer
              // than the size of the buffer. Response: Drop the connection.
              logger.warn("Client sent event exceeding the maximum length");
              counterGroup.incrementAndGet("events.failed");
              writer.write("FAILED: Event exceeds the maximum length (" +
                  buffer.capacity() + " chars, including newline)\n");
              writer.flush();
              break;
            }
          }
        }

        socketChannel.close();

        counterGroup.incrementAndGet("sessions.completed");
      } catch (IOException e) {
        counterGroup.incrementAndGet("sessions.broken");
        try {
          socketChannel.close();
        } catch (IOException ex) {
          logger.error("Unable to close socket channel. Exception follows.", ex);
        }
      }

      logger.debug("Connection handler exiting");
    }

run方法中有一个处理事件的方法processEvents()

  private int processEvents(CharBuffer buffer, Writer writer)
        throws IOException {

      int numProcessed = 0;

      boolean foundNewLine = true;
      while (foundNewLine) {
        foundNewLine = false;

        int limit = buffer.limit();
        //读取字节流
        for (int pos = buffer.position(); pos < limit; pos++) {
          if (buffer.get(pos) == '\n') {

            // parse event body bytes out of CharBuffer
            buffer.limit(pos); // temporary limit
            ByteBuffer bytes = Charsets.UTF_8.encode(buffer);
            buffer.limit(limit); // restore limit

            // build event object
            //将字节转化成事件
            byte[] body = new byte[bytes.remaining()];
            bytes.get(body);
            Event event = EventBuilder.withBody(body);

            // process event
            ChannelException ex = null;
            try {
            //通道处理器处理事件
              source.getChannelProcessor().processEvent(event);
              ex = chEx;
            }

            if (ex == null) {
              counterGroup.incrementAndGet("events.processed");
              numProcessed++;
              if (true == ackEveryEvent) {
                writer.write("OK\n");
              }
            } else {
              counterGroup.incrementAndGet("events.failed");
              logger.warn("Error processing event. Exception follows.", ex);
              writer.write("FAILED: " + ex.getMessage() + "\n");
            }
            writer.flush();

            // advance position after data is consumed
            buffer.position(pos + 1); // skip newline
            foundNewLine = true;

            break;
          }
        }

      }

      return numProcessed;
    }

processEvents中有一个通道处理器处理事件的方法processEvent()

public void processEvent(Event event) {
//拦截器链
    event = interceptorChain.intercept(event);
    if (event == null) {
      return;
    }

    // Process required channels
    //选择器得到所有必须的通道
    List<Channel> requiredChannels = selector.getRequiredChannels(event);
    //遍历通道
    for (Channel reqChannel : requiredChannels) {
    //得到事务
      Transaction tx = reqChannel.getTransaction();
      Preconditions.checkNotNull(tx, "Transaction object must not be null");
      try {
        tx.begin();
    //把事件放到每个通道里
        reqChannel.put(event);

        tx.commit();
      } catch (Throwable t) {
        tx.rollback();
        if (t instanceof Error) {
          LOG.error("Error while writing to required channel: " + reqChannel, t);
          throw (Error) t;
        } else if (t instanceof ChannelException) {
          throw (ChannelException) t;
        } else {
          throw new ChannelException("Unable to put event on required " +
              "channel: " + reqChannel, t);
        }
      } finally {
        if (tx != null) {
          tx.close();
        }
      }
    }

    // Process optional channels
    //通过选择器得到可选通道
    List<Channel> optionalChannels = selector.getOptionalChannels(event);
    for (Channel optChannel : optionalChannels) {
      Transaction tx = null;
      try {
        tx = optChannel.getTransaction();
        tx.begin();

        optChannel.put(event);

        tx.commit();
      } catch (Throwable t) {
        tx.rollback();
        LOG.error("Unable to put event on optional channel: " + optChannel, t);
        if (t instanceof Error) {
          throw (Error) t;
        }
      } finally {
        if (tx != null) {
          tx.close();
        }
      }
    }
  }
}
  •  
  •  
  •  

source流程:Source–>Event–>processEvents–>InterceptorChain–>Channel s

对应源码:

 

2.2 source chanel:

? chanel 有几类? 分别是啥?如何agent?

1.1 Memory Channel(内存Channels)

1.2 JDBC Channel

1.3 Kafka Channel

1.4 File Channel

1.5 Spillable Memory Channel

 

 

1.5 Spillable Memory Channel

 

1.7 Custom Channel

 

 

 

 

2.3   souce sink

?  整体agent 如何代理?

如何agent?

在这里插入图片描述

 

1.首先Flume中的组件最先接收到数据的是Source

2.Source在接收到数据后,会把数据包装成Event,并且把数据交给Channel处理
3.由ChannelProcessor决定具体怎么交到Channel以及交到哪个Channel

4.在ChannelProcessor处理流程的过程中,首先会将事件拿过来发给拦截器(链)。拦截器(链)可以先进行数据的清洗、处理不合格的数据。比较常用的是给数据加一些header。
拦截器尽量不要写过重的逻辑,否则会影响流式处理的链条,整个效率都会变慢。

5.将处理后的事件交给ChannelSelector(Channel选择器),ChannelSelector根据事件的属性(header,可以通过拦截器加或Source本身的)决定当前的事件该去往哪一个Channel。(ChannelSelector的作用就是选出Event将要被发往哪个Channel。其共有两种类型,分别是Replicating(复制)和Multiplexing(多路复用)。
ReplicatingSelector会将同一个Event发往所有的Channel,Multiplexing会根据相应的原则,将不同的Event发往不同的Channel。)

6.ChannelSelector都处理完后会重新发送给ChannelProcessor

7.根据Channel选择器的选择结果,将事件写入到对应的Channel

8.每个Channel都有一个独立的SinkProcessor,Sink在Channel中也不是直接拉取数据的,一次拉多少,怎么拉这种事都是由SinkProcessor来决定的。SinkProcessor决定了Sink以什么样的行为模式来Channel中拉取数据,默认的SinkProcessor一共有三种分别是
DefaultSinkProcessor:对应Sink只有一个的时候
LoadBalancingSinkProcessor:可以实现负载均衡的功能
FailoverSinkProcessor:容灾,一个Sink只要“不死”就使劲的拉,知道挂了换另一个,可以错误恢复的功能。
DefaultSinkProcessor对应的是单个的Sink,LoadBalancingSinkProcessor和FailoverSinkProcessor对应的是Sink Group,

 

 

 

2.4 to hdfs

flume 是如何存储到hdfs 的,流程是啥? 时机是啥? 如何扩展?

hdfs sinks:

  1. 配置文件
    a1.sources = r1
    a1.sinks = k1
    a1.channels = c1

    a1.sources.r1.type = netcat
    al.sources.r1.bind = localhost
    a1.sources.r1.port = 44444

    a1.sinks.k1.type = hdfs
    a1.sinks.k1.hdfs.path = /flume/%y-%m-%d/%H/%M/%S
    a1.sinks.k1.hdfs.filePrefix = events-
    a1.sinks.k1.hdfs.round = true
    a1.sinks.k1.hdfs.roundValue = 10
    a1.sinks.k1.hdfs.roundUnit = minute

    a1.channels.c1.type = memory
    a1.channels.c1.capacity = 1000
    a1.channels.c1.transactionCapacity = 100
    a1.sinks.k1.hdfs.useLocalTimeStamp = true

    a1.sources.r1.channels = c1
    a1.sinks.k1.channel = c1

  2. 启动flume
    $> hdfs dfs -mkdir /flume
    flume $> $ bin/flume-ng agent --conf conf --conf-file conf/hdfs.conf --name a1

3.如何扩展,扩展到kafka 中:

写config/flue-kafka.properties配置文件

# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
 
# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
 
# Describe the sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.bootstrap.servers=192.168.23.128:9092
a1.sinks.k1.kafka.topic=flume2kafka
a1.sinks.k1.serializer.class=kafka.serializer.StringEncoder
a1.sinks.k1.kafka.producer.acks=1
a1.sinks.k1.custom.encoding=UTF-8
 
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
 
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

 

bin/kafka-console-consumer.sh --bootstrap-server 192.168.23.128:9092 --topic flume2kafka --from-beginning

6.启动kafka consumer,查看flume传过来的数据

bin/kafka-console-consumer.sh --bootstrap-server 192.168.23.128:9092 --topic flume2kafka --from-beginning

 

存储层hbase 使用:

hbase 架构:

alt

 存储层hbase 源码分析:

  • Master

    HBase Master 用于协调多个 Region Server,侦测各个 Region Server 之间的状态,并平衡 Region Server 之间的负载。HBase Master 还有一个职责就是负责分配 Region 给 Region Server。HBase 允许多个 Master 节点共存,但是这需要 Zookeeper 的帮助。不过当多个 Master 节点共存时,只有一个 Master 是提供服务的,其他的 Master 节点处于待命的状态。当正在工作的 Master 节点宕机时,其他的 Master 则会接管 HBase 的集群。

  • Region Server

    对于一个 Region Server 而言,其包括了多个 Region。Region Server 的作用只是管理表格,以及实现读写操作。Client 直接连接 Region Server,并通信获取 HBase 中的数据。对于 Region 而言,则是真实存放 HBase 数据的地方,也就说 Region 是 HBase 可用性和分布式的基本单位。如果当一个表格很大,并由多个 CF 组成时,那么表的数据将存放在多个 Region 之间,并且在每个 Region 中会关联多个存储的单元(Store)。

  • Zookeeper

    对于 HBase 而言,Zookeeper 的作用是至关重要的。首先 Zookeeper 是作为 HBase Master 的 HA 解决方案。也就是说,是 Zookeeper 保证了至少有一个 HBase Master 处于运行状态。并且 Zookeeper 负责 Region 和 Region Server 的注册。其实 Zookeeper 发展到目前为止,已经成为了分布式大数据框架中容错性的标准框架。不光是 HBase,几乎所有的分布式大数据相关的开源框架,都依赖于 Zookeeper 实现 HA。

 hbase 使用:

1、Hbase shell客户端使用

       a、进入客户端 hbase shell

       b、常用命令

             list  列出Hbase中存在的所有表

             alter 修改列簇(column family)模式

             count  统计表中行的数量

             create 创建表

             describe 显示表相关的详细信息

             delete 删除指定对象的值(可以为表,行、列对应的值,另外也可以指定时间戳的值)

             deleteall  删除指定行的所有元素值

             disable 使表无效

             drop 删除表

             enable 使表有效

             exists 测试表是否存在

             exit 退出Hbaseshell

             get 获取行或单元(cell)的值

             incr 增加指定表,行或列的值

             put 向指向的表单元添加值

             tools列出Hbase所支持的工具

             scan 通过对表的扫描来获取对用的值

             status 返回Hbase集群的状态信息

             shutdown 关闭Hbase集群(与exit不同)

      c、关于表: (创建表create、查看表列表list、查看表的详细信息desc、删除表drop、清空表truncate、修改表的定义alter、)

      d、关于数据的操作(增put、删delete、查get + scan,改=变相的增加)

      e、查看有哪些命令: help;如果哪个命令不会使用 help "command" 

3.flume 代理VS 其他代理的区别是啥?

 

 

 分析层
        智能算法:

按照 粒子群算法为例:

粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源于对鸟群捕食的行为研究 。该算法最初是受到飞鸟集群活动的规律性启发,进而利用群体智能建立的一个简化模型。粒子群算法在对动物集群活动行为观察基础上,利用群体中的个体对信息的共享使整个群体的运动在问题求解空间中产生从无序到有序的演化过程,从而获得最优解。

鸟被抽象为没有质量和体积的微粒(点),并延伸到N维空间,粒子i在N维空间的位置表示为矢量Xi=(x1,x2,…,xN),飞行速度表示为矢量Vi=(v1,v2,…,vN)。每个粒子都有一个由目标函数决定的适应值(fitness value),并且知道自己到目前为止发现的最好位置(pbest)和现在的位置Xi。这个可以看作是粒子自己的飞行经验。除此之外,每个粒子还知道到目前为止整个群体中所有粒子发现的最好位置(gbest)(gbest是pbest中的最好值),这个可以看作是粒子同伴的经验。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。

理论分析:

 

2.算法流程:


         报表BI

推荐几款1.Smartbi Insight

2. Zoho Analytics

3.3. Host

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执于代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值