《重新定义Spring Cloud实战》——3.5.7 基于metadata路由实例

举报
华章计算机 发表于 2019/06/04 15:23:50 2019/06/04
【摘要】 本书摘自《重新定义Spring Cloud实战》——书中第3章,第3.5.7节,作者是许进、叶志远、钟尊发、蔡波斯、方志朋、郭芳碧、朱德明。

3.5.7 基于metadata路由实例

对于Eureka来说,最常见的就是通过metadata属性,进行灰度控制或者是不宕机升级。这里结合Netflix Ribbon的例子,介绍一下这类应用场景的实现。

1. ILoadBalancer接口

Netflix Ribbon的ILoadBalancer接口定义了loadBalancer的几个基本方法,如下:

public interface ILoadBalancer 

    public void addServers(List<Server> newServers);

    public Server chooseServer(Object key);

    public void markServerDown(Server server);

    @Deprecated

    public List<Server> getServerList(boolean availableOnly);

    public List<Server> getReachableServers();

    public List<Server> getAllServers();

}

可以看到这里有个chooseServer方法,用于从一堆服务实例列表中进行过滤,选取一个Server出来,给客户端请求用。

在Ribbon中,ILoadBalancer选取Server的逻辑主要由一系列IRule来实现。

2. IRule接口

public interface IRule{

    public Server choose(Object key);

    public void setLoadBalancer(ILoadBalancer lb);

    public ILoadBalancer getLoadBalancer();    

}

最常见的IRule接口有RoundRobinRule,采用轮询调度算法规则来选取Server,其主要代码如下:

public Server choose(ILoadBalancer lb, Object key) {

    if (lb == null) {

        log.warn("no load balancer");

        return null;

    }

    Server server = null;

    int count = 0;

    while (server == null && count++ < 10) {

        List<Server> reachableServers = lb.getReachableServers();

        List<Server> allServers = lb.getAllServers();

        int upCount = reachableServers.size();

        int serverCount = allServers.size();


        if ((upCount == 0) || (serverCount == 0)) {

            log.warn("No up servers available from load balancer: " + lb);

                return null;

            }


            int nextServerIndex = incrementAndGetModulo(serverCount);

            server = allServers.get(nextServerIndex);


            if (server == null) {

                /* Transient. */

                Thread.yield();

                continue;

            }


            if (server.isAlive() && (server.isReadyToServe())) {

                return (server);

            }


            // Next.

            server = null;

        }


        if (count >= 10) {

            log.warn("No available alive servers after 10 tries from load balancer: "

                    + lb);

        }

        return server;

    }

3. MetadataAwarePredicate

这里,由于我们需要根据实例的metadata进行过滤,因此,可以自定义实现自己的rule。Netflix提供了PredicateBasedRule,可以基于Guava的Predicate进行过滤。jmnarloch在《Spring Cloud: Ribbon dynamic routing》(https://jmnarloch.wordpress.com/2015/11/25/spring-cloud-ribbon-dynamic-routing/)中给出了针对metadata过滤的rule,如下:

public class MetadataAwarePredicate extends DiscoveryEnabledPredicate {


    @Override

    protected boolean apply(DiscoveryEnabledServer server) {


        final RibbonFilterContext context = RibbonFilterContextHolder.getCurrentContext();

        final Set<Map.Entry<String, String>> attributes = Collections.unmodifiableSet(context.getAttributes().entrySet());

        final Map<String, String> metadata = server.getInstanceInfo().getMetadata();

        return metadata.entrySet().containsAll(attributes);

    }

}

这个Predicate将Server的metadata跟上下文传递的attributes信息进行匹配,全部匹配上才返回true。比如attributes的map有个entry,key是env,value是canary,表示该实例是canary实例,如果请求上下文要求路由到canary实例,可以从request url参数或者header中标识这个路由请求,然后携带到上下文中,最后由Predicate进行判断,完成整个ILoadBalancer的choose。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。