spring-cloud之Eureka服务注册与消费

spring-cloud之Eureka服务注册与消费

Eureka简介

    EurekaNetfilx开源的服务发现组件,本身是一个基于REST的服务。它包含Eureka ServerEureka Client两个部分。

    Eureka Server提供服务注册功能,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点。

    Eureka Client是一个Java客户端,用于简化与Eureka Server的交互。主要用于消费服务。

Eureka和Zookeeper对比

    CAPCAP是一个经过证实的理论,一个分布式系统最多只能满足一致性(Consistency)/可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

 

    一致性:分布式环境中的一致性是指数据在多个副本之间是否能够保持一致的特性。如果一个节点A的数据被更新了,那么节点B的数据是否可以更新到和A节点一样的状态。

 

    可用性:指系统提供的服务必须一直处于可用的状态,对于用户的每一个请求总是能够在有限的时间内返回结果,如果超过了这个时间范围,那么系统就被认为是不可用的。

 

    分区容错性:所谓分区指在分布式系统中,节点组成的网络由于某些故障,导致节点之间网络不连通,整个分布式系统由于网络隔离就被划分为几个区块,数据散落在这些不连通的区域中。这样节点之间的数据就不可以相互访问,分区容错性是无法容忍的。

 

    由于分区容错性是必须要解决,所以分布式系统就只有两中情况可以选择CP(一致性和分区容错性)和AP(可用性和分区容错性)

 

    Zookeeper保证CP当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。

 

    Eureka保证APEureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。

Spring Cloud基础学习

    Spring cloud分布式应用是基于Spring boot框架搭建的,所以学习Spring cloud之前你应该对Spring boot有一定的了解和认识。如果没有学习过spirng boot可以参照下面的地址学习。对于企业开发中会用到的技术都有了基本的了解和认识即可。

快速构建spirng-boot项目:https://blog.csdn.net/sinat_32366329/article/details/82764483

Spring Boot替换启动Logo:https://blog.csdn.net/sinat_32366329/article/details/82766330

Spring-boot配置文件属性大全(2.0.5版本):https://blog.csdn.net/sinat_32366329/article/details/82833841

Spring boot整合mysql和druid:https://blog.csdn.net/sinat_32366329/article/details/84404944

Spring boot整合redishttps://blog.csdn.net/sinat_32366329/article/details/84455398

Spring boot整合mongodbhttps://blog.csdn.net/sinat_32366329/article/details/84484776

Spring boot整合jpahttps://blog.csdn.net/sinat_32366329/article/details/84486406

Springboot整合filterlistenerhttps://blog.csdn.net/sinat_32366329/article/details/84575234

Spring boot整合mybatishttps://blog.csdn.net/sinat_32366329/article/details/86516124

Spring Boot整合ActiveMQhttps://blog.csdn.net/sinat_32366329/article/details/86616649

Eureka搭建服务注册中心

    分布式首先要有服务注册中心,作用就是服务提供者注册自己提供的服务,服务消费者可在注册中心订阅自己需要的服务。所以我们开发分布式系统首先要搭建一个服务注册中心,spring cloud的服务注册中心是基于Eureka搭建的。

项目结构

    首先要使用spring boot创建要给eurekaspring boot应用。因为spring cloud都是基于spring boot创建的应用。

 

POM

    导入pom中的maven时候需要特别注意,spring cloudspring boot的包版本是有指定的依赖的,可以说spring cloud的每个版本都有对应的spring boot版本,所以不懂的话可以去官网参考每个spring cloud版本说明。

    Spring cloud的版本和其他框架的版本是有区别的,spring cloud的版本都是使用英国伦敦的地铁站名字命名的,后面另外带有版本。这个谷歌或百度就有版本介绍,这里不多说。

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka</name>
    <description>Demo project for Spring Boot</description>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Application.yml

server:
  port: 8761
eureka:
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      default-zone: http://localhost:8761/eureka/

简单介绍一下application.yml的配置属性:

  1. register-with-eureka:表示是否将自己注册到Eureka Server,默认是true。由于当前应用就是Eureka Server,所以不需要注册自己。后面讲解到搭建高可用的Eureka Server集群的时候会设置为true
  2. fetch-registry:表示是否从Eureka Server中获取注册信息,默认是true。因为目前的Eureka Server是单节点的注册中心,不需要同步其他的Eureka Server节点的数据。同样后面讲解搭建高可用的Eureka Server集群时候会从集群的其他节点同步数据。
  3. default-zone:设置与Eureka Server交互的地址。服务提供者注册服务和服务消费者订阅服务都依赖这个地址和注册中心交互。多个地址可以使用”,”逗号隔开。

EurekaApplication启动类

package com.example.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {

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

}

简单介绍EurekaApplication启动类:

@EnableEurekaServer通过这个注解启动一个服务注册中心提供给其他应用进行对话。只需要在一个普通的spring boot应用中添加这个注解就可以开启此功能。

 

启动注册中心

打开浏览器访问:http://localhost:8761/  可以看到如下界面,这个就是注册中心的管理界面,由于我们还没有注册服务和订阅服务所以信息很多都是空的。

既然注册中心已经正常启动了,接下来我们就学习如何创建服务和将服务注册到Eureka Server注册中心。

将服务注册到Eureka Server注册中心

    为了节约时间成本,我们将刚才的注册中心eureka项目拷贝一份将名称和POM中的artifactId修改为provider-8762,8762主要是标记端口,这个服务我们使用8762端口。新的应用项目接口如下:

POM

    服务提供者和注册中心所依赖的spring cloud包不同具体区别就是将spring-cloud-starter-eureka-server包替换为spring-cloud-starter-eureka包即可。具体的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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>provider-8762</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka</name>
    <description>Demo project for Spring Boot</description>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- 服务提供者添加这个pom -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Application.yml

server:
  port: 8762

eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  application:
    name: provider-8762

这里解释一下yml文件的配置意思:

  1. port:我们使用该服务使用8762端口访问,自定义端口主要是为了避免端口冲突的情况出现。
  2. default-zone:Eureka Server注册中心里面也有这个属性,在服务提供者的作用是将自己的服务通过这个地址进行注册。也就是我们刚才所说的注册中心的对外地址。
  3. application.name:这个是对应用命名,主要是区分不同的应用访问方式同时可以在注册中心通过这个名称区分不同的服务。
  4. instance:表示将自己的ip注册到Eureka Server上。如果设置为false,表示将微服务所在操作系统的hostname注册到Eureka Server。

Provider8762Application启动类

package com.example.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class Provider8762Application {

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

}

对启动类的注解说明一下:

  1. @EnableDiscoveryClient:通过该注解声明是一个Eureka Client类。
  2. EnableDiscoveryClient注解和EnableEurekaClient作用是一样的。但是EnableDiscoveryClient为Zookeeper/Consul等各种服务组件提供了支持,该注解是spring-cloud-commons项目的注解。而EnableEurekaClient标记该类是要给Eureka Client,这个注解是spring-cloud-netflix项目的注解,是可以和Eureka一起工作配合使用。

启动

  1. 启动注册中心,注意服务需要注册到注册中心,如果没有启动注册中心而是先启动了服务,就会报错。
  2. 启动服务,在注册中心启动后启动服务,那么就可以将服务注册到注册中心。
  3. 访问http://localhost:8761/注册中心界面
  4. 可以看到有一个Application名称是PROVIDER-8762的服务注册到了Eureka Server注册中心上。
  5. 另外在启动服务的时候,可以在注册中心的控制台看到类似Registered instance PROVIDER-8762/DESKTOP-K59VO2B:provider-8762:8762 with status UP (replication=true)的信息,这个就是服务向注册中心注册的信息。

服务发现与消费

    上一步我们已经成功将服务注册到注册中心,那么现在我们就需要消费注册到服务中心的服务。

    Spring cloud的服务发现其中一个方式就是ribbon。Ribbon默认是轮询的方式去消费服务的,当然也可以自定义随机或者其他模式。为了提现ribbon的轮询消费服务,所以我们需要将provider-8762拷贝一份命名为provider-8763,其他可以不改变,但是端口需要修改为8763不然启动时候会提示端口冲突。

    最后修改两个服务application.yml文件的spring.application.name属性的值为provider。因为spring cloud是根据名称判断是不是同一个服务的。具体如下:

spring:
  application:
    name: provider

    我们上面创建的两个服务还没有提供任何的接口调用,所以我们创建一个ProviderController类,添加一个接口。这个展示的是provider-8762的代码,那么provider-8763的只需要将return的值8762修改为8763即可。这样是因为要显示ribbon的轮询功能。代码如下:

@RestController
public class ProviderController {

    @GetMapping(value = "/hello")
    public String hello() {
        return "Hello 8762 World";
    }

}

    启动注册中心,再启动两个服务提供者,刷新注册中心页面就可以看到provider服务的数量是2个。接下来我们创建服务消费者。同样是一个spring boot功能。

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 http://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>1.5.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>consumer-8862</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>consumer-8862</name>
    <description>Demo project for Spring Boot</description>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Application.yml

server:
  port: 8862

eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/

启动类

    @LoadBalanced注解就表示使用ribbon的轮询功能,每次调用会分别调用provider-8762和provider-8763

@EnableDiscoveryClient
@SpringBootApplication
public class Consumer8862Application {

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

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

}

ConsumerController

    这个类的功能主要是提供访问,这里通过ribbon调用PROVIDER服务的hello接口。

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer")
    public String helloConsumer() {
        return restTemplate.getForEntity("http://PROVIDER/hello", String.class).getBody();
    }

}

验证

   刚才我们分别启动了注册中心和provider-8762/provider-8763两个服务。现在可以启动consumer服务消费者了。现在访问ConsumerController的consumer方法,这个时候不断刷新会分别返回Hello 8762 World和Hello 8763 World两个不同的字符串,就是ribbon的轮询功能分别访问了两个服务。

    好了到这里你已经基本掌握了spring cloud的搭建注册中心/服务注册/服务消费功能。但是大家有没有思考一个问题,我们注册中心只有一个节点,如果生产的时候节点蹦了或者网络断开了,那不是新的服务无法注册和发现了吗?下一篇博客我会讲解如何搭建注册中心集群实现高可用。

关注微信公众号(程序员小兔)不定期分享技术

发布了222 篇原创文章 · 获赞 189 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/sinat_32366329/article/details/90383664