侧边栏壁纸
博主头像
樯哥的技术分享网博主等级

学无止境,学以致用,志存高远。

  • 累计撰写 17 篇文章
  • 累计创建 10 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

服务之间互相调用以及负载均衡

随心
2023-06-14 / 0 评论 / 0 点赞 / 49 阅读 / 17635 字

前面的文章我们讲了服务的注册发现,本篇文章来讲一下如何在我们自己的服务中互相调用。

一、创建服务提供者集群

  1. 首先,我们创建一个父工程,工程名叫spring-cloud-demo,其中pom.xml文件配置如下:
    注意修改其中nacos的配置为自己的配置,尤其是命名空间id的值

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.1.0</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>top.jiangqiang</groupId>
        <artifactId>spring-cloud-demo</artifactId>
        <packaging>pom</packaging>
        <modules>
            <module>service-provider-01</module>
            <module>service-provider-02</module>
            <module>service-consumer</module>
            <module>service-gateway</module>
            <module>service-sentinel-feign-consumer</module>
        </modules>
        <version>${revision}</version>
        <name>${project.artifactId}</name>
        <description>spring-cloud-demo</description>
        <properties>
            <revision>1.0</revision>
            <java.version>17</java.version>
            <spring-cloud.version>2022.0.3</spring-cloud.version>
            <spring.cloud.alibaba.version>2022.0.0.0-RC2</spring.cloud.alibaba.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--提供了一些endpoint,可以查看项目信息-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>${spring.cloud.alibaba.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <profiles>
            <profile>
                <id>dev</id>
                <activation>
                    <activeByDefault>true</activeByDefault>
                </activation>
                <properties>
                    <!-- 开发环境 -->
                    <profile.name>dev</profile.name>
                    <!--nacos服务访问地址-->
                    <nacos.server-addr>127.0.0.1:8848</nacos.server-addr>
                    <!--命名空间id-->
                    <nacos.namespace>75d49a80-72f9-4b15-97b8-08ad100100b0</nacos.namespace>
                    <!--nacos用户名和密码-->
                    <nacos.username>nacos</nacos.username>
                    <nacos.password>nacos</nacos.password>
                </properties>
            </profile>
            <profile>
                <id>test</id>
                <properties>
                    <!-- 测试环境,打包命令:mvn clean install -Ptest -->
                    <profile.name>test</profile.name>
                    <nacos.server-addr>127.0.0.1:8848</nacos.server-addr>
                    <nacos.namespace></nacos.namespace>
                    <nacos.username></nacos.username>
                    <nacos.password></nacos.password>
                </properties>
            </profile>
        </profiles>
    </project>
  2. 然后我们创建一个子模块作为其中一个服务,子模块名字为service-provider-01,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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>top.jiangqiang</groupId>
            <artifactId>spring-cloud-demo</artifactId>
            <version>${revision}</version>
        </parent>
        <artifactId>service-provider-01</artifactId>
        <name>${project.artifactId}</name>
        <description>service-provider-01</description>
        <properties>
            <java.version>17</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    </project>
  3. application.yaml文件配置如下:

    server:
      port: 8001
    spring:
      application:
        name: service-provider #如果多个应用的此属性一致,会被注册中心识别为同一个应用的集群
      cloud:
        nacos:
          username: @nacos.username@
          password: @nacos.password@
          config:
            server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址
            namespace: @nacos.namespace@ #命名空间
          discovery:
            server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。
            namespace: @nacos.namespace@
      config:
        import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置
            - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务
            - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略
            - nacos:common.yaml
    
    management:
      endpoints:
        web:
          exposure:
            include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8001/actuator/nacosdiscovery 可以看见nacos配置信息
  4. 新增一个controller类,内容如下:

    @RestController
    public class TestController {
        @Value("${server.port}")
        private String port;
    
        @RequestMapping(value = "getPort")
        public String getPort() {
            return port;
        }
    }
  5. 将我们刚才创建的子模块service-provider-01复制一份,快速创建和他相同的另一个子模块,名字为service-provider-02。注意修改service-provider-02的端口号与子模块service-provider-01的端口号不一致,但是服务名必须一致(这样才能作为集群)。

    service-provider-02修改后的yaml文件内容为:

    server:
      port: 8002
    spring:
      application:
        name: service-provider
      cloud:
        nacos:
          username: @nacos.username@
          password: @nacos.password@
          config:
            server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址
            namespace: @nacos.namespace@ #命名空间
          discovery:
            server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。
            namespace: @nacos.namespace@
      config:
        import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置
          - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务
          - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略
          - nacos:common.yaml
    
    management:
      endpoints:
        web:
          exposure:
            include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8002/actuator/nacosdiscovery 可以看见nacos配置信息

启动这两个模块后,我们就创建了一个简单的服务提供者集群,两个服务使用相同的服务名访问,可以使用nacos的负载均衡技术自动选择。

二、创建服务消费者服务

  1. 创建一个子模块service-consumer,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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>top.jiangqiang</groupId>
            <artifactId>spring-cloud-demo</artifactId>
            <version>${revision}</version>
        </parent>
        <artifactId>service-consumer</artifactId>
        <name>${project.artifactId}</name>
        <description>service-consumer</description>
        <properties>
            <java.version>17</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <!--必须依赖,用于负载均衡-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            </dependency>
            <!--使用feign调用接口时必须依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
        </dependencies>
    
    </project>
  2. 创建启动类如下:该类中,我们通过@EnableFeignClients 注解启用feign客户端,并且注入了RestTemplate实例。@LoadBalanced注解的作用是提供负载均衡,框架底层已经为我们实现了负载均衡功能,此处我们只需要一个注解即可使用。当我们使用RestTemplate的实例调用集群中的服务时,程序会自动选择集群中的一个服务进行调用。具体如何选择,完全在于负载均衡策略。

    //该注解可以省略
    @EnableDiscoveryClient
    @SpringBootApplication
    //使用feign客户端时必须
    @EnableFeignClients
    public class ServiceConsumerApplication {
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceConsumerApplication.class, args);
        }
    
    }

    RestTemplate可用于http接口访问,在此服务中我们使用RestTemplate的实例请求其他服务中的接口,这是一种服务之间的远程调用的方式。同时,我们也可以使用Feign作为另一种远程调用方式,而使用Feign进行远程调用时,会自动启用负载均衡功能。

  3. 创建Feign的服务类,用于调用远程接口:

    @FeignClient(name = "service-provider")
    public interface FeignService {
        @GetMapping(value = "/getPort")
        String getPort();
    }
  4. 创建一个controller类:

    @RestController
    @RequestMapping("/")
    @RequiredArgsConstructor
    public class TestController {
    
        private final RestTemplate restTemplate;
        private final FeignService feignService;
    
        /**
         * 使用RestTemplate实例进行远程调用
         * @return
         */
        @RequestMapping(value = "/getPort1")
        public String getPort1() {
            return "RestTemplate:" + restTemplate.getForObject("http://service-provider/getPort", String.class);
        }
    
        /**
         * 使用Fetch进行远程调用
         * @return
         */
        @RequestMapping(value = "/getPort2")
        public String getPort2() {
            return "Feign:" + feignService.getPort();
        }
    }
  5. application.yaml文件中配置如下:注意loadbalancer这里的配置,如果不配置的话,默认的负载均衡是轮询策略,可以删掉该配置自己试试看。加上之后则是nacos提供的服务端负载均衡策略。

    server:
      port: 8003
    spring:
      application:
        name: service-consumer
      cloud:
        nacos:
          username: @nacos.username@ #@***@这种写法表示从pom.xml文件读取配置
          password: @nacos.password@
          config:
            file-extension: yaml
            server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址
            namespace: @nacos.namespace@ #命名空间
          discovery:
            server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。
            namespace: @nacos.namespace@
        loadbalancer: #使用 Spring Cloud Alibaba 社区针对 Spring Cloud Loadbalancer 负载均衡依赖提供的负载均衡策略,以便使用 Spring Cloud Alibaba 提供的所有的能力
          ribbon:
            enabled: false #关闭ribbon默认的轮询负载均衡策略
          nacos: #使用nacos提供的负载均衡,不使用此配置时,默认的负载均衡是轮询
            enabled: true
      config:
        import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置
          - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务
          - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略
          - nacos:common.yaml
    
    management:
      endpoints:
        web:
          exposure:
            include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8003/actuator/nacosconfig 可以看见nacos配置信息
  6. 启动项目,然后多次访问:localhost:8003/getPort2localhost:8003/getPort1 根据端口号你可以看出请求最终是由哪个服务处理了,你会发现多次访问同一个接口,端口号会发生变化。这表明你的请求被分配给不同的服务了。如果删除yaml文件中loadbalancer相关的配置,你会发现连续两次请求会被分给不同的服务处理。

  7. 进入nacos后台,点击服务提供者集群的详情按钮。详情页如图所示,我们点击下线按钮,再次访问上一步骤中的地址,看看有啥变化。

    当我们下线其中一个服务后,我们的请求就会始终交给另一个没有下线的服务处理,如果是通过RestTemplate远程调用,下线过程可能有半分钟的延迟,半分钟之后我们的请求都会交给唯一没有下线的那个服务去处理。如果两个服务都被下线了,此时我们访问URL就会报错。很显然,当我们需要对某个服务进行重新部署时,最好先在此处点击下线,避免程序正在处理业务时,直接就被杀死。

0

评论区