负载均衡Ribbon&声明式服务调用Feign

1. 负载均衡Ribbon

1.1 ribbon概述

  • 什么是Ribbon?

        ribbon是基于netfilx ribbon实现的一个工作在consumer端的负载均衡工具,提供了很多负载均衡策略:轮询策略随机策略...

  • Ribbon的启动器

        nacos已经集成了ribbon,故无启动器。

1.2 Ribbon入门案例

  • ConfigBean
@Configuration
public class BeanConfig {

    /**
     * 负载均衡工作原理:
     * 1.Ribbon会给RestTemplate添加一个拦截器,RestTemplate通过服务名“ribbon_provider”获取到List<ServiceList>
     * 2.通过负载均衡算法得到serviceInstance
     * 3.通过serviceInstance把url中的服务名“ribbon_provider”替换成ip和port
     * @return
     */
    @Bean
    @LoadBalanced // 开启负载均衡,默认为轮询策略
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    // 使用随机策略调用服务提供者
    @Bean
    public IRule iRule(){
        return new RandomRule();
    }
}
  • Controller
@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/getUserById/{id}")
    public User getUserById(@PathVariable Integer id) {
        //不使用ribbon:ip:port
        //String serviceUrl = "127.0.0.1:9090";
        //使用ribbon:不再使用ip:port的方式,而是改成了serviceId(即Nacos中注册的服务名称)
        String serviceUrl = "ribbon-provider";
        return restTemplate.getForObject("http://" + serviceUrl + 
                                         "/provider/getUserById/" + id, User.class);
    }
}
  • 测试

分别使用轮询和随机策略调用服务提供者

2. 声明式服务调用Feign

2.1 feign介绍

  • 什么是feign

        Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。

        Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。总结来说:ribbon + restTemplate = feign。

  •  feign的启动器

        spring-cloud-starter-openfeign

2.2 feign的入门案例

   1. 创建feign_provider

        复制一个nacos_provider即可。

   2. 创建feign_interface

  • pom.xml
<!--Spring Cloud OpenFeign Starter -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>com.sanjin</groupId>
    <artifactId>springcloud_common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  • feign接口
package com.bjpowernode.feign;
@FeignClient(value="feign-provider") // 调用指定服务,@FeignClient("服务名")
@RequestMapping(value = "/provider")
public interface UserFeign {
    @RequestMapping(value = "/getUserById/{id}")
    public User getUserById(@PathVariable(value="id") Integer id);
}

   3. 创建feign_consumer

  • pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.sanjin</groupId>
    <artifactId>springcloud_common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<!--feign接口-->
<dependency>
    <groupId>com.sanjin</groupId>
    <artifactId>feign_interface</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  •  application.yml
server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.75.131:8848 #nacos注册地址
        namespace: dev
        group: springcloud_parent
  application:
    name: feign-consumer
  • controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {

    @Autowired
    private UserFeign userFeign;

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        return userFeign.getUserById(id);
    }
}
  • APP
package com.sanjin;

@SpringBootApplication
@EnableDiscoveryClient // 向注册中心注册该服务并发现其他服务
//@EnableFeignClients(basePackages = "com.bjpowernode.feign") 扫描指定包
@EnableFeignClients // 开启feign注解扫描
public class FeignConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignConsumerApplication.class, args);
    }
}

   2.3 feign工作原理 

    1、扫描feign接口生成代理类并交给spring容器去管理
        @EnableFeignClient开启feign注解扫描:FeignClientsRegistrar.registerFeignClients()扫描被@FeignClient标识的接口并生成代理类,再把代理类交给spring的容器去管理。
    2、为接口的方法创建requestTemplate
        当consumer调用feign接口的代理类时,会调用SynchronousMethodHandler.invoke()创建RequestTemplate(HttpMethod、UriTemplate、Body)。
    3、发送请求
        代理类会通过requestTemplate创建request对象,然后client(HttpClient、URLConnect、OkHttp)使用request发送请求。

    2.4 feign传参方式

        restful风格:

                 feign接口:@PathVarible("id")

  ?传参:

                feign接口:@RequestParam("id")

        pojo:

                feign接口:@RequestBody

        案例:

  • ConsumerController
@RestController
@RequestMapping("/consumer")
public class ConsumerController {

    @Autowired
    private UserFeign userFeign;

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        return userFeign.getUserById(id);
    }

    @RequestMapping("/delUserById")
    public User delUserById( Integer id){
        return userFeign.delUserById(id);
    }

    @RequestMapping("/updateUser")
    public User updateUser(User user){
        return userFeign.updateUser(user);
    }

    @RequestMapping("/addUser")
    public List<User> addUser(){
        List<User> userList = new ArrayList<>();
        userList.add(new User(1, "ljx", 18));
        userList.add(new User(2, "mxx", 18));
        return userFeign.addUser(userList);
    }

    @RequestMapping("/delUserByIds")
    public Integer[] delUserByIds(Integer[] ids){
        return userFeign.delUserByIds(ids);
    }
}
  • UserFeign接口
@FeignClient("feign-provider") // 调用指定服务,@FeignClient("服务名")
@RequestMapping("/provider")
public interface UserFeign {
    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id);

    @RequestMapping("/delUserById")
    public User delUserById(@RequestParam("id") Integer id);

    @RequestMapping("/updateUser")
    public User updateUser(@RequestBody User user);

    @RequestMapping("/addUser")
    List<User> addUser(@RequestBody List<User> userList);

    @RequestMapping("/delUserByIds")
    Integer[] delUserByIds(@RequestParam("ids") Integer[] ids);
}
  • ProviderController
@RestController
@RequestMapping("/provider")
public class ProviderController {

    @Autowired
    private UserService userService;

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable Integer id){
        return userService.getUserByUserId(id);
    }

    @RequestMapping("/delUserById")
    public User delUserById(Integer id){
        return userService.delUserById(id);
    }

    @RequestMapping("/updateUser")
    public User updateUser(@RequestBody User user){
        return userService.updateUser(user);
    }

    @RequestMapping("/addUser")
    public List addUser(@RequestBody List<User> userList){
        return userService.addUser(userList);
    }

    @RequestMapping("/delUserByIds")
    public Integer[] delUserByIds(Integer[] ids){
        return userService.delUserByIds(ids);
    }
}
  • UserService
public interface UserService {
    User getUserByUserId(Integer id);

    User delUserById(Integer id);

    User updateUser(User user);

    List addUser(List<User> userList);

    Integer[] delUserByIds(Integer[] ids);
}
  • UserServiceImpl
@Service
public class UserServiceImpl implements UserService {

    @Override
    public User getUserByUserId(Integer id) {
        return new User(id, "ljx-1", 18);
    }

    @Override
    public User delUserById(Integer id) {
        return new User(0-id, "ljx", -18);
    }

    @Override
    public User updateUser(User user) {
        return user;
    }

    @Override
    public List<User> addUser(List<User> userList) {
        return userList;
    }

    @Override
    public Integer[] delUserByIds(Integer[] ids) {
        return ids;
    }
}

2.5 feign优化

   1. 开启feign日志

feign:
  client:
    config:
#      default: # 所有服务都生效
      feign-provider: #指定服务生效
        loggerLevel: full # 输出feign远程调用的详细信息
logging:
  level:
    com.sanjin.feign: debug

    2. http连接池

      仅需添加依赖即可

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

效果图:

   3.GZIP 压缩

        server:
          port: 80
          compression:
            enabled: true #开启浏览器<---->consumer的gzip压缩
        feign:
          compression: #开启feign<---->provider的gzip压缩
            request:
              enabled: true
            response:
              enabled: true

     效果图:

 

   4. feign超时

        注意:当开启feign日志后,feign调用的时间会被延长,在一定时间内不会超时。

        方式一:
            ribbon:
              ConnectionTimeout: 5000 #请求连接的超时时候
              ReadTimeout: 5000 #请求响应的超时时间
        方式二:
            feign:
              client:
                config:
                  #default:
                  feign-provider:
                    ConnectionTimeout: 5000 #请求连接的超时时候
                    ReadTimeout: 5000 #请求响应的超时时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值