Sentinel源码解析之命令中心

命令中心

命令中心会接收sentinel-dashboard发送过例如添加流控规则,添加熔断规则等命令,将规则写入到客户端。

处理流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-owA94JTM-1636547474509)(C:\Users\易讯通\AppData\Roaming\Typora\typora-user-images\image-20211110201029857.png)]

源码追踪

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();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值