• sofa-rpc 服务端源码流程走读


    sofa-rpc是阿里开源的一款高性能的rpc框架,这篇文章主要是对sofa-rpc provider启动服务流程的一个代码走读,下面是我简单绘制的一个基本的关系流程图

    下面我们根据sofa-rpc代码,对流程进行一个跟踪与走读。我们以BoltServer的为例

        public static void main(String[] args) {
            ApplicationConfig application = new ApplicationConfig().setAppName("test-server");
    
            ServerConfig serverConfig = new ServerConfig()
                .setPort(22000)
                .setDaemon(false);
    
            ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
                .setInterfaceId(HelloService.class.getName())
                .setApplication(application)
                .setRef(new HelloServiceImpl())
                .setServer(serverConfig)
                .setRegister(false);
    
            ProviderConfig<EchoService> providerConfig2 = new ProviderConfig<EchoService>()
                .setInterfaceId(EchoService.class.getName())
                .setApplication(application)
                .setRef(new EchoServiceImpl())
                .setServer(serverConfig)
                .setRegister(false);
    
            providerConfig.export();
            providerConfig2.export();
    
            LOGGER.warn("started at pid {}", RpcRuntimeContext.PID);
        }

    可以看到sofa-rpc通过ProviderConfig类对服务提供方Provider进行了配置信息的初始化,同时也提供了export做为服务启动的入口。

        public synchronized void export() {
            if (providerBootstrap == null) {
                providerBootstrap = Bootstraps.from(this);
            }
            providerBootstrap.export();
        }
    根据ProviderConfig中setBootstrap()配置的Bootstrap类型,我们通过Bootstaps.from(this)可以获取到不同的Bootstrap引导服务,分别是DefaultProviderBootstrap与 DubboProviderBootstrap 
        /**
         * 发布一个服务
         *
         * @param providerConfig 服务发布者配置
         * @param <T>            接口类型
         * @return 发布启动类
         */
        public static <T> ProviderBootstrap<T> from(ProviderConfig<T> providerConfig) {
            String bootstrap = providerConfig.getBootstrap();
            if (StringUtils.isEmpty(bootstrap)) {
                // Use default provider bootstrap 无的话就返回默认DefaultProviderBootstrap
                bootstrap = RpcConfigs.getStringValue(RpcOptions.DEFAULT_PROVIDER_BOOTSTRAP);
                providerConfig.setBootstrap(bootstrap);
            }
            ProviderBootstrap providerBootstrap = ExtensionLoaderFactory.getExtensionLoader(ProviderBootstrap.class)
                .getExtension(bootstrap, new Class[] { ProviderConfig.class }, new Object[] { providerConfig });
            return (ProviderBootstrap<T>) providerBootstrap;
        }
    
    

    DefaultProviderBootstrap与 DubboProviderBootstrap 都继承自ProviderBootstrap。

    DefaultProviderBootstrap又被BoltProviderBootstrap、Http2ClearTextProviderBootstrap、RestProviderBootstrap三个类所继承,这其实对应了sofa-rpc中的三种server服务方式。

    我们看下DefaultProviderBootstrap服务启动源码

        @Override
        public void export() {
            if (providerConfig.getDelay() > 0) { // 延迟加载,单位毫秒
                Thread thread = factory.newThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(providerConfig.getDelay());
                        } catch (Throwable ignore) { // NOPMD
                        }
                        doExport();
                    }
                });
                thread.start();
            } else {
                doExport();
            }
        }
    
        private void doExport() {
            if (exported) {
                return;
            }
    
            // 检查参数
            checkParameters();
    
            String appName = providerConfig.getAppName();
    
            //key  is the protocol of server,for concurrent safe
            Map<String, Boolean> hasExportedInCurrent = new ConcurrentHashMap<String, Boolean>();
            // 将处理器注册到server
            List<ServerConfig> serverConfigs = providerConfig.getServer();
            for (ServerConfig serverConfig : serverConfigs) {
                String protocol = serverConfig.getProtocol();
    
                String key = providerConfig.buildKey() + ":" + protocol;
    
                if (LOGGER.isInfoEnabled(appName)) {
                    LOGGER.infoWithApp(appName, "Export provider config : {} with bean id {}", key, providerConfig.getId());
                }
    
                // 注意同一interface,同一uniqleId,不同server情况
                AtomicInteger cnt = EXPORTED_KEYS.get(key); // 计数器
                if (cnt == null) { // 没有发布过
                    cnt = CommonUtils.putToConcurrentMap(EXPORTED_KEYS, key, new AtomicInteger(0));
                }
                int c = cnt.incrementAndGet();
                hasExportedInCurrent.put(serverConfig.getProtocol(), true);
                int maxProxyCount = providerConfig.getRepeatedExportLimit();
                if (maxProxyCount > 0) {
                    if (c > maxProxyCount) {
                        decrementCounter(hasExportedInCurrent);
                        // 超过最大数量,直接抛出异常
                        throw new SofaRpcRuntimeException("Duplicate provider config with key " + key
                            + " has been exported more than " + maxProxyCount + " times!"
                            + " Maybe it's wrong config, please check it."
                            + " Ignore this if you did that on purpose!");
                    } else if (c > 1) {
                        if (LOGGER.isInfoEnabled(appName)) {
                            LOGGER.infoWithApp(appName, "Duplicate provider config with key {} has been exported!"
                                + " Maybe it's wrong config, please check it."
                                + " Ignore this if you did that on purpose!", key);
                        }
                    }
                }
    
            }
    
            try {
                // 构造请求调用器
                providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
                // 初始化注册中心
                if (providerConfig.isRegister()) {
                    List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
                    if (CommonUtils.isNotEmpty(registryConfigs)) {
                        for (RegistryConfig registryConfig : registryConfigs) {
                            RegistryFactory.getRegistry(registryConfig); // 提前初始化Registry
                        }
                    }
                }
                // 将处理器注册到server
                for (ServerConfig serverConfig : serverConfigs) {
                    try {
                        //构建Server
                        Server server = serverConfig.buildIfAbsent();
                        // 注册序列化接口
                        server.registerProcessor(providerConfig, providerProxyInvoker);
                        if (serverConfig.isAutoStart()) {
                            //启动服务
                            server.start();
                        }
    
                    } catch (SofaRpcRuntimeException e) {
                        throw e;
                    } catch (Exception e) {
                        LOGGER.errorWithApp(appName, "Catch exception when register processor to server: "
                            + serverConfig.getId(), e);
                    }
                }
    
                // 注册到注册中心
                providerConfig.setConfigListener(new ProviderAttributeListener());
                register();
            } catch (Exception e) {
                decrementCounter(hasExportedInCurrent);
    
                if (e instanceof SofaRpcRuntimeException) {
                    throw (SofaRpcRuntimeException) e;
                } else {
                    throw new SofaRpcRuntimeException("Build provider proxy error!", e);
                }
            }
    
            // 记录一些缓存数据
            RpcRuntimeContext.cacheProviderConfig(this);
            exported = true;
        }

    代码中通过serverConfig.buildIfAbsent()构建Server服务对象,而在buildIfAbsent()函数中我们可以看到,sever是通过SeverFactory工厂获取到的,在SeverFactory的getSever()中根据SeverConfig的配置获取Sever的具体实例,并执行Init()进行初始化。

        /**
         * 启动服务
         *
         * @return the server
         */
        public synchronized Server buildIfAbsent() {
            if (server != null) {
                return server;
            }
            // 提前检查协议+序列化方式
            // ConfigValueHelper.check(ProtocolType.valueOf(getProtocol()),
            //                SerializationType.valueOf(getSerialization()));
            
            //在sever工厂中拿到sever实例
            server = ServerFactory.getServer(this);
            return server;
        }
        /**
         * 初始化Server实例
         *
         * @param serverConfig 服务端配置
         * @return Server
         */
        public synchronized static Server getServer(ServerConfig serverConfig) {
            try {
                Server server = SERVER_MAP.get(Integer.toString(serverConfig.getPort()));
                if (server == null) {
                    // 算下网卡和端口
                    resolveServerConfig(serverConfig);
    
                    ExtensionClass<Server> ext = ExtensionLoaderFactory.getExtensionLoader(Server.class)
                        .getExtensionClass(serverConfig.getProtocol());
                    if (ext == null) {
                        throw ExceptionUtils.buildRuntime("server.protocol", serverConfig.getProtocol(),
                            "Unsupported protocol of server!");
                    }
                    server = ext.getExtInstance();
                    //服务初始化
                    server.init(serverConfig);
                    SERVER_MAP.put(serverConfig.getPort() + "", server);
                }
                return server;
            } catch (SofaRpcRuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new SofaRpcRuntimeException(e.getMessage(), e);
            }
        }

    sofa-rpc提供了三种server类型 BoltServer,RestServer与AbstractHttpServer

    BoltServer中通讯底层通过RemotingServer实现的,RemotingServer是基于阿里sofa-bolt通信框架开发的。

        /**
         * Bolt服务端
         */
        protected RemotingServer       remotingServer;
    
       @Override
        public void start() {
            if (started) {
                return;
            }
            synchronized (this) {
                if (started) {
                    return;
                }
                // 生成阿里基于netty的bolt服务Server对象 
                remotingServer = initRemotingServer();
                try {
                    if (remotingServer.start(serverConfig.getBoundHost())) {
                        if (LOGGER.isInfoEnabled()) {
                            LOGGER.info("Bolt server has been bind to {}:{}", serverConfig.getBoundHost(),
                                serverConfig.getPort());
                        }
                    } else {
                        throw new SofaRpcRuntimeException("Failed to start bolt server, see more detail from bolt log.");
                    }
                    started = true;
    
                    if (EventBus.isEnable(ServerStartedEvent.class)) {
                        EventBus.post(new ServerStartedEvent(serverConfig, bizThreadPool));
                    }
    
                } catch (SofaRpcRuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw new SofaRpcRuntimeException("Failed to start bolt server!", e);
                }
            }
        }

    AbstractHttpServer 提供http服务,底层通信通过ServerTransport类实现的

        /**
         * 服务端通讯层
         */
        private ServerTransport         serverTransport;
    
        @Override
        public void init(ServerConfig serverConfig) {
            this.serverConfig = serverConfig;
            this.serverTransportConfig = convertConfig(serverConfig);
            // 启动线程池
            this.bizThreadPool = initThreadPool(serverConfig);
            // 服务端处理器
            this.serverHandler = new HttpServerHandler();
    
            // set default transport config
            this.serverTransportConfig.setContainer(container);
            this.serverTransportConfig.setServerHandler(serverHandler);
        }
    
        @Override
        public void start() {
            if (started) {
                return;
            }
            synchronized (this) {
                if (started) {
                    return;
                }
                try {
                    // 启动线程池
                    this.bizThreadPool = initThreadPool(serverConfig);
                    this.serverHandler.setBizThreadPool(bizThreadPool);
                    //实例化服务,具体代码见
                    serverTransport = ServerTransportFactory.getServerTransport(serverTransportConfig);
                    started = serverTransport.start();
    
                    if (started) {
                        if (EventBus.isEnable(ServerStartedEvent.class)) {
                            EventBus.post(new ServerStartedEvent(serverConfig, bizThreadPool));
                        }
                    }
                } catch (SofaRpcRuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw new SofaRpcRuntimeException("Failed to start HTTP/2 server!", e);
                }
            }
        }

    ServerTransport是个抽象类,具体实现为transport包下AbstractHttp2ServerTransport

        /**
         * 构造函数
         *
         * @param transportConfig 服务端配置
         */
        protected AbstractHttp2ServerTransport(ServerTransportConfig transportConfig) {
            super(transportConfig);
        }
    
     @Override
        public boolean start() {
            if (serverBootstrap != null) {
                return true;
            }
            synchronized (this) {
                if (serverBootstrap != null) {
                    return true;
                }
                boolean flag = false;
                SslContext sslCtx = SslContextBuilder.build();
    
                // Configure the server.
                EventLoopGroup bossGroup = NettyHelper.getServerBossEventLoopGroup(transportConfig);
    
                //可以看到然是基于Netty
                HttpServerHandler httpServerHandler = (HttpServerHandler) transportConfig.getServerHandler();
                bizGroup = NettyHelper.getServerBizEventLoopGroup(transportConfig, httpServerHandler.getBizThreadPool());
    
                serverBootstrap = new ServerBootstrap();
    
                serverBootstrap.group(bossGroup, bizGroup)
                    .channel(transportConfig.isUseEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, transportConfig.getBacklog())
                    .option(ChannelOption.SO_REUSEADDR, transportConfig.isReuseAddr())
                    .option(ChannelOption.RCVBUF_ALLOCATOR, NettyHelper.getRecvByteBufAllocator())
                    .option(ChannelOption.ALLOCATOR, NettyHelper.getByteBufAllocator())
                    .childOption(ChannelOption.SO_KEEPALIVE, transportConfig.isKeepAlive())
                    .childOption(ChannelOption.TCP_NODELAY, transportConfig.isTcpNoDelay())
                    .childOption(ChannelOption.SO_RCVBUF, 8192 * 128)
                    .childOption(ChannelOption.SO_SNDBUF, 8192 * 128)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .childOption(ChannelOption.ALLOCATOR, NettyHelper.getByteBufAllocator())
                    .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(
                        transportConfig.getBufferMin(), transportConfig.getBufferMax()))
                    .childHandler(new Http2ServerChannelInitializer(bizGroup, sslCtx,
                        httpServerHandler, transportConfig.getPayload()));
    
                // 绑定到全部网卡 或者 指定网卡
                ChannelFuture future = serverBootstrap.bind(
                    new InetSocketAddress(transportConfig.getHost(), transportConfig.getPort()));
                ChannelFuture channelFuture = future.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            if (LOGGER.isInfoEnabled()) {
                                LOGGER.info("HTTP/2 Server bind to {}:{} success!",
                                    transportConfig.getHost(), transportConfig.getPort());
                            }
                        } else {
                            LOGGER.error("HTTP/2 Server bind to {}:{} failed!",
                                transportConfig.getHost(), transportConfig.getPort());
                            stop();
                        }
                    }
                });
    
                try {
                    channelFuture.await();
                    if (channelFuture.isSuccess()) {
                        flag = Boolean.TRUE;
                    } else {
                        throw new SofaRpcRuntimeException("Server start fail!", future.cause());
                    }
                } catch (InterruptedException e) {
                    LOGGER.error(e.getMessage(), e);
                }
                return flag;
            }
        }

    RestServer 提供Rest服务,底层通信实现具体可见SofaNettyJaxrsServer。

        /**
         * Rest服务端
         */
        protected SofaNettyJaxrsServer httpServer;
    
        @Override
        public void init(ServerConfig serverConfig) {
            this.serverConfig = serverConfig;
            httpServer = buildServer();
        }

    SofaNettyJaxrsServer中服务启动的具体代码

     @Override
        public void start() {
            // CHANGE: 增加线程名字
            boolean daemon = serverConfig.isDaemon();
            boolean isEpoll = serverConfig.isEpoll();
            NamedThreadFactory ioFactory = new NamedThreadFactory("SEV-REST-IO-" + port, daemon);
            NamedThreadFactory bizFactory = new NamedThreadFactory("SEV-REST-BIZ-" + port, daemon);
            eventLoopGroup = isEpoll ? new EpollEventLoopGroup(ioWorkerCount, ioFactory)
                : new NioEventLoopGroup(ioWorkerCount, ioFactory);
            eventExecutor = isEpoll ? new EpollEventLoopGroup(executorThreadCount, bizFactory)
                : new NioEventLoopGroup(executorThreadCount, bizFactory);
            // Configure the server.
            bootstrap = new ServerBootstrap()
                .group(eventLoopGroup)
                .channel(isEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .childHandler(createChannelInitializer())
                .option(ChannelOption.SO_BACKLOG, backlog)
                .childOption(ChannelOption.SO_KEEPALIVE, serverConfig.isKeepAlive()); // CHANGE: setKeepAlive
    
            for (Map.Entry<ChannelOption, Object> entry : channelOptions.entrySet()) {
                bootstrap.option(entry.getKey(), entry.getValue());
            }
    
            for (Map.Entry<ChannelOption, Object> entry : childChannelOptions.entrySet()) {
                bootstrap.childOption(entry.getKey(), entry.getValue());
            }
    
            final InetSocketAddress socketAddress;
            if (null == hostname || hostname.isEmpty()) {
                socketAddress = new InetSocketAddress(port);
            } else {
                socketAddress = new InetSocketAddress(hostname, port);
            }
    
            bootstrap.bind(socketAddress).syncUninterruptibly();
        }

     OK,以上就是sofa-rpc服务端启动的一个基本的流程,这里关注的只是简单的服务启动流程,没有深入代码功能进行分析,在此基础上,我们可以进一步探究代码的具体实现。

    关注微信公众号,查看更多技术文章。

  • 相关阅读:
    [加密]公钥密码学和对称加密
    [加密]公钥/私钥/数字签名理解
    [加密]对称加密和非对称加密
    [进程]kill 9和15,以及pkill, killall
    [服务]Crontab和每隔10S执行一次
    sh脚本异常:/bin/sh^M:bad interpreter: No such file or directory
    前端利器躬行记(2)——Babel
    前端利器躬行记(1)——npm
    React躬行记(13)——React Router
    React躬行记(12)——Redux中间件
  • 原文地址:https://www.cnblogs.com/dafanjoy/p/9762366.html
Copyright © 2020-2023  润新知