• springcloud3-服务到服务调用ribbon及openfeign


    1,课程回顾
    2,本章重点
    ribbon (负载均衡器)如何实现服务到服务的调用
    feign 服务到服务的调用
    3,具体内容
    3.1 ribbon
    3.1.1 概念
    Ribbon是一种客户端负载平衡器,可让您对HTTP和TCP客户端的行为进行大量控制(借助spring封装类RestTemplate,所有的入参,请求URL及出参数都是自己配置)。Feign已使用Ribbon,因此,如果使用@FeignClient,则本节也适用。
    Ribbon中的中心概念是指定客户的概念。每个负载均衡器都是组件的一部分,这些组件可以一起工作以按需联系远程服务器,并且该组件具有您作为应用程序开发人员提供的名称(指定远程调用的服务名称,例如,使用@FeignClient批注)。根据需要,Spring Cloud通过使RibbonClientConfiguration为每个命名的客户端创建一个新的集合作为ApplicationContext。其中包含ILoadBalancer,RestClient和ServerListFilter。

    3.1.2 工作流程
    图片: https://uploader.shimo.im/f/4Uvxcn6i5gSDhP0R.png

    3.1.3 实现过程
    模拟场景:根据商品编号查询商品中,要使用订单对象,在展示商品的同时,展示订单
    根据order_server_1 创建order_server_2,order_server_3
    创建goods_server_ribbon微服务
    1),引入jar
    考虑到微服务项目之间调用都可以使用ribbon方式,直接把jar放到micro_services项目pom.xml


    org.springframework.cloud
    spring-cloud-starter-netflix-ribbon

    2),创建商品表,反向工程生成代码
    – 创建商品 模拟

    CREATE TABLE `tb_product` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `shop_id` bigint(20) NOT NULL COMMENT '店铺ID',
      `brand_id` bigint(20) DEFAULT NULL COMMENT '品牌ID',
      `category_id` bigint(20) DEFAULT NULL COMMENT '产品类别ID',
      `name` varchar(64) NOT NULL,
      `pic` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
     
    INSERT INTO `tb_product` VALUES ('1', '1001', '2001', '3001', '上衣', 'path1');
    INSERT INTO `tb_product` VALUES ('2', '1002', '2002', '3003', '男裤', 'path2');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    – 给商品表添加字段
    alter table tb_product add order_id int;
    – 查看表结构
    desc tb_product;

    3),添加application.yml配置
    #当前服务端口号
    server:
    port: 14131

    servlet:

    #配置上下文对象 访问的项目名称

    context-path: /ordera

    #阿里druid连接池配置
    spring:
      datasource:
        druid:
          url: jdbc:mysql://localhost:3306/db_qy141?useUnicode=true&characterEncoding=utf8
          username: root
          password: root
          initial-size: 5
          max-active: 20
          min-idle: 10
          max-wait: 10
      application:
        #当前应用的名称  注册后,注册中心会显示该名称,其他服务调用时,也是使用该名称
        name: goodsService
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
    mybatis-plus:
      # mapper.xml配置
      mapper-locations: classpath:mapper/*.xml
      configuration:
        #控制台日志输出配置
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      #别名包配置
      type-aliases-package: com.aaa.gs.entity
    #swagger配置
    swagger:
      base-package: com.aaa.gs.controller
      title: "电商项目-商品模块-商品swagger"
      description: "描述"
      version: "3.0"
      contact:
        name: "AAA"
        email: "test@163.com"
        url: "https://www.baidu.com"
      terms-of-service-url: "服务条款:https://www.baidu.com"
    #eureka:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    client:

    #eureka客户端注册域地址

    service-url:

    defaultZone: http://localhost:14112/eureka/

    4),RestTemplate 用法
    RestTemplate简介:
    spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。 (spring模板模式的体现)
    RestTemplate常用方法:

    public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables){}
    public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
    public <T> T getForObject(URI url, Class<T> responseType)      
    
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables){}
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables){}
    public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType){}
    
    public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables)
                throws RestClientException {}
    public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables)
                throws RestClientException {}
    public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException {}
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    https://www.cnblogs.com/javazhiyin/p/9851775.html
    5)两种方式配置ribbon
    ribbon配置方法1:
    配置类RibbonConfiguration:
    package com.aaa.gs.config;
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RandomRule;
    import com.netflix.loadbalancer.RoundRobinRule;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    import java.util.Random;
    /**

    • @ fileName:RibbonConfig

    • @ description:

    • @ author:zhz

    • @ createTime:2022/2/19 9:53

    • @ version:1.0.0
      /
      @Configuration
      public class RibbonConfig {
      /
      *

      • 实例化RestTemplate 并添加负载均衡配置
      • @return
        /
        @Bean
        @LoadBalanced //远程调用服务时,如果远程服务是多个,使用负载均衡
        public RestTemplate restTemplate(){
        return new RestTemplate();
        }
        /
        *
      • 实例化IRule的子类 配置负载均衡算法
      • @return
        */
        @Bean
        public IRule iRule(){
        //随机
        //return new RandomRule();
        //轮询
        return new RoundRobinRule();
        }
        }

      ribbon配置方法2:
      启动类上添加注解:
      @RibbonClient(name = “ribbonc”,configuration = RibbonConfig.class)
      启动类上添加方法:
      @Bean
      @LoadBalanced
      public RestTemplate restTemplate(){
      return new RestTemplate();
      }
      编写MyRule:
      @Configuration
      public class RibbonConfig {
      /**

      • 实例化IRule的子类 配置负载均衡算法
      • @return
        */
        @Bean
        public IRule iRule(){
        //随机
        //return new RandomRule();
        //轮询
        return new RoundRobinRule();
        }

    }
    6) 业务类的编写
    package com.aaa.gs.service.impl;
    import com.aaa.core.bo.Order;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.baomidou.mybatisplus.extension.api.R;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.aaa.gs.dao.ProductDao;
    import com.aaa.gs.entity.Product;
    import com.aaa.gs.service.ProductService;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    import springfox.documentation.spring.web.json.Json;
    import javax.annotation.Resource;
    import java.io.Serializable;
    /**

    • (Product)表服务实现类

    • @author makejava

    • @since 2022-02-19 09:38:00
      */
      @Service(“productService”)
      public class ProductServiceImpl extends ServiceImpl<ProductDao, Product> implements ProductService {

      @Resource
      private RestTemplate restTemplate;

      @Override
      public Product getById(Serializable id) {
      //根据商品id查询商品
      Product product = this.baseMapper.selectById(id);
      //int orderId = product.getOrderId;
      //假如商品中有订单id
      // url http://服务名称一定是想调用服务注册到注册中心的名称
      R resultR = restTemplate.getForObject(“http://orderService/order/selectOne/8”, R.class);
      //toJSONString json对象转为字符串
      Order orderBo = JSON.parseObject(JSON.toJSONString(resultR.getData()), Order.class);
      product.setOrder(orderBo);
      //product.setR(resultR);
      return product;
      }
      }

    图片: https://uploader.shimo.im/f/JrgDpvsTdUkzP2OT.png

    7),测试
    先启动注册中心(eureka/nacos),再启动3个提供者order_server,最后启动消费者goods_server
    http://localhost:14131/swagger-ui/index.html#/product-controller/selectOneUsingGET
    http://localhost:14131/product/selectOne/2

    http://localhost:14820/product/queryById?id=1
    图片: https://uploader.shimo.im/f/zWPimcEa6QkyMKPp.png

    3.1.4 七种负载均衡算法
    1、RoundRobinRule----默认算法,轮询
    2、RandomRule----随机
    3、AvailabilityFilteringRule----会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
    4、WeightedResponseTimeRule----根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule
    在任意一个服务上,让它速度变慢,修改负载均衡策略,再测试效果:
    /try {
    //让响应速度变慢
    Thread.sleep(500);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    /
    /**

    • 配置负载均衡算法

    • @return
      */
      @Bean //
      public IRule iRule(){
      //使用随机算法
      //return new RandomRule();
      //使用轮询算法
      //return new RoundRobinRule();
      //按照响应时间,响应时间越短的,权重会高 更多的请求会到该服务器
      return new WeightedResponseTimeRule();
      }
      5、RetryRule----先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
      6,BestAvailableRule----会先过滤掉由于多次访问故障而处于断路器跳闸(打开)状态的服务,然后选择一个并发量最小的服务

      7、ZoneAvoidanceRule----默认规则,复合判断server所在区域的性能和server的可用性选择服务器
      3.1.5 随机算法的源码解析
      package com.aaa.gs.config;
      import com.netflix.client.config.IClientConfig;
      import com.netflix.loadbalancer.AbstractLoadBalancerRule;
      import com.netflix.loadbalancer.ILoadBalancer;
      import com.netflix.loadbalancer.Server;
      import java.util.List;
      import java.util.concurrent.ThreadLocalRandom;
      /**

    • @ fileName:MyCustomRule

    • @ description:

    • @ author:zhz

    • @ createTime:2022/2/19 11:21

    • @ version:1.0.0
      /
      public class MyCustomRule extends AbstractLoadBalancerRule {
      public MyCustomRule() {
      }
      /
      *

      • 从众多正常工作的服务器选择一台进行请求
      • @param lb
      • @param key
      • @return
        /
        //SuppressWarnings抑制警告
        @SuppressWarnings({“RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE”})
        public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
        return null;
        } else {
        System.out.println(“ILoadBalancer开始--------”+lb+“--------ILoadBalancer开始”);
        Server server = null;
        //只要后台有参与负载均衡的服务器,必然要返回一个服务
        while(server == null) {
        /
        *
        * 判断刚在获取到正常的服务器是否线程中断(出现故障)
        */
        if (Thread.interrupted()) {
        return null;
        }
        //获取正在运行的服务器
        List upList = lb.getReachableServers();
        System.out.println(“正在运行的服务器:”+upList);
        List allList = lb.getAllServers();
        System.out.println(“所有的服务器:”+allList);
        int serverCount = allList.size();
        System.out.println(“服务器数量:”+serverCount);
        if (serverCount == 0) {
        return null;
        }
        //随机算法
        int index = this.chooseRandomInt(serverCount);
        System.out.println(“随机出的数字必须是:0-”+(serverCount-1)+“中的一个是:”+index);
        //按照随机的下标获取对象
        server = (Server)upList.get(index);
        System.out.println(“当前被选中的服务器为:”+server);
        //再次判断
        if (server == null) {
        //让出CPU时间,让其他线程再次获取server
        Thread.yield();
        } else {
        //再次判断没有活着
        if (server.isAlive()) {
        return server;
        }
        server = null;
        Thread.yield();
        }
        }
        return server;
        }
        }

      public Server choose(Object key)
      {
      return this.choose(this.getLoadBalancer(), key);
      }
      /**

      • 随机算法方法
      • @param serverCount
      • @return
        */
        protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
        }

      public void initWithNiwsConfig(IClientConfig clientConfig) {
      }
      }

    3.2 openfeign
    https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/
    3.2.1简介:
    OpenFeign是一种声明式、模板化的HTTP客户端。是server to server 服务到服务的相互调用的一个组件,推荐使用,和ribbon比较,更符合程序员编写代码的习惯,集成了ribbon 可以进行负载均衡
    1)声明式rest客户端 组件(写在消费者/客户端)
    2) 支持springmvc注解 (@RequestMapping @GetMapping @PutMapping @PostMapping…@RequestParam @RequestBoby @ResponseBody @PathVariable…)
    3) 集成了ribbon ,支持负载均衡
    3.2.2 运行流程:
    图片: https://uploader.shimo.im/f/4yVKLyNBFEHW4aCT.png

    3.2.3 实现过程:
    社交服务中评论对象远程调用查询订单服务中的订单对象
    1)引入jar(在micro_services引入,所有微服务都可能使用openfeign)

    org.springframework.cloud spring-cloud-starter-openfeign 2) 创建评论表,创建项目,反向工程生成代码 CREATE TABLE tb_comment ( id bigint(20) PRIMARY key NOT NULL AUTO_INCREMENT , shop_id bigint(20) NOT NULL , order_id bigint(20) NULL DEFAULT NULL COMMENT '订单ID' , product_id bigint(20) NULL DEFAULT NULL COMMENT '订单为单一商品时,该字段有值' , member_nick_name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , product_name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , star int(3) NULL DEFAULT NULL COMMENT '评价星数:0->5' );

    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘1’, ‘1’, ‘1’, ‘1’, ‘1’, ‘1’, ‘1’);
    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘2’, ‘2’, ‘2’, ‘2’, ‘2’, ‘2’, ‘2’);
    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘3’, ‘1’, ‘11’, ‘11’, ‘测试昵称’, ‘测试商品’, ‘11’);
    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘24’, ‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’);
    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘25’, ‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’);
    INSERT INTO tb_comment (id, shop_id, order_id, product_id, member_nick_name, product_name, star) VALUES (‘28’, ‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’);

    3)编写启动类,添加配置文件application.yml配置
    启动类:
    @SpringBootApplication
    @MapperScan(“com.aaa.ss.dao”)
    @EnableSwagger2
    @EnableDiscoveryClient // 开启发现客户端功能 任何注册中心都可以
    application.yml配置:
    #当前服务端口号
    server:
    port: 14132

    servlet:

    #配置上下文对象 访问的项目名称

    context-path: /ordera

    #阿里druid连接池配置

    spring:
      datasource:
        druid:
          url: jdbc:mysql://localhost:3306/db_qy141?useUnicode=true&characterEncoding=utf8
          username: root
          password: root
          initial-size: 5
          max-active: 20
          min-idle: 10
          max-wait: 10
      application:
        #当前应用的名称  注册后,注册中心会显示该名称,其他服务调用时,也是使用该名称
        name: snsService
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
    mybatis-plus:
      # mapper.xml配置
      mapper-locations: classpath:mapper/*.xml
      configuration:
        #控制台日志输出配置
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      #别名包配置
      type-aliases-package: com.aaa.ss.entity
    #swagger配置
    swagger:
      base-package: com.aaa.ss.controller
      title: "电商项目-商品模块-商品swagger"
      description: "描述"
      version: "3.0"
      contact:
        name: "AAA"
        email: "test@163.com"
        url: "https://www.baidu.com"
      terms-of-service-url: "服务条款:https://www.baidu.com"
    #eureka:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    client:

    #eureka客户端注册域地址

    service-url:

    defaultZone: http://localhost:14112/eureka/

    4) 启动类新加:
    @EnableFeignClients
    5) 服务接口:

     package com.aaa.ss.service;
    import com.baomidou.mybatisplus.extension.api.R;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    /**
     * @ fileName:RemoteOrderService
     * @ description:
     * @ author:zhz
     * @ createTime:2022/2/21 9:23
     * @ version:1.0.0
     */
    //通过声明式注解调用远程服务,在name/value必须配置要调用远程服务在注册中心注册的名称
    @FeignClient(value = "orderService")
    public interface RemoteOrderService {
    
        /**
         * 远程接口调用时 1,要求返回值必须和远程方法的返回值一致
         *               2,要求参数必须和远程方法的参数一致 并且如果是普通属性必须加@RequestParam
         *                  如果对象必须使用json必须加@RequestBody
         *               3, 必须使用restfull风格调用 请求方式和资源定义方式必须一致 也就是说
         *                   远程方法的注解是 @GetMapping,本地调用远程方法,也必须是@GetMapping
         * @param id
         * @return
         */
        @GetMapping("/order/selectOne")
        public R selectOrderOne(@RequestParam("id") Integer id);
    }
        
    远程接口调用时 注意事项:
                      1,要求返回值必须和远程方法的返回值一致
                      2,要求参数必须和远程方法的参数一致 并且如果是普通属性必须加@RequestParam  如果对象必须使用json必须加@RequestBody
                      3, 必须使用restfull风格调用 请求方式和资源定义方式必须一致 也就是说  
                          远程方法的注解是 @GetMapping,本地调用远程方法,也必须是@GetMapping
    图片: https://uploader.shimo.im/f/rPvJ7h0yJC1OOZFO.png
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    1. 本地服务合并数据方法
    package com.aaa.ss.service.impl;
    import com.aaa.ss.service.RemoteOrderService;
    import com.baomidou.mybatisplus.extension.api.R;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.aaa.ss.dao.CommentDao;
    import com.aaa.ss.entity.Comment;
    import com.aaa.ss.service.CommentService;
    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
    import java.io.Serializable;
    /**
     * (Comment)表服务实现类
     *
     * @author makejava
     * @since 2022-02-21 09:11:50
     */
    @Service("commentService")
    public class CommentServiceImpl extends ServiceImpl<CommentDao, Comment> implements CommentService {
        //依赖注入
        @Resource
        private RemoteOrderService remoteOrderService;
        /**
         * 在当前方法中,封装上远程请求到的订单数据
         * @param id
         * @return
         */
        @Override
        public Comment getById(Serializable id) {
            //在评论中封装上订单数据
            Comment comment = baseMapper.selectById(id);
            Long orderId = comment.getOrderId();
            //获取远程数据
            R result = remoteOrderService.selectOrderOne(Integer.valueOf(orderId.toString()));
            comment.setResult(result);
            return comment;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    7)测试:
    先启动注册中心,再启动提供者(order_server_a,b,c),再启动消费者(sns_server_feign)

    3.2.4 openfeign和ribbon有什么区别(面试题):
    1), 启动方式不同
    ribbon 使用:@RibbonClient
    feign 使用: @EnableFeignClients
    2),负载均衡位置不同
    ribbon在RibbonClient注解上配置
    feign 在接口注解上@feignclient 配置的
    3),ribbon借助于RestTemplate使用的Http和Tcp协议,实现服务调用和负载均衡
    feign 使用程序猿习惯的调用方式,调用接口,支持springmvc的注解 底层使用代理
    4,知识点总结
    ribbon 客户端负载均衡器
    openfeign 内置ribbon 使用接口的方式进行远程调用
    5,本章面试题

    5.1 微服务之间是如何独立通讯的
    同步:dubbo 使用rpc(rpc参考帖子),springcloud使用restful传递json(ribbon,openfeign)
    异步:使用消息队列框架(MQ:kafka,activeMQ,rabbitMq等等)
    https://blog.csdn.net/lizhiqiang1217/article/details/89682328

    5.2 ribbon 和nginx 区别:
    1)Ribbon是从注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略一种客户端负载平衡器。
    nginx是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,一个服务器端负载均衡。
    2) 负载均衡算法不一样。nginx 5种 ribbon 7种
    5.3 远程接口调用技术:
    HttpClient RestTemplate 等等 (底层 Url类封装)

  • 相关阅读:
    前端开发禁止用户缩放页面
    java-net-php-python-67ssm在线投票系统计算机毕业设计程序
    linux 配置 NTP 服务器
    虚拟机查看IP地址
    UDS入门至精通系列:Service 29
    低代码助力中小企业数字化
    golang超时控制(转)
    基于Pandas+余弦相似度+大数据智能护肤品推荐系统——机器学习算法应用(含Python工程源码)+数据集
    【填坑】乐鑫ESP32C3 Bootloader开发(上)
    win10任务栏卡死桌面正常的解决方法
  • 原文地址:https://blog.csdn.net/zhangchen124/article/details/125475945