liuyangming / ByteTCC

ByteTCC is a distributed transaction manager based on the TCC(Try/Confirm/Cancel) mechanism. It’s compatible with the JTA specification. User guide: https://github.com/liuyangming/ByteTCC/wiki
https://www.bytesoft.org/
GNU Lesser General Public License v3.0
2.9k stars 913 forks source link

关于CompensableLoadBalancerRuleImpl 的疑问和建议 #19

Open hi-sb opened 7 years ago

hi-sb commented 7 years ago

在排查代码的过程中发现,byte定义了一个IRule 叫做 CompensableLoadBalancerRuleImpl,这个类定义了随机的负载均衡策略,同时运行了 interceptor.afterCompletion(server); @See CompensableLoadBalancerRuleImpl


package org.bytesoft.bytetcc.supports.springcloud.loadbalancer;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.Random;
import org.bytesoft.bytetcc.supports.springcloud.SpringCloudBeanRegistry;
import org.bytesoft.bytetcc.supports.springcloud.loadbalancer.CompensableLoadBalancerInterceptor;

public class CompensableLoadBalancerRuleImpl extends AbstractLoadBalancerRule implements IRule {
    static Random random = new Random();
    private IClientConfig clientConfig;

    public CompensableLoadBalancerRuleImpl() {
    }

    public Server choose(Object key) {
        SpringCloudBeanRegistry registry = SpringCloudBeanRegistry.getInstance();
        CompensableLoadBalancerInterceptor interceptor = registry.getLoadBalancerInterceptor();
        if(interceptor == null) {
            return this.chooseServer(key);
        } else {
            ILoadBalancer loadBalancer = this.getLoadBalancer();
            List servers = loadBalancer.getAllServers();
            Server server = null;

            try {
                List serverList = interceptor.beforeCompletion(servers);
                server = this.chooseServer(key, serverList);
            } finally {
                interceptor.afterCompletion(server);
            }

            return server;
        }
    }

    public Server chooseServer(Object key) {
        ILoadBalancer loadBalancer = this.getLoadBalancer();
        List reachableServers = loadBalancer.getReachableServers();
        List allServers = loadBalancer.getAllServers();
        return reachableServers != null && !reachableServers.isEmpty()?(Server)reachableServers.get(random.nextInt(reachableServers.size())):(allServers != null && !allServers.isEmpty()?(Server)allServers.get(random.nextInt(allServers.size())):null);
    }

    public Server chooseServer(Object key, List<Server> serverList) {
        return serverList != null && !serverList.isEmpty()?(serverList.size() == 1?(Server)serverList.get(0):(Server)serverList.get(random.nextInt(serverList.size()))):null;
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }

    public IClientConfig getClientConfig() {
        return this.clientConfig;
    }
}

因为我们的项目中自定义了 IRule

参考代码:

    @Bean
    @Scope("prototype")
    public IRule getIRule() {
        return new IRuleFactory();
    }

导致这个负载均衡器失效了,出现了调用的provider 事物不被确认的情况。反过来说如果bytetcc 的 IRule 生效了,那么我自定义的负载均衡策略就失效了,这又导致了不兼容的情况。

也不知道我理解的对不对

liuyangming commented 7 years ago

ByteTCC现有版本(0.4.0)不支持自定义Rule,TCC型服务的远程调用默认都用CompensableLoadBalancerRuleImpl。该Rule通过CompensablePropertySource类进行定义。

如果不希望使用该Rule实现,也可以通过org.bytesoft.bytetcc.feign.inclusions/org.bytesoft.bytetcc.feign.exclusions属性来配置哪些appName的服务使用/不使用该Rule(不过,TCC型服务建议还是使用)。

如果需要做深度定制的话,也可以重写CompensableLoadBalancerRuleImpl的chooseServer部分逻辑,但其他逻辑不可以随意修改(完整自定义也可,但要保证提供CompensableLoadBalancerRuleImpl中不可缺少的逻辑)。

ByteTCC默认支持的按事务粒度负载均衡策略对SpringCloud/dubbo的loadbalancer配置要求相对严格,后续版本计划推出按请求粒度的负载均衡策略,将不会对loadbalancer做任何要求。敬请关注。

hi-sb commented 7 years ago

我在其他 负载均衡策略中,提供了 是否可用的判断,那么是不是可以不用以下代码来选择:


        List serverList = interceptor.beforeCompletion(servers);
                server = this.chooseServer(key, serverList);
hi-sb commented 7 years ago

interceptor.beforeCompletion(servers); 和 this.getLoadBalancer().getReachableServers();有什么区别呢?

liuyangming commented 7 years ago

interceptor.beforeCompletion(servers)限制了servers的范围。

按事务粒度的负载均衡策略要求:在特定事务T内的应用(consumer)实例C1一旦按某种策略(如CompensableLoadBalancerRuleImpl中的随机策略)选中了应用P(provider)的一个实例P1,那么,后续在事务T内,C1对P的访问始终会落在P1实例上,直到该事务T完成。

不同的事务互不干涉。

hi-sb commented 7 years ago

明白了 谢谢解答 哦