/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed 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.weibo.api.motan.transport.netty;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import com.weibo.api.motan.common.ChannelState;
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.core.DefaultThreadFactory;
import com.weibo.api.motan.exception.MotanFrameworkException;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.rpc.Response;
import com.weibo.api.motan.rpc.URL;
import com.weibo.api.motan.transport.AbstractServer;
import com.weibo.api.motan.transport.MessageHandler;
import com.weibo.api.motan.transport.TransportException;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.StatisticCallback;
import com.weibo.api.motan.util.StatsUtil;
/**
*
* <pre>
* netty server 的相关优化
* 1) server 的 executor handler 相关防护
* 2) server 的 隔离保护,不同方法。
* 3) 线程池调优
* 4) client 请求drop (提供主动和被动策略)
* 5) 增加降级开关。
* 6) server 端的超时控制
* 7) 关注 OOM的问题
* 8) Queue 大小的设置
* 9) server端接收包的大小限制
* </pre>
*
* @author maijunsheng
*
*/
public class NettyServer extends AbstractServer implements StatisticCallback {
// default io thread is Runtime.getRuntime().availableProcessors() * 2
private final static ChannelFactory channelFactory = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(new DefaultThreadFactory("nettyServerBoss", true)),
Executors.newCachedThreadPool(new DefaultThreadFactory("nettyServerWorker", true)));
// 单端口需要对应单executor 1) 为了更好的隔离性 2) 为了防止被动releaseExternalResources:
private StandardThreadExecutor standardThreadExecutor = null;
protected NettyServerChannelManage channelManage = null;
private org.jboss.netty.channel.Channel serverChannel;
private ServerBootstrap bootstrap;
private MessageHandler messageHandler;
public NettyServer(URL url, MessageHandler messageHandler) {
super(url);
this.messageHandler = messageHandler;
}
@Override
public Response request(Request request) throws TransportException {
throw new MotanFrameworkException("NettyServer request(Request request) method unsupport: url: " + url);
}
@Override
public synchronized boolean open() {
if (isAvailable()) {
LoggerUtil.warn("NettyServer ServerChannel already Open: url=" + url);
return true;
}
LoggerUtil.info("NettyServer ServerChannel start Open: url=" + url);
initServerBootstrap();
serverChannel = bootstrap.bind(new InetSocketAddress(url.getPort()));
state = ChannelState.ALIVE;
StatsUtil.registryStatisticCallback(this);
LoggerUtil.info("NettyServer ServerChannel finish Open: url=" + url);
return state.isAliveState();
}
private synchronized void initServerBootstrap() {
boolean shareChannel = url.getBooleanParameter(URLParamType.shareChannel.getName(),
URLParamType.shareChannel.getBooleanValue());
final int maxContentLength = url.getIntParameter(URLParamType.maxContentLength.getName(),
URLParamType.maxContentLength.getIntValue());
int maxServerConnection = url.getIntParameter(URLParamType.maxServerConnection.getName(),
URLParamType.maxServerConnection.getIntValue());
int workerQueueSize = url.getIntParameter(URLParamType.workerQueueSize.getName(),
URLParamType.workerQueueSize.getIntValue());
int minWorkerThread = 0, maxWorkerThread = 0;
if (shareChannel) {
minWorkerThread = url.getIntParameter(URLParamType.minWorkerThread.getName(),
MotanConstants.NETTY_SHARECHANNEL_MIN_WORKDER);
maxWorkerThread = url.getIntParameter(URLParamType.maxWorkerThread.getName(),
MotanConstants.NETTY_SHARECHANNEL_MAX_WORKDER);
} else {
minWorkerThread = url.getIntParameter(URLParamType.minWorkerThread.getName(),
MotanConstants.NETTY_NOT_SHARECHANNEL_MIN_WORKDER);
maxWorkerThread = url.getIntParameter(URLParamType.maxWorkerThread.getName(),
MotanConstants.NETTY_NOT_SHARECHANNEL_MAX_WORKDER);
}
standardThreadExecutor = (standardThreadExecutor != null && !standardThreadExecutor.isShutdown()) ? standardThreadExecutor
: new StandardThreadExecutor(minWorkerThread, maxWorkerThread, workerQueueSize,
new DefaultThreadFactory("NettyServer-" + url.getServerPortStr(), true));
standardThreadExecutor.prestartAllCoreThreads();
// 连接数的管理,进行最大连接数的限制
channelManage = new NettyServerChannelManage(maxServerConnection);
bootstrap = new ServerBootstrap(channelFactory);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
final NettyChannelHandler handler = new NettyChannelHandler(NettyServer.this, messageHandler,
standardThreadExecutor);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
// FrameDecoder非线程安全,每个连接一个 Pipeline
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("channel_manage", channelManage);
pipeline.addLast("decoder", new NettyDecoder(codec, NettyServer.this, maxContentLength));
pipeline.addLast("encoder", new NettyEncoder(codec, NettyServer.this));
pipeline.addLast("handler", handler);
return pipeline;
}
});
}
@Override
public synchronized void close() {
close(0);
}
@Override
public synchronized void close(int timeout) {
if (state.isCloseState()) {
LoggerUtil.info("NettyServer close fail: already close, url={}", url.getUri());
return;
}
if (state.isUnInitState()) {
LoggerUtil.info("NettyServer close Fail: don't need to close because node is unInit state: url={}",
url.getUri());
return;
}
try {
// close listen socket
serverChannel.close();
// close all clients's channel
channelManage.close();
// shutdown the threadPool
standardThreadExecutor.shutdownNow();
// 设置close状态
state = ChannelState.CLOSE;
// 取消统计回调的注册
StatsUtil.unRegistryStatisticCallback(this);
LoggerUtil.info("NettyServer close Success: url={}", url.getUri());
} catch (Exception e) {
LoggerUtil.error("NettyServer close Error: url=" + url.getUri(), e);
}
}
@Override
public boolean isClosed() {
return state.isCloseState();
}
@Override
public boolean isAvailable() {
return state.isAliveState();
}
@Override
public URL getUrl() {
return url;
}
/**
* 统计回调接口
*/
@Override
public String statisticCallback() {
return String.format(
"identity: %s connectionCount: %s taskCount: %s queueCount: %s maxThreadCount: %s maxTaskCount: %s",
url.getIdentity(), channelManage.getChannels().size(), standardThreadExecutor.getSubmittedTasksCount(),
standardThreadExecutor.getQueue().size(), standardThreadExecutor.getMaximumPoolSize(),
standardThreadExecutor.getMaxSubmittedTaskCount());
}
/**
* 是否已经绑定端口
*/
@Override
public boolean isBound() {
return serverChannel != null && serverChannel.isBound();
}
public MessageHandler getMessageHandler() {
return messageHandler;
}
public void setMessageHandler(MessageHandler messageHandler) {
this.messageHandler = messageHandler;
}
}