Search in sources :

Example 1 with Pair

use of com.netflix.util.Pair in project ribbon by Netflix.

the class LoadBalancerContext method getServerFromLoadBalancer.

/**
     * Compute the final URI from a partial URI in the request. The following steps are performed:
     * <ul>
     * <li> if host is missing and there is a load balancer, get the host/port from server chosen from load balancer
     * <li> if host is missing and there is no load balancer, try to derive host/port from virtual address set with the client
     * <li> if host is present and the authority part of the URI is a virtual address set for the client, 
     * and there is a load balancer, get the host/port from server chosen from load balancer
     * <li> if host is present but none of the above applies, interpret the host as the actual physical address
     * <li> if host is missing but none of the above applies, throws ClientException
     * </ul>
     *
     * @param original Original URI passed from caller
     */
public Server getServerFromLoadBalancer(@Nullable URI original, @Nullable Object loadBalancerKey) throws ClientException {
    String host = null;
    int port = -1;
    if (original != null) {
        host = original.getHost();
    }
    if (original != null) {
        Pair<String, Integer> schemeAndPort = deriveSchemeAndPortFromPartialUri(original);
        port = schemeAndPort.second();
    }
    // Various Supported Cases
    // The loadbalancer to use and the instances it has is based on how it was registered
    // In each of these cases, the client might come in using Full Url or Partial URL
    ILoadBalancer lb = getLoadBalancer();
    if (host == null) {
        // well we have to just get the right instances from lb - or we fall back
        if (lb != null) {
            Server svc = lb.chooseServer(loadBalancerKey);
            if (svc == null) {
                throw new ClientException(ClientException.ErrorType.GENERAL, "Load balancer does not have available server for client: " + clientName);
            }
            host = svc.getHost();
            if (host == null) {
                throw new ClientException(ClientException.ErrorType.GENERAL, "Invalid Server for :" + svc);
            }
            logger.debug("{} using LB returned Server: {} for request {}", new Object[] { clientName, svc, original });
            return svc;
        } else {
            // bail out
            if (vipAddresses != null && vipAddresses.contains(",")) {
                throw new ClientException(ClientException.ErrorType.GENERAL, "Method is invoked for client " + clientName + " with partial URI of (" + original + ") with no load balancer configured." + " Also, there are multiple vipAddresses and hence no vip address can be chosen" + " to complete this partial uri");
            } else if (vipAddresses != null) {
                try {
                    Pair<String, Integer> hostAndPort = deriveHostAndPortFromVipAddress(vipAddresses);
                    host = hostAndPort.first();
                    port = hostAndPort.second();
                } catch (URISyntaxException e) {
                    throw new ClientException(ClientException.ErrorType.GENERAL, "Method is invoked for client " + clientName + " with partial URI of (" + original + ") with no load balancer configured. " + " Also, the configured/registered vipAddress is unparseable (to determine host and port)");
                }
            } else {
                throw new ClientException(ClientException.ErrorType.GENERAL, this.clientName + " has no LoadBalancer registered and passed in a partial URL request (with no host:port)." + " Also has no vipAddress registered");
            }
        }
    } else {
        // Full URL Case
        // This could either be a vipAddress or a hostAndPort or a real DNS
        // if vipAddress or hostAndPort, we just have to consult the loadbalancer
        // but if it does not return a server, we should just proceed anyways
        // and assume its a DNS
        // For restClients registered using a vipAddress AND executing a request
        // by passing in the full URL (including host and port), we should only
        // consult lb IFF the URL passed is registered as vipAddress in Discovery
        boolean shouldInterpretAsVip = false;
        if (lb != null) {
            shouldInterpretAsVip = isVipRecognized(original.getAuthority());
        }
        if (shouldInterpretAsVip) {
            Server svc = lb.chooseServer(loadBalancerKey);
            if (svc != null) {
                host = svc.getHost();
                if (host == null) {
                    throw new ClientException(ClientException.ErrorType.GENERAL, "Invalid Server for :" + svc);
                }
                logger.debug("using LB returned Server: {} for request: {}", svc, original);
                return svc;
            } else {
                // just fall back as real DNS
                logger.debug("{}:{} assumed to be a valid VIP address or exists in the DNS", host, port);
            }
        } else {
            // consult LB to obtain vipAddress backed instance given full URL
            //Full URL execute request - where url!=vipAddress
            logger.debug("Using full URL passed in by caller (not using load balancer): {}", original);
        }
    }
    // end of creating final URL
    if (host == null) {
        throw new ClientException(ClientException.ErrorType.GENERAL, "Request contains no HOST to talk to");
    }
    return new Server(host, port);
}
Also used : ClientException(com.netflix.client.ClientException) URISyntaxException(java.net.URISyntaxException) Pair(com.netflix.util.Pair)

Example 2 with Pair

use of com.netflix.util.Pair in project ribbon by Netflix.

the class LoadBalancerContext method deriveHostAndPortFromVipAddress.

/**
     * Derive the host and port from virtual address if virtual address is indeed contains the actual host 
     * and port of the server. This is the final resort to compute the final URI in {@link #getServerFromLoadBalancer(java.net.URI, Object)}
     * if there is no load balancer available and the request URI is incomplete. Sub classes can override this method
     * to be more accurate or throws ClientException if it does not want to support virtual address to be the
     * same as physical server address.
     * <p>
     *  The virtual address is used by certain load balancers to filter the servers of the same function 
     *  to form the server pool. 
     *  
     */
protected Pair<String, Integer> deriveHostAndPortFromVipAddress(String vipAddress) throws URISyntaxException, ClientException {
    Pair<String, Integer> hostAndPort = new Pair<String, Integer>(null, -1);
    URI uri = new URI(vipAddress);
    String scheme = uri.getScheme();
    if (scheme == null) {
        uri = new URI("http://" + vipAddress);
    }
    String host = uri.getHost();
    if (host == null) {
        throw new ClientException("Unable to derive host/port from vip address " + vipAddress);
    }
    int port = uri.getPort();
    if (port < 0) {
        port = getDefaultPortFromScheme(scheme);
    }
    if (port < 0) {
        throw new ClientException("Unable to derive host/port from vip address " + vipAddress);
    }
    hostAndPort.setFirst(host);
    hostAndPort.setSecond(port);
    return hostAndPort;
}
Also used : ClientException(com.netflix.client.ClientException) URI(java.net.URI) Pair(com.netflix.util.Pair)

Aggregations

ClientException (com.netflix.client.ClientException)2 Pair (com.netflix.util.Pair)2 URI (java.net.URI)1 URISyntaxException (java.net.URISyntaxException)1