/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.executor.spout;
public class SpoutOutputCollectorImpl implements ISpoutOutputCollector {
private final SpoutExecutor executor;
private final Task taskData;
private final int taskId;
private final MutableLong emittedCount;
private final boolean hasAckers;
private final Random random;
private final Boolean isEventLoggers;
private final Boolean isDebug;
private final RotatingMap pending;
@SuppressWarnings("unused")
public SpoutOutputCollectorImpl(ISpout spout, SpoutExecutor executor, Task taskData, int taskId,
MutableLong emittedCount, boolean hasAckers, Random random,
Boolean isEventLoggers, Boolean isDebug, RotatingMap pending) {
this.executor = executor;
this.taskData = taskData;
this.taskId = taskId;
this.emittedCount = emittedCount;
this.hasAckers = hasAckers;
this.random = random;
this.isEventLoggers = isEventLoggers;
this.isDebug = isDebug;
this.pending = pending;
}
@Override
public List emit(String streamId, List
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.executor.bolt;
public class BoltOutputCollectorImpl implements IOutputCollector {
private static final Logger LOG = LoggerFactory.getLogger(BoltOutputCollectorImpl.class);
private final BoltExecutor executor;
private final Task taskData;
private final int taskId;
private final Random random;
private final boolean isEventLoggers;
private final boolean isDebug;
public BoltOutputCollectorImpl(BoltExecutor executor, Task taskData, int taskId, Random random,
boolean isEventLoggers, boolean isDebug) {
this.executor = executor;
this.taskData = taskData;
this.taskId = taskId;
this.random = random;
this.isEventLoggers = isEventLoggers;
this.isDebug = isDebug;
}
public List emit(String streamId, Collection anchors, List tuple) {
return boltEmit(streamId, anchors, tuple, null);
}
@Override
public void emitDirect(int taskId, String streamId, Collection anchors, List tuple) {
boltEmit(streamId, anchors, tuple, taskId);
}
/**
* 1.首先Bolt调用boltEmit() 发送一个tuple到下游bolt
* @param streamId
* @param anchors
* @param values
* @param targetTaskId
* @return
*/
private List boltEmit(String streamId, Collection anchors, List values, Integer targetTaskId) {
List outTasks;
if (targetTaskId != null) {
outTasks = taskData.getOutgoingTasks(targetTaskId, streamId, values);
} else {
outTasks = taskData.getOutgoingTasks(streamId, values);
}
for (Integer t : outTasks) {
Map anchorsToIds = new HashMap<>();
if (anchors != null) {
for (Tuple a : anchors) {
Set rootIds = a.getMessageId().getAnchorsToIds().keySet();
if (rootIds.size() > 0) {
long edgeId = MessageId.generateId(random);
((TupleImpl) a).updateAckVal(edgeId);
for (Long root_id : rootIds) {
putXor(anchorsToIds, root_id, edgeId);
}
}
}
}
MessageId msgId = MessageId.makeId(anchorsToIds);
TupleImpl tupleExt = new TupleImpl(executor.getWorkerTopologyContext(), values, taskId, streamId, msgId);
executor.getExecutorTransfer().transfer(t, tupleExt);
}
if (isEventLoggers) {
executor.sendToEventLogger(executor, taskData, values, executor.getComponentId(), null, random);
}
return outTasks;
}
@Override
public void ack(Tuple input) {
long ackValue = ((TupleImpl) input).getAckVal();
Map anchorsToIds = input.getMessageId().getAnchorsToIds();
for (Map.Entry entry : anchorsToIds.entrySet()) {
executor.sendUnanchored(taskData, Acker.ACKER_ACK_STREAM_ID,
new Values(entry.getKey(), Utils.bitXor(entry.getValue(), ackValue)),
executor.getExecutorTransfer());
}
long delta = tupleTimeDelta((TupleImpl) input);
if (isDebug) {
LOG.info("BOLT ack TASK: {} TIME: {} TUPLE: {}", taskId, delta, input);
}
BoltAckInfo boltAckInfo = new BoltAckInfo(input, taskId, delta);
boltAckInfo.applyOn(taskData.getUserContext());
if (delta >= 0) {
((BoltExecutorStats) executor.getStats()).boltAckedTuple(
input.getSourceComponent(), input.getSourceStreamId(), delta);
}
}
@Override
public void fail(Tuple input) {
Set roots = input.getMessageId().getAnchors();
for (Long root : roots) {
executor.sendUnanchored(taskData, Acker.ACKER_FAIL_STREAM_ID,
new Values(root), executor.getExecutorTransfer());
}
long delta = tupleTimeDelta((TupleImpl) input);
if (isDebug) {
LOG.info("BOLT fail TASK: {} TIME: {} TUPLE: {}", taskId, delta, input);
}
BoltFailInfo boltFailInfo = new BoltFailInfo(input, taskId, delta);
boltFailInfo.applyOn(taskData.getUserContext());
if (delta >= 0) {
((BoltExecutorStats) executor.getStats()).boltFailedTuple(
input.getSourceComponent(), input.getSourceStreamId(), delta);
}
}
@Override
public void resetTimeout(Tuple input) {
Set roots = input.getMessageId().getAnchors();
for (Long root : roots) {
executor.sendUnanchored(taskData, Acker.ACKER_RESET_TIMEOUT_STREAM_ID,
new Values(root), executor.getExecutorTransfer());
}
}
@Override
public void reportError(Throwable error) {
executor.getErrorReportingMetrics().incrReportedErrorCount();
executor.getReportError().report(error);
}
private long tupleTimeDelta(TupleImpl tuple) {
Long ms = tuple.getProcessSampleStartTime();
if (ms != null) {
return Time.deltaMs(ms);
}
return -1;
}
private void putXor(Map pending, Long key, Long id) {
Long curr = pending.get(key);
if (curr == null) {
curr = 0l;
}
pending.put(key, Utils.bitXor(curr, id));
}
}
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.executor;
public class ExecutorTransfer implements EventHandler, Callable {
private static final Logger LOG = LoggerFactory.getLogger(ExecutorTransfer.class);
private final WorkerState workerData;
private final DisruptorQueue batchTransferQueue;
private final Map topoConf;
private final KryoTupleSerializer serializer;
private final MutableObject cachedEmit;
private final boolean isDebug;
public ExecutorTransfer(WorkerState workerData, DisruptorQueue batchTransferQueue, Map topoConf) {
this.workerData = workerData;
this.batchTransferQueue = batchTransferQueue;
this.topoConf = topoConf;
this.serializer = new KryoTupleSerializer(topoConf, workerData.getWorkerTopologyContext());
this.cachedEmit = new MutableObject(new ArrayList<>());
this.isDebug = ObjectReader.getBoolean(topoConf.get(Config.TOPOLOGY_DEBUG), false);
}
//4.ExecutorTransfer将tuple添加目标task信息,将tuple封装成AddressedTuple。并将封装后的结果AddressedTuple publish到batchTransferQueue队列中。
// batchTransferQueue也就是Executor的发送队列。
public void transfer(int task, Tuple tuple) {
AddressedTuple val = new AddressedTuple(task, tuple);
if (isDebug) {
LOG.info("TRANSFERRING tuple {}", val);
}
batchTransferQueue.publish(val);
}
@VisibleForTesting
public DisruptorQueue getBatchTransferQueue() {
return this.batchTransferQueue;
}
/**
* 6.ExecutorTransfer的Call方法被调用。batchTransferQueue批量的消费消息
* @return
* @throws Exception
*/
@Override
public Object call() throws Exception {
batchTransferQueue.consumeBatchWhenAvailable(this);
return 0L;
}
public String getName() {
return batchTransferQueue.getName();
}
/**
* 7.相应事件,不断的批量消费batchTransferQueue中的AddressedTuple对象
* @param event
* @param sequence
* @param endOfBatch
* @throws Exception
*/
@Override
public void onEvent(Object event, long sequence, boolean endOfBatch) throws Exception {
ArrayList cachedEvents = (ArrayList) cachedEmit.getObject();
cachedEvents.add(event);
if (endOfBatch) {
//8.调用WorkerState的transfer方法。对AddressedTuple进行序列化操作
workerData.transfer(serializer, cachedEvents);
cachedEmit.setObject(new ArrayList<>());
}
}
}
public abstract class Executor implements Callable, EventHandler {
private static final Logger LOG = LoggerFactory.getLogger(Executor.class);
........
/**
* separated from mkExecutor in order to replace executor transfer in executor data for testing
*/
public ExecutorShutdown execute() throws Exception {
LOG.info("Loading executor tasks " + componentId + ":" + executorId);
registerBackpressure();
//5.在Executor线程 执行execute()方法后,不断的Loop调用executorTransfer的Callable接口。一旦sendQueue buffer达到一定的阈值后。
// 调用ExecutorTransfer的Call方法
Utils.SmartThread systemThreads =
Utils.asyncLoop(executorTransfer, executorTransfer.getName(), reportErrorDie);
String handlerName = componentId + "-executor" + executorId;
Utils.SmartThread handlers =
Utils.asyncLoop(this, false, reportErrorDie, Thread.NORM_PRIORITY, true, true, handlerName);
setupTicks(StatsUtil.SPOUT.equals(type));
LOG.info("Finished loading executor " + componentId + ":" + executorId);
return new ExecutorShutdown(this, Lists.newArrayList(systemThreads, handlers), idToTask, receiveQueue, sendQueue);
.............}}
ExecutorTransfer源码
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.executor;
public class ExecutorTransfer implements EventHandler, Callable {
private static final Logger LOG = LoggerFactory.getLogger(ExecutorTransfer.class);
private final WorkerState workerData;
private final DisruptorQueue batchTransferQueue;
private final Map topoConf;
private final KryoTupleSerializer serializer;
private final MutableObject cachedEmit;
private final boolean isDebug;
public ExecutorTransfer(WorkerState workerData, DisruptorQueue batchTransferQueue, Map topoConf) {
this.workerData = workerData;
this.batchTransferQueue = batchTransferQueue;
this.topoConf = topoConf;
this.serializer = new KryoTupleSerializer(topoConf, workerData.getWorkerTopologyContext());
this.cachedEmit = new MutableObject(new ArrayList<>());
this.isDebug = ObjectReader.getBoolean(topoConf.get(Config.TOPOLOGY_DEBUG), false);
}
//4.ExecutorTransfer将tuple添加目标task信息,将tuple封装成AddressedTuple。并将封装后的结果AddressedTuple publish到batchTransferQueue队列中。
// batchTransferQueue也就是Executor的发送队列。
public void transfer(int task, Tuple tuple) {
AddressedTuple val = new AddressedTuple(task, tuple);
if (isDebug) {
LOG.info("TRANSFERRING tuple {}", val);
}
batchTransferQueue.publish(val);
}
@VisibleForTesting
public DisruptorQueue getBatchTransferQueue() {
return this.batchTransferQueue;
}
/**
* 6.ExecutorTransfer的Call方法被调用。batchTransferQueue批量的消费消息
* @return
* @throws Exception
*/
@Override
public Object call() throws Exception {
batchTransferQueue.consumeBatchWhenAvailable(this);
return 0L;
}
public String getName() {
return batchTransferQueue.getName();
}
/**
* 7.相应事件,不断的批量消费batchTransferQueue中的AddressedTuple对象
* @param event
* @param sequence
* @param endOfBatch
* @throws Exception
*/
@Override
public void onEvent(Object event, long sequence, boolean endOfBatch) throws Exception {
ArrayList cachedEvents = (ArrayList) cachedEmit.getObject();
cachedEvents.add(event);
if (endOfBatch) {
//8.调用WorkerState的transfer方法。对AddressedTuple进行序列化操作
workerData.transfer(serializer, cachedEvents);
cachedEmit.setObject(new ArrayList<>());
}
}
}
2.4 WorkerState调用transfer方法
WorkerState是Worker类的一个成员变量,保存着Worker中大量的存在的状态以及对Worker进程通信以及一些操作。这里介绍WorkerState的transfer方法。在WorkerState的Transfer方法中,首先定义了两个局部变量。一个是List local 还有一个是 Map> remoteMap。分别用来保存Executor中AddressTuple发送到本地Worker进程和远程Worke进程中相应TaskID的Map集合。
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.daemon.worker;
public class WorkerState {
........
//12.注册回调函数,WorkerState中的registerCallbacks()方法中注册反序列化连接回调函数。
public void registerCallbacks() {
LOG.info("Registering IConnectionCallbacks for {}:{}", assignmentId, port);
receiver.registerRecv(new DeserializingConnectionCallback(topologyConf,
getWorkerTopologyContext(),
this::transferLocal));
}
//14.调用用第一个步骤声明的transferLocal()方法 在Worker内部本地发送到相应的线程
public void transferLocal(List tupleBatch) {
Map> grouped = new HashMap<>();
for (AddressedTuple tuple : tupleBatch) {
Integer executor = taskToShortExecutor.get(tuple.dest);
if (null == executor) {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
continue;
}
List current = grouped.get(executor);
if (null == current) {
current = new ArrayList<>();
grouped.put(executor, current);
}
current.add(tuple);
}
for (Map.Entry> entry : grouped.entrySet()) {
DisruptorQueue queue = shortExecutorReceiveQueueMap.get(entry.getKey());
if (null != queue) {
queue.publish(entry.getValue());
} else {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
}
}
}
//9.不断的对AddressedTuple进行序列化操作,并将要发送到相同的task的AddressedTuple进行打包批量的发送消息。
// 如果需要发送到本地worker的taskid,我们调用WorkerState的transferLocal方法发送到本地。本地发送不需要序列化
// 需要发送到远程Worker的消息,序列化后进行打包成Map>对象发送到Worker的传输队列中去
public void transfer(KryoTupleSerializer serializer, List tupleBatch) {
if (trySerializeLocal) {
assertCanSerialize(serializer, tupleBatch);
}
List local = new ArrayList<>();
Map> remoteMap = new HashMap<>();
LOG.info("the time of start serializing : {}", System.currentTimeMillis());
for (AddressedTuple addressedTuple : tupleBatch) {
int destTask = addressedTuple.getDest();
if (taskIds.contains(destTask)) {
// Local task
local.add(addressedTuple);
} else {
// Using java objects directly to avoid performance issues in java code
if (! remoteMap.containsKey(destTask)) {
remoteMap.put(destTask, new ArrayList<>());
}
remoteMap.get(destTask).add(new TaskMessage(destTask, serializer.serialize(addressedTuple.getTuple())));
}
}
LOG.info("the time of end serializing : {}", System.currentTimeMillis());
if (!local.isEmpty()) {
transferLocal(local);
}
if (!remoteMap.isEmpty()) {
transferQueue.publish(remoteMap);
}
}
.........
}
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.daemon.worker;
public class Worker implements Shutdownable, DaemonCommon {
.........
public void start() throws Exception {
LOG.info("Launching worker for {} on {}:{} with id {} and conf {}", topologyId, assignmentId, port, workerId,
conf);
// because in local mode, its not a separate
// process. supervisor will register it in this case
// if ConfigUtils.isLocalMode(conf) returns false then it is in distributed mode.
if (!ConfigUtils.isLocalMode(conf)) {
// Distributed mode
SysOutOverSLF4J.sendSystemOutAndErrToSLF4J();
String pid = Utils.processPid();
FileUtils.touch(new File(ConfigUtils.workerPidPath(conf, workerId, pid)));
FileUtils.writeStringToFile(new File(ConfigUtils.workerArtifactsPidPath(conf, topologyId, port)), pid,
Charset.forName("UTF-8"));
}
final Map topologyConf =
ConfigUtils.overrideLoginConfigWithSystemProperty(ConfigUtils.readSupervisorStormConf(conf, topologyId));
List acls = Utils.getWorkerACL(topologyConf);
IStateStorage stateStorage =
ClusterUtils.mkStateStorage(conf, topologyConf, acls, new ClusterStateContext(DaemonType.WORKER));
IStormClusterState stormClusterState =
ClusterUtils.mkStormClusterState(stateStorage, acls, new ClusterStateContext());
Credentials initialCredentials = stormClusterState.credentials(topologyId, null);
Map initCreds = new HashMap<>();
if (initialCredentials != null) {
initCreds.putAll(initialCredentials.get_creds());
}
autoCreds = AuthUtils.GetAutoCredentials(topologyConf);
subject = AuthUtils.populateSubject(null, autoCreds, initCreds);
backpressureZnodeTimeoutMs = ObjectReader.getInt(topologyConf.get(Config.BACKPRESSURE_ZNODE_TIMEOUT_SECS)) * 1000;
Subject.doAs(subject, new PrivilegedExceptionAction() {
@Override public Object run() throws Exception {
workerState =
new WorkerState(conf, context, topologyId, assignmentId, port, workerId, topologyConf, stateStorage,
stormClusterState);
// Heartbeat here so that worker process dies if this fails
// it's important that worker heartbeat to supervisor ASAP so that supervisor knows
// that worker is running and moves on
doHeartBeat();
executorsAtom = new AtomicReference<>(null);
// launch heartbeat threads immediately so that slow-loading tasks don't cause the worker to timeout
// to the supervisor
workerState.heartbeatTimer
.scheduleRecurring(0, (Integer) conf.get(Config.WORKER_HEARTBEAT_FREQUENCY_SECS), () -> {
try {
doHeartBeat();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
workerState.executorHeartbeatTimer
.scheduleRecurring(0, (Integer) conf.get(Config.WORKER_HEARTBEAT_FREQUENCY_SECS),
Worker.this::doExecutorHeartbeats);
//11.worker注册相应的回调函数用来接受远程worker发送来的消息。
workerState.registerCallbacks();
workerState.refreshConnections(null);
workerState.activateWorkerWhenAllConnectionsReady();
workerState.refreshStormActive(null);
workerState.runWorkerStartHooks();
List newExecutors = new ArrayList();
for (List e : workerState.getExecutors()) {
if (ConfigUtils.isLocalMode(topologyConf)) {
newExecutors.add(
LocalExecutor.mkExecutor(workerState, e, initCreds)
.execute());
} else {
newExecutors.add(
Executor.mkExecutor(workerState, e, initCreds)
.execute());
}
}
executorsAtom.set(newExecutors);
//10.Worker的传输线程不断的异步从Worker的传输队列中循环调用,不断的批量消费传输队列中的消息。发送到相应的远程Worker中
EventHandler tupleHandler = (packets, seqId, batchEnd) -> workerState
.sendTuplesToRemoteWorker((HashMap>) packets, seqId, batchEnd);
// This thread will publish the messages destined for remote tasks to remote connections
transferThread = Utils.asyncLoop(() -> {
workerState.transferQueue.consumeBatchWhenAvailable(tupleHandler);
return 0L;
});
DisruptorBackpressureCallback disruptorBackpressureHandler =
mkDisruptorBackpressureHandler(workerState);
workerState.transferQueue.registerBackpressureCallback(disruptorBackpressureHandler);
workerState.transferQueue
.setEnableBackpressure((Boolean) topologyConf.get(Config.TOPOLOGY_BACKPRESSURE_ENABLE));
workerState.transferQueue
.setHighWaterMark(ObjectReader.getDouble(topologyConf.get(Config.BACKPRESSURE_DISRUPTOR_HIGH_WATERMARK)));
workerState.transferQueue
.setLowWaterMark(ObjectReader.getDouble(topologyConf.get(Config.BACKPRESSURE_DISRUPTOR_LOW_WATERMARK)));
WorkerBackpressureCallback backpressureCallback = mkBackpressureHandler(topologyConf);
backpressureThread = new WorkerBackpressureThread(workerState.backpressureTrigger, workerState, backpressureCallback);
if ((Boolean) topologyConf.get(Config.TOPOLOGY_BACKPRESSURE_ENABLE)) {
backpressureThread.start();
stormClusterState.topologyBackpressure(topologyId, backpressureZnodeTimeoutMs, workerState::refreshThrottle);
int pollingSecs = ObjectReader.getInt(topologyConf.get(Config.TASK_BACKPRESSURE_POLL_SECS));
workerState.refreshBackpressureTimer.scheduleRecurring(0, pollingSecs, workerState::refreshThrottle);
}
credentialsAtom = new AtomicReference(initialCredentials);
establishLogSettingCallback();
workerState.stormClusterState.credentials(topologyId, Worker.this::checkCredentialsChanged);
workerState.refreshCredentialsTimer.scheduleRecurring(0,
(Integer) conf.get(Config.TASK_CREDENTIALS_POLL_SECS), new Runnable() {
@Override public void run() {
checkCredentialsChanged();
if ((Boolean) topologyConf.get(Config.TOPOLOGY_BACKPRESSURE_ENABLE)) {
checkThrottleChanged();
}
}
});
workerState.checkForUpdatedBlobsTimer.scheduleRecurring(0,
(Integer) conf.getOrDefault(Config.WORKER_BLOB_UPDATE_POLL_INTERVAL_SECS, 10), new Runnable() {
@Override public void run() {
try {
LOG.debug("Checking if blobs have updated");
updateBlobUpdates();
} catch (IOException e) {
// IOException from reading the version files to be ignored
LOG.error(e.getStackTrace().toString());
}
}
});
// The jitter allows the clients to get the data at different times, and avoids thundering herd
if (!(Boolean) topologyConf.get(Config.TOPOLOGY_DISABLE_LOADAWARE_MESSAGING)) {
workerState.refreshLoadTimer.scheduleRecurringWithJitter(0, 1, 500, Worker.this::doRefreshLoad);
}
workerState.refreshConnectionsTimer.scheduleRecurring(0,
(Integer) conf.get(Config.TASK_REFRESH_POLL_SECS), workerState::refreshConnections);
workerState.resetLogLevelsTimer.scheduleRecurring(0,
(Integer) conf.get(Config.WORKER_LOG_LEVEL_RESET_POLL_SECS), logConfigManager::resetLogLevels);
workerState.refreshActiveTimer.scheduleRecurring(0, (Integer) conf.get(Config.TASK_REFRESH_POLL_SECS),
workerState::refreshStormActive);
LOG.info("Worker has topology config {}", Utils.redactValue(topologyConf, Config.STORM_ZOOKEEPER_TOPOLOGY_AUTH_PAYLOAD));
LOG.info("Worker {} for storm {} on {}:{} has finished loading", workerId, topologyId, assignmentId, port);
return this;
};
});
.......................
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.daemon.worker;
public class WorkerState {
........
/**
* WorkerState调用sendTuplesToRemoteWorker将packets发送到相应的远程Worker中。不断的将数据添加到TransferDrainer贮水池中。
* 当数据批次到达批次末尾的时候,然后调用TransferDrainer的send方法将数据将数据发送到远程的Worker中去。
* @param packets
* @param seqId
* @param batchEnd
*/
public void sendTuplesToRemoteWorker(HashMap> packets, long seqId, boolean batchEnd) {
drainer.add(packets);
if (batchEnd) {
ReentrantReadWriteLock.ReadLock readLock = endpointSocketLock.readLock();
try {
readLock.lock();
drainer.send(cachedTaskToNodePort.get(), cachedNodeToPortSocket.get());
} finally {
readLock.unlock();
}
drainer.clear();
}
}
.........
}
TransferDrainer调用Send方法将数据发送到相应的远程Worker进程。
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.utils;
public class TransferDrainer {
private Map>> bundles = new HashMap();
private static final Logger LOG = LoggerFactory.getLogger(TransferDrainer.class);
public void add(HashMap> taskTupleSetMap) {
for (Map.Entry> entry : taskTupleSetMap.entrySet()) {
addListRefToMap(this.bundles, entry.getKey(), entry.getValue());
}
}
public void send(Map taskToNode, Map connections) {
HashMap>> bundleMapByDestination = groupBundleByDestination(taskToNode);
for (Map.Entry>> entry : bundleMapByDestination.entrySet()) {
NodeInfo hostPort = entry.getKey();
IConnection connection = connections.get(hostPort);
if (null != connection) {
ArrayList> bundle = entry.getValue();
Iterator iter = getBundleIterator(bundle);
if (null != iter && iter.hasNext()) {
connection.send(iter);
}
} else {
LOG.warn("Connection is not available for hostPort {}", hostPort);
}
}
}
private HashMap>> groupBundleByDestination(Map taskToNode) {
HashMap>> bundleMap = Maps.newHashMap();
for (Integer task : this.bundles.keySet()) {
NodeInfo hostPort = taskToNode.get(task);
if (hostPort != null) {
for (ArrayList chunk : this.bundles.get(task)) {
addListRefToMap(bundleMap, hostPort, chunk);
}
} else {
LOG.warn("No remote destination available for task {}", task);
}
}
return bundleMap;
}
private void addListRefToMap(Map>> bundleMap,
T key, ArrayList tuples) {
ArrayList> bundle = bundleMap.get(key);
if (null == bundle) {
bundle = new ArrayList>();
bundleMap.put(key, bundle);
}
if (null != tuples && tuples.size() > 0) {
bundle.add(tuples);
}
}
private Iterator getBundleIterator(final ArrayList> bundle) {
if (null == bundle) {
return null;
}
return new Iterator () {
private int offset = 0;
private int size = 0;
{
for (ArrayList list : bundle) {
size += list.size();
}
}
private int bundleOffset = 0;
private Iterator iter = bundle.get(bundleOffset).iterator();
@Override
public boolean hasNext() {
return offset < size;
}
@Override
public TaskMessage next() {
TaskMessage msg;
if (iter.hasNext()) {
msg = iter.next();
} else {
bundleOffset++;
iter = bundle.get(bundleOffset).iterator();
msg = iter.next();
}
if (null != msg) {
offset++;
}
return msg;
}
@Override
public void remove() {
throw new RuntimeException("not supported");
}
};
}
public void clear() {
bundles.clear();
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.daemon.worker;
public class WorkerState {
........
//12.注册回调函数,WorkerState中的registerCallbacks()方法中注册反序列化连接回调函数。
public void registerCallbacks() {
LOG.info("Registering IConnectionCallbacks for {}:{}", assignmentId, port);
receiver.registerRecv(new DeserializingConnectionCallback(topologyConf,
getWorkerTopologyContext(),
this::transferLocal));
}
//14.调用用第一个步骤声明的transferLocal()方法 在Worker内部本地发送到相应的线程
public void transferLocal(List tupleBatch) {
Map> grouped = new HashMap<>();
for (AddressedTuple tuple : tupleBatch) {
Integer executor = taskToShortExecutor.get(tuple.dest);
if (null == executor) {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
continue;
}
List current = grouped.get(executor);
if (null == current) {
current = new ArrayList<>();
grouped.put(executor, current);
}
current.add(tuple);
}
for (Map.Entry> entry : grouped.entrySet()) {
DisruptorQueue queue = shortExecutorReceiveQueueMap.get(entry.getKey());
if (null != queue) {
queue.publish(entry.getValue());
} else {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
}
}
}
//9.不断的对AddressedTuple进行序列化操作,并将要发送到相同的task的AddressedTuple进行打包批量的发送消息。
// 如果需要发送到本地worker的taskid,我们调用WorkerState的transferLocal方法发送到本地。本地发送不需要序列化
// 需要发送到远程Worker的消息,序列化后进行打包成Map>对象发送到Worker的传输队列中去
public void transfer(KryoTupleSerializer serializer, List tupleBatch) {
if (trySerializeLocal) {
assertCanSerialize(serializer, tupleBatch);
}
List local = new ArrayList<>();
Map> remoteMap = new HashMap<>();
LOG.info("the time of start serializing : {}", System.currentTimeMillis());
for (AddressedTuple addressedTuple : tupleBatch) {
int destTask = addressedTuple.getDest();
if (taskIds.contains(destTask)) {
// Local task
local.add(addressedTuple);
} else {
// Using java objects directly to avoid performance issues in java code
if (! remoteMap.containsKey(destTask)) {
remoteMap.put(destTask, new ArrayList<>());
}
remoteMap.get(destTask).add(new TaskMessage(destTask, serializer.serialize(addressedTuple.getTuple())));
}
}
LOG.info("the time of end serializing : {}", System.currentTimeMillis());
if (!local.isEmpty()) {
transferLocal(local);
}
if (!remoteMap.isEmpty()) {
transferQueue.publish(remoteMap);
}
}
.........
}
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.messaging;
/**
* A class that is called when a TaskMessage arrives.
*/
public class DeserializingConnectionCallback implements IConnectionCallback, IMetric {
private static final Logger LOG = LoggerFactory.getLogger(DeserializingConnectionCallback.class);
private final WorkerState.ILocalTransferCallback cb;
private final Map conf;
private final GeneralTopologyContext context;
private final ThreadLocal _des =
new ThreadLocal() {
@Override
protected KryoTupleDeserializer initialValue() {
return new KryoTupleDeserializer(conf, context);
}
};
// Track serialized size of messages.
private final boolean sizeMetricsEnabled;
private final ConcurrentHashMap byteCounts = new ConcurrentHashMap<>();
public DeserializingConnectionCallback(final Map conf, final GeneralTopologyContext context, WorkerState.ILocalTransferCallback callback) {
this.conf = conf;
this.context = context;
cb = callback;
sizeMetricsEnabled = ObjectReader.getBoolean(conf.get(Config.TOPOLOGY_SERIALIZED_MESSAGE_SIZE_METRICS), false);
}
//13.当有消息发送到Worker中时。Worker接收线程从接收队列中读取TaskMessage序列化后的数据,然后将其进行反序列化操作。最终得到带有消息头的AddressTuple。
//然后调用回调函数的transfer方法。
@Override
public void recv(List batch) {
KryoTupleDeserializer des = _des.get();
ArrayList ret = new ArrayList<>(batch.size());
LOG.info("the time of start deserializing : {}", System.currentTimeMillis());
for (TaskMessage message: batch) {
Tuple tuple = des.deserialize(message.message());
AddressedTuple addrTuple = new AddressedTuple(message.task(), tuple);
updateMetrics(tuple.getSourceTask(), message);
ret.add(addrTuple);
}
LOG.info("the time of start deserializing : {}", System.currentTimeMillis());
cb.transfer(ret);
}
/**
* Returns serialized byte count traffic metrics.
* @return Map of metric counts, or null if disabled
*/
@Override
public Object getValueAndReset() {
if (!sizeMetricsEnabled) {
return null;
}
HashMap outMap = new HashMap<>();
for (Map.Entry ent : byteCounts.entrySet()) {
AtomicLong count = ent.getValue();
if (count.get() > 0) {
outMap.put(ent.getKey(), count.getAndSet(0L));
}
}
return outMap;
}
/**
* Update serialized byte counts for each message.
* @param sourceTaskId source task
* @param message serialized message
*/
protected void updateMetrics(int sourceTaskId, TaskMessage message) {
if (sizeMetricsEnabled) {
int dest = message.task();
int len = message.message().length;
String key = Integer.toString(sourceTaskId) + "-" + Integer.toString(dest);
byteCounts.computeIfAbsent(key, k -> new AtomicLong(0L)).addAndGet(len);
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.storm.daemon.worker;
public class WorkerState {
........
//14.调用用第一个步骤声明的transferLocal()方法 在Worker内部本地发送到相应的线程
public void transferLocal(List tupleBatch) {
Map> grouped = new HashMap<>();
for (AddressedTuple tuple : tupleBatch) {
Integer executor = taskToShortExecutor.get(tuple.dest);
if (null == executor) {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
continue;
}
List current = grouped.get(executor);
if (null == current) {
current = new ArrayList<>();
grouped.put(executor, current);
}
current.add(tuple);
}
for (Map.Entry> entry : grouped.entrySet()) {
DisruptorQueue queue = shortExecutorReceiveQueueMap.get(entry.getKey());
if (null != queue) {
queue.publish(entry.getValue());
} else {
LOG.warn("Received invalid messages for unknown tasks. Dropping... ");
}
}
}
.........
}
public class PC {
/**
* 题目:生产者-消费者。
* 同步访问一个数组Integer[10],生产者不断地往数组放入整数1000,数组满时等待;消费者不断地将数组里面的数置零,数组空时等待。
*/
private static final Integer[] val=new Integer[10];
private static
在oracle连接(join)中使用using关键字
34. View the Exhibit and examine the structure of the ORDERS and ORDER_ITEMS tables.
Evaluate the following SQL statement:
SELECT oi.order_id, product_id, order_date
FRO
If i select like this:
SELECT id FROM users WHERE id IN(3,4,8,1);
This by default will select users in this order
1,3,4,8,
I would like to select them in the same order that i put IN() values so:
$(document).ready(
function() {
var flag = true;
$('#changeform').submit(function() {
var projectScValNull = true;
var s ="";
var parent_id = $("#parent_id").v
Mac 在国外很受欢迎,尤其是在 设计/web开发/IT 人员圈子里。普通用户喜欢 Mac 可以理解,毕竟 Mac 设计美观,简单好用,没有病毒。那么为什么专业人士也对 Mac 情有独钟呢?从个人使用经验来看我想有下面几个原因:
1、Mac OS X 是基于 Unix 的
这一点太重要了,尤其是对开发人员,至少对于我来说很重要,这意味着Unix 下一堆好用的工具都可以随手捡到。如果你是个 wi