Spring Cloud Eureka是Spring Cloud Netflix微服务套件中的一部分,它基于Netflix Eureka做了二次封装,主要负责完成微服务架构中的服务治理功能。

1.服务治理

服务治理是微服务架构中最核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现。

服务注册:在服务治理框架中通常会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号、版本号、通信协议、等一些附加信息告知注册中心,注册中心按服务名分类名分类组织服务清单。

服务发现:由于在服务治理框架下运作,服务间的调用不再通过指明具体的实例地址来实现,而是通过向服务名发起请求调用实现。所以服务调用方在调用服务提供方接口的时候,并不知道具体的服务实例位置。因此,调用方需要向服务注册中心咨询服务,并获取所有服务的实例清单,以实现对具体服务实例的访问。

假如此时有两个提供服务A的进程分别运行与192.168.0.100:8000和192.168.0.101:8000位置上,则此时的服务注册为:

服务名位置
服务A192.168.0.100:8000、192.168.0.101:8000

当有个服务B希望调用服务A时,服务B就需要向注册中心发起咨询服务请求,服务注册中心就会将服务A的位置返回给服务B,此时返回的是192.168.0.100:8000、192.168.0.101:8000。当服务B要发起调用的时候便会从该清单中以某种轮询策略取出一个位置来进行服务调用。

2.Netflix Eureka

Spring Cloud Eureka,使用Netflix Eureka来实现服务注册与发现,它既包含了服务端组件也包含了客户端组件,并且服务端和客户端均采用Java编写,所以Eureka主要适用于通过Java实现分布式系统或与Jvm兼容语言的系统。

Eureka服务端(服务注册中心)它同其他服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。

Eureka客户端(服务注册与发现)客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,Eureka客户端向注册中心注册自身提供的服务并周期性的发送心跳来更新它的服务租约。同时他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性的刷新服务状态。

3.搭建服务注册中心

这里我用的是idea,首先新建一个boot项目然后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>

    <groupId>com.example</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-server</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</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>
        </dependencies>
    </dependencyManagement>

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


</project>

通过@EnableEurekaServer注解启动一个服务注册中心提供给其他应用进行对话。如:

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,在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/

eureka.client.register-with-eureka:由于该应用为注册中心,所以设置为false,代表不向注册中心注册自己。

eureka.client.fetch-registry:由于注册中心的职责就是维护服务实例,它不需要去检索服务,所以也设置为false。

启动后访问localhost:1111

此时nstances currently registered with Eureka是空的,说明注册中心还没注册任何服务。

4.注册服务提供者

首先再新建一个SpringBoot项目,其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>

    <groupId>com.example</groupId>
    <artifactId>eureka-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-service</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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>

    <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>

然后添加一个控制器:

@RestController
public class HelloController {
    @Autowired
    private DiscoveryClient client;

    @RequestMapping("/hello")
    public String index() {
        return "Hello";
    }

}

通过在主类上添加@EnableDiscoveryClient注解激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例)

然后在application.propertiess配置文件中通过spring.application.name为服务命名,再通过eureka.client.serviceUrl.defaultZone属性指定服务注册中心的地址:

spring.application.name=hello-service
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

然后启动两个服务可以看到:

或者通过访问Eureka的信息面板可以看到注册信息:

5.高可用注册中心

在分布式环境中我们需要考虑发生故障的情况,所以在生成环境中必须对各个组件进行高可用部署。

Eureka Server的设计一开始就考虑了高可用问题,在Eureka的服务治理设计中,所有节点即是服务提供方也是服务消费方,服务注册中心也不例外。所以通过设置下面两个参数让服务注册中心不注册自己:

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

Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的下过。下面来简单尝试下搭建一个双节点的服务注册中心集群。

首先创建application-peer1.properties和application-peer2.properties

两个文件分别如下:

spring.application.name=eureka-server
server.port=1111

eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
spring.application.name=eureka-server
server.port=1112

eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/

然后修改C:\Windows\System32\drivers\etc\hosts文件添加下面两行内容:

127.0.0.1 peer1
127.0.0.1 peer2

然后通过spring.profiles.active属性来启动peer1和peer2:

首先cd到这个目录下,使用mvn install,如:

最后成功如上所示,然后到target目录下:

G:\eureka\eureka-server\target>java -jar eureka-server-0.0.1-SNAPSHOT.jar --spri
ng.profiles.active=peer1

G:\eureka\eureka-server\target>java -jar eureka-server-0.0.1-SNAPSHOT.jar --spri
ng.profiles.active=peer2

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

这里以eureka-service为例子:

修改其application.properties

spring.application.name=hello-service
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/,http://localhost:1112/eureka/

通过对eureka.client.serviceUrl.defaultZone属性做改变,将注册中心指向了peer1和peer2

因此,如果断开了peer1由于eureka-service也向peer2进行了注册,所以peer2上的其他服务任然能访问到hello-service,从而实现服务注册中心得高可用。

如果要用ip的形式来定义注册中心的地址,则要在配置文件中增加配置参数eureka.instance.prefer-ip-address=true其默认为false。

需要注意的是如果将eureka-server的application.properties这两行进行注释。

#eureka.client.register-with-eureka=false 
#eureka.client.fetch-registry=false

那么服务启动后的效果是:

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐