Spring Cloud Alibaba 微服务

学习目标:

  • Nacos概述和安装

  • Nacos注册中心

  • Nacos配置中心

  • Nacos集群和持久化

  • 负载均衡Ribbon

  • 声明式服务调用Feign

目录

学习目标:

注意:

                Spring Boot和Spring Cloud的版本号说明

1.Nacos概述和安装

1.1.案例准备

1.1.1、创建springcloud_parent

1.1.2.创建springcloud_common

1.1.3.创建nacos_provider

1、pom.xml

1.1.4.创建nacos_consumer

1.1.5.问题

1.2.Nacos简介

1.2.1.为什么叫Nacos

1.2.2.Nacos是什么

1.3.Nacos安装和启动

1.3.1.下载

1.3.2.安装 (在Linux中安装)

1.3.3.启动和关闭

1.3.4.测试

2. Nacos注册中心

2.1 什么是注册中心

2.2.Nacos注册中心入门

2.2.1.修改nacos_provider

2.3.修改nacos_consumer

2.3.1.pom.xml

2.3.2.application.yml

2.3.3.APP

2.3.4.controller

2.3.5.测试

 3.Nacos配置中心

3.1.什么是Nacos配置中心

3.2.Nacos配置中心入门

3.2.1.创建nacos_config

3.2.2.往Nacos添加配置信息

3.2.3.测试

3.3.配置隔离

3.3.1.Nacos配置管理模型

3.3.2.namespace隔离

3.3.3.group隔离

3.4.服务隔离

3.4.1.修改配置文件

​3.4.2.测试

4.Nacos集群和持久化

4.1.持久化

4.1.1.切换数据库

4.1.2.初始化数据库

4.1.3.测试

4.2.集群

4.2.1.部署架构图:

4.2.2.节点规划

4.2.3.集群搭建

4.3.配置代理服务

4.3.1.安装nginx

4.3.2.配置nginx代理nacos

4.4.测试

5.负载均衡Ribbon

5.1.什么是负载均衡

5.2.自定义实现负载均衡

5.2.1.创建服务提供者

5.2.2.创建服务消费者

5.2.3.测试

5.3.Ribbon介绍

5.3.1.什么是Ribbon

5.3.2.负载均衡策略

5.4.基于ribbon实现负载均衡

5.4.1.修改ribbon_consumer

5.4.2.测试

6.声明式服务调用Feign

6.1.背景

6.2.Feign概述

6.3.Feign入门

 6.3.1.创建工程

 6.3.2.创建feign接口

 6.3.3.创建服务消费者

6.4.Feign原理

6.4.1.将Feign接口代理类注入到Spring容器中

6.4.2.RequestTemplate封装请求信息

6.4.3.发起请求

6.5.Feign参数传递

6.6.Feign请求超时

6.6.1.模拟超时

6.6.2.测试

6.6.3.设置feign超时时间


注意:


Spring Boot和Spring Cloud的版本号说明


  • 版本号说明

    Spring Cloud是基于Springboot的对应版本号开发的,属于依赖的关系,所以不能都选用最新版本

  • Spring Boot和Spring Cloud的版本号如下:

    Spring Boot版本号:Spring Boot

    Spring Cloud版本号:Spring Cloud

    Spring Cloud Alibaba版本号:Spring Cloud Alibaba

  • 下表为按时间顺序发布的 Spring Cloud Alibaba 以及对应的适配 Spring Cloud 和 Spring Boot 版本关系

    Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version
    2021.0.1.0Spring Cloud 2021.0.12.6.3
    2.2.7.RELEASESpring Cloud Hoxton.SR122.3.12.RELEASE
    2021.1Spring Cloud 2020.0.12.4.2
    2.2.6.RELEASESpring Cloud Hoxton.SR92.3.2.RELEASE
    2.1.4.RELEASESpring Cloud Greenwich.SR62.1.13.RELEASE
    2.2.1.RELEASESpring Cloud Hoxton.SR32.2.5.RELEASE
    2.2.0.RELEASESpring Cloud Hoxton.RELEASE2.2.X.RELEASE
    2.1.2.RELEASESpring Cloud Greenwich2.1.X.RELEASE
    2.0.4.RELEASE(停止维护,建议升级)Spring Cloud Finchley2.0.X.RELEASE
    1.5.1.RELEASE(停止维护,建议升级)Spring Cloud Edgware1.5.X.RELEASE

1.Nacos概述和安装


1.1.案例准备

1.1.1、创建springcloud_parent

     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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zzcsy</groupId>
    <artifactId>springcloud_parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <properties>
        <!-- 项目源码及编译输出的编码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 项目编译JDK版本 -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!--Spring Boot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Netflix-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud 阿里巴巴-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1.1.2.创建springcloud_common

1、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.zzcsy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud_common</artifactId>

</project>

2、pojo

public class User {
    private Integer id;
    private String name;
    private Integer age;

    public User() {
    }

    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

1.1.3.创建nacos_provider

1、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.zzcsy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos_provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.zzcsy</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

2、application.yml

server:
  port: 9090

3、APP (启动项:命名规范为项目名+App)

@SpringBootApplication
public class ProviderApp {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

4、service

@Service
public class UserServiceImpl implements UserService {

	@Override
	public User getUserById(Integer id) {
		return new User(id,"李二狗",18);
	}
}

5、controller

@RestController
@RequestMapping("/provider")
public class ProviderController {
	
	@Autowired
	private UserService userService;

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

1.1.4.创建nacos_consumer

1、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.zzcsy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos_consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.zzcsy</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

2、application.yml

server:
  port: 80

3、App

@SpringBootApplication
public class ConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

4、config

@Configuration
public class ConfigBean {

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

5、controller

@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {
	
	//访问Rest服务的客户端
	@Autowired
	private RestTemplate restTemplate;

	@RequestMapping(value="/getUserById/{id}")
	public User getUserById(@PathVariable Integer id){
		//调用服务
		String url = "http://127.0.0.1:9090/provider/getUserById/"+id;
		return restTemplate.getForObject(url, User.class);
	}
}

1.1.5.问题


通过这一章的操作,我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:

  • 一旦服务提供者地址变化,就需要手工修改代码

  • 一旦是多个服务提供者,无法实现负载均衡功能

  • 一旦服务变得越来越多,人工维护调用关系困难

那么应该怎么解决呢,这时候就需要通过注册中心动态的实现服务治理。

1.2.Nacos简介

1.2.1.为什么叫Nacos

前面四个字母分别表示 Naming 和 Configuration 的前两个字母, 最后一个s 为 Service

1.2.2.Nacos是什么

Nacos 是阿里巴巴的新开源项目,其核心定位是 “一个更易于帮助构建云原生应用的集注册中心与配置中心于一体的管理平台”。

1.3.Nacos安装和启动

1.3.1.下载

下载地址:Tags · alibaba/nacos · GitHub

1.3.2.安装 (在Linux中安装)

解压安装包:

[root@localhost ~]# cd /usr/upload 
[root@localhost upload]# tar -zxvf nacos-server-1.4.1.tar.gz -C /usr/local  

1.3.3.启动和关闭

启动:

[root@localhost local]# cd nacos/bin/ 
[root@localhost bin]# ./startup.sh -m standalone #非集群模式启动 
... ... nacos is starting with standalone nacos is starting,
you can check the /usr/java/nacos/logs/start.out

关闭:

[root@localhost bin]# ./shutdown.sh 
The nacosServer(3543) is running... Send shutdown request to nacosServer(3543) OK [root@localhost bin]

1.3.4.测试

浏览器访问:http://192.168.216.133:8848/nacos,(Ip地址为安装Nacos的Linux ip地址  包括后文中yml中的地址)默认用户名/密码为: nacos/nacos

 

2. Nacos注册中心


2.1 什么是注册中心


注册中心主要有三部分组成:

Ø Nacos-Server:注册中心

提供服务的注册和发现。

Ø Nacos-Provider:服务提供方

把自身的服务实例注册到 Nacos Server 中

Ø Nacos-Consumer:服务调用方

通过 Nacos Server 获取服务列表,消费服务。


2.2.Nacos注册中心入门


2.2.1.修改nacos_provider

1、pom.xml

       <!--nacos客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2、application.yml    

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848 #nacos服务的地址 
  application:
    name: nacos-provider #向注册中心注册的名字

3、APP

@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
public class ProviderApp {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

4、测试

2.3.修改nacos_consumer

2.3.1.pom.xml

        <!--nacos客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2.3.2.application.yml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848 #nacos服务的地址
  application:
    name: nacos-consumer #向注册中心注册的名字

2.3.3.APP

@SpringBootApplication
@EnableDiscoveryClient//向注册中心注册该服务,并可以获取其他服务的调用地址
public class ConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

2.3.4.controller

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

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;//发现服务的工具类

    @RequestMapping("/getUserById/{id}")
    public User getUserById(@PathVariable Integer id) {

        //获取nacos中注册的所有服务信息
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            System.out.println(service);
        }
        //获取nacos中注册的指定服务信息
        ServiceInstance instance = discoveryClient.getInstances("nacos-provider").get(0);
        String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/provider/getUserById/" + id;
        return restTemplate.getForObject(url, User.class);
    }
}

2.3.5.测试

 3.Nacos配置中心


3.1.什么是Nacos配置中心


微服务架构下关于配置文件的一些问题:

  • 配置文件相对分散。在一个微服务架构下,配置文件会随着微服务的增多变的越来越多,而且分散在各个微服务中,不好统一配置和管理。

  • 配置文件无法区分环境。微服务项目可能会有多个环境,例如:测试环境、预发布环境、生产环境。每一个环境所使用的配置理论上都是不同的,一旦需要修改,就需要我们去各个微服务下手动维护,这比较困难。

  • 配置文件无法实时更新。我们修改了配置文件之后,必须重新启动微服务才能使配置生效,这对一个正在运行的项目来说是非常不友好的。

基于上面这些问题,我们就需要配置中心的加入来解决这些问题,配置中心的思路是:

  1. 首先把项目中各种配置全部都放到一个集中的地方进行统一管理。

  2. 当各个服务需要获取配置的时候,就来配置中心的接口拉取自己的配置。

  3. 当配置中心中的各种参数有更新的时候,也能通知到各个服务实时的过来同步最新的信息,使之动态更新。

3.2.Nacos配置中心入门


3.2.1.创建nacos_config

1、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>ccom.zzcsy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>nacos_config</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--nacos配置中心的启动器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    </dependencies>
</project>

2、bootstrap.yml

  • 注意:

    • 客户端配置文件的名称必须为bootstrap.yml

  • bootstrap/ application 的应用场景:

    • bootstrap.ymlapplicaton.yml 优先加载,应用于系统级别参数配置,一般不会变动;

    • application.yml应用于SpringBoot项目的自动化配置;

  •  案例:
    spring:
      cloud:
        nacos:
          config:
            server-addr: 192.168.216.133:8848
            file-extension: yaml #后缀名,只支持 properties 和 yaml 类型
            prefix: nacos-config #文件名,如果没有配置则默认为 ${spring.appliction.name}

    3、App

  • @SpringBootApplication
    @EnableDiscoveryClient
    public class NacosConfigApp {
        public static void main(String[] args) {
            SpringApplication.run(NacosConfigApp.class,args);
        }
    }

    4、controller

  • @RestController
    @RefreshScope//修改配置文件后重新生成bean
    public class ConfigController {
    
        @Value("${spring.datasource.driver-class-name}")
        private String driverClassName;
        @Value("${spring.datasource.url}")
        private String url;
        @Value("${spring.datasource.username}")
        private String username;
        @Value("${spring.datasource.password}")
        private String password;
        @Value("${spring.datasource.type}")
        private String type;
    
        @GetMapping("/config/info")
        public String getConfigInfo() {
            String configInfo = driverClassName + "<br>" + url + "<br>" + username + "<br>"
                    + password + "<br>" + type;
            System.out.println(this);
            return configInfo;
        }
    }

    3.2.2.往Nacos添加配置信息

    1、Nacos的Data ID

  • 在 Nacos 中,dataId(配置文件的命名的规则) 的完整格式如下:

    ${spring.cloud.nacos.config.prefix}.${spring.cloud.nacos.config.file-extension}

  • 说明:

    • spring.cloud.nacos.config.prefix:默认是当前服务的服务名称

    • spring.cloud.nacos.config.file-extension:配置文件的格式(后缀),目前只支持yaml和properties

·        2、创建配置文件

               1.新建配置文件

                2.添加配置文件

                  1.填写配置文件名称、格式、内容

                 2.内容为:

server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848
  application:
    name: nacos-config
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.216.130:3306/health?characterEncoding=UTF-8
    username: root
    password: 2222
    type: com.alibaba.druid.pool.DruidDataSource

3.2.3.测试


  1. 启动时加载配置文件

    2.修改配置文件后nacos监听到MD5有变化则推送消息给客户端,客户端收到消息后会拉取最新         配置(参考 配置管理->监听查询菜单)

3.浏览器访问:http://127.0.0.1/config/info

3.3.配置隔离

3.3.1.Nacos配置管理模型

  • 对于Nacos配置管理,通过Namespace、group、Data ID能够定位到一个配置集。

  • Namespace Group DataId介绍:

    • Namespace: 代表不同的环境的配置隔离, 如: 开发、测试, 生产等

    • Group: 可以代表某个项目, 如XX医疗项目, XX电商项目

    • DataId: 每个项目下往往有若干个工程, 每个配置集(DataId)是一个工程的主配置文件

  • 获取配置集需要指定:

    1. nacos服务地址,必须指定

    2. namespace,如不指定默认public

    3. group,如不指定默认 DEFAULT_GROUP

    4. dataId,必须指定

3.3.2.namespace隔离

前面已经介绍过,命名空间(Namespace)是用于隔离多个环境的(如开发、测试、生产),而每个应用在不同环境的同一个配置(如数据库数据源)的值是不一样的。因此,我们应针对企业项目实际研发流程、环境进行规划。如某软件公司拥有开发、测试、生产三套环境,那么我们应该针对这三个环境分别建立三个namespace。

1、新建namespace

2、建立好所有namespace后,在配置管理与服务管理模块下所有页面,都会包含用于切换namespace的选项卡,如下图:

3、克隆配置文件

点击左下角克隆按钮,将会弹出克隆对话框,此功能可用于将配置迁移到其他Namespace。

 

4、读取配置文件

spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.216.133:8848
        file-extension: yaml
        prefix: nacos-config
        namespace: a66ca122-fb24-46ba-bde0-58508c2d6689 #开发环境

3.3.3.group隔离

1、新建配置文件

1.新建配置文件并修改Group名

2.不同的配置分组下可以有相同的配置

2、读取配置文件

spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.216.132:8848
        file-extension: yaml
        prefix: nacos-config
        namespace: a66ca122-fb24-46ba-bde0-58508c2d6689
        group: NACOS_GROUP #nacos项目

3.4.服务隔离

3.4.1.修改配置文件

3.4.2.测试


4.Nacos集群和持久化


Nacos默认有自带嵌入式数据库derby,但是如果做集群模式的话,就不能使用自己的数据库不然每个节点一个数据库,那么数据就不统一了,需要使用外部的mysql

4.1.持久化

4.1.1.切换数据库

修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql,版本要求:5.6.5+)

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.31.19:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=1111

4.1.2.初始化数据库

创建nacos数据库并导入sql

4.1.3.测试

重启nacos测试nacos所有写到嵌入式数据库的数据是否都写到了mysql:

4.2.集群

4.2.1.部署架构图:

4.2.2.节点规划

节点端口
192.168.216.1338848
192.168.216.1338849
192.168.216.1338850

4.2.3.集群搭建

  1、 找到conf/cluster.conf.example ,将其改名为 conf/cluster.conf ,并将内容改为如下:

# ip:port 
192.168.216.133:8848 
192.168.216.133:8849 
192.168.216.133:8850

  2、复制三份Nacos

[root@localhost bin]# cd /usr/local
[root@localhost java]# mkdir nacos_cluster 
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8848 
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8849 
[root@localhost java]# cp -r nacos nacos_cluster/nacos_8850

  3、将 conf/application.properties 中的端口号分别改为:

server.port=8848 
server.port=8849 
server.port=8850

4.3.配置代理服务

4.3.1.安装nginx

  • 安装nginx的依赖库

yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
  • 下载nginx

wget -c https://nginx.org/download/nginx-1.12.0.tar.gz
  • 解压安装包

tar -zxvf nginx-1.12.0.tar.gz

配置nginx安装包

cd nginx-1.12.0 ​ 
./configure --prefix=/usr/local/nginx

注意:./configure配置nginx安装到/usr/java/nginx目录下

  • 编译并安装

make && make install

4.3.2.配置nginx代理nacos

upstream nacos {
  server 192.168.216.133:8848;
  server 192.168.216.133:8849;
  server 192.168.216.133:8850;
}
​
server {
  listen 80;
  server_name  localhost;
  location / {
    proxy_pass http://nacos;
  }
}

4.4.测试

1.启动nacos集群

[root@localhost upload]# cd /usr/local/nacos_cluster/nacos_8848/bin [root@localhost bin]# ./startup.sh 
[root@localhost bin]# cd /usr/local/nacos_cluster/nacos_8849/bin 
[root@localhost bin]# ./startup.sh 
[root@localhost bin]# cd /usr/local/nacos_cluster/nacos_8850/bin 
[root@localhost bin]# ./startup.sh

2.启动nginx

[root@localhost nginx]# cd /usr/local/nginx/sbin/ 
[root@localhost sbin]# ./nginx 

3.将微服务注册到Nacos集群

4.访问nacos集群

启动nacos-config服务,并通过nginx访问nacos集群:http://192.168.209.129/nacos

 


5.负载均衡Ribbon


5.1.什么是负载均衡

        通俗的讲,负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。

 

5.2.自定义实现负载均衡

5.2.1.创建服务提供者

1、创建工程

 2、application.yml

server:
  port: 9090
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848
  application:
    name: ribbon-provider
server:
  port: 9091
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848
  application:
    name: ribbon-provider

5.2.2.创建服务消费者

1、创建工程

2、application.yml

server:
  port: 80
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848
  application:
    name: ribbon-consumer

3、controller

@RestController
@RequestMapping("/consumer")
public class ConsumerController {
	
	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private DiscoveryClient discoveryClient;

	private int index;

	@RequestMapping(value="/getUserById/{id}")
	public User getUserById(@PathVariable Integer id){
		List<ServiceInstance> serviceList = 
            				discoveryClient.getInstances("ribbon-provider");

		//随机方式获得服务
		//int currentIndex = new Random().nextInt(serviceList.size());
		//轮询方式获得服务
		index=index + 1;
        int currentIndex = (index) % serviceList.size();
		
		ServiceInstance instance = serviceList.get(currentIndex);
		String serviceUrl = instance.getHost() + ":" + instance.getPort();
        System.out.println("serviceUrl:"+serviceUrl);
		String url = "http://"+serviceUrl+"/provider/getUserById/"+id;
		return restTemplate.getForObject(url, User.class);
	}
}

5.2.3.测试

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

5.3.Ribbon介绍

5.3.1.什么是Ribbon

  • Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

  • 我们不需要去引入ribbon的依赖,因为在nacos里面已经集成了ribbon的依赖:

  • Ribbon默认提供 很多种负载均衡算法,例如轮询、随机 等等。

5.3.2.负载均衡策略

负载均衡接口:com.netflix.loadbalancer.IRule  

1、随机策略

com.netflix.loadbalancer.RandomRule:该策略实现了从服务清单中随机选择一个服务实例的功能。

       

 

2、轮询策略

com.netflix.loadbalancer.RoundRobinRule:该策略实现按照线性轮询的方式依次选择实例的功能。具体实现如下,在循环中增加了一个count计数变量,该变量会在每次轮询之后累加并求余服务总数

 

 

5.4.基于ribbon实现负载均衡

5.4.1.修改ribbon_consumer

1、ConfigBean

@Configuration
public class ConfigBean {

	@Bean
	/**
	 * 添加了@LoadBalanced注解之后,Ribbon会给restTemplate请求添加一个拦截器,在拦截器中获取
	 * 注册中心的服务列表,并使用Ribbon内置的负载均衡算法从服务列表里选中一个服务,通过获取到的服务信息        * (ip,port)替换 serviceId 实现负载请求。
	 */
	@LoadBalanced //开启负载均衡
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}

	//随机策略
	@Bean
	public IRule iRule() {
		return new RandomRule();
	}
}

2、controller

@RestController
@RequestMapping("/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);
    }
}

5.4.2.测试

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

6.声明式服务调用Feign

6.1.背景

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

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

6.2.Feign概述

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

Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。

6.3.Feign入门

 6.3.1.创建工程

        1、 拷贝ribbon_provider_1

                

        2、application.yml

server:
  port: 9090
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.216.133:8848
  application:
    name: feign-provider

 6.3.2.创建feign接口

         1、创建工程

               

           2、pom.xml

 <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>

        3、feign

@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {

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

6.3.3.创建服务消费者

        1.创建工程

         2、pom.xml

        <!--feign接口-->
        <dependency>
            <groupId>com.zzcsy</groupId>
            <artifactId>feign_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        3、controller

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

   @Autowired
    private UserFeign userFeign;//代理类

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

        4、App

@SpringBootApplication
@EnableDiscoveryClient
//@EnableFeignClients(basePackages = "com.bjpowernode.feign")
@EnableFeignClients//开启feign接口扫描
public class ConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

6.4.Feign原理

6.4.1.将Feign接口代理类注入到Spring容器中

@EnableFeignClients注解开启Feign扫描,先调用FeignClientsRegistrar.registerFeignClients()方法扫描@FeignClient注解的接口,再将这些接口注入到Spring IOC容器中,方便后续被调用。

public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		... ... ...
         //扫描feign接口   
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) 
                                                              candidateComponent;
                      //获得UserFeign的详细信息
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");

					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(FeignClient.class.getCanonicalName());
					String name = getClientName(attributes);
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));
                      //注入Feign接口代理类到Spring容器中
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

6.4.2.RequestTemplate封装请求信息

SynchronousMethodHandler.invoke(): 当定义的的Feign接口中的方法被调用时,通过JDK的代理方式为Feign接口生成了一个动态代理类,当生成代理时,Feign会为每个接口方法创建一个RequestTemplate。该对象封装了HTTP请求需要的全部信息,如请url、参数,请求方式等信息都是在这个过程中确定的。

 public Object invoke(Object[] argv) throws Throwable {
        //创建一个RequestTemplate
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
                //发出请求
                return this.executeAndDecode(template);
            } catch (RetryableException var8) {
                ... ... ...
            }
        }
    }
package feign;

public final class RequestTemplate implements Serializable {
    ... ... ... ... ... ...
    private UriTemplate uriTemplate;
    private HttpMethod method;
    private Body body;
    ... ... ... ... ... ...
}    

6.4.3.发起请求

SynchronousMethodHandler.executeAndDecode():

通过RequestTemplate生成Request,然后把Request交给Client去处理,Client可以是JDK原生的URLConnection,Apache的HttpClient,也可以时OKhttp,最后Client结合Ribbon负载均衡发起服务调用。

 Object executeAndDecode(RequestTemplate template) throws Throwable {
        //生成请求对象
        Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }

        long start = System.nanoTime();

        Response response;
        try {
            //发起请求
            response = this.client.execute(request, this.options);
        } catch (IOException var15) {
            ... ... ...

            throw FeignException.errorExecuting(request, var15);
        }
 }       

6.5.Feign参数传递

传参方式:

  • restful风格:

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

  • ?传参

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

  • pojo参数

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

6.6.Feign请求超时

6.6.1.模拟超时

  • 修改feign_privider:

    @Service
    public class UserServiceImpl implements UserService {
    
    	@Override
    	public User getUser() {
            //模拟网络延迟
    		try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		return new User(1,"李二狗",18);
    	}
    }

    6.6.2.测试

     

    6.6.3.设置feign超时时间

ribbon:
  ConnectTimeout: 5000 #请求连接的超时时间
  ReadTimeout: 5000 #请求处理的超时时间

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值