Fork me on GitHub

springcloud组件-eureka

1、eureka什么?

2、eureka单节点如何使用?

3、eureka集群配置?

4、zookeeper的cp性与eureka的ap性

5、关于eureka的自我保护机制


1、eureka是什么?

  springcloud中的eureka就相当于之前dubbo中的zookeeper,也是一个注册中心。

一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,并且支持集群部署。

 

2、eureka单节点?

  以自身所写的项目来说:

   首先新建一个父项目Springcloud,分别去新建子项目:

    springcloud-consumer-management:各个消费者项目

    springcloud-provider-management:各个提供者项目

    springcloud-management:MVC层

    springcloud-eureka-management:eureka项目

  下一步所要做的是:

    (1)在父项目中引入所需要的所有jar包

    (2)在springcloud-management中将Mapper、model、service层新建出来,

      并进行层级依赖的建立:mapper-->model    service-->mapper

    (3)在consumer-management中去引入对应的依赖,并新建一个consumer的子工程:6081

    (4)在provider-management中去引入对应的依赖,并新建一个consumer的子工程:8081

  实现:

  (1)父项目的依赖:

 1 <!--
 2         项目jar包的构建:
 3             之前使用的parent标签直接引入项目中,可以继承父项目的jar包
 4             但是项目中已经使用到了springcloud和springboot
 5             springcloud和springboot需要些两个parent,但是在pom工程中不能这样实现
 6             所以直接引入springboot和springcloud的jar包工程,并且使用dependencyManagement标签进行管理,用到了什么jar包直接重写
 7 
 8             springboot-parent, springcloud-parent的父级工程都是dependencies
 9     -->
10 
11     <dependencyManagement>
12         <dependencies>
13             <dependency>
14                 <groupId>org.springframework.boot</groupId>
15                 <artifactId>spring-boot-dependencies</artifactId>
16                 <version>2.1.8.RELEASE</version>
17                 <type>pom</type>
18                 <scope>import</scope>
19             </dependency>
20             <dependency>
21                 <groupId>org.springframework.cloud</groupId>
22                 <artifactId>spring-cloud-dependencies</artifactId>
23                 <version>Greenwich.SR3</version>注意版本号
24                 <type>pom</type>
25                 <scope>import</scope>
26             </dependency>
27             <dependency>
28                 <groupId>io.zipkin.java</groupId>
29                 <artifactId>zipkin-server</artifactId>
30                 <version>2.11.8</version>
31                 <exclusions>
32                     <exclusion>
33                         <groupId>org.apache.logging.log4j</groupId>
34                         <artifactId>log4j-slf4j-impl</artifactId>
35                     </exclusion>
36                 </exclusions>
37             </dependency>
38             <dependency>
39                 <groupId>io.zipkin.java</groupId>
40                 <artifactId>zipkin-autoconfigure-ui</artifactId>
41                 <version>2.11.8</version>
42             </dependency>
43             <dependency>
44                 <groupId>mysql</groupId>
45                 <artifactId>mysql-connector-java</artifactId>
46                 <version>5.0.4</version>
47             </dependency>
48             <dependency>
49                 <groupId>com.alibaba</groupId>
50                 <artifactId>druid</artifactId>
51                 <version>1.0.31</version>
52             </dependency>
53             <dependency>
54                 <groupId>org.mybatis.spring.boot</groupId>
55                 <artifactId>mybatis-spring-boot-starter</artifactId>
56                 <version>1.3.0</version>
57             </dependency>
58         </dependencies>
59     </dependencyManagement>

 

 

(2)springcloud-management中的各层级:

Mapper层的pom: 
1
<?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>springcloud-management</artifactId> 7 <groupId>com.aaa.liu.springcloud</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>springcloud-mapper</artifactId> 13 14 15 <dependencies> 16 <dependency> 17 <groupId>com.aaa.liu.springcloud</groupId> 18 <artifactId>springcloud-model</artifactId> 19 <version>1.0-SNAPSHOT</version> 20 </dependency> 21 <!-- 22 需要引入mysql mybatis springboot druid 23 --> 24 <dependency> 25 <groupId>mysql</groupId> 26 <artifactId>mysql-connector-java</artifactId> 27 </dependency> 28 <dependency> 29 <groupId>com.alibaba</groupId> 30 <artifactId>druid</artifactId> 31 </dependency> 32 <dependency> 33 <groupId>org.mybatis.spring.boot</groupId> 34 <artifactId>mybatis-spring-boot-starter</artifactId> 35 </dependency> 36 <dependency> 37 <groupId>org.springframework.boot</groupId> 38 <artifactId>spring-boot-starter-web</artifactId> 39 </dependency> 40 </dependencies> 41 </project>

 

 

 service层的pom:
1
<?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>springcloud-management</artifactId> 7 <groupId>com.aaa.liu.springcloud</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>springcloud-service</artifactId> 13 14 <dependencies> 15 <dependency> 16 <groupId>com.aaa.liu.springcloud</groupId> 17 <artifactId>springcloud-mapper</artifactId> 18 <version>1.0-SNAPSHOT</version> 19 </dependency> 20 </dependencies> 21 </project>

 

 

(3)consumer-management依赖:

 1 <dependencies>
 2         <dependency>
 3             <groupId>com.aaa.liu.springcloud</groupId>
 4             <artifactId>springcloud-model</artifactId>
 5             <version>1.0-SNAPSHOT</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>org.springframework.boot</groupId>
 9             <artifactId>spring-boot-starter-web</artifactId>
10         </dependency>
11     </dependencies>

 

 

 

(4)provider-management项目的依赖:

 1 <dependencies>
 2         <dependency>
 3             <groupId>org.springframework.cloud</groupId>
 4             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 5         </dependency>
 6         <dependency>
 7             <groupId>org.springframework.boot</groupId>
 8             <artifactId>spring-boot-starter-actuator</artifactId>
 9         </dependency>
10         <dependency>
11             <groupId>com.aaa.liu.springcloud</groupId>
12             <artifactId>springcloud-service</artifactId>
13             <version>1.0-SNAPSHOT</version>
14         </dependency>
15     </dependencies>

 

 

 

正式开始:

先进行尝试consumer是否能够直接调用到provider中的方法

  在provider-management新建的第一个provider为provider-8081,

在Java下的包中只需要添加controller包和一个主启动类:

主启动类:

@SpringBootApplication
@MapperScan("com.aaa.liu.springcloud.mapper")
public class ApplicationRun8081 {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationRun8081.class,args);
    }
}

 

controller层下的UserController:

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/userAll")
    public List<User> selectAllUsers(){
        System.out.println("8081");
        return userService.selectAllUsers();
    }
}

 

然后在provider下的resources中新建config包,包下是application.properties:

基本的一些配置:
server.port=8081
server.servlet.context-path=/

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.aaa.liu.springcloud.model
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

 

 

下面是consumer-management中新建一个consumer6081:

主启动类:

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

 

在Java包下新建了一个config包和controller包

config包下的ConfigRest:

/**
 * 对配置类,需要加上configuration或者SpringbootApplication
 * RestTemplate:模拟http协议,使得两个controller调用
 */
@SpringBootApplication
public class ConfigRest {
    @Bean
    public RestTemplate getTemplate(){
        return  new RestTemplate();
    }
}

 

controller包下的UserController:

@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;
    //调用service,consumer项目的controller调用的是provider项目的controller(使用的是http协议)
    //如果可以模拟http协议,就可以实现两个controller之间的调用
    //getForObject:(使用get请求方式)该方法有两个参数
    //第一个参数:URL(请求路径(localhost:8081/userAll))
    //第二个参数:规定返回值的类型

    @RequestMapping("/userAll")
    public List<User> selectAllUsers(){
        return restTemplate.getForObject("http://localhost:8081/userAll",List.class);
    }
}

 

resource下的application.properties(由于只是请求服务,不用与数据打交道,不用数据源):

server.port=6081
server.servlet.context-path=/

 

完事!分别启动provider和consumer,在浏览器中访问localhost:6081/userAll,请求到数据,则调用无碍。

 

下面开始eureka的单节点设置:

  代码很简单,在eureka-management中新建一个eureka7081项目

在Java中只有一个主启动类:

/**
 * @EnableEurekaServer:就是开启eureka的服务器
 * @EnableEurekaClient:不让用,因为springcloud1.x的注解(我们使用的是格林威治RS3版本)
 */
@SpringBootApplication
@EnableEurekaServer
public class ApplicationRun7081 {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationRun7081.class,args);
    }
}

 

resource中的properties.properties:

server.port=7081
server.servlet.context-path=/

# eureka服务器端的实例名称
eureka.instance.hostname=eureka01

# eureka也会把自己注册进注册中心里,这里因为最终eureka是不需要被发现的服务,
# 所以不再需要把自己注册到注册中心里
# 默认值为true,表示把自己注册进注册中心
eureka.client.register-with-eureka=false
# 表示自己就是注册中心,注册中心的职责是维护服务实例,并不需要从注册中心里去发现自己
eureka.client.fetch-registry=false
# 配置eureka的注册地址
# zookeeper需要在linux服务器上进行配置,最终的情况下使用zookeeper的时候必须要指向zookeeper的IP地址
# eureka不需要做任何服务器配置,但是也必须要指向地址(直接指向eureka的项目即可:http://localhost:7081/eureka)
# 该地址中的localhost就是eureka.instance.hostname的值,端口号就是server.port的值,/eureka:固定的(eureka自己提供)
# defaultZone:eureka默认所提供的命名空间
# 在eureka的注册地址中,是可以分空间(zone)的,是命名空间,根据空间的不同来配置不同集群的eureka来实现不同的作用
# 如果为单节点可以随意配置,但是如果为集群则目前为止必须要配置成defaultZone(因为如果是集群版就必须先要声明命名空间,如果不声明则无法使用)
eureka.client.service-url.defaultZone=http://localhost:7081/eureka

 

在provider8081中进行配置:

  现在主启动类中添加:@EnableDiscoveryClient 注解,与eureka的主启动类的@EnableEurekaServer对应

(对于eureka来说,provider就是客户端,而eureka是服务端)

然后就是.properties配置文件了:

spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.aaa.liu.springcloud.model
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

# 配置的是在eureka中显示的服务名(Application)
# 如果不配置,则会显示UNKNOWN
spring.application.name=user-provider

# 配置eureka的注册地址(实现provider这个客户端注册进了eureka中)
# GreenWich rs.3:无论是单节点还是集群模式,
# eureka的服务器端和客户端的命名空间务必要保持一致,否则会报错(找不到服务实例)
eureka.client.service-url.defaultZone=http://localhost:7081/eureka

# 是在eureka中配置实例的名字(也就是说Eureka的Status下的显示的名字)
# 不允许重复  (相当于mysql数据库中的表的主键id)
eureka.instance.instance-id=user-provider-8081

# 在eureka中显示IP地址
eureka.instance.prefer-ip-address=true

# 点击eureka的服务名显示出该服务的具体信息
# 根据服务的具体内容,作者,公司,以及对整个服务的描述来进行
# 相当于在HTML页面上有一个a标签<a href="/actuator/info"></a>--> 跳转到controller:@RequestMapping("/actuator/info">
# 开头用info  其他的随便输入
info.author.name=Liu
info.company.name=AAA SOFTWARE EDU
info.project.description=this is Demo

 

!这个颜色标注的配置信息是可以不用配置的!

OK!接下类分别启动eureka、provider、consumer(顺序不要错了,否则会报出无法发现服务异常)

在浏览器中访问localhost:7081就可以看到eureka的界面了,在上面可以看到关于注册进eureka的provider信息

 

3、集群版eureka:

在eureka-management中再新建两个eureka项目,分别为7082、7083

将eureka组成一个集群,eureka与zookeeper不同,eureka组成集群,是需要在eureka配置信息里分别

注入其他两台的信息,让他们能够互相知道。

server.port=7081
server.servlet.context-path=/

# eureka服务器端的实例名称
eureka.instance.hostname=eureka01-->三台分别为eureka01、eureka02、eureka03

# eureka也会把自己注册进注册中心里,这里因为最终eureka是不需要被发现的服务,
# 所以不再需要把自己注册到注册中心里
# 默认值为true,表示把自己注册进注册中心
eureka.client.register-with-eureka=false
# 表示自己就是注册中心,注册中心的职责是维护服务实例,并不需要从注册中心里去发现自己
eureka.client.fetch-registry=false
# 配置eureka的注册地址
# zookeeper需要在linux服务器上进行配置,最终的情况下使用zookeeper的时候必须要指向zookeeper的IP地址
# eureka不需要做任何服务器配置,但是也必须要指向地址(直接指向eureka的项目即可:http://localhost:7081/eureka)
# 该地址中的localhost就是eureka.instance.hostname的值,端口号就是server.port的值,/eureka:固定的(eureka自己提供)
# defaultZone:eureka默认所提供的命名空间
# 在eureka的注册地址中,是可以分空间(zone)的,是命名空间,根据空间的不同来配置不同集群的eureka来实现不同的作用
# 如果为单节点可以随意配置,但是如果为集群则目前为止必须要配置成defaultZone(因为如果是集群版就必须先要声明命名空间,如果不声明则无法使用)
#eureka.client.service-url.defaultZone=http://localhost:7081/eureka
eureka.client.service-url.defaultZone=http://eureka02:7082/eureka,http://eureka03:7083/eureka

 

与单机版的.properties配置改动很少,主要在两个地方,一个是名字上的区分,一个是最后一行命名空间的配置。

 

4、zookeeper和eureka的区别?

  zookeeper保证的是数据CP性,即数据一致性,而eureka保证的是AP性,即服务可用性。

 

5、关于eureka的自我保护机制

  如果长时间不去连接(激活)eureka的时候,会出现自我保护机制,在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中注册过的服务会定时向eureka发送心跳,当网络故障/网络延迟/服务宕机等情况下,服务器不再向eureka

发送心跳,eureka从接不到心跳开始计时,默认在90秒(这个时间可以修改)之后,eureka会将这个服务剔除。

但此处有关剔除的机制有一个点:假设现在有100台服务,其中三台别检测认为宕机,eureka会剔除这三台;

  但如果此刻有198台provider都没有心跳,eureka不会把这198台provider剔除,而是会保留,这也是eureka的保护机制,

也就是说eureka不会大量剔除服务。这就是eureka的AP性。

为什么eureka不会剔除大量的服务呢

  AP:只保证了服务的可用性,不保证数据的一致性。

  CP:只保证数据的一致性,不保证服务的可用性。

  如果eureka把所有的服务全部剔除,当consumer尽心访问的时候,发现eureka没有任何服务了,整个项目都处于瘫痪状态,

整个客户端的体验就会很差,也就是相当于500.

  假设当大面积服务都没有心跳,eureka不剔除的情况下,consumer进行访问调用的时候依然可以找到服务,然后就可以获取数据,

这些数据可能不是最新的数据,但最起码eureka中还存在服务。

 

我们是可以将eureka的保护机制关掉的,但通常不允许这么做,一般可以对它进行失效操作。

关闭eureka的自我保护机制:

  在eureka-7081项目的application.properties配置文件中,添加:

  eureka.server.enable-self-preservation=false

  然后重新请求eureka,可以在页面上看到THE SELF PRESERVATION MODE IS TURNED OFF等信息。

让eureka的自我保护机制失效:

  首先eureka会定时检测provider的心跳,假如现在eureka检测provider的时间间隔 ,我们给更改为10s.

即在eureka-7081的配置文件中添加:eureka.server.eviction-interval-timer-in-ms=10000

注:单位是毫秒

  其次,假如在provider端是一个集群,现在其中一台provider不需要eureka的自我保护机制,也就是说我们要让

eureka的自我保护机制在这一台上失效。

  在provider的配置文件中进行配置:告诉eureka,我每隔5秒向你发送心跳,你每隔8秒检测一次,如果没有检测到,

就直接把我剔除。这样一来,eureka会按照我们在provide的配置来执行,我们就打成了让eureka的自我保护失效的目的。

provide配置:

  # 规定自己向eureka发送心跳的时间,单位是秒,我们设置为5秒

  eureka.instance.lease-renewal-interval-in-seconds=5

  # 当eureka最后一次检测到心跳的时间间隔(单位是秒),我们给他设置成8秒

  eureka.instance.lease-expiration-duration-in-seconds=8

  

我们现在对provider进行集群搭建:

在provider-management中新建两个provider8082、provider8083

由于只是对provider进行集群配置,所以三台provider上的项目应该是一样的,只是相较于单台provider来说,

我们需要在配置文件中进行一点修改:

server.port=8081
server.servlet.context-path=/

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/teach?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.aaa.lee.springcloud.model
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

# 配置的是在eureka中显示的服务名(Application)
# 如果不配置,则会显示UNKNOWN(这个是细节!!,以后有问题)
spring.application.name=user-provider

# 配置eureka的注册地址(实现provider这个客户端注册进了eureka中)
# GreenWich RS.3:无论是单节点还是集群模式,eureka的服务器端和客户端的命名空间必要保持一致,否则会报错(找不到服务实例)
#eureka.client.service-url.defaultZone=http://localhost:7081/eureka
eureka.client.service-url.defaultZone=http://eureka01:7081/eureka,http://eureka02:7082/eureka,http://eureka03:7083/eureka

# 是在eureka中配置实例的名字(也就是说Eureka的Status下的显示的名字)
# !!!不允许重复!!!(相当于mysql数据库中的表的主键id)
eureka.instance.instance-id=user-provider-8081

# 在eureka中显示IP地址
eureka.instance.prefer-ip-address=true

# 点击eureka的服务名显示出该服务的具体信息
# 根据服务的具体内容,作者,公司,以及对整个服务的描述来进行显示
# 相当于在HTML页面上有一个a标签<a href="/actuator/info"></a> --> 跳转到controller:@RequestMapping("/actuator/info")
# !!开头用info!!其他的随便输入
info.author.name=Liu
info.company.name=AAA SOFTWARE EDU
info.project.description=This is Demo
info.dsadasda=eqwewq321312daa

# 规定自己向eureka发送心跳的时间
# 单位是秒
#eureka.instance.lease-renewal-interval-in-seconds=5
# 当eureka最后一次检测到心跳的时间间隔(单位是秒)
# eg:15:05:20是最后一次检测到心跳-->检测8秒之后还是无法检测心跳的时候直接剔除
#eureka.instance.lease-expiration-duration-in-seconds=8

 

这里要注意一点:eureka的同步问题!!!

  在provider的配置中,我们需要将provider注册进eureka中, 由于eureka是集群,所以我们在添加配置的时候需要这样写:

eureka.client.service-url.defaultZone=http://eureka01:7081/eureka,http://eureka02:7082/eureka,http://eureka03:7083/eureka

 

但其实我们只写http://eureka01:7081,我们会发现,在eureka中其它两台eureka中也能看到这台provider,原因是eureka进行了同步。

已有的Eureka Server:在运行过程中,Eureka Server之间会定时同步实例的注册信息。

这样即使新的Application Service只向集群中一台注册服务,则经过一段时间会集群中所有的

Eureka Server都会有这个实例的信息。那么Eureka Server节点之间如何相互发现,

各个节点之间定时(时间由eureka.server.peer-eureka-nodes-update-interval-ms决定)更新节点信息,进行相互发现。

Service Consumer:Service Consumer刚启动时,它会从配置文件读取Eureka Server的地址信息。

当集群中新增一个Eureka Server中时,那么Service Provider如何发现这个Eureka Server?Service Consumer会定时(

此值由eureka.client.eureka
-service-url-poll-interval-seconds决定)调用Eureka Server集群接口,获取所有的Eureka Server信息的并更新本地配置。

 

posted @ 2019-10-02 12:06  秋刀  阅读(303)  评论(0编辑  收藏  举报