读accumlator

JobManager

在job finish的时候会汇总accumulator的值,

newJobStatus match {
case JobStatus.FINISHED =>
try {
val accumulatorResults = executionGraph.getAccumulatorsSerialized()
val result = new SerializedJobExecutionResult(
jobID,
jobInfo.duration,
accumulatorResults) jobInfo.client ! decorateMessage(JobResultSuccess(result))
}

 

在client请求accumulation时,

public Map<String, Object> getAccumulators(JobID jobID, ClassLoader loader) throws Exception {
ActorGateway jobManagerGateway = getJobManagerGateway(); Future<Object> response;
try {
response = jobManagerGateway.ask(new RequestAccumulatorResults(jobID), timeout);
} catch (Exception e) {
throw new Exception("Failed to query the job manager gateway for accumulators.", e);
}

 

消息传到job manager

case message: AccumulatorMessage => handleAccumulatorMessage(message)
private def handleAccumulatorMessage(message: AccumulatorMessage): Unit = {
message match {
case RequestAccumulatorResults(jobID) =>
try {
currentJobs.get(jobID) match {
case Some((graph, jobInfo)) =>
val accumulatorValues = graph.getAccumulatorsSerialized()
sender() ! decorateMessage(AccumulatorResultsFound(jobID, accumulatorValues))
case None =>
archive.forward(message)
}
}

 

ExecuteGraph

获取accumulator的值

/**
* Gets a serialized accumulator map.
* @return The accumulator map with serialized accumulator values.
* @throws IOException
*/
public Map<String, SerializedValue<Object>> getAccumulatorsSerialized() throws IOException { Map<String, Accumulator<?, ?>> accumulatorMap = aggregateUserAccumulators(); Map<String, SerializedValue<Object>> result = new HashMap<String, SerializedValue<Object>>();
for (Map.Entry<String, Accumulator<?, ?>> entry : accumulatorMap.entrySet()) {
result.put(entry.getKey(), new SerializedValue<Object>(entry.getValue().getLocalValue()));
} return result;
}

 

execution的accumulator聚合,

/**
* Merges all accumulator results from the tasks previously executed in the Executions.
* @return The accumulator map
*/
public Map<String, Accumulator<?,?>> aggregateUserAccumulators() { Map<String, Accumulator<?, ?>> userAccumulators = new HashMap<String, Accumulator<?, ?>>(); for (ExecutionVertex vertex : getAllExecutionVertices()) {
Map<String, Accumulator<?, ?>> next = vertex.getCurrentExecutionAttempt().getUserAccumulators();
if (next != null) {
AccumulatorHelper.mergeInto(userAccumulators, next);
}
} return userAccumulators;
}

具体merge的逻辑,

public static void mergeInto(Map<String, Accumulator<?, ?>> target, Map<String, Accumulator<?, ?>> toMerge) {
for (Map.Entry<String, Accumulator<?, ?>> otherEntry : toMerge.entrySet()) {
Accumulator<?, ?> ownAccumulator = target.get(otherEntry.getKey());
if (ownAccumulator == null) {
// Create initial counter (copy!)
target.put(otherEntry.getKey(), otherEntry.getValue().clone());
}
else {
// Both should have the same type
AccumulatorHelper.compareAccumulatorTypes(otherEntry.getKey(),
ownAccumulator.getClass(), otherEntry.getValue().getClass());
// Merge target counter with other counter
mergeSingle(ownAccumulator, otherEntry.getValue());
}
}
}

 

更新accumulator

JobManager

收到task发来的heartbeat,其中附带accumulators

case Heartbeat(instanceID, metricsReport, accumulators) =>
updateAccumulators(accumulators)

根据jobid,更新到ExecutionGraph

private def updateAccumulators(accumulators : Seq[AccumulatorSnapshot]) = {
accumulators foreach {
case accumulatorEvent =>
currentJobs.get(accumulatorEvent.getJobID) match {
case Some((jobGraph, jobInfo)) =>
future {
jobGraph.updateAccumulators(accumulatorEvent)
}(context.dispatcher)
case None =>
// ignore accumulator values for old job
}
}
}

根据ExecutionAttemptID, 更新Execution中

/**
* Updates the accumulators during the runtime of a job. Final accumulator results are transferred
* through the UpdateTaskExecutionState message.
* @param accumulatorSnapshot The serialized flink and user-defined accumulators
*/
public void updateAccumulators(AccumulatorSnapshot accumulatorSnapshot) {
Map<AccumulatorRegistry.Metric, Accumulator<?, ?>> flinkAccumulators;
Map<String, Accumulator<?, ?>> userAccumulators;
try {
flinkAccumulators = accumulatorSnapshot.deserializeFlinkAccumulators();
userAccumulators = accumulatorSnapshot.deserializeUserAccumulators(userClassLoader); ExecutionAttemptID execID = accumulatorSnapshot.getExecutionAttemptID();
Execution execution = currentExecutions.get(execID);
if (execution != null) {
execution.setAccumulators(flinkAccumulators, userAccumulators);
}
}
}

对于execution,只要状态不是结束,就直接更新

/**
* Update accumulators (discarded when the Execution has already been terminated).
* @param flinkAccumulators the flink internal accumulators
* @param userAccumulators the user accumulators
*/
public void setAccumulators(Map<AccumulatorRegistry.Metric, Accumulator<?, ?>> flinkAccumulators,
Map<String, Accumulator<?, ?>> userAccumulators) {
synchronized (accumulatorLock) {
if (!state.isTerminal()) {
this.flinkAccumulators = flinkAccumulators;
this.userAccumulators = userAccumulators;
}
}
}

 

再看TaskManager如何更新accumulator,并发送heartbeat,

 /**
* Sends a heartbeat message to the JobManager (if connected) with the current
* metrics report.
*/
protected def sendHeartbeatToJobManager(): Unit = {
try {
val metricsReport: Array[Byte] = metricRegistryMapper.writeValueAsBytes(metricRegistry) val accumulatorEvents =
scala.collection.mutable.Buffer[AccumulatorSnapshot]() runningTasks foreach {
case (execID, task) =>
val registry = task.getAccumulatorRegistry
val accumulators = registry.getSnapshot
accumulatorEvents.append(accumulators)
} currentJobManager foreach {
jm => jm ! decorateMessage(Heartbeat(instanceID, metricsReport, accumulatorEvents))
}
}
}

可以看到会把每个running task的accumulators放到accumulatorEvents,然后通过Heartbeat消息发出

 

而task的accumlators是通过,task.getAccumulatorRegistry.getSnapshot得到

看看
AccumulatorRegistry
/**
* Main accumulator registry which encapsulates internal and user-defined accumulators.
*/
public class AccumulatorRegistry { protected static final Logger LOG = LoggerFactory.getLogger(AccumulatorRegistry.class); protected final JobID jobID; //accumulators所属的Job
protected final ExecutionAttemptID taskID; //taskID /* Flink's internal Accumulator values stored for the executing task. */
private final Map<Metric, Accumulator<?, ?>> flinkAccumulators = //内部的Accumulators
new HashMap<Metric, Accumulator<?, ?>>(); /* User-defined Accumulator values stored for the executing task. */
private final Map<String, Accumulator<?, ?>> userAccumulators = new HashMap<>(); //用户定义的Accumulators /* The reporter reference that is handed to the reporting tasks. */
private final ReadWriteReporter reporter; /**
* Creates a snapshot of this accumulator registry.
* @return a serialized accumulator map
*/
public AccumulatorSnapshot getSnapshot() {
try {
return new AccumulatorSnapshot(jobID, taskID, flinkAccumulators, userAccumulators);
} catch (IOException e) {
LOG.warn("Failed to serialize accumulators for task.", e);
return null;
}
}
}

snapshot的逻辑也很简单,

public AccumulatorSnapshot(JobID jobID, ExecutionAttemptID executionAttemptID,
Map<AccumulatorRegistry.Metric, Accumulator<?, ?>> flinkAccumulators,
Map<String, Accumulator<?, ?>> userAccumulators) throws IOException {
this.jobID = jobID;
this.executionAttemptID = executionAttemptID;
this.flinkAccumulators = new SerializedValue<Map<AccumulatorRegistry.Metric, Accumulator<?, ?>>>(flinkAccumulators);
this.userAccumulators = new SerializedValue<Map<String, Accumulator<?, ?>>>(userAccumulators);
}

 

最后,我们如何将统计数据累加到Accumulator上的?

直接看看Flink内部的Accumulator是如何更新的,都是通过这个reporter来更新的

/**
* Accumulator based reporter for keeping track of internal metrics (e.g. bytes and records in/out)
*/
private static class ReadWriteReporter implements Reporter { private LongCounter numRecordsIn = new LongCounter();
private LongCounter numRecordsOut = new LongCounter();
private LongCounter numBytesIn = new LongCounter();
private LongCounter numBytesOut = new LongCounter(); private ReadWriteReporter(Map<Metric, Accumulator<?,?>> accumulatorMap) {
accumulatorMap.put(Metric.NUM_RECORDS_IN, numRecordsIn);
accumulatorMap.put(Metric.NUM_RECORDS_OUT, numRecordsOut);
accumulatorMap.put(Metric.NUM_BYTES_IN, numBytesIn);
accumulatorMap.put(Metric.NUM_BYTES_OUT, numBytesOut);
} @Override
public void reportNumRecordsIn(long value) {
numRecordsIn.add(value);
} @Override
public void reportNumRecordsOut(long value) {
numRecordsOut.add(value);
} @Override
public void reportNumBytesIn(long value) {
numBytesIn.add(value);
} @Override
public void reportNumBytesOut(long value) {
numBytesOut.add(value);
}
}

 

何处调用到这个report的接口,

对于in, 在反序列化到record的时候会统计Bytesin和Recordsin

AdaptiveSpanningRecordDeserializer
public DeserializationResult getNextRecord(T target) throws IOException {
// check if we can get a full length;
if (nonSpanningRemaining >= 4) {
int len = this.nonSpanningWrapper.readInt(); if (reporter != null) {
reporter.reportNumBytesIn(len);
} if (len <= nonSpanningRemaining - 4) {
// we can get a full record from here
target.read(this.nonSpanningWrapper); if (reporter != null) {
reporter.reportNumRecordsIn(1);
}

 

所以对于out,反之则序列化的时候写入

SpanningRecordSerializer
@Override
public SerializationResult addRecord(T record) throws IOException {
int len = this.serializationBuffer.length();
this.lengthBuffer.putInt(0, len); if (reporter != null) {
reporter.reportNumBytesOut(len);
reporter.reportNumRecordsOut(1);
}

 

使用accumulator时,需要首先extends RichFunction by callinggetRuntimeContext().addAccumulator

flink - accumulator的更多相关文章

  1. Flink DataSet API Programming Guide

     https://ci.apache.org/projects/flink/flink-docs-release-0.10/apis/programming_guide.html   Example ...

  2. Flink Program Guide (1) -- 基本API概念(Basic API Concepts -- For Java)

    false false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-n ...

  3. Apache Flink Quickstart

    Apache Flink 是新一代的基于 Kappa 架构的流处理框架,近期底层部署结构基于 FLIP-6 做了大规模的调整,我们来看一下在新的版本(1.6-SNAPSHOT)下怎样从源码快速编译执行 ...

  4. Flink学习(三)状态机制于容错机制,State与CheckPoint

    摘自Apache官网 一.State的基本概念 什么叫State?搜了一把叫做状态机制.可以用作以下用途.为了保证 at least once, exactly once,Flink引入了State和 ...

  5. Flink – WindowedStream

    在WindowedStream上可以执行,如reduce,aggregate,min,max等操作 关键是要理解windowOperator对KVState的运用,因为window是用它来存储wind ...

  6. Flink 中的kafka何时commit?

    https://ci.apache.org/projects/flink/flink-docs-release-1.6/internals/stream_checkpointing.html @Ove ...

  7. Flink 部署文档

    Flink 部署文档 1 先决条件 2 下载 Flink 二进制文件 3 配置 Flink 3.1 flink-conf.yaml 3.2 slaves 4 将配置好的 Flink 分发到其他节点 5 ...

  8. 聊聊flink的Async I/O

    // This example implements the asynchronous request and callback with Futures that have the // inter ...

  9. Flink学习笔记:Flink API 通用基本概念

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

随机推荐

  1. sina sae 部署 java ssh 项目

    转自:http://jacobcookie.iteye.com/blog/1876798 1. 在sae上使用struts,需要添加的Listener,在com.company.listener中添加 ...

  2. AsyncTask下载网络图片

    MyTask task = new MyTask(); task.execute(url); class MyTask extends AsyncTask<String, Integer, Bi ...

  3. 简单几何(推公式) UVA 11646 Athletics Track

    题目传送门 题意:给了长宽比例,操场一圈400米,问原来长宽的长度 分析:推出公式 /************************************************ * Author ...

  4. HDU1247 Hat’s Words(Trie树)

    常规做法是枚举每个字符串每个位置,时间复杂度O(n*len*len),(建字典树O(n*len)). 然而我看这题第一眼想的是时间复杂度O(n*len)的算法..就是建正反两棵字典树,每个字符串跑分别 ...

  5. CSS Counters 计数属性

    CSS Counters其实就是一计数器,早期在CSS中计数器仅存在于ul和ol元素.如果要使用在div这样的元素上,只能通过list-style-image或者是元素的backgroud-image ...

  6. object-c 要理解协议的几个重要概念

    协议的声明/定义 调用协议 设置委托 协议的实现

  7. 达成成就:排名和AC数相同

    233333 纪念一下.(268会不会是幸运数字呢0.0

  8. TV测试中的按键长按操作模拟

    从UiAutomator在TV测试中的局限性说起: 智能TV的操作和手机的操作有很大不同,一般智能TV的操作为遥控器按键操作,来向TV OS发送  KeyCode,以完成指定操作. UiAutomat ...

  9. JS按位非(~)运算符与~~运算符的理解分析

    按位非运算符,简单的理解就是改变运算数的符号并减去1,当然,这是只是简单的理解能转换成number类型的数据. 那么,对于typeof var!==”number”的类型来说,进行运算时,会尝试转化成 ...

  10. 8.0 Qweb 报表编写步骤

    8.0 采用的是Qweb报表,摒弃了7.0中的RML报表. 1.首先在xml文件中注册一个报表: <report id="qweb_test_report" model=&q ...