3、SOFA RPC 源码解析 —— 服务调用篇

前两讲过了SOFA RPC的服务发布SPI,再次基础上我们在讲一下服务调用,也就是consumer端,我们首先看一段SOFA RPC的example上面的一段代码:

/**
 * Quick Start client
 */
public class QuickStartClient {

    private final static Logger LOGGER = LoggerFactory.getLogger(QuickStartClient.class);

    public static void main(String[] args) {

        ConsumerConfig<HelloService> consumerConfig = new ConsumerConfig<HelloService>()
            .setInterfaceId(HelloService.class.getName()) // 指定接口
            .setProtocol("bolt") // 指定协议
            .setDirectUrl("bolt://127.0.0.1:12200") // 指定直连地址
            .setConnectTimeout(10 * 1000);

        HelloService helloService = consumerConfig.refer();

        while (true) {
            try {
                LOGGER.info(helloService.sayHello("world"));
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

    /**
     * 引用服务
     *
     * @return 服务代理类 t
     */
    public T refer() {
        if (consumerBootstrap == null) {
            consumerBootstrap = Bootstraps.from(this);
        }
        return consumerBootstrap.refer();
    }

这个发布我们就以DefaultConsumerBootstrap为例

    public T refer() {
        if (proxyIns != null) {
            return proxyIns;
        }
        synchronized (this) {
            if (proxyIns != null) {
                return proxyIns;
            }
            String key = consumerConfig.buildKey();
            String appName = consumerConfig.getAppName();
            // 检查参数,这里是空调用
            checkParameters();
            // 提前检查接口类
            if (LOGGER.isInfoEnabled(appName)) {
                LOGGER.infoWithApp(appName, "Refer consumer config : {} with bean id {}", key, consumerConfig.getId());
            }

            // 注意同一interface,同一tags,同一protocol情况
            AtomicInteger cnt = REFERRED_KEYS.get(key); // 计数器
            if (cnt == null) { // 没有发布过
                cnt = CommonUtils.putToConcurrentMap(REFERRED_KEYS, key, new AtomicInteger(0));
            }
            int c = cnt.incrementAndGet();
            int maxProxyCount = consumerConfig.getRepeatedReferLimit();
            if (maxProxyCount > 0) {
                if (c > maxProxyCount) {
                    cnt.decrementAndGet();
                    // 超过最大数量,直接抛出异常
                    throw new SofaRpcRuntimeException("Duplicate consumer config with key " + key
                        + " has been referred 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 consumer config with key {} has been referred!"
                            + " Maybe it's wrong config, please check it."
                            + " Ignore this if you did that on purpose!", key);
                    }
                }
            }

            try {
                // build cluster,根据SPI加载配置的路由
                cluster = ClusterFactory.getCluster(this);
                // build listeners,设置监听器,这个作用主要是用来做路由改变时自动更新providerGroup
                consumerConfig.setConfigListener(buildConfigListener(this));
                consumerConfig.setProviderInfoListener(buildProviderInfoListener(this));
                // init cluster,这里加上前面的几步都是用来构建路由,并且设置变化监听
                cluster.init();
                // 构造Invoker对象(执行链)
                proxyInvoker = buildClientProxyInvoker(this);
                // 创建代理类
                proxyIns = (T) ProxyFactory.buildProxy(consumerConfig.getProxy(), consumerConfig.getProxyClass(),
                    proxyInvoker);

                //动态配置
                final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS);
                if (StringUtils.isNotBlank(dynamicAlias)) {
                    final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager(
                        consumerConfig.getAppName(), dynamicAlias);
                    dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId());
                }
            } catch (Exception e) {
                if (cluster != null) {
                    cluster.destroy();
                    cluster = null;
                }
                consumerConfig.setConfigListener(null);
                consumerConfig.setProviderInfoListener(null);
                cnt.decrementAndGet(); // 发布失败不计数
                if (e instanceof SofaRpcRuntimeException) {
                    throw (SofaRpcRuntimeException) e;
                } else {
                    throw new SofaRpcRuntimeException("Build consumer proxy error!", e);
                }
            }
            if (consumerConfig.getOnAvailable() != null && cluster != null) {
                cluster.checkStateChange(false); // 状态变化通知监听器
            }
            RpcRuntimeContext.cacheConsumerConfig(this);
            return proxyIns;
        }
    }

我们来看下这个服务调用都做了些啥:
1、构建自动路由寻址
2、构造Invoker对象执行链,创建代理类
3、加载一些动态配置

我们来看下第一步:

    public synchronized void init() {
        if (initialized) { // 已初始化
            return;
        }
        // 构造Router链
        routerChain = RouterChain.buildConsumerChain(consumerBootstrap);
        // 负载均衡策略 考虑是否可动态替换?
        loadBalancer = LoadBalancerFactory.getLoadBalancer(consumerBootstrap);
        // 地址管理器
        addressHolder = AddressHolderFactory.getAddressHolder(consumerBootstrap);
        // 连接管理器
        connectionHolder = ConnectionHolderFactory.getConnectionHolder(consumerBootstrap);
        // 构造Filter链,最底层是调用过滤器
        this.filterChain = FilterChain.buildConsumerChain(this.consumerConfig,
            new ConsumerInvoker(consumerBootstrap));

        if (consumerConfig.isLazy()) { // 延迟连接
            if (LOGGER.isInfoEnabled(consumerConfig.getAppName())) {
                LOGGER.infoWithApp(consumerConfig.getAppName(), "Connection will be initialized when first invoke.");
            }
        }

        // 启动重连线程
        connectionHolder.init();
        try {
            // 得到服务端列表
            List<ProviderGroup> all = consumerBootstrap.subscribe();
            if (CommonUtils.isNotEmpty(all)) {
                // 初始化服务端连接(建立长连接)
                updateAllProviders(all);
            }
        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SofaRpcRuntimeException("Init provider's transport error!", e);
        }

        // 启动成功
        initialized = true;

        // 如果check=true表示强依赖
        if (consumerConfig.isCheck() && !isAvailable()) {
            throw new SofaRpcRuntimeException("The consumer is depend on alive provider " +
                "and there is no alive provider, you can ignore it " +
                "by ConsumerConfig.setCheck(boolean) (default is false)");
        }
    }
    /**
     * 构建Router链
     *
     * @param consumerBootstrap 服务端订阅者配置
     * @return 路由链
     */
    public static RouterChain buildConsumerChain(ConsumerBootstrap consumerBootstrap) {
    	// 获取到调用者配置
        ConsumerConfig<?> consumerConfig = consumerBootstrap.getConsumerConfig();
        // 初始化配置路由,如果没有配置就是空的
        List<Router> customRouters = consumerConfig.getRouterRef() == null ? new ArrayList<Router>()
            : new CopyOnWriteArrayList<Router>(consumerConfig.getRouterRef());
        // 先解析是否有特殊处理,判断是否需要排除系统过滤器
        HashSet<String> excludes = parseExcludeRouter(customRouters);

        // 准备数据:用户通过别名的方式注入的router,需要解析
        List<ExtensionClass<Router>> extensionRouters = new ArrayList<ExtensionClass<Router>>();
        List<String> routerAliases = consumerConfig.getRouter();
        if (CommonUtils.isNotEmpty(routerAliases)) {
            for (String routerAlias : routerAliases) {
            	// 排除用的特殊字符,有"-"和"!"则会加入excludes
                if (startsWithExcludePrefix(routerAlias)) { 
                    excludes.add(routerAlias.substring(1));
                } else {
                	// 使用spi加载获得ExtensionClass<Router>,EXTENSION_LOADER会自动初始化,因为是静态的
                	// 增加了监听,如果配置了AutoActive每次加载完毕会加入CONSUMER_AUTO_ACTIVES
                    extensionRouters.add(EXTENSION_LOADER.getExtensionClass(routerAlias));
                }
            }
        }
        // 解析自动加载的router
        // 配了-*和-default表示不加载内置
        if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) { 
            for (Map.Entry<String, ExtensionClass<Router>> entry : CONSUMER_AUTO_ACTIVES.entrySet()) {
                if (!excludes.contains(entry.getKey())) {
                    extensionRouters.add(entry.getValue());
                }
            }
        }
        excludes = null; // 不需要了
        // 按order从小到大排序
        if (extensionRouters.size() > 1) {
            Collections.sort(extensionRouters, new OrderedComparator<ExtensionClass>());
        }
        List<Router> actualRouters = new ArrayList<Router>();
        for (ExtensionClass<Router> extensionRouter : extensionRouters) {
        	// 初始化
            Router actualRoute = extensionRouter.getExtInstance();
            actualRouters.add(actualRoute);
        }
        // 加入自定义的过滤器
        actualRouters.addAll(customRouters);
        return new RouterChain(actualRouters, consumerBootstrap);
    }

构建路由链完毕,接下来的负载均衡策略,地址管理器,连接管理器都只是通过SPI加载一下没有做特殊处理,我们先过了,我们来看下构造Filter链

	// 构造Filter链,最底层是调用过滤器
	this.filterChain = FilterChain.buildConsumerChain(this.consumerConfig,
	new ConsumerInvoker(consumerBootstrap));

    /**
     * 构造调用端的执行链
     *
     * @param consumerConfig consumer配置
     * @param lastFilter     最后一个filter
     * @return filter执行链
     */
    public static FilterChain buildConsumerChain(ConsumerConfig<?> consumerConfig, FilterInvoker lastFilter) {
    	// selectActualFilters 这个方法和我们讲的上面的buildConsumerChain逻辑是一样的,这里不再赘述
        return new FilterChain(selectActualFilters(consumerConfig, CONSUMER_AUTO_ACTIVES), lastFilter, consumerConfig);
    }

    /**
     * 构造执行链
     *
     * @param filters     包装过滤器列表
     * @param lastInvoker 最终过滤器
     * @param config      接口配置
     */
    protected FilterChain(List<Filter> filters, FilterInvoker lastInvoker, AbstractInterfaceConfig config) {
        // 调用过程外面包装多层自定义filter
        // 前面的过滤器在最外层
        invokerChain = lastInvoker;
        if (CommonUtils.isNotEmpty(filters)) {
            loadedFilters = new ArrayList<Filter>();
            for (int i = filters.size() - 1; i >= 0; i--) {
                try {
                    Filter filter = filters.get(i);
                    // 是否需要加载。默认是可以加载的,如果重写了needToLoad就按自己实现的来
                    if (filter.needToLoad(invokerChain)) {
                        invokerChain = new FilterInvoker(filter, invokerChain, config);
                        // cache this for filter when async respond
                        loadedFilters.add(filter);
                    }
                } catch (Exception e) {
                    LOGGER.error("Error when build filter chain", e);
                    throw new SofaRpcRuntimeException("Error when build filter chain", e);
                }
            }
        }
    }

接下来看下启动重连线程

    // 启动重连线程
    connectionHolder.init();
    /**
     * 启动重连+心跳线程
     */
    protected void startReconnectThread() {
        final String interfaceId = consumerConfig.getInterfaceId();
        // 启动线程池
        // 默认每隔10秒重连
        int reconnect = consumerConfig.getReconnectPeriod();
        if (reconnect > 0) {
            reconnect = Math.max(reconnect, 2000); // 最小2000
            reconThread = new ScheduledService("CLI-RC-" + interfaceId, ScheduledService.MODE_FIXEDDELAY, new
                Runnable() {
                    @Override
                    public void run() {
                        try {
                            doReconnect();
                        } catch (Throwable e) {
                            LOGGER.errorWithApp(consumerConfig.getAppName(),
                                "Exception when retry connect to provider", e);
                        }
                    }
                }, reconnect, reconnect, TimeUnit.MILLISECONDS).start();
        }
    }
    /**
     * 重连断开和死亡的节点
     */
    private void doReconnect() {
        String interfaceId = consumerConfig.getInterfaceId();
        String appName = consumerConfig.getAppName();
        int thisTime = reconnectFlag.incrementAndGet();
        boolean print = thisTime % 6 == 0; //是否打印error,每6次打印一次
        boolean isAliveEmptyFirst = isAvailableEmpty();
        // 检查可用连接  todo subHealth
        for (Map.Entry<ProviderInfo, ClientTransport> alive : aliveConnections.entrySet()) {
            ClientTransport connection = alive.getValue();
            if (connection != null && !connection.isAvailable()) {
                aliveToRetry(alive.getKey(), connection);
            }
        }
        for (Map.Entry<ProviderInfo, ClientTransport> entry : getRetryConnections()
            .entrySet()) {
            ProviderInfo providerInfo = entry.getKey();
            int providerPeriodCoefficient = CommonUtils.parseNum((Integer)
                providerInfo.getDynamicAttr(ProviderInfoAttrs.ATTR_RC_PERIOD_COEFFICIENT), 1);
            if (thisTime % providerPeriodCoefficient != 0) {
                continue; // 如果命中重连周期,则进行重连
            }
            ClientTransport transport = entry.getValue();
            if (LOGGER.isDebugEnabled(appName)) {
                LOGGER.debugWithApp(appName, "Retry connect to {} provider:{} ...", interfaceId, providerInfo);
            }
            try {
                transport.connect();
                // 双重检查,防止连上就被踢下线,如果重连成功
                if (doubleCheck(interfaceId, providerInfo, transport)) {
                    providerInfo.setDynamicAttr(ProviderInfoAttrs.ATTR_RC_PERIOD_COEFFICIENT, 1);
                    // 从重试列表放入存活列表
                    retryToAlive(providerInfo, transport);
                }
            } catch (Exception e) {
                if (print) {
                    if (LOGGER.isWarnEnabled(appName)) {
                        LOGGER.warnWithApp(appName, "Retry connect to {} provider:{} error ! The exception is " + e
                            .getMessage(), interfaceId, providerInfo);
                    }
                } else {
                    if (LOGGER.isDebugEnabled(appName)) {
                        LOGGER.debugWithApp(appName, "Retry connect to {} provider:{} error ! The exception is " + e
                            .getMessage(), interfaceId, providerInfo);
                    }
                }
            }
        }
        if (isAliveEmptyFirst && !isAvailableEmpty()) { // 原来空,变成不空
        	// 通知监听器现在已经有可请求的服务了
            notifyStateChangeToAvailable();
        }
    }
posted @ 2019-09-05 16:51  paul丶  阅读(691)  评论(0编辑  收藏  举报