Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.ltsopensource.remoting.AbstractRemoting Maven / Gradle / Ivy
package com.github.ltsopensource.remoting;
import com.github.ltsopensource.core.commons.utils.StringUtils;
import com.github.ltsopensource.core.domain.Pair;
import com.github.ltsopensource.core.logger.Logger;
import com.github.ltsopensource.core.logger.LoggerFactory;
import com.github.ltsopensource.core.support.SystemClock;
import com.github.ltsopensource.remoting.codec.Codec;
import com.github.ltsopensource.remoting.codec.DefaultCodec;
import com.github.ltsopensource.remoting.common.RemotingHelper;
import com.github.ltsopensource.remoting.common.SemaphoreReleaseOnlyOnce;
import com.github.ltsopensource.remoting.common.ServiceThread;
import com.github.ltsopensource.remoting.exception.RemotingSendRequestException;
import com.github.ltsopensource.remoting.exception.RemotingTimeoutException;
import com.github.ltsopensource.remoting.exception.RemotingTooMuchRequestException;
import com.github.ltsopensource.remoting.protocol.RemotingCommand;
import com.github.ltsopensource.remoting.protocol.RemotingCommandHelper;
import com.github.ltsopensource.remoting.protocol.RemotingProtos;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.*;
/**
* Server与Client公用抽象类
*/
public abstract class AbstractRemoting {
private static final Logger LOGGER = LoggerFactory.getLogger(RemotingHelper.RemotingLogName);
// 信号量,Oneway情况会使用,防止本地缓存请求过多
protected final Semaphore semaphoreOneway;
// 信号量,异步调用情况会使用,防止本地缓存请求过多
protected final Semaphore semaphoreAsync;
// 缓存所有对外请求
protected final ConcurrentHashMap responseTable =
new ConcurrentHashMap(256);
// 注册的各个RPC处理器
protected final HashMap> processorTable =
new HashMap>(64);
protected final RemotingEventExecutor remotingEventExecutor = new RemotingEventExecutor();
// 默认请求代码处理器
protected Pair defaultRequestProcessor;
protected final ChannelEventListener channelEventListener;
public AbstractRemoting(final int permitsOneway, final int permitsAsync, ChannelEventListener channelEventListener) {
this.semaphoreOneway = new Semaphore(permitsOneway, true);
this.semaphoreAsync = new Semaphore(permitsAsync, true);
this.channelEventListener = channelEventListener;
}
public ChannelEventListener getChannelEventListener() {
return this.channelEventListener;
}
public void putRemotingEvent(final RemotingEvent event) {
this.remotingEventExecutor.putRemotingEvent(event);
}
public void processRequestCommand(final Channel channel, final RemotingCommand cmd) {
final Pair matched = this.processorTable.get(cmd.getCode());
final Pair pair =
null == matched ? this.defaultRequestProcessor : matched;
if (pair != null) {
Runnable run = new Runnable() {
@Override
public void run() {
try {
final RemotingCommand response = pair.getKey().processRequest(channel, cmd);
// Oneway形式忽略应答结果
if (!RemotingCommandHelper.isOnewayRPC(cmd)) {
if (response != null) {
response.setOpaque(cmd.getOpaque());
RemotingCommandHelper.markResponseType(cmd);
try {
channel.writeAndFlush(response).addListener(new ChannelHandlerListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (!future.isSuccess()) {
LOGGER.error("response to " + RemotingHelper.parseChannelRemoteAddr(channel) + " failed", future.cause());
LOGGER.error(cmd.toString());
LOGGER.error(response.toString());
}
}
});
} catch (Exception e) {
LOGGER.error("process request over, but response failed", e);
LOGGER.error(cmd.toString());
LOGGER.error(response.toString());
}
} else {
// 收到请求,但是没有返回应答,可能是processRequest中进行了应答,忽略这种情况
}
}
} catch (Exception e) {
LOGGER.error("process request exception", e);
LOGGER.error(cmd.toString());
if (!RemotingCommandHelper.isOnewayRPC(cmd)) {
final RemotingCommand response =
RemotingCommand.createResponseCommand(RemotingProtos.ResponseCode.SYSTEM_ERROR.code(),//
StringUtils.toString(e));
response.setOpaque(cmd.getOpaque());
channel.writeAndFlush(response);
}
}
}
};
try {
// 这里需要做流控,要求线程池对应的队列必须是有大小限制的
pair.getValue().submit(run);
} catch (RejectedExecutionException e) {
LOGGER.warn(RemotingHelper.parseChannelRemoteAddr(channel) //
+ ", too many requests and system thread pool busy, RejectedExecutionException " //
+ pair.getKey().toString() //
+ " request code: " + cmd.getCode());
if (!RemotingCommandHelper.isOnewayRPC(cmd)) {
final RemotingCommand response =
RemotingCommand.createResponseCommand(RemotingProtos.ResponseCode.SYSTEM_BUSY.code(),
"too many requests and system thread pool busy, please try another server");
response.setOpaque(cmd.getOpaque());
channel.writeAndFlush(response);
}
}
} else {
String error = " request type " + cmd.getCode() + " not supported";
final RemotingCommand response =
RemotingCommand.createResponseCommand(RemotingProtos.ResponseCode.REQUEST_CODE_NOT_SUPPORTED.code(),
error);
response.setOpaque(cmd.getOpaque());
channel.writeAndFlush(response);
LOGGER.error(RemotingHelper.parseChannelRemoteAddr(channel) + error);
}
}
public void processResponseCommand(Channel channel, RemotingCommand cmd) {
final ResponseFuture responseFuture = responseTable.get(cmd.getOpaque());
if (responseFuture != null) {
responseFuture.setResponseCommand(cmd);
responseFuture.release();
// 异步调用
if (responseFuture.getAsyncCallback() != null) {
boolean runInThisThread = false;
ExecutorService executor = this.getCallbackExecutor();
if (executor != null) {
try {
executor.submit(new Runnable() {
@Override
public void run() {
try {
responseFuture.executeInvokeCallback();
} catch (Exception e) {
LOGGER.warn("execute callback in executor exception, and callback throw", e);
}
}
});
} catch (Exception e) {
runInThisThread = true;
LOGGER.warn("execute callback in executor exception, maybe executor busy", e);
}
} else {
runInThisThread = true;
}
if (runInThisThread) {
try {
responseFuture.executeInvokeCallback();
} catch (Exception e) {
LOGGER.warn("", e);
}
}
}
// 同步调用
else {
responseFuture.putResponse(cmd);
}
} else {
LOGGER.warn("receive response, but not matched any request, "
+ RemotingHelper.parseChannelRemoteAddr(channel));
LOGGER.warn(cmd.toString());
}
responseTable.remove(cmd.getOpaque());
}
public void processMessageReceived(Channel channel, final RemotingCommand cmd) throws Exception {
if (cmd != null) {
switch (RemotingCommandHelper.getRemotingCommandType(cmd)) {
case REQUEST_COMMAND:
processRequestCommand(channel, cmd);
break;
case RESPONSE_COMMAND:
processResponseCommand(channel, cmd);
break;
default:
break;
}
}
}
protected abstract ExecutorService getCallbackExecutor();
public void scanResponseTable() {
Iterator> it = this.responseTable.entrySet().iterator();
while (it.hasNext()) {
Entry next = it.next();
ResponseFuture rep = next.getValue();
if ((rep.getBeginTimestamp() + rep.getTimeoutMillis() + 1000) <= SystemClock.now()) {
it.remove();
rep.release();
try {
rep.executeInvokeCallback();
} catch (Exception e) {
LOGGER.error("scanResponseTable, operationComplete exception", e);
}
LOGGER.warn("remove timeout request, " + rep);
}
}
}
public RemotingCommand invokeSyncImpl(final Channel channel, final RemotingCommand request,
final long timeoutMillis) throws InterruptedException, RemotingSendRequestException,
RemotingTimeoutException {
try {
final ResponseFuture responseFuture =
new ResponseFuture(request.getOpaque(), timeoutMillis, null, null);
this.responseTable.put(request.getOpaque(), responseFuture);
channel.writeAndFlush(request).addListener(new ChannelHandlerListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (future.isSuccess()) {
responseFuture.setSendRequestOK(true);
return;
} else {
responseFuture.setSendRequestOK(false);
}
responseTable.remove(request.getOpaque());
responseFuture.setCause(future.cause());
responseFuture.putResponse(null);
LOGGER.warn("send a request command to channel <" + channel.remoteAddress() + "> failed.");
LOGGER.warn(request.toString());
}
});
RemotingCommand responseCommand = responseFuture.waitResponse(timeoutMillis);
if (null == responseCommand) {
// 发送请求成功,读取应答超时
if (responseFuture.isSendRequestOK()) {
throw new RemotingTimeoutException(RemotingHelper.parseChannelRemoteAddr(channel),
timeoutMillis, responseFuture.getCause());
}
// 发送请求失败
else {
throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel),
responseFuture.getCause());
}
}
return responseCommand;
} finally {
this.responseTable.remove(request.getOpaque());
}
}
public void invokeAsyncImpl(final Channel channel, final RemotingCommand request,
final long timeoutMillis, final AsyncCallback asyncCallback) throws InterruptedException,
RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
boolean acquired = this.semaphoreAsync.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
if (acquired) {
final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreAsync);
final ResponseFuture responseFuture =
new ResponseFuture(request.getOpaque(), timeoutMillis, asyncCallback, once);
this.responseTable.put(request.getOpaque(), responseFuture);
try {
channel.writeAndFlush(request).addListener(new ChannelHandlerListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (future.isSuccess()) {
responseFuture.setSendRequestOK(true);
return;
} else {
responseFuture.setSendRequestOK(false);
}
responseFuture.putResponse(null);
responseFuture.executeInvokeCallback();
responseTable.remove(request.getOpaque());
LOGGER.warn("send a request command to channel <" + channel.remoteAddress() + "> failed.");
LOGGER.warn(request.toString());
}
});
} catch (Exception e) {
once.release();
LOGGER.warn("write send a request command to channel <" + channel.remoteAddress() + "> failed.");
throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
}
} else {
if (timeoutMillis <= 0) {
throw new RemotingTooMuchRequestException("invokeAsyncImpl invoke too fast");
} else {
LOGGER.warn("invokeAsyncImpl tryAcquire semaphore timeout, " + timeoutMillis
+ " waiting thread nums: " + this.semaphoreAsync.getQueueLength());
LOGGER.warn(request.toString());
throw new RemotingTimeoutException("tryAcquire timeout(ms) " + timeoutMillis);
}
}
}
public void invokeOnewayImpl(final Channel channel, final RemotingCommand request,
final long timeoutMillis) throws InterruptedException, RemotingTooMuchRequestException,
RemotingTimeoutException, RemotingSendRequestException {
RemotingCommandHelper.markOnewayRPC(request);
boolean acquired = this.semaphoreOneway.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
if (acquired) {
final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreOneway);
try {
channel.writeAndFlush(request).addListener(new ChannelHandlerListener() {
@Override
public void operationComplete(Future future) throws Exception {
once.release();
if (!future.isSuccess()) {
LOGGER.warn("send a request command to channel <" + channel.remoteAddress()
+ "> failed.");
LOGGER.warn(request.toString());
}
}
});
} catch (Exception e) {
once.release();
LOGGER.warn("write send a request command to channel <" + channel.remoteAddress() + "> failed.");
throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
}
} else {
if (timeoutMillis <= 0) {
throw new RemotingTooMuchRequestException("invokeOnewayImpl invoke too fast");
} else {
LOGGER.warn("invokeOnewayImpl tryAcquire semaphore timeout, " + timeoutMillis
+ " waiting thread nums: " + this.semaphoreOneway.getQueueLength());
LOGGER.warn(request.toString());
throw new RemotingTimeoutException("tryAcquire timeout(ms) " + timeoutMillis);
}
}
}
class RemotingEventExecutor extends ServiceThread {
private final LinkedBlockingQueue eventQueue = new LinkedBlockingQueue();
private final int MaxSize = 10000;
public void putRemotingEvent(final RemotingEvent event) {
if (this.eventQueue.size() <= MaxSize) {
this.eventQueue.add(event);
} else {
LOGGER.warn("event queue size[{}] enough, so drop this event {}", this.eventQueue.size(),
event.toString());
}
}
@Override
public void run() {
LOGGER.info(this.getServiceName() + " service started");
final ChannelEventListener listener = AbstractRemoting.this.getChannelEventListener();
while (!this.isStopped()) {
try {
RemotingEvent event = this.eventQueue.poll(3000, TimeUnit.MILLISECONDS);
if (event != null) {
switch (event.getType()) {
case ALL_IDLE:
listener.onChannelIdle(IdleState.ALL_IDLE, event.getRemoteAddr(), event.getChannel());
break;
case WRITER_IDLE:
listener.onChannelIdle(IdleState.WRITER_IDLE, event.getRemoteAddr(), event.getChannel());
break;
case READER_IDLE:
listener.onChannelIdle(IdleState.READER_IDLE, event.getRemoteAddr(), event.getChannel());
break;
case CLOSE:
listener.onChannelClose(event.getRemoteAddr(), event.getChannel());
break;
case CONNECT:
listener.onChannelConnect(event.getRemoteAddr(), event.getChannel());
break;
case EXCEPTION:
listener.onChannelException(event.getRemoteAddr(), event.getChannel());
break;
default:
break;
}
}
} catch (Exception e) {
LOGGER.warn(this.getServiceName() + " service has exception. ", e);
}
}
LOGGER.info(this.getServiceName() + " service end");
}
@Override
public String getServiceName() {
return RemotingEventExecutor.class.getSimpleName();
}
}
protected Codec getCodec() {
// TODO 改为SPI
return new DefaultCodec();
}
}