Dubbo基础(泛化、服务降级、主机绑定)

Dubbo泛化

我们每次去发布一个服务,必然会先定义一个接口,并且把这个接口放在一个api的jar包中,给到服务调用方来使用。本质上,对于开发者来说仍然是面向接口编程,而且对于使用者来说,可以不需要关心甚至不需要知道这个接口到底是怎么触发调用的。简而言之,泛化调用,最最直接的表现就是服务消费者不需要有任何接口的实现,就能完成服务的调用。

代码实例:

  • provider

在服务端定义了一个接口

@DubboService(protocol = {"dubbo"})
public class DemoService implements IDemoService{

    @Override
    public String getTxt() {
        return "Hello world!!!";
    }
}

注册到nacos的元数据

side=provider

methods=getTxt

release=2.7.7

deprecated=false

dubbo=2.0.2

pid=10884

interface=com.springboot.dubbo.provider.services.IDemoService

generic=false

path=com.springboot.dubbo.provider.services.IDemoService

protocol=dubbo

application=spring-boot-dubbo-sample-provider

dynamic=true

category=providers

anyhost=true

timestamp=1608312655153
  • consumer
@RestController
public class DemoController {
    // 设置generic=true代表开启泛化功能
    @DubboReference(interfaceName = "com.springboot.dubbo.provider.services.IDemoService",generic = true,check = false)
    GenericService genericService;

    @GetMapping("/demo")
    public String demo(){
        //对象的传值
        Map<String,Object> user=new HashMap<>();
        user.put("",""); //key表达user对象中的属性,value表达属性的值
        return genericService.$invoke("getTxt",new String[0],null).toString();
    }
}
  • 结果(调用http://localhost:port/demo)
Hello world!!!

服务降级

@RestController
public class SayController {

    @DubboReference(registry = {"shanghai","hunan"},
            protocol = "dubbo",
            loadbalance = "consistenthash",
            mock = "com.springboot.dubbo.consumer.SayHelloService",
            timeout = 500,
            cluster = "failfast",check = false,
            methods = {
            @Method(loadbalance = "",name ="sayHello" )
    },
            retries = 5)
    ISayHelloService sayHelloService;

    @GetMapping("/say")
    public String say(){
        return sayHelloService.sayHello("hello");
    }
}

主机绑定

代码位置

DubboBootstrap.start() -> exportServices() -> ServiceConfigBase.export() -> ServiceConfig.doExport() -> doExportUrls() -> doExportUrlsFor1Protocol()

String host = findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = findConfigedPorts(protocolConfig, name, map);

findConfigedHosts

 private String findConfigedHosts(ProtocolConfig protocolConfig,
                                 List<URL> registryURLs,
                                 Map<String, String> map) {
    boolean anyhost = false;

    String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
    if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
        throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
    }

    // 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 (isInvalidLocalHost(hostToBind)) {
            anyhost = true;
            try {
                logger.info("No valid ip found from environment, try to find valid host from DNS.");
                hostToBind = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.warn(e.getMessage(), e);
            }
            if (isInvalidLocalHost(hostToBind)) {
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                    for (URL registryURL : registryURLs) {
                        if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
                            // skip multicast registry since we cannot connect to it via Socket
                            continue;
                        }
                        try (Socket socket = new Socket()) {
                            SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                            socket.connect(addr, 1000);
                            hostToBind = socket.getLocalAddress().getHostAddress();
                            break;
                        } catch (Exception e) {
                            logger.warn(e.getMessage(), e);
                        }
                    }
                }
                if (isInvalidLocalHost(hostToBind)) {
                    hostToBind = getLocalHost();
                }
            }
        }
    }

    map.put(BIND_IP_KEY, hostToBind);

    // registry ip is not used for bind ip by default
    String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
    if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
        throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
    } else if (StringUtils.isEmpty(hostToRegistry)) {
        // bind ip is used as registry ip by default
        hostToRegistry = hostToBind;
    }

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

    return hostToRegistry;
}
  • 查找环境变量中是否存在启动参数 [DUBBO_IP_TO_BIND] =服务注册的ip

  • 读取配置文件, dubbo.protocols.dubbo.host= 服务注册的ip

  • InetAddress.getLocalHost().getHostAddress() 获得本机ip地址

  • 通过Socket去连接注册中心,从而获取本机IP

  • 会轮询本机的网卡,直到找到合适的IP

  • 地址上面获取到的ip地址是bindip,如果需要作为服务注册中心的ip, DUBBO_IP_TO_REGISTRY -dDUBBO_IP_TO_REGISTRY=ip

配置的优先级问题

服务端配置的信息,都会装载到url上

dubbo%3A%2F%2F169.254.99.173%3A20880%2Fcom.springboot.dubbo.ISayHelloService%3Fanyhost%3Dtrue%26application%3Dspring-boot-dubbo-sample-provider%26cluster%3Dfailover%26deprecated%3D
false%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dcom.springboot.dubbo.ISayHelloService%26methods%3DsayHello%26pid%3D10884%26release%3D2.7.7%26side%3Dprovider
%26timestamp%3D1608312656576 

非集群(cluster=failver)

  • 客户端没有配置

    • 以客户端优先
  • 客户端有配置

    • 方法层面的配置要优先于接口层面的配置, 接口层面的配置要优先于全局配置
    • 如果级别一样,以客户端的配置优先,服务端次之
原文地址:https://www.cnblogs.com/snail-gao/p/14157876.html