命令中心
命令中心会接收sentinel-dashboard发送过例如添加流控规则,添加熔断规则等命令,将规则写入到客户端。
处理流程
源码追踪
Env中的静态块执行了InitExecutor.doInit()方法,通过SPI加载了所有的InitFunc的实现,其中命令中心的实现为CommandCenterInitFunc。
public class CommandCenterInitFunc implements InitFunc {
@Override
public void init() throws Exception {
// 获取到通过SPI加载的CommandCenter,默认加载的实现为SimpleHttpCommandCenter
CommandCenter commandCenter = CommandCenterProvider.getCommandCenter();
if (commandCenter == null) {
RecordLog.warn("[CommandCenterInitFunc] Cannot resolve CommandCenter");
return;
}
// 获取通过SPI加载的CommandHandler实现,并进行注册
commandCenter.beforeStart();
// 启动命令中心
commandCenter.start();
RecordLog.info("[CommandCenterInit] Starting command center: "
+ commandCenter.getClass().getCanonicalName());
}
commandCenter.start()方法启动命令中心,获取到客户端配置的sentinel通信端口,尝试建立socket如果失败尝试三次后端口号+1,直到找到未被占用的端口并且建立连接。
public void start() throws Exception {
// 获取CPU核心线程数量
int nThreads = Runtime.getRuntime().availableProcessors();
this.bizExecutor = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10),
new NamedThreadFactory("sentinel-command-center-service-executor"),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
CommandCenterLog.info("EventTask rejected");
throw new RejectedExecutionException();
}
});
Runnable serverInitTask = new Runnable() {
int port;
{
try {
port = Integer.parseInt(TransportConfig.getPort());
} catch (Exception e) {
port = DEFAULT_PORT;
}
}
@Override
public void run() {
boolean success = false;
// 根据配置的端口尝试建立连接
ServerSocket serverSocket = getServerSocketFromBasePort(port);
if (serverSocket != null) {
CommandCenterLog.info("[CommandCenter] Begin listening at port " + serverSocket.getLocalPort());
socketReference = serverSocket;
executor.submit(new ServerThread(serverSocket));
success = true;
port = serverSocket.getLocalPort();
} else {
CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work");
}
if (!success) {
port = PORT_UNINITIALIZED;
}
TransportConfig.setRuntimePort(port);
executor.shutdown();
}
};
new Thread(serverInitTask).start();
}
获取到的连接放入新启的线程中,调用erverSocket.accept();方法等待消息,并将接收到的消息放入线程池中进行处理。
class ServerThread extends Thread {
private ServerSocket serverSocket;
ServerThread(ServerSocket s) {
this.serverSocket = s;
setName("sentinel-courier-server-accept-thread");
}
@Override
public void run() {
while (true) {
Socket socket = null;
try {
socket = this.serverSocket.accept();
setSocketSoTimeout(socket);
// 接收到的socket封装到HttpEventTask,加入线程池中执行
HttpEventTask eventTask = new HttpEventTask(socket);
bizExecutor.submit(eventTask);
} catch (Exception e) {
CommandCenterLog.info("Server error", e);
if (socket != null) {
try {
socket.close();
} catch (Exception e1) {
CommandCenterLog.info("Error when closing an opened socket", e1);
}
}
try {
// In case of infinite log.
Thread.sleep(10);
} catch (InterruptedException e1) {
// Indicates the task should stop.
break;
}
}
}
}
解析socket请求,根据请求内容找到对应的CommandHandler实现处理请求,完成添加流控规则,添加熔断规则等操作。
// 获取请求的命令名称并校验
String commandName = HttpCommandUtils.getTarget(request);
if (StringUtil.isBlank(commandName)) {
badRequest(printWriter, "Invalid command");
return;
}
// 根据命令名称找到对应的handler
CommandHandler<?> commandHandler = SimpleHttpCommandCenter.getHandler(commandName);
if (commandHandler != null) {
// 调用handle方法处理请求
CommandResponse<?> response = commandHandler.handle(request);
handleResponse(response, printWriter, outputStream);
} else {
// 没有匹配的handle响应
badRequest(printWriter, "Unknown command `" + commandName + '`');
}
printWriter.flush();