# 思路

# 代码组件-ServerListUpdater

# 功能:获取到所有的服务列表

# 代码组件-ILoadBalancer

# 功能:提供客户端的负载均衡功能

# 代码组件-IRule

# 功能:提供具体的负载均衡策略

# 具体实现

项目结构如下:

# ServerListUpdater 服务列表更新

默认实现: DefaultServerListUpdater

/**
 * <p> 默认服务列表更新 </p>
 *
 * @Author 彳失口亍
 */
public class DefaultServerListUpdater extends Thread implements ServerListUpdater {

    public DefaultServerListUpdater(ILoadBalancer loadBalancer) {
        this.loadBalancer = loadBalancer;
    }

    /** 负载均衡对象 **/
    private ILoadBalancer loadBalancer;

    /** 最后更新时间 **/
    private volatile String lastUpdate;

    /** 服务列表集合  **/
    private static List<Server> serverList = new ArrayList<>();

    @Override
    public void start(UpdateAction updateAction) {
        updateAction.doUpdate();
        lastUpdate = System.currentTimeMillis() + "";
    }

    @Override
    public void run() {
        while(true){
            this.start(()->{
                // update action
                synchronized (this){
                    // 模拟从其他平台拉取到的服务数据
                    List<Server> serversOnRepository = Arrays.asList(
                            new Server("ribbon-server", "127.0.0.1", "9530"));
                    // 更新服务列表 (增量更新-剔除 host 和 port 相同的新增数据)
                    List<Server> addServers = new ArrayList<>();
                    serversOnRepository.forEach(item ->{
                        if(!serverList.contains(item)){
                            addServers.add(item);
                        }
                    });
                    if(!CollectionUtils.isEmpty(addServers)){
                        serverList.addAll(addServers);
                        loadBalancer.addServers(addServers);
                    }
                }
            });

            try {
                TimeUnit.SECONDS.sleep(20);
            } catch (InterruptedException e) {
                break;
            }
        }
    }

    @Override
    public String getLastUpdate() {
        return lastUpdate;
    }
}

主要方法逻辑在 run 方法中,定时从某个地址获取服务列表(这里空实现),然后将新增的服务信息保存起来。

# ILoadBalancer 负载均衡功能实现类

默认实现:DefaultLoadBalancer

/**
 * <p> 默认的负载均衡器 </p>
 *
 * @Author 彳失口亍
 */
public class DefaultLoadBalancer implements ILoadBalancer{

    public DefaultLoadBalancer(IRule rule) {
        this.rule = rule;
    }

    /** 服务列表集合 key:serverName,value Server.class **/
    private static List<Server> serverList = new ArrayList<>();

    /** 服务获取算法 **/
    private IRule rule;

    @Override
    public void addServers(List<Server> newServers) {
        serverList.addAll(newServers);
    }

    @Override
    public Server chooseServer(Object key) {
        if(null == key){
            throw new RuntimeException("not found the server " + key);
        }
        // 获取到指定服务名称的服务列表
        List<Server> servers = serverList.stream()
                .filter(filter -> filter.getServerName().equals(key))
                .collect(Collectors.toList());

        if(StringUtils.isEmpty(servers)){
            throw new RuntimeException("not found the server " + key);
        }
        return rule.choose(servers);
    }

    @Override
    public List<Server> getAllServers() {
        return Collections.unmodifiableList(serverList);
    }
}

DefaultLoadBalancer 维护了 服务列表 serverList 该服务列表是由 ServerListUpdater 更新后同步过来的。

具体的负载均衡策略委派给了 IRule 来完成。

# IRule 负载均衡策略实现

默认实现:RandomRule

/**
 * <p> 随机算法 </p>
 *
 * @Author 彳失口亍
 */
public class RandomRule implements IRule{

    @Override
    public Server choose(List<Server> servers) {
        int serverIndex = new Random().nextInt(servers.size());
        return servers.get(serverIndex);
    }
}

# RestTemplate 请求过滤器

默认实现:LoadBalanceClientHttpRequestInterceptor

/**
 * <p> 负载均衡过滤器 RestTemplate 过滤器</p>
 *
 * @Author 彳失口亍
 */
public class LoadBalanceClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    public LoadBalanceClientHttpRequestInterceptor(ILoadBalancer loadBalancer) {
        this.loadBalancer = loadBalancer;
    }

    private ILoadBalancer loadBalancer;

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        LoadBalanceHttpRequest loadBalanceHttpRequest = new LoadBalanceHttpRequest(request, loadBalancer);
        ClientHttpResponse originalResponse = execution.execute(loadBalanceHttpRequest, body);
        return originalResponse;
    }

    /** 请求包装类 **/
    public static class LoadBalanceHttpRequest extends HttpRequestWrapper{
        private ILoadBalancer loadBalancer;
        public LoadBalanceHttpRequest(HttpRequest request,ILoadBalancer loadBalancer) {
            super(request);
            this.loadBalancer = loadBalancer;
        }

        @Override
        public URI getURI() {
            URI originUri = super.getURI();
            URI newUri = null;
            // 如果能从服务列表中获取到服务信息,则进行 url 的重新拼接
            Server server = loadBalancer.chooseServer(originUri.getHost());
            if(null != server){
                StringBuffer sb = new StringBuffer();
                sb.append(server.getHost())
                        .append(":")
                        .append(Optional.ofNullable(server.getPort()).orElse("80"));
                String newHost = sb.toString();
                try{
                    String url = originUri.toURL().toString();
                    String newUrl = url.replaceFirst(originUri.getHost(), newHost);
                    newUri = new URI(newUrl);
                }catch (URISyntaxException e){

                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                return newUri;
            }
            return super.getURI();
        }
    }
}

# 测试

# 测试代码1

自己手动拼接 url

/**
 * <p> 客户端 API 测试 </p>
 *
 * @Author 彳失口亍
 */
@RestController
public class ClientApi {
    @Autowired
    private ILoadBalancer loadBalancer;

    @RequestMapping("/ribbon-client/demo")
    public String demo(){
        Server server = loadBalancer.chooseServer("ribbon-server");
        StringBuffer sb = new StringBuffer();
        sb.append("http://")
                .append(server.getHost())
                .append(":")
                .append(server.getPort())
                .append("/ribbon-server/api");
        // url = http://127.0.0.1:9530/ribbon-server/api
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> entity = restTemplate.getForEntity(sb.toString(), String.class);
        String result = entity.getBody();
        return result;
    }
}

# 测试代码2

让 RestTemplate 帮我们拼接

@Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/ribbon-client/demo2")
    public String demo2(){
        String serverName = "ribbon-server";
        StringBuffer sb = new StringBuffer();
        sb.append("http://")
                .append(serverName)
                .append("/ribbon-server/api");
        // url = http://ribbon-server/ribbon-server/api
        ResponseEntity<String> entity = restTemplate.getForEntity(sb.toString(), String.class);
        String result = entity.getBody();
        return result;
    }

# 代码逻辑图

精彩内容推送,请关注公众号!
最近更新时间: 4/16/2020, 7:40:17 PM