注册中心Eureka

2019-01-23  本文已影响5人  放开那个BUG

从上一节我们看到,我们存在硬编码的问题,虽然我们可以通过把url配置到配置文件中,再从代码中读取配置的方式来解决。但是,每次我们的地址换的时候,配置文件都需要修改,很不方便。所以,我们可以通过服务的注册、发现机制来完成。

微服务注册与发现

最基本的原理图如下:


可以看出:

  • 服务提供者将服务注册到注册中心。
  • 服务消费者通过注册中心查找服务。
  • 查找到服务后进行调用(这里就是无需硬编码url的解决方案)。
  • 服务消费者与服务注册中心保存心跳连接,一旦服务提供者的地址发生变更,注册中心会通知服务消费者。

注册中心Eureka

SpringCloud提供了多种注册中心的实现,例如:Eureka、Zookeeper,但是SpringCloud推荐Eureka。

Eureka是Netfix开源的服务发现组件,本身就是一个基于REST的服务。它包含Server端和Client端。Server就是注册中心,而Client就是指服务被注册成client。它的原理图如图:


从上图可以看此,Eureka包含两个组件:Eureka Server和Eureka Client。

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表将会存储所有可用服务节点的信息,服务节点的信息可以再界面上直观的看到。

Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端内置一个使用轮询(round-robin)负载均衡算法的负载均衡器。

在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server再多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中巴这个服务节点移除(默认90秒)。

Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然能够利用缓存中的消息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

编写Eureka Server

第一步,新建一个eureka server的模块,然后编辑pom.xml文件,其中最重要的是加入Eureka服务和Spring Cloud的依赖,如图:


然后,我们我们只需要再运行文件中加入@EnableEurekaServer,申明这是一个Eureka服务。

package com.example.eureka;

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

@EnableEurekaServer  //申明这是一个Eureka服务
@SpringBootApplication
public class EurekaApplication {

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

}

然后我们编辑application.yml文件:

server:
  port: 6868 #服务端口

eureka:
  client:
    registerWithEureka: false #是否将自己注册到Eureka服务中,本身就是所有无需注册
    fetchRegistry: false #是否从Eureka中获取注册信息

然后启动程序进行测试:


就可以再控制台中查看信息。

将商品微服务注册到Eureka中

有了注册中心,我们不需要向以前那样去指定具体的地址了。所以,我们需要将商品微服务注册到Eureka服务中。所以,我们需要修改商品微服务的pom.xml文件,引入SpringCloud依赖和Eureka服务的依赖。


然后我们需要修改application.yml文件

server:
  port: 8081 #服务端口

spring:
  application:
    name: xushu-microservice-item #指定服务名

eureka:
  client:
    registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true
    fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
    serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
      defaultZone: http://127.0.0.1:6868/eureka/
  instance:
    prefer-ip-address: true #将自己的ip地址注册到Eureka服务中

然后我们需要再启动类增加@EnableDiscoveryClient注解,至此全部完毕。然后进行测试,可以看到我们的微服务已经注册到Eureka Server中了。


订单系统从Eureka中发现服务

之前我们在订单系统中对地址进行硬编码,现在由于已经将商品的微服务注册到Eureka中,所以只需要从Eureka中发现服务即可。那么,还是需要添加依赖,和商品微服务一样,接着便修改配置文件

server:
  port: 8082 #服务端口

spring:
  application:
    name: xushu-microservice-order #指定服务名

eureka:
  client:
    registerWithEureka: false #是否将自己注册到Eureka服务中,默认为true
    fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
    serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
      defaultZone: http://127.0.0.1:6868/eureka/

修改ItemService的逻辑:

package com.xushu.microservice.order.service;

import com.xushu.microservice.order.pojo.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;

@Service
public class ItemService {
    //Spring框架对RESTful方式的http请求做了封装,来简化操作
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     *调用商品的微服务提供的接口进行查询数据
     * @param id
     * @return
     */
    public Item queryItemById(Long id) {
        String serviceId = "xushu-microservice-item";
        List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
        if(instances.isEmpty()){
            return null;
        }
        // 为了演示,在这里只获取一个实例
        ServiceInstance serviceInstance = instances.get(0);
        String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
        return this.restTemplate.getForObject("http://" + url + "/item/" + id, Item.class);
    }
}

现在,我们只需要指定服务名称,就能够得到它的实例了。测试如下:


为Eureka添加用户认证

在前面的示例中,我们无需登录即可访问Eureka服务,很不安全。所以我们需要为Eureka添加用户认证。首先我们需要为Eureka Server添加依赖:

<!-- 安全认证 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

然后修改application.xml文件:

security: 
  basic:  
    enable: true #开启基于HTTP basic的认证
  user: #配置用户的账号信息
    name: xushu
password: xushu

但是此时服务注册者会出现错误,所以当有服务注册到注册中心时,需要设置如下信息(eureka地址选择你的服务器地址):http://USER:PASSWORD@127.0.0.1:6868/eureka/

小插曲
这里有个小插曲,因为最新的Spring security 会默认开启防csrf攻击,我们需要关闭它,所以我们需要在Eureka Server上写一个配置类,然后手动关闭它:

package com.example.eureka.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }
}

配置如图:



然后就可以了。

Eureka的自我保护模式

如图,Eureka进入了自我保护模式。在默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认为90秒)。但是当忘了分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能非常危险。因为微服务本身是健康的,只是网络故障而已,不应该注销这个服务。

Eureka通过“自我保护模式”来解决这个问题。当Eureka Server节点在短时间内丢失过多客户端时,那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点就会自动退出自我保护模式。

一般进入自我保护模式,无需处理。所以,不建议禁用自我保护模式。

Eureka的高可用

前面的实例中,Eureka服务是一个单点服务,在实际的生产环境中,为了实现高可用,我们需要Eureka集群。

简历Eureka机器很简单,只需要启动多个Eureka服务并且让这些服务彼此注册即可。在这里,我们再新建一个anotereureka模块,然后application.yml文件修改如下(eureka修改也差不多):


测试就会发现有两个eureka服务,多个服务同理。这时,如果一般的功能微服务需要注册到集群,要修改 defaultZone 为多个地址即可。


上一篇下一篇

猜你喜欢

热点阅读