SrpingCloud 服务与消费 初识Eureka Consumer Ribbon

        因为Spring Boot 的更迭,很多资料的不匹配,特别是依赖的问题,让我折腾了两天才正常的运行起来。深受其苦,所以,写一个完整的流程,希望可以帮助到大家。

  1. 搭建服务注册中心

     

      pom.xml 的依赖内容如下,spring-cloud-dependencies 和 spring-cloud-starter-netflix-eureka-server 一定要注意版本:

    <?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>2.5.3</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>eureka-server</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>eureka-server</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>2020.0.3</spring-cloud.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
                <version>3.0.3</version>
            </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>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

      
      application.properties 配置信息:

    ​
    server.port=1111
    
    eureka.instance.hostname=localhost
    # 让服务中心不注册自己
    eureka.client.register-with-eureka=false
    eureka.client.fetch-registry=false
    eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
    
    ​

        完成了上面的配置后,启动应用并访问 http://localhost:1111/​ 

  2. 注册服务提供者
        继续快速创建一个 spring Boot 项目,将其作为一个微服务应用向服务注册中心发布自己。因为涉及控制台输出,所以额外引入了 log4j
    <?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>2.5.3</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.hello</groupId>
        <artifactId>consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>consumer</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>2020.0.3</spring-cloud.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
                <version>3.0.3</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-log4j</artifactId>
                <version>1.3.7.RELEASE</version>
                <type>pom</type>
            </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>
            </dependencies>
        </dependencyManagement>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

            接着,实现 /hello 请求处理接口,通过注入 DiscoveryCLient 对象,在日志中打印相关的服务。

    package com.hello.consumer;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.cloud.client.serviceregistry.Registration;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    public class HelloController {
    
        private final Logger logger = Logger.getLogger(getClass());
    
        @Autowired
        private DiscoveryClient client;
        @Autowired
        private Registration registration; // 服务注册
        
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
        public String index() {
            ServiceInstance instance = null;
            String serviceId = registration.getServiceId();
            List<ServiceInstance> instanceList = client.getInstances(serviceId);
            if (instanceList != null && instanceList.size() > 0) {
                instance = instanceList.get(0);
            }
            System.out.println(instance.toString());
            logger.info("/hello, host:" + instance.getHost() + ", service_id:" + instance.getServiceId());
            return "Hello World";
        }
    }
    

            然后,在主类中通过加上 @EnablesDiscoveryClient 注解,激活 Eureka 中的 DiscoveryClient 实现。
     

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

            application.properties 配置文件

    # 服务名
    spring.application.name=hello-service
    # 指定服务注册中心地址
    eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
    

            下面分别启动服务注册中心和服务提供者。Tomcat 启动之后,打印了注册信息,表示服务注册成功。

    而此时,服务注册中心的控制台中,可以看到类似的输出,表示 hello-service  注册成功了!

             通过访问 Eureka 的信息面板,一样可以看到服务的注册信息

              通过访问  http://localhost:8080/hello,发起请求,在控制台中可以看懂如下输出:

            这些输出内容就是之前在 HelloController 注入的 DiscoveryClient 接口对象,从服务注册中心获取的相关服务信息。 要配置log4j的打印级别,才会输出。

  3. 高可用注册中心
            在 Eureka 的服务治理设计中,所有节点即是服务提供方,也是服务消费方。Eureka Server 的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务中心,以实现服务清单的互相同步,达到高可用效果。

          创建 application-peer1.properties,作为 peer1 服务中心的配置,并将 serviceUrl  指向 peer2
           
    spring.application.name=eureka-server
    server.port=1111
    
    eureka.instance.hostname=peer1
    eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
          创建 application-peer2.properties,作为 peer2 服务中心的配置,并将 serviceUrl  指向 peer1
    
    spring.application.name=eureka-server
    server.port=1112
    
    eureka.instance.hostname=peer2
    eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
            在/etc/hosts 文件中添加对 peer1 和 peer2 的转换,让上面配置的 host 形式 serviceUrl   能在本地正确访问到。
    127.0.0.1 peer1
    127.0.0.1 peer2
            通过 spring.profiles.active 属性分别来启动 peer1 和 peer2。
           
    java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
    java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

            此时访问 peer1 的注册中心,发现 registere-replicas 中已经有 peer2 节点的 eureka-server 了。同样的,访问 peer2 的注册中心,发现 registere-replicas 中已经有 peer1节点的 eureka-server 了。

           但是  available-replicas (可用分片)之中,没有节点。要在 application-peer1.properties 和 application-peer2.properties 添加如下配置:让服务中心注册自己

    eureka.client.register-with-eureka=true
    eureka.client.fetch-registry=true

            再进去就可以看到,可用分片之中就有了节点。

    但是关闭 peer1节点,在peer2的服务注册中心,发现peer1一直都还在可用节点中。application-peer1.properties 和 application-peer2.properties添加如下配置:

    # 注册表:缓存过期时间,默认180s
    eureka.server.response-cache-auto-expiration-in-seconds=5
    # 注册表:缓存更新间隔
    eureka.server.response-cache-update-interval-ms=5000
    # 启用主动失效,主动失效检测间隔3s
    eureka.server.eviction-interval-timer-in-ms=3000
    # 服务过期时间,默认90s,超过这个时间没收到心跳,EurekaServer会剔除该实例
    eureka.instance.lease-expiration-duration-in-seconds=15
    # 服务刷新时间间隔,默认30s会主动心跳一次
    eureka.instance.lease-renewal-interval-in-seconds=5
    
    # 关闭自我保护模式 【注意】保护模式未关闭时,上面即使配置了过期,eureka还是不会剔除下线的实例
    eureka.server.enable-self-preservation=false
    

    在设置了多节点的服务注册中心之后,服务提供方还需要做一些简单的配置才能将服务注册到 Eureka Server 集群中。

    # 服务名
    spring.application.name=hello-service
    # 指定服务注册中心地址
    eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer1:1112/eureka/

          

  4. 服务发现与消费

          现在已经有了 服务注册中心 和 服务提供者,下面构建一个服务消费者,它主要完成两个目标 ,发现服务已经消费服务。其中服务发现的任务由  Eureka 的客户端完成,而服务消费的任务由  Ribbon 完成。Ribbon 是有一个基于 HTTP 和 TCP 的客户端负载均衡器,它可以通过客户端中配置的 ribbonServerList 服务端列表去轮询访问以达到负载均衡的作用。

          首先,启动之前实现的服务注册中心 以及 hello-service 服务,为了实验 Ribbon 的客户端负载均衡功能,启动两个不同端口的 hello-service。
    java -jar consumer-0.0.1-SNAPSHOT.jar --server.port=8081
    java -jar consumer-0.0.1-SNAPSHOT.jar --server.port=8082

           在启动成功后,Eureka 信息面板如下所示:

            创建一个 Spring Boot的基础工程来实现服务消费者,取名为 ribbon-consumer,pom.xml依赖如下。刚开始按照hello-service的pom.xml配置,服务启动,在注册中心显示都没问题,但是调用hello-serivice服务就有问题,SpringCloud、Eureka、ribbon报错No instances available for xxx!搜了一天半各种办法,最后参考这个 https://blog.csdn.net/qq_40781284/article/details/113830607 把spring-cloud-starter-netflix-ribbon依赖删除即可 ,因为pom.xml导入的jar包冲突,spring-cloud-starter-netflix-eureka-client 3.0版本的已经内置ribbon 。就没问题了!!!

    <?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>2.4.9</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.tripodfan</groupId>
        <artifactId>ribbon-consumer</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>consumer</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>2020.0.3</spring-cloud.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!--eureka-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
                <version>3.0.1</version>
            </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>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

            创建应用主类 ConsumerApplication。

    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class ConsumerApplication {
        
         @Bean
         @LoadBalanced
         RestTemplate  restTemplate() {
            return new RestTemplate();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    
    }
    

     创建 ConsumerController 并实现  /ribbon-consumer 接口。这里的 HELLO-SERVICE 我试了大小写都没问题。

    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    
    @RestController
    public class ConsumerController {
    
        @Autowired
        RestTemplate restTemplate;
    
        @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
        public String helloConsumer() {
            String url="http://hello-service/hello";
    //        String url="http://HELLO-SERVICE/hello";
            return restTemplate.getForEntity(url, String.class).getBody();
        }
    }
    

      在 application.properties 配置 Eureka 服务注册中心的位置

    spring.application.name=ribbon-consumer
    server.port=9000
    
    
    eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

    启动 ribbon-consumer 应用。

     通过访问 http://localhost:9000/ribbon-consumer,陈宫返回了 “Hello World”。

  5.  关闭一个 hello-service,继续测试,没有问题。wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==两个服务的时候,8081 和 8082交替被调用。可以看到 控制台会交替打印下面的日志:

        在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。如何解决这样的问题呢?服务容错保护, Spring Cloud Hystrix  https://blog.csdn.net/qq_15700115/article/details/119459686

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值