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

本文介绍如何使用Ribbon实现负载均衡及Feign声明式服务调用,包括配置和服务间通信流程。

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

1.负载均衡Ribbon

1.1.创建服务提供者

1.1.1.创建工程

请添加图片描述

1.1.2.application.yml分别改为
server:
  port: 9090
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.241.131:8848
  application:
    name: ribbon-provider
server:
  port: 9091
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.241.131:8848
  application:
    name: ribbon-provider
1.1.3.service实现类分别改为
@Service
public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Integer id) {
        return new User(id, "自来也_1", 25);
    }
}
@Service
public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Integer id) {
        return new User(id, "自来也_2", 25);
    }
}

1.2.创建服务消费者

1.2.1.创建工程

请添加图片描述

1.2.2.application.yml
server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.241.131:8848
  application:
    name: ribbon-consumer
1.2.3.controller
package com.bjpowernode.controller;

import com.bjpowernode.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

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

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        List<ServiceInstance> serverList = discoveryClient.getInstances("ribbon-provider");
        String url = "http://ribbon-provider/provider/getUserById/" + id;
        return restTemplate.getForObject(url, User.class);
    }
}
1.2.4.修改BeanConfig

在方法名上加上@LoadBalanced注解

    @Bean
    @LoadBalanced
    public RestTemplate RestTemplate(){
        return new RestTemplate();
    }

1.3.测试

浏览器访问http://127.0.0.1/cousumer/getUserById/25通过不断的刷新会轮询出现自来也_1自来也_2

2.声明式服务调用Feign

2.1.背景

当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻

那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。

2.2.Feign入门

2.2.1.创建服务提供者
2.2.1.1.创建工程

请添加图片描述

2.2.1.2.application.yml
server:
  port: 8090
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.241.131:8848
        namespace: dev
        group: springcloud_parent
  application:
    name: feign-provide

2.2.2.创建feign接口

2.2.2.1.创建工程

请添加图片描述

2.2.2.2.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.bjpowernode</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feign_interface</artifactId>

    <dependencies>
        <!--Spring Cloud OpenFeign Starter -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
2.2.2.3.创建消费者

请添加图片描述

2.2.2.4.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_parent</artifactId>
        <groupId>com.bjpowernode</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ribbon_consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign接口-->
        <dependency>
            <groupId>com.bjpowernode</groupId>
            <artifactId>feign_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
2.2.2.5.application.yml
server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.241.131:8848
        namespace: dev
        group: springcloud_parent
  application:
    name: feign-consumer
2.2.2.6.Consumer.Controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {

    @Autowired
    private UserServiceFeign userServiceFeign;

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

    @RequestMapping("/editUser")
    public User editUser(User user){

        return userServiceFeign.editUser(user);
    }

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

    @RequestMapping("/addUser")
    public List<User> addUser(){
        List<User> userList = new ArrayList<>();
        userList.add(new User(1, "张三", 20));
        userList.add(new User(2, "李四", 20));
        userList.add(new User(3, "王五", 20));
        userList.add(new User(4, "赵六", 20));
        userList.add(new User(5, "钱七", 20));
        return userServiceFeign.addUser(userList);
    }

    @RequestMapping("/delUserByIds")
    public Integer[] delUserByIds(Integer[] ids){
        return userServiceFeign.delUserByIds(ids);
    }
}
2.2.2.7.FeignConsumerApp
@SpringBootApplication
@EnableDiscoveryClient  //允许 注册服务和发现服务
@EnableFeignClients  //开启feign注解扫描
public class FeignConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(FeignConsumerApp.class, args);
    }
}

2.2.2.8.feign_interface(feign_interface相当于浏览器,会代替我们发送请求)
package com.bjpowernode.feign;

import com.bjpowernode.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserServiceFeign {
    @RequestMapping("/getUserById/{id}")  //发送请求:provider/getUserById/id
    User getUserById(@PathVariable("id") Integer id);


    @RequestMapping("/editUser")  //发送请求:provider/editUser
    User editUser(@RequestBody User user); //@RequestBody:pojo-->json


    @RequestMapping("/delUserById")  //发送请求:provider/delUserById?id=?
    User delUser(@RequestParam("id") Integer id);



    @RequestMapping("/addUser")  //发送请求:provider/addUser
    List<User> addUser(@RequestBody List<User> userList);


    @RequestMapping("/delUserByIds")  //发送请求:provider/delUserByIds
    Integer[] delUserByIds(@RequestParam("ids") Integer[] ids);
}
2.2.2.9.feign_provider.Controller
@RestController
@RequestMapping("/provider")
public class ProviderController {

    @Autowired
    private UserService userService;

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

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

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

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

    @RequestMapping("/delUserByIds")
    public Integer[] delUserByIds(Integer[] ids){
        return userService.delUserByIds(ids);
    }
}
2.2.2.10.feign_provider.service
public interface UserService {
    User getUserById(Integer id);

    User editUser(User user);

    User delUser(Integer id);


    List<User> addUser(List<User> userList);

    Integer[] delUserByIds(Integer[] ids);
}
2.2.2.11.feign_provider.serviceImpl
@Service
public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Integer id) {
        return new User(id, "自来也", 25);
    }

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

    @Override
    public User delUser(Integer id) {
        return new User(0-id, "佐助", -16);
    }

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

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

2.3.Feign参数传递

传参方式:

  • restful风格:

​ feign接口:@PathVarible【拼接restful形式的url】

  • ?传参

​ feign接口:@RequestParam【拼接?形式的url】

  • pojo参数

​ provider: @RequestBody User user【获取请求体中的json串】

2.4.测试

2.4.1.浏览器访问不同的url

一、访问 localhost/cousumer/getUserById/25

请添加图片描述

二、访问 localhost/consumer/delUserById?id=3

请添加图片描述

三、访问 localhost/consumer/editUser?id=1&name=鸣人&age=16

请添加图片描述

四、访问 localhost/consumer/addUser

请添加图片描述

五、访问 localhost/consumer/delUserByIds?ids=1,2,3,4,5

请添加图片描述

2.5.Feign优化

2.5.1.开启Feign日志
feign:
  client:
    config:
     #dfault:
       feign-provider:
        loggerLevel: full #输出feign远程调用的详细信息
logging:
  level:
    com.bjpowernode.feign: debug #log4j的日志级别
2.5.2.Http连接池

​ HTTP协议是全双工的协议,所以建立连接与断开连接是要经过三次握手与四次挥手的。显然在这种设计中,每次发送Http请求都会消耗很多的额外资源,即连接的建立与销毁。

​ 于是,HTTP协议的也进行了发展,通过持久连接的方法来进行socket连接复用。

只需加入下面依赖便可以开启Http连接池

<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
2.5.3.GZIP压缩
server:
          port: 80
          compression:
            enabled: true #开启浏览器<---->consumer的gzip压缩
        feign:
          compression: #开启feign<---->provider的gzip压缩
            request:
              enabled: true
            response:
              enabled: true

请添加图片描述

2.5.4.Feign超时(feign默认超时时间是1秒)
方式一:
  ribbon:
    ConnectionTimeout: 5000 #请求连接的超时时候
    ReadTimeout: 5000 #请求响应的超时时间
方式二:
  feign:
   client:
    config:
     #default:
     feign-provider:
      ConnectionTimeout: 5000 #请求连接的超时时候
      ReadTimeout: 5000 #请求响应的超时时间

#### 2.5.4.Feign超时(feign默认超时时间是1秒)

```yaml
方式一:
  ribbon:
    ConnectionTimeout: 5000 #请求连接的超时时候
    ReadTimeout: 5000 #请求响应的超时时间
方式二:
  feign:
   client:
    config:
     #default:
     feign-provider:
      ConnectionTimeout: 5000 #请求连接的超时时候
      ReadTimeout: 5000 #请求响应的超时时间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值