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. 创建父项目

    父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;
        }
    }
    

    服务提供者创建完成。

  1. 创建服务消费者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();
        }
    }
    

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

  2. 服务和负载均衡测试

    我们将三个模块的服务都启动,如下图:


    在这里插入图片描述

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

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

    在这里插入图片描述

    在这里插入图片描述

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

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

    Blog传送门

    本项目代码传送门

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容