dubbo备忘录

1.负载均衡策略

Random LoadBalance :随机,按权重设置随机概率。 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance :轮询,按公约后的权重设置轮询比率。 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance :最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance :一致性 Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
    算法参见:http://en.wikipedia.org/wiki/Consistent_hashing
    缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />
    缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />

2.集群容错策略

Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

3.dubbo停机

1.服务提供方
停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。
然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
2.服务消费方
停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
这里还有两件事,取消注册,以及取消订阅

4.dubbo启动

5.dubbo注册ip

DUBBO启动时通过ServiceConfig 的 findConfigedHosts寻找本机地址
首先是判断是否有配置host ip,通过环境变量DUBBO_IP_TO_REGISTRY查找,第二优先级是通过配置中的dubbo.protocol.host来获取本机ip,并注册
如果没有配置,那么通过本机的hostname来查找本机的ip;

/**
     * Register & bind IP address for service provider, can be configured separately.
     * Configuration priority: environment variables -> java system properties -> host property in config file ->
     * /etc/hosts -> default network address -> first available network address
     *
     * @param protocolConfig
     * @param registryURLs
     * @param map
     * @return
     */
    private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
        boolean anyhost = false;

        String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND);

        // if bind ip is not found in environment, keep looking up
        if (StringUtils.isEmpty(hostToBind)) {
            hostToBind = protocolConfig.getHost();
            if (provider != null && StringUtils.isEmpty(hostToBind)) {
                hostToBind = provider.getHost();
            }

            if (StringUtils.isEmpty(hostToBind)) {
                anyhost = true;
                hostToBind = getLocalHost();

                if (StringUtils.isEmpty(hostToBind)) {
                    hostToBind = findHostToBindByConnectRegistries(registryURLs);
                }
            }
        }

        map.put(Constants.BIND_IP_KEY, hostToBind);

        // registry ip is not used for bind ip by default
        String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY);
        if (StringUtils.isEmpty(hostToRegistry)) {
            // bind ip is used as registry ip by default
            hostToRegistry = hostToBind;
        }

        map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost));

        return hostToRegistry;
    }

6.服务端连接池

系统默认使用FixedThreadPoll,连接池大小默认200,队列大小默认为0;

7.消费端Reference初始化

消费端会通过@Reference来注入provider引用,对应的就是dubbo的ReferenceBean,实现了spring的FactoryBean(FactoryBean 通常是用来创建比较复杂的bean);
注入reference的入口是通过ReferenceAnnotationBeanPostProcessor初始化的






8.dubbo调用链


//消费端发送请求
InvokerInvocationHandler.invoke 
    MockClusterInvoker.invoke
        AbstractInvoker.invoke
            DubboInvoker.doInvoke(final Invocation invocation)
                ReferenceCountExchangeClient.request(Object request, int timeout)
                    HeaderExchangeClient.request(Object request, int timeout)
                        HeaderExchangeChannel.request(Object request, int timeout)
                            AbstractPeer.send(Object message)
                                NettyChannel.send(Object message, boolean sent)
                                    AbstractChannel.writeAndFlush(Object msg)



//服务端接收请求
netty
    AllChannelHandler.received(Channel channel, Object message)
asyn-----------------------------------------------------

ChannelEventRunnable.run()
    DecodeHandler.received(Channel channel, Object message)
        HeaderExchangeHandler.received(Channel channel, Object message)
			DubboProtocol.reply(ExchangeChannel channel, Object message)
				CallbackRegistrationInvoker.invoke(Invocation invocation)
					ProtocolFilterWrapper$1.invoke(next, invocation)
					.
					.
					.
					AbstractProxyInvoker.invoke(Invocation invocation)
			HeaderExchangeChannel.send(response)
			
			
//消费端接受响应
netty
    AllChannelHandler.received(Channel channel, Object message)
asyn-----------------------------------------------------

ChannelEventRunnable.run()
    DecodeHandler.received(Channel channel, Object message)
        HeaderExchangeHandler.received(Channel channel, Object message)
		    HeaderExchangeHandler.handleResponse(channel, (Response) message)
			    DefaultFuture.received(channel, response) 获取到response对应的DefaultFuture,并将response写入DefaultFuture,将DefaultFuture置为completed



9.处理请求(处理响应)的线程池创建链路

//DubboProtocol.java
@Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service

        //export an stub service for dispatching event

        //创建ExchangeServer
        openServer(url);
        optimizeSerialization(url);

        return exporter;
    }

private void openServer(URL url) {
    // find server.
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(IS_SERVER_KEY, true);
    if (isServer) {
        ExchangeServer server = serverMap.get(key);
        if (server == null) {
            synchronized (this) {
                server = serverMap.get(key);
                //如果第一次,那么需要创建ExchangeServer
                if (server == null) {
                    serverMap.put(key, createServer(url));
                }
            }
        } else {
            // server supports reset, use together with override
            server.reset(url);
        }
    }
}


//WrappedChannelHandler.java
public WrappedChannelHandler(ChannelHandler handler, URL url) {
    this.handler = handler;
    this.url = url;
    //在这里根据url上的配置,去创建指定thread数量,指定队列数量的线程池
    executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url);

    String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
    if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
        componentKey = CONSUMER_SIDE;
    }
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    dataStore.put(componentKey, Integer.toString(url.getPort()), executor);
}

posted on 2019-09-19 17:11  mindSucker  阅读(196)  评论(0编辑  收藏  举报