SpringCloud Netflix Eureka

IsanaYashiro 2020-02-13

Eureka是Netflix开源的服务发现组件,基于REST,SpringCloud将它集成在子项目Spring Cloud Netflix中,从而实现服务的注册、发现。

Eureka包含Server、Client两部分:

  • Eureka Server  接收服务注册、保存各服务节点的信息
  • Eureka Client  即各服务节点,内置Ribbon(实现负载均衡)。消费者通过Ribbon从提供该服务的节点列表中确定一个要使用的节点。

Eureka的架构

SpringCloud  Netflix Eureka 


搭建单个Eureka Server

1、创建空项目,作为容器

因为微服务是独立的模块,单独开发部署,不建议使用父子工程。

SpringCloud  Netflix Eureka


2、新建模块eureka-server,作为eureka服务器

(1)pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      <version>2.2.1.RELEASE</version>
    </dependency>
  </dependencies>

(2)application.properties

### eureka server config ###
#使用的端口
server.port=9001

#服务名,eureka集群时会作为一个服务注册到其它server上
#spring.application.name=eureka-server

#这个eureka server的ip,不是预定义的key,下面要取出来用。上线时要改为真实的ip
eureka.server.ipAddress=127.0.0.1

#erueka实例名,注册到eureka server上时,这个名称就代表该服务节点。集群使用,只有一个server时可不用
#eureka.instance.instance-id=${eureka.server.ipAddress}:${server.port}

#这个eureka server的注册中心地址
eureka.client.serviceUrl.defaultZone=http://${eureka.server.ipAddress}:${server.port}/eureka/


#是否将自己作为Eureka Client注册到其它Eureka Server上,默认为true。因为只有一个eureka server,所以设置为false
eureka.client.register-with-eureka=false
#是否同步其它Eureka Server节点的数据(复制),默认为true。因为只有一个eureka server,所以设置为false
eureka.client.fetch-registry=false


#注册时以ip地址注册,默认以主机名注册。如果注册主机名,使用时还需要转换为ip,浪费时间
eureka.instance.prefer-ip-address=true


#期待心跳间隔时间,默认30s
#eureka.instance.lease-renewal-interval-in-seconds=30
#服务节点失效时间,默认为90s,即90s内没有接收到某个服务节点的心跳,就认为该节点失效
#eureka.instance.lease-expiration-duration-in-seconds=90
###调试时可把上面2个值写小些###


#是否启用服务的自我保护模式,默认为true,调试时设置为false,正式部署设置为true
eureka.server.enableSelfPreservation=false#清理间隔,每隔60s清理一次无效节点,默认为60000(60s)#eureka.server.eviction-interval-timer-in-ms=60000

#设置缓存过期时间。eureka集群时,要从其它server拉取数据,此设置指定拉取的数据的有效期,即每隔多少秒拉取、更新一次
#注意是缓存,是从其他server拉取的,不是本机的注册中心的节点信息,默认180s更新一次
eureka.server.response-cache-auto-expiration-in-seconds=180
#数值设置大,可用性高,因为其它server下线,本server也可以维持某些节点一段时间,但节点信息更新慢,数据一致性差

(3)引导类

@SpringBootApplication
@EnableEurekaServer  //作为Eureka Server
public class EurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer.class, args);
    }
}

启动之后,在   http://localhost:9001/ 查看eureka server的信息。


3、新建子模块order-server(服务提供者),作为eureka client

1、pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
  </parent>

  <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-client</artifactId>
      <version>2.0.0.RELEASE</version>
    </dependency>
  </dependencies>

2、application.properties

### eureka client config###

#使用的端口
server.port=10001

#提供的服务,服务名称
spring.application.name=order-server

#注册到哪些Eureka Server的注册中心。可配置多个值,逗号隔开即可
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9001/eureka/

#本机地址,上线时要改为机器实际的ip
eureka.client.ipAddress=127.0.0.1
#eureka实例名,以ip:port的形式注册到server上
eureka.instance.instance-id=${eureka.client.ipAddress}:${server.port}

#注册节点时IP优先,默认为false——注册主机名
eureka.instance.prefer-ip-address=true

#多久发送一次心跳,默认30s,调试时可设置短些
#eureka.instance.lease-renewal-interval-in-seconds=30

3、引导类

@SpringBootApplication
@EnableEurekaClient  //作为Eureka Client
public class OrderServer {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer.class, args);
    }

}

4、我们再写一个controller作为测试

@Controller
@RequestMapping("/order")
public class OrderController {

    //模拟根据用户id查找该用户的所有订单
    @GetMapping("/{user_id}")
    @ResponseBody
    public String findAllByUserId(@PathVariable Integer user_id){
        return "this is orderList of " + user_id ;
    }
}

4、新建子模块user-server(服务消费者),作为eureka client

1、pom.xml

都是eureka的客户端,引入的依赖和order-server的相同。

2.application.properties

都是eureka客户端,配置和order-server差不多,改一下端口号、服务名称就ok。(实际上线时还需要改ip)

3、引导类

@SpringBootApplication
@EnableEurekaClient  //作为Eureka Client
public class UserServer {
    @Bean
    @LoadBalanced  //使用Ribbon的负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

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

消费者、提供者相比,消费者要使用Ribbon的负载均衡。

4、再写一个controller作为测试

@Controller
@RequestMapping("/user")
public class UserController {
    //springcloud使用的消息是REST,通过RestTempalte来调用服务
    private RestTemplate restTemplate;

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    //模拟根据用户id查找用户所有订单
    @GetMapping("/order/{user_id}")
    @ResponseBody
    public String findOrdersByUserId(@PathVariable Integer user_id){
        //不写具体的ip:port,使用服务名代替,Ribbon会通过负载均衡找到该服务的合适的节点
        String orders = restTemplate.getForObject("http://order-server/order/{user_id}", String.class, user_id);
        return orders;
    }
}

启动order-server、user-server,看到已经注册到eureka-server上,

即使关闭eureka的自我保护机制,服务下线后需要90s才会删除节点信息,所以有时候会看到重复的节点信息。

页面上经常 红字提示 “自我保护机制.....“,不必管。

地址栏输入 http://localhost:10002/user/order/1 ,显示“this is orderList of 1”,搭建成功。


Eureka的集群

为了提供可用性,Eureka一般都要集群。

1、eureka server集群

application.properties修改如下:

### eureka server config ###

#使用的端口
server.port=9001

#服务名,eureka集群时会作为一个服务注册到其它server上
spring.application.name=eureka-server
#这个eureka server的ip,上线时要改为真实的ip
eureka.server.ipAddress=127.0.0.1
#erueka实例名,以实例名注册到eureka server上。
eureka.instance.instance-id=${eureka.server.ipAddress}:${server.port}


#要写其它注册中心的地址,有多少写多少
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9002/eureka/,http://127.0.0.1:9003/eureka/


#把自己作为一个服务(eureka client)注册到其它Eureka Server上,默认就是true
eureka.client.register-with-eureka=true
#同步其它Eureka Server节点的数据(复制),默认为true
eureka.client.fetch-registry=true


#注册时优先以ip地址注册
eureka.instance.prefer-ip-address=true

#多久更新一次从其它server拉取的数据
eureka.server.response-cache-auto-expiration-in-seconds=180
##是否启用此Eureka Server的自我保护模式,默认为true,调试时设置为false,正式部署设置为true##eureka.server.enableSelfPreservation=false#清理间隔,每隔60s清理一次失效的节点,默认为60000#eureka.server.eviction-interval-timer-in-ms=60000

#期待心跳间隔时间,默认30s
#eureka.instance.lease-renewal-interval-in-seconds=30
#服务节点失效时间,默认为90s,即90s内没有接收到某个服务节点的心跳,就认为该节点失效
#eureka.instance.lease-expiration-duration-in-seconds=90
###调试时可把上面2个值写小些###

要部署多少个集群,就copy多少份这个子模块,把application.properties改下就ok。

如果是正式部署,部署到多台机器上,需要修改副本的ip、注册中心地址;

如果是在同一台机器上测试,直接运行此模块|项目的多个实例即可,修改下端口号(包括注册中心的端口号)就ok。

2、eureka client集群

要部署多少个集群,就copy多少份这个子模块,把application.properties改下就ok:

#注册到哪个注册中心,需配置多个注册中心,逗号隔开
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:9001/eureka/,http://127.0.0.1:9002/eureka/,http://127.0.0.1:9003/eureka/

虽然配置了多个注册中心,但只会注册到第一个,第一个下线了才会选择注册到第二个,以此类推。(后面的全是备胎)

这样做是为了提高可用性,某些注册中心挂了,也没问题。

如果是正式部署到多台机器,改下ip就ok;

如果是在一台机器上进行测试,在IDEA下运行多个实例,改下端口号就行。

ps:可能指定的注册中心还没上线,控制台会报错“请求失败,拒绝连接”,问题不大,等注册中心上线即可。(注意灯是绿的,仍是运行状态;如果没在运行了,那就是其它错误)


微服务项目的部署

将各子模块打包为jar或war(基于SpringBoot,即可打包为jar,又可打包为war),安装、部署到各台机器上即可。


Eureka server  服务的自我保护模式

eureka server默认是开启服务的自我保护模式的。

90s内未接受到某个服务节点的心跳,就开启为期15min的心跳检测,如果15min接收到该节点的心跳小于85%(默认值0.85,可设置),就认为是网络故障导致的,一直保留该节点的信息,依然被使用;

如果大于85%,就认为是该节点自身除了问题,删除该节点的信息。

造成的问题:该节点可能出问题了(成为无效节点),但依然和正常节点一样被使用,就是说返回给client的可能含有一些无效节点。

关闭服务保护、手动清理无效节点:(90s内没收到过心跳即为无效节点)

# 关闭服务的自我保护
eureka.server.enableSelfPreservation=false
# 清理间隔,每隔60s清理一次失效的节点
eureka.server.eviction.interval-timer-in-ms=60000

商业项目中不推荐关闭服务保护,因为网络不可靠很容易造成网络波动、延迟、断线。

在商业项目中,服务的数量一般是几十个、成百上千个,如果关闭服务保护,可能导致大量的服务反复注册、删除、再注册,会降低程序性能。


Eureka client的缓存机制

客户端会缓存eureka server返回的服务列表,缓存一直有效,直到此客户端下线。

第一次请求eureka server获取到服务列表后,之后调用该服务时都是从缓存中找。除非缓存的该服务的所有节点都失效,才会从server重新获取节点列表。

即便Eureka Server集群的所有节点都宕机失效,服务消费者、提供者依然能正常通信。

相关推荐