zoukankan      html  css  js  c++  java
  • 【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(下)

    前提回顾

    【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(中)

    【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)

    内容简介

    在项目开发中,除了考虑正常的调用之外,负载均衡和故障转移也是关注的重点,这也是feign + ribbon的优势所在,基于上面两篇文章的基础,接下来我们开展最后一篇原生态fegin结合ribbon服务进行服务远程调用且实现负载均衡机制,也帮助大家学习ribbon奠定基础。

    maven依赖

    <dependencies>
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-core</artifactId>
            <version>8.18.0</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-jackson</artifactId>
            <version>8.18.0</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-ribbon</artifactId>
            <version>8.18.0</version>
        </dependency>
    	<dependency>
        <groupId>com.netflix.archaius</groupId>
        <artifactId>archaius-core</artifactId>
    </dependency>
    
    </dependencies>
    

    其中feign-core和feign-ribbon是必须的,如果需要在服务消费端和服务生产端之间进行对象交互,建议使用feign-jackson

    配置读取

    import com.netflix.config.ConfigurationManager;
    import feign.Feign;
    import feign.jackson.JacksonDecoder;
    import feign.jackson.JacksonEncoder;
    import feign.ribbon.RibbonClient;
    public class AppRun {
        public static void main(String[] args) throws Exception {
            User param = new User();
            param.setUsername("test");
            RemoteService service = Feign.builder().client(RibbonClient.create())
    				.encoder(new JacksonEncoder())
                    .decoder(new JacksonDecoder())
    			    .options(new Options(1000, 3500))
                    .retryer(new Retryer.Default(5000, 5000, 3))
    			    .target(RemoteService.class, "http://remote-client/gradle-web");
            /**
             * 调用测试
             */
            for (int i = 1; i <= 10; i++) {
                User result = service.getOwner(param);
                System.out.println(result.getId() + "," + result.getUsername());
            }
        }
    }
    
    • 声明了一个User类型的对象param,该对象将作为参数被发送至服务生产端。

    • 重点在于通过RibbonClient.create()使得Feign对象获得了Ribbon的特性。之后通过encoder,decoder设置编码器与解码器,并通过target方法将之前定义的接口RemoteService与一个URL地址http://remote-client/gradle-web进行了绑定。

    现在来看remote-client.properties中的配置项,主要多是RemoteClient的配置机制

    remote-client.ribbon.MaxAutoRetries=1
    remote-client.ribbon.MaxAutoRetriesNextServer=1
    remote-client.ribbon.OkToRetryOnAllOperations=true
    remote-client.ribbon.ServerListRefreshInterval=2000
    remote-client.ribbon.ConnectTimeout=3000
    remote-client.ribbon.ReadTimeout=3000
    remote-client.ribbon.listOfServers=127.0.0.1:8080,127.0.0.1:8085
    remote-client.ribbon.EnablePrimeConnections=false
    

    所有的key都以remote-client开头,表明这些配置项作用于名为remote-client的服务。其实就是与之前绑定RemoteService接口的URL地址的schema相对应。

    重点看remote-client.ribbon.listOfServers配置项,该配置项指定了服务生产端的真实地址。

    之前与RemoteService接口绑定的URL地址是 : http://remote-client/gradle-web

    在调用时会被替换为:

    @RequestLine指定的地址进行拼接,得到最终请求地址。本例中最终请求地址为:

    由于使用的ribbon,所以feign不再需要配置超时时长,重试策略。ribbon提供了更为完善的策略实现。

    本例中,服务生产端是一个简单的springMvc,实现如下:

    @RestController
    @RequestMapping(value="users")
    public class UserController {
        @RequestMapping(value="/list",method={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT})
        public User list(@RequestBody User user) throws InterruptedException{
            HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
            user.setId(new Long(request.getLocalPort()));
            user.setUsername(user.getUsername().toUpperCase());
            return user;
        }
    }
    
    

    故障转移是通过remote-client.properties中的配置项进行配置。

    • 首先利用archaius项目的com.netflix.config.ConfigurationManager读取配置文件remote-client.properties,该文件位于src/main/resources下。

    负载均衡的策略又是如何设置呢?

    import com.netflix.client.ClientFactory;
    import com.netflix.client.config.IClientConfig;
    import com.netflix.config.ConfigurationManager;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.RandomRule;
    import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
    import feign.Feign;
    import feign.jackson.JacksonDecoder;
    import feign.jackson.JacksonEncoder;
    import feign.ribbon.LBClient;
    import feign.ribbon.LBClientFactory;
    import feign.ribbon.RibbonClient;
    public class AppRun {
        public static void main(String[] args) throws Exception {
            ConfigurationManager.loadPropertiesFromResources("remote-client.properties");
            User param = new User();
            param.setUsername("test");
            RibbonClient client = RibbonClient.builder().lbClientFactory(new LBClientFactory() {
                @Override
                public LBClient create(String clientName) {
                    IClientConfig config = ClientFactory.getNamedConfig(clientName);
                    ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
                    ZoneAwareLoadBalancer zb = (ZoneAwareLoadBalancer) lb;
                    zb.setRule(new RandomRule());
                    return LBClient.create(lb, config);
                }
            }).build();
            RemoteService service = Feign.builder().client(client).encoder(new JacksonEncoder())
                    .decoder(new JacksonDecoder()).options(new Options(1000, 3500))
                    .retryer(new Retryer.Default(5000, 5000, 3)).target(RemoteService.class, "http://remote-client/gradle-web");
            /**
             * 调用测试
             */
            for (int i = 1; i <= 10; i++) {
                User result = service.getOwner(param);
                System.out.println(result.getId() + "," + result.getUsername());
            }
        }
    }
    

    其他负载均衡策略

     /**
         * Ribbon负载均衡策略实现
         * 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,
         * 剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。
         * @return
         */
    
    	private IRule zoneAvoidanceRule() {
            return new ZoneAvoidanceRule();
        }
    
        /**
         * Ribbon负载均衡策略实现
         * 随机选择一个server。
         * @return
         */
        private IRule randomRule() {
            return new RandomRule();
        }
    

    不再使用RibbonClient.create()来创建默认的RibbonClient,而是通过RibbonClient.builder()获得feign.ribbon.Builder,进而设置LBClientFactory的实现来定制LBClient,在创建LBClient的过程中即可指定负载策略的具体实现。

    极限就是为了超越而存在的
  • 相关阅读:
    Java的基本数据类型
    第五小组链表讨论作业
    WLST 命令和变量
    Linux之find命令详解
    Linux之netstat命令详解
    Linux之 sort,uniq,cut,wc命令详解
    Linux之grep命令详解
    Linux之awk命令详解
    Linux之sed命令详解
    关于表 datatable的条件查询
  • 原文地址:https://www.cnblogs.com/liboware/p/15132234.html
Copyright © 2011-2022 走看看