Spring Cloud Alibaba使用Nacos做注册中心,Feign负载均衡远程调用

对在Spring Cloud Alibaba使用nacos做注册和动态配置中心,Feign远程调用,并实现负载均衡的学习过程做一下总结,希望大家共同进步。


一. 安装nacos服务

  1. 具体安装步骤可参考这篇博客:
    https://blog.csdn.net/qq_32352777/article/details/86560333

    写的很不错,感谢作者。

  2. 安装问题总结

    • 测试环境一般建议安装单机版的,简单快速。集群安装的话,为了符合高可用的要求,MySQL也需要安装成集群形式。如Master-Slave模式。

    • 如果是在虚拟机上安装,一般的虚拟机我们不会给分配太大内存。所以我们得根据自己的机子内存情况修改一下nacos启动时默认分配的虚拟机内存,否则会启动失败,我们去查看nacos的安装目录下的log目录的nacos.log日志,会发现报内存不足的异常。

      (1)在nacos安装目录下,打开nacos启动脚本。

      vim  bin/startup.sh
      

      (2)vim模式下ctrl+f向后翻页,找到如下部分
      在这里插入图片描述
      (3)根据实际情况进行对nacos启动jvm虚拟机内存设置进行修改。

二. 代码实现

  1. 创建父项目

    扫描二维码关注公众号,回复: 9687955 查看本文章

    父pom,具体说明在注释里面

        <?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>
    	<groupId>com.test</groupId>
    	<artifactId>cloud-test</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>cloud-test</name>
    	<packaging>pom</packaging>
    
    	<!--子模块-->
    	<modules>
    		<module>cloud-service1</module>
    		<module>cloud-service2</module>
    		<module>cloud-consumer</module>
    		<module>cloud-common</module>
    	</modules>
    
    	<!--依赖的组件的大版本号-->
    	<properties>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
    		<spring-cloud-alibaba.version>0.9.0.RELEASE</spring-cloud-alibaba.version>
    		<spring-boot-starter-parent.version>2.2.2.RELEASE</spring-boot-starter-parent.version>
    	</properties>
    
    	<!--依赖jar包版本管理-->
    	<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>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-alibaba-dependencies</artifactId>
    				<version>${spring-cloud-alibaba.version}</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    			<dependency>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-starter-parent</artifactId>
    				<version>${spring-boot-starter-parent.version}</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    	    
    	<dependencies>
    		<!--服务发现(注册中心)-->
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    		</dependency>
    		<!--配置中心-->
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>fastjson</artifactId>
    			<version>LATEST</version>
    		</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>
    

    项目结构图:

    在这里插入图片描述

  2. 创建公共子模块

    公共做模块是放服务调用的接口和一些公共实体类和公共工具的。结构如下:

    在这里插入图片描述

    pom文件:

        <?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>
        <artifactId>cloud-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cloud-consumer</name>
        <packaging>jar</packaging>
    
        <parent>
            <groupId>com.test</groupId>
            <artifactId>cloud-test</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
    
            <dependency>
                <groupId>com.test</groupId>
                <artifactId>cloud-common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    创建一个测试的实体类User

    package com.common.model;
    
    import lombok.Data;
    
    /**
     * Author: yhl
     * DateTime: 2019/12/8 23:13
     * Description: write some description
     */
    @Data
    public class User {
        private Long id;
        private String name;
        private String url;
    }
    

    创建微服务调用的接口IUserService

    package com.common.service;
    
    import com.common.model.User;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.Map;
    
    /**
     * Author: yhl
     * DateTime: 2019/12/8 23:13
     * Description: write some description
     */
    public interface IUserService {
    
        @RequestMapping("/testOut")
        Map<Object,Object> test(@RequestParam("name") String name);
    
        @RequestMapping("/testOutObj")
        User testObj(@RequestBody User user);
    
        @RequestMapping("/testNacosDynamicProp")
        String testNacosDynamicProp();
    }
    

    配置文件application.yml可以放置一些公共的参数配置,比如加解密私钥等等

  3. 创建服务提供者

    此模块为服务提供方,实现真正的业务逻辑。结构如下:

    在这里插入图片描述

    为了测试Feign的负载均衡,创建两个一样结构和内容的服务提供者,分别命名为cloud-service1和cloud-service2,在它们各自的application.yml中,使用不同的端口号来模拟不同地址的相同的服务。

    pom:

        <?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>com.test</groupId>
            <artifactId>cloud-test</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
        <artifactId>cloud-service1</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cloud-service1</name>
        <packaging>jar</packaging>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
    
            <!--引入公共模块-->
            <dependency>
                <groupId>com.test</groupId>
                <artifactId>cloud-common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    </project>
    

    创建配置文件bootstrap.yaml和application.yml

    bootstrap.yml如下:

    spring:
    application:
    # 服务提供者名称
    name: cloud-service
    cloud:
    nacos:
      discovery:
        # 服务注册于发现地址
        server-addr: 192.168.31.217:8848
      config:
        # 配置中心地址
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        # 配置中心配置文件的格式,如果不设置此项,默认为.properties格式
        file-extension: yaml
    

    application.yml如下:

    #服务端口,这里我们设置cloud-service1为8001,cloud-service2为8002
    server:
      port: 8081
    

    有了application.yml,为什么还要创建一个bootstrap.yml呢,它们俩的区别如下:

    https://blog.csdn.net/ThinkWon/article/details/100007093

    感谢这篇文章的作者,解开了我的迷惑。

    创建启动类ServiceApplication1

    package com.service;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    public class ServiceApplication1 {
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceApplication1.class, args);
        }
    
    }
    

    创建服务提供类UserServiceProvider

    package com.service.controller;
    
    import com.common.model.User;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Author: yhl
     * DateTime: 2019/12/8 23:17
     * Description: write some description
     */
    @RestController
    public class UserServiceProvider {
    
        @RequestMapping("/testOut")
        public Map test(@RequestParam("name") String name, HttpServletRequest req) {
            Map<Object, Object> map = new HashMap<>();
            map.put("url", req.getRequestURL().toString());
            map.put("name", name);
            return map;
        }
    
        @RequestMapping("/testOutObj")
        public User testObj(@RequestBody() User user, HttpServletRequest req) {
            user.setUrl(req.getRequestURL().toString());
            return user;
        }
    }
    

    服务提供者创建完成。

  4. 创建服务消费者cloud-consumer

    pom文件:

    	<?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>
        <artifactId>cloud-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cloud-consumer</name>
        <packaging>jar</packaging>
    
        <parent>
            <groupId>com.test</groupId>
            <artifactId>cloud-test</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.test</groupId>
                <artifactId>cloud-common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    		
    		<!-Feign--->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    	</dependencies>
    </project>
    

    因为远程调用使用的是Feign组件,所以pom中加了Feign的依赖。

    创建配置文件bootstrap.yaml和application.yml

    bootstrap.yml如下:

    spring:
    application:
    # 服务提供者名称
    name: cloud-consumer
    cloud:
    nacos:
      discovery:
        # 服务注册于发现地址
        server-addr: 192.168.31.217:8848
      config:
        # 配置中心地址
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        # 配置中心配置文件的格式,如果不设置此项,默认为.properties格式
        file-extension: yaml
    

    application.yml如下:

    #服务端口,这里我们设置cloud-service1为8001,cloud-service2为8002
    server:
      port: 8080
    

    创建服务消费者启动类ConsumerApplication

    package com.consumer;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableFeignClients//开启feign
    public class ConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    

    在启动类上加@EnableFeignClients,代表开启了对feign组件的支持。

    继承服务提供方接口UserService

    @FeignClient(name ="cloud-service")
    public interface UserService extends IUserService {
    }
    

    此接口方法继承了我们在common模块定义的微服务接口,加上@FeignClient注解之后,表示可使用Feign来调用此接口中方法中@RequestMapping映射路径的服务提供者的http服务。
    此接口是我抽象出来的,目的是不用在common模块中也引入Feign的依赖,当然也可以不用这么写。直接在IUserService接口加上@FeignClient注解。

    @FeignClient中的name属性配置的为bootstrap.yml中配置的服务提供者名称。

    创建消费者接口UserConsumerController

    package com.consumer.controller;
    
    import com.common.model.User;
    import com.consumer.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Map;
    
    /**
     * Author: yhl
     * DateTime: 2019/12/8 23:12
     * Description: write some description
     */
    @RestController
    public class UserConsumerController {
    
        @Autowired
        private UserService userService;
    
        @RequestMapping("/test")
        public Map<Object,Object> test() {
            return userService.test("张三");
        }
    
        @RequestMapping("/testObj")
        public User testObj() {
            return userService.testObj(new User());
        }
    
        @RequestMapping("/testNacosDynamicProp")
        public String testNacosDynamicProp() {
            return userService.testNacosDynamicProp();
        }
    }
    

    创建负载均衡配置类ConfigBean

    package com.consumer.config;
    
    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;
    
    /**
     * @author: yhl
     * @DateTime: 2019/12/9 13:37
     * @Description:
     */
    
    @Configuration
    public class ConfigBean {
        /**
         * 默认按顺序轮询
         * @return
         */
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    

    至此,我们的模块都创建完毕了,接下来进行测试。

  5. 服务和负载均衡测试

    我们将三个模块的服务都启动,如下图:
    在这里插入图片描述

    利用http接口测试工具来测试我们的接口

    选择一个接口进行测试,如 http://localhost:8080/test

    在这里插入图片描述
    在这里插入图片描述

    发送两次请求,会发现打印的请求地址的端口号不同,说明实现了负载均衡。
    连续发送多次请求,端口号会交替变化,因为默认的负载均衡策略为轮训法。

     由于本篇内容过程长,关于feign的负载均衡细节,单独再开一篇blog,感兴趣的话可以接着看
    

    Blog传送门

    本项目代码传送门

    有什么问题欢迎大家交流。

发布了23 篇原创文章 · 获赞 18 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35457078/article/details/103465130