SpringCloud注册中心Eureka

标签: SpringCloud

1. 关于Eureka的简单介绍

服务治理:
为了实现各个微服务实例的自动化注册与发现;
服务注册:
①按照服务名进行分类。②服务注册中心以心跳的方式监测清单中的服务是否可用;
服务发现:
①通过向服务名发起请求调用实现;②轮询策略
Eureka:
Eureka服务端(即为注册中心):支持高可用性,依托于强一致性提供良好的服务实例可用性,可以多种不同的故障场景;以集群方式部署,具有自我保护;
Eureka客户端(处理服务的注册与发现):向注册中心注册自身服务并周期性的发送心跳来更新它的服务续租;

2.为什么选择Eureka

a)Eureka完全开源;
b)Eureka能够与SpringCloud无缝衔接;
c)Eureka与负载均衡组件Ribbon、熔断器组件Hystrix、熔断器监控组件等相互配合,能够很容易实现服务注册、负载均衡、熔断和智能路由能功能。

3. Eureka的最基本架构

a)Register Service:服务注册中心,是一个Eureka Server,提供服务注册和发现的功能;
b)Provider Service:服务提供者,是一个Eureka Client,提供服务;
c)Provider Service:服务消费者,是一个Eureka Client,消费服务。

4. 简单的Eureka搭建

可以简单的分为三步:具体的创建就不截图了
SpringCloud是基于SpringBoot进行开发的,所以现创建一个SpringBoot的maven主工程,然后再创建俩module,一个作为服务注册中心 eureka server,另一个作为eureka client;
配置主pom.xml文件:
这里主要导入Springboot和SpringCloud相关的依赖

<?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>cloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!-- 这里是包含的client -->
    <modules>
        <module>server</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.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>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- 添加SpringCloud总依赖 -->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <!-- Web的起步依赖spring-boot-starter-web -->
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- SpringCloud的自动配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!-- 添加SpringCloud eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka</artifactId>
        </dependency>
        <!-- 添加SpringCloud eureka client,总pom中添加了这个依赖,在client中只需要依赖即可 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
    </dependencies>

</project>

(1)创建一个服务注册中心server module

步骤:
右键工程->创建model-> 选择spring initialir
下一步->选择cloud discovery->eureka server ,然后一直下一步就行
配置
配置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>

    <!-- 定义对父pom的依赖 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <!-- 定义自己 -->
    <artifactId>server</artifactId>

    <dependencies>
       <!-- 定义当前为eureka server -->
       <!-- 在默认情况下,erureka server也是一个eureka client ,必须要指定一个 server,并在application.yml文件中进行配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
    </dependencies>

</project>

(2)添加服务注册中心启动类注解

package com.example.server;

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

@SpringBootApplication
//作为eureka server启动
@EnableEurekaServer
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

(3)配置application.yml文件

server:
  port: 8081
eureka:
  instance:
    hostname: localhost
  client:
    <!-- 防止自己被注册 -->
    registerWithEureka: false
    fetchRegistry: false
    <!-- 定义其他eureka client访问自己的URL -->
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

现在我们就可以成功启动server 注册中心,并看到下面的界面:
这里写图片描述
这是后还没有eureka client进行注册,所以这里是No instances available.

(4) 接下来就在同理上面的步骤,创建一个**服务提供者**eureka client:

1). 创建一个新的module—client001
配置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>

    <!-- 添加对父pom的依赖 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>client001</artifactId>

</project>

2)注解启动类

package com.example.client001;

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

@SpringBootApplication
@EnableEurekaClient
public class Client001Application {

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

3) 修改application.yml配置文件

<!-- 定义当前module要去注册自己的服务中心地址 -->
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka/
spring:
  application:
  <!-- 后期服务与服务之间相互调用 都使用这个name -->
    name: client001
server:
  port: 8082

接下来启动client001,重新访问http://localhost:8081/eureka/ 服务列表中会新增一个注册服务:
这里写图片描述
这样一个简单的服务搭建就完成了。
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

这里会出现红色字样,实际上,该警告就是触发了Eureka Server的自我保护机制。之前我们介绍过,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境中通常是网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能的保护这些注册信息。在这段保护 期间内实例出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。
由于本地调试很容易触发注册中心的保护机制,这会使得注册中心维护的服务实例不那么准确。所以,我们在本地进行开发的时候,可以使eureka.server.enable-self-preservation=false参数关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。

当改变client的端口,重启一次,刷新server界面,其中会看到同一个名字的两个服务:
这里写图片描述
这边切换端口重启,服务列表中会增加。关闭client的服务,刷新界面服务列表中还是存在up的服务,并没有被剔除,这是为什么呢?
这里注册了两个实例,相当于是一个小型的集群了。

5. 定义一个服务消费者

微服务中,我们通常会把业务拆分成不同的服务,服务于服务之间通讯是基于http restful的。Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。在这一篇文章首先讲解下基于ribbon+rest。

首先先来看下基于ribbon+restTemplate的服务消费方式:

进行上文中的操作,我们注册了两个服务实例,分别是服务端口为8082和8083的CLIENT001实例。
(1)重新建一个Module(SpringBoot的maven项目),再pom中单独添加 一个 spring-cloud-starter-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
    <groupId>com.example</groupId>
    <artifactId>cloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>client001</artifactId>

</project>

配置文件application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka/
spring:
  application:
  <!-- 访问的服务名称 -->
    name: client001
server:
  port: 8082

在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册;并且向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。

package com.example.client001;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@RestController
public class Client001Application {

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

    @Value("${server.port}")
    String port;

    @RequestMapping("/hi")
    public String home(@RequestParam String name) {
        return "hi "+name+",i am from port:" +port;
    }

}
package com.example.serviceribbon;

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;

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {

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

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

}

定义一个service和controller:

package com.example.serviceribbon.controller;

import com.example.serviceribbon.service.HiService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class HiController {

    @Resource
    HiService hiService;

    @RequestMapping(value = "/hi")
    public String GetHiContentController(@RequestParam String name) {
        return hiService.HiAmethyst(name);
    }

}


package com.example.serviceribbon.service;

public interface HiService {

    /**
     *
     * @param name
     * @return
     */
    public String HiAmethyst(String name);

}

通过之前注入ioc容器的restTemplate来消费service-hi服务的“/hi”接口,在这里我们直接用的程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名,代码如下:

package com.example.serviceribbon.service.impl;

import com.example.serviceribbon.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HiServiceImpl implements HiService {

    @Autowired
    RestTemplate restTemplate;

    @Override
    public String HiAmethyst(String name) {
        return restTemplate.getForObject("http://CLIENT001/hi?name=" + name, String.class);
    }
}

在浏览器上多次访问http://localhost:8084/hi?name=Amethyst,浏览器交替显示:

hi Amethyst,i am from port:8082
hi Amethyst,i am from port:8083

我们来捋一下:
当前有一个服务注册中心,端口号为:8081
两个名为Client001的实例,端口号分比为8082.8083
一个名为server-rebioon的实例,也向服务中心注册,后在service中,通过restTemplate调用client001的hi接口时,因为用ribbon进行了负载均衡,会轮流的调用CLIENT001:8082和8083 两个端口的hi接口;


还有一个类型的服务消费者(Feign),作为原理理解Eureka,这里不做详细的解释。


6.配置高可用 Eureka Server

实现方式:
编写多个application.yml文件

server:
  port: 8080

spring:
  <!-- 指定profile = peer1 -->
  profiles: peer1
eureka:
  instance:
    <!-- 指定当profile = peer1时,主机名为peer1 -->
    hostname: peer1
  client:
    serviceUrl:
      <!-- 将自己注册到peer2 Eureka上去 -->
      defaultZone: http://peer2:8081/eureka/
server:
  port: 8081

spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1:8080/eureka/

hostname为不同服务的IP地址,将client注册到其中一个server peer1中,查看注册中心server中的服务注册实例列表,在DS Resplicas中看到peer2。

结合5、6,就可以构建一个高可用的集群式Eureka服务。
这里写图片描述


深入理解,待续…

原文链接:加载失败,请重新获取