Java tutorial
/** * 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 com.alibaba.jstorm.message.netty; import backtype.storm.Config; import backtype.storm.messaging.TaskMessage; import backtype.storm.utils.DisruptorQueue; import backtype.storm.utils.Utils; import com.alibaba.jstorm.common.metric.AsmGauge; import com.alibaba.jstorm.common.metric.QueueGauge; import com.alibaba.jstorm.metric.*; import com.alibaba.jstorm.utils.JStormServerUtils; import com.alibaba.jstorm.utils.JStormUtils; import com.alibaba.jstorm.utils.TimeUtils; import com.codahale.metrics.Gauge; import com.lmax.disruptor.EventHandler; import com.lmax.disruptor.WaitStrategy; import com.lmax.disruptor.dsl.ProducerType; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; class NettyClientSync extends NettyClient implements EventHandler { private static final Logger LOG = LoggerFactory.getLogger(NettyClientSync.class); private ConcurrentLinkedQueue<MessageBatch> batchQueue; private DisruptorQueue disruptorQueue; private ExecutorService bossExecutor; private ExecutorService workerExecutor; private AtomicLong emitTs = new AtomicLong(0); @SuppressWarnings("rawtypes") NettyClientSync(Map storm_conf, ChannelFactory factory, ScheduledExecutorService scheduler, String host, int port, ReconnectRunnable reconnector) { super(storm_conf, factory, scheduler, host, port, reconnector); batchQueue = new ConcurrentLinkedQueue<MessageBatch>(); WaitStrategy waitStrategy = (WaitStrategy) Utils .newInstance((String) storm_conf.get(Config.TOPOLOGY_DISRUPTOR_WAIT_STRATEGY)); disruptorQueue = DisruptorQueue.mkInstance(name, ProducerType.MULTI, MAX_SEND_PENDING * 8, waitStrategy); disruptorQueue.consumerStarted(); if (connectMyself == false) { registerSyncMetrics(); } Runnable trigger = new Runnable() { @Override public void run() { trigger(); } }; scheduler.scheduleAtFixedRate(trigger, 10, 1, TimeUnit.SECONDS); /** * In sync mode, it can't directly use common factory, it will occur problem when client close and restart */ ThreadFactory bossFactory = new NettyRenameThreadFactory( MetricDef.NETTY_CLI + JStormServerUtils.getName(host, port) + "-boss"); bossExecutor = Executors.newCachedThreadPool(bossFactory); ThreadFactory workerFactory = new NettyRenameThreadFactory( MetricDef.NETTY_CLI + JStormServerUtils.getName(host, port) + "-worker"); workerExecutor = Executors.newCachedThreadPool(workerFactory); clientChannelFactory = new NioClientSocketChannelFactory(bossExecutor, workerExecutor, 1); start(); LOG.info(this.toString()); } public void registerSyncMetrics() { if (enableNettyMetrics) { JStormMetrics.registerNettyMetric( MetricUtils.nettyMetricName(MetricDef.NETTY_CLI_SYNC_BATCH_QUEUE + nettyConnection.toString(), MetricType.GAUGE), new AsmGauge(new Gauge<Double>() { @Override public Double getValue() { return (double) batchQueue.size(); } })); QueueGauge cacheQueueGauge = new QueueGauge(disruptorQueue, MetricDef.NETTY_CLI_SYNC_DISR_QUEUE, nettyConnection.toString()); JStormMetrics.registerNettyMetric( MetricUtils.nettyMetricName(MetricDef.NETTY_CLI_SYNC_DISR_QUEUE + nettyConnection.toString(), MetricType.GAUGE), new AsmGauge(cacheQueueGauge)); JStormHealthCheck.registerWorkerHealthCheck( MetricDef.NETTY_CLI_SYNC_DISR_QUEUE + ":" + nettyConnection.toString(), cacheQueueGauge); } } /** * Enqueue a task message to be sent to server */ @Override public void send(List<TaskMessage> messages) { for (TaskMessage msg : messages) { disruptorQueue.publish(msg); } } @Override public void send(TaskMessage message) { disruptorQueue.publish(message); } public void flushBatch(MessageBatch batch, Channel channel) { emitTs.set(System.currentTimeMillis()); if (batch == null) { LOG.warn("Handle no data to {}, this shouldn't occur", name); } else if (channel == null || channel.isWritable() == false) { LOG.warn("Channel occur exception, during batch messages {}", name); batchQueue.offer(batch); } else { flushRequest(channel, batch); } } /** * Don't take care of competition */ public void sendData() { long start = System.nanoTime(); try { MessageBatch batch = batchQueue.poll(); if (batch == null) { disruptorQueue.consumeBatchWhenAvailable(this); batch = batchQueue.poll(); } Channel channel = channelRef.get(); flushBatch(batch, channel); } catch (Throwable e) { LOG.error("Occur e", e); String err = name + " nettyclient occur unknow exception"; JStormUtils.halt_process(-1, err); } finally { long end = System.nanoTime(); if (sendTimer != null) { sendTimer.update((end - start) / TimeUtils.NS_PER_US); } } } public void sendAllData() { long start = System.nanoTime(); try { disruptorQueue.consumeBatch(this); MessageBatch batch = batchQueue.poll(); while (batch != null) { Channel channel = channelRef.get(); if (channel == null) { LOG.info("No channel {} to flush all data", name); return; } else if (channel.isWritable() == false) { LOG.info("Channel {} is no writable", name); return; } flushBatch(batch, channel); batch = batchQueue.poll(); } } catch (Throwable e) { LOG.error("Occur e", e); String err = name + " nettyclient occur unknow exception"; JStormUtils.halt_process(-1, err); } finally { long end = System.nanoTime(); if (sendTimer != null) { sendTimer.update((end - start) / TimeUtils.NS_PER_US); } } } @Override public void handleResponse() { emitTs.set(0); sendData(); } @Override public void onEvent(Object event, long sequence, boolean endOfBatch) throws Exception { if (event == null) { return; } TaskMessage message = (TaskMessage) event; MessageBatch messageBatch = messageBatchRef.getAndSet(null); if (null == messageBatch) { messageBatch = new MessageBatch(messageBatchSize); } messageBatch.add(message); if (messageBatch.isFull()) { batchQueue.offer(messageBatch); } else if (endOfBatch == true) { batchQueue.offer(messageBatch); } else { messageBatchRef.set(messageBatch); } } /** * Handle lost message case */ void trigger() { if (isClosed() == true) { return; } // if long time no receive NettyServer response // it is likely lost message long emitTime = emitTs.get(); if (emitTime == 0) { return; } long now = System.currentTimeMillis(); long delt = now - emitTime; if (delt < timeoutMs) { return; } Channel channel = channelRef.get(); if (channel != null) { LOG.info("Long time no response of {}, {}s", name, delt / 1000); channel.write(ControlMessage.EOB_MESSAGE); } } protected void shutdownPool() { bossExecutor.shutdownNow(); workerExecutor.shutdownNow(); try { bossExecutor.awaitTermination(1, TimeUnit.SECONDS); workerExecutor.awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { LOG.error("Error when shutting down client scheduler", e); } clientChannelFactory.releaseExternalResources(); } public void unregisterSyncMetrics() { if (enableNettyMetrics) { JStormMetrics.unregisterNettyMetric(MetricUtils.nettyMetricName( MetricDef.NETTY_CLI_SYNC_BATCH_QUEUE + nettyConnection.toString(), MetricType.GAUGE)); JStormMetrics.unregisterNettyMetric(MetricUtils.nettyMetricName( MetricDef.NETTY_CLI_SYNC_DISR_QUEUE + nettyConnection.toString(), MetricType.GAUGE)); JStormHealthCheck.unregisterWorkerHealthCheck( MetricDef.NETTY_CLI_SYNC_DISR_QUEUE + ":" + nettyConnection.toString()); } } @Override public void close() { LOG.info("Begin to close connection to {} and flush all data, batchQueue {}, disruptor {}", name, batchQueue.size(), disruptorQueue.population()); sendAllData(); disruptorQueue.haltWithInterrupt(); if (connectMyself == false) { unregisterSyncMetrics(); } super.close(); shutdownPool(); } @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); } }