Sentinel通信模块解析

Sentinel通信模块解析

概览

在Sentinel中有两个模块需要进行远程通信,分别是Sentinel Client与Dashboard的通信以及Sentinel Client与Token Server的通信,分别位于Sentinel项目中的sentinel-transport模块与sentinel-cluster模块。其中Sentinel Client与Dashboard之间相互通信采用的是传统HTTP方式,Client开放HTTP接口接收来自Dashboard的控制指令,Dashboard开放HTTP接口接收来自Client的数据上报。而Sentinel Client与Token Server的通信采用的TCP长链接的方式。

image-20210722161912357.png

Sentinel-Transport

sentinel-transport项目是用于Sentinel Client接收控制命令的,coomon子模块定义了一些通用的基础抽象类,例如请求体、请求响应体、命令处理器等等。实际的通信功能是由其余的子模块来提供的,目前提供了由netty、nio以及spring-mvc实现的三种不同HTTP端点。通常情况下我们希望sentinel的控制端口能够与业务的web端口分离,sentinel端口不对外暴露,所以一般采用的transport都是netty-http或是simple-http,这里我们着重来看一下netty实现的http transport。

netty server相关功能是由HttpServer类负责实现的,而启动是由NettyHttpCommandCenter负责的。NettyHttpCommandCenter实现了CommandCenter接口,这个接口定义了beforeStart、start、stop三个函数,从定义上来看CommandCenter更像是Lifecycle Listener,并没有定义命令处理的相关接口。那么CommandCenter的beforeStart、start是由谁负责调用的呢?在Sentinel中InitExecutor负责初始化所有实现了InitFunc的接口的实现类,其中查找所有实现InitFunc接口的实现类并不是采用我们常见的Bean查找的方式,而是利用自实现的SpiLoader在META-INF/services/目录下的文件定义来加载所有的实现类。

@InitOrder(-1)
public class CommandCenterInitFunc implements InitFunc {
   

    @Override
    public void init() throws Exception {
   
        CommandCenter commandCenter = CommandCenterProvider.getCommandCenter();

        if (commandCenter == null) {
   
            RecordLog.warn("[CommandCenterInitFunc] Cannot resolve CommandCenter");
            return;
        }

        commandCenter.beforeStart();
        commandCenter.start();
        RecordLog.info("[CommandCenterInit] Starting command center: "
                + commandCenter.getClass().getCanonicalName());
    }
}

在NettyHttpCommandCenter中首先初始化一个HttpServer对象,这里比较特别的是NettyHttpCommandCenter并没有通过直接创建一个线程的方式来启动Netty server,而是使用了一个单线程的线程池,将启动任务提交至线程池中,这么做的好处是方便了线程的管理。

@Override
public void start() throws Exception {
   
    pool.submit(new Runnable() {
   
        @Override
        public void run() {
   
            try {
   
                server.start();
            } catch (Exception ex) {
   
                RecordLog.warn("[NettyHttpCommandCenter] Failed to start Netty transport server", ex);
                ex.printStackTrace();
            }
        }
    });
}

接着来看下Sentinel对于Netty的使用,从HttpServer的start函数中我们可以很直观的看到与Seata的Netty Server不同的是,Sentinel并没有做过多的设置,只是完成了简单的HTTP功能的初始化,其中HttpServerHandler则是处理Http请求的关键类。

public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
   

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
   
        ChannelPipeline p = socketChannel.pipeline();

        p.addLast(new HttpRequestDecoder());
        p.addLast(new HttpObjectAggregator(1024 * 1024));
        p.addLast(new HttpResponseEncoder());

        p.addLast(new HttpServerHandler());
    }
}

HttpServerHandler继承自SimpleChannelInboundHandler,整体处理的逻辑也比较直观,将Http请求解析成CommandRequest对象,根据请求的Request Target找到命令处理器CommandHandler,处理完请求后返回CommandResponse对象。

private void handleRequest(CommandRequest request, ChannelHandlerContext ctx, boolean keepAlive)
    throws Exception {
   
    String commandName = HttpCommandUtils.getTarget(request);
    // Find the matching command handler.
    CommandHandler<?> commandHandler = getHandler(commandName);
    if (commandHandler != null) {
   
        CommandResponse<?> response = commandHandler.handle(request)<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值