bigdata
采集层
flume 采集
flume 源码分析
存储层
存储层hbase 使用
存储层hbase 源码分析
分析层
智能算法
报表BI
----------------------------------------------------
flume 采集:
Flume
是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。Flume
可以采集文件,socket
数据包、文件、文件夹、kafka
等各种形式源数据,又可以将采集到的数据(下沉sink
)输出到HDFS
、hbase
、hive
、kafka
等众多外部存储系统中。
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:
-
配置文件
a1.sources = r1
a1.sinks = k1
a1.channels = c1a1.sources.r1.type = netcat
al.sources.r1.bind = localhost
a1.sources.r1.port = 44444a1.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 = minutea1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
a1.sinks.k1.hdfs.useLocalTimeStamp = truea1.sources.r1.channels = c1
a1.sinks.k1.channel = c1 -
启动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 架构:
存储层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