Eureka注册中心

Spring Cloud微服务入门、实战与进阶(目录总览)


Spring Cloud的官网地址: https://spring.io/projects/spring-cloud

1、Eureka注册中心

Spring Cloud Eureka是Spring Cloud Netflix微服务套件的一部分, 基于Netflix Eureka做了二次封装,主要负责实现微服务架构中的服务治理功能。SpringCloudEureka是一个基于REST的服务,并且提供了基于Java 的客户端组件,能够非常方便地将服务注册到 Spring Cloud Eureka中进行统一管理。

服务治理是微服务架构中必不可少的部分, 阿里开源的Dobbo根架就是针对服务治理的。服务治理必须要有一个注册中心,除了用Eureka作为注册中心外,我们还可以使用 Consul、Etcd、 Zookeeper 等来作为服务的注册中心。

用过Dubbo的读者应该清楚,Dubbo中也有几种注册中心,比如基于Zookeeper.基于Redis等,不过用得最多的还是Zookeeper方式。至于使用哪种方式都是可以的,注册中心无非就是管理所有服务的信息和状态。

例如: 当我们需要调用一个服务时,你会先去Eureka中去拉取服务列表,查看你调用的服务在不在其中,在的话就拿到服务地址、端口等信息,然后调用。

为什么Eureka比Zookeeper更适合作为注册中心呢?
主要是因为Eureka是基于AP原则构建的,而ZooKeeper是基于CP原则构建的。在分布式系统领域有个著名的CAP定理, 即C为数据一致性; A为服务可用性; P为服务对网络分区故障的容错性。这三个特性在任何分布式系统中都不能同时满足,最多同时满足两个。

Zookeeper有一个Leader,而且在这个Leader无法使用的时候通过Paxos(ZAB)算法选举出一个新的Leader。 这个Leader的任务就是保证写数据的时候只向这个Leader写入,Leader会同步信息到其他节点。通过这个操作就可以保证数据的一致性。

总而言之,想要保证AP就要用Eureka, 想要保证CP就要用Zookeeper。Dubbo中大部分都是基于Zookeeper作为注册中心的。而Spring Cloud首选Eureka。
那应该如何编写Eureka编写注册中心呢?

2、使用Eureka编写注册中心服务

首先创建一个Maven项目,或者直接创建一个Spring Initializr项目,取名为eureka-server,引入如下依赖:pom.xml:

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

<!--eureka-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<!--Spring Cloud-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

启动类EurekaServerApplication,添加@EnableEurekaServer,作用:表示开启Eureka Server。

接下来是application.peoperties配置:

spring.application.name=eureka-server
server.port=8761
# 由于该应用为注册中心,所以设置为false,代表不向注册中心注册自己
eureka.client.register-with-eureka=false
# 由于注册中心的职责就是维护服务实例,它并不需要去检索服务,所以也设置为false
eureka.client.fetch-registry=false

eureka.client.register-with-eureka一定要配置false,不然启动时会把自己当做客户端向自己注册,会报错。

运行之后访问http://localhost:8761/,可以看到Eureka提供的Web控制台:
在这里插入图片描述

3、编写服务提供者

1)、创建项目注册到Eureka

注册中心已经创建并启动好了,接下来我们实现将一个服务提供给eureka-client-user-service注册到Eureka中,并提供一个接口给其他服务调用。
首先在创一个Maven或Spring Initializr项目,pom.xml:

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

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

<!--Spring Cloud-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

创建一个启动类App:
@EnableDiscoveryClient表示当前服务是一个Eureka的客户端

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

application.properties配置:

spring.application.name=eureka-client-user-service
server.port=8081
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
# 采用IP注册
eureka.instance.prefer-ip-address=true
# 定义实例ID格式
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}

eureka.client.serviceUrl.defaultZone的地址就是我们之前启动的Eureka服务地址,在启动的时候需要将自身的信息注册到Eureka中去;
执行App启动服务,可以在控制台看到一个输出注册信息的日志:

DiscoveryClient_EUREKA-CLIENT-USER-SERVICE/eureka-client-user-service:172.20.10.5:8081 - registration status: 204

而我们回到之前打开的Eureka的Web控制台,刷新一下,就可以看到新注册的服务信息:
在这里插入图片描述

2)、编写提供接口

创建一个controller包,提供一个接口给其他服务查询:

@RestController
public class UserController {

    @GetMapping("/user/hello")
    public String hello() {
        return "hello";
    }
}

重启App服务,访问http://localhost:8081/user/hello,如果能看到我们返回的Hello字符串就证明接口提供成功。

4、编写服务消费者

1)、直接调用接口

创建服务消费者,消费我们刚刚编写的user/hello接口,同样需要先创建一个Maven项目eureka-client-article-service,然后添加依赖,依赖和服务提供者的一样,然后创建App启动类,启动代码也和服务提供者相同,唯一不同的是application.properties文件中的配置信息:

spring.application.name=eureka-client-article-service
server.port=8082

ResTemplae是Spring 提供的用于访问Rest服务的客户端. RestTemplale 提供了多种便捷访问远程Http服务的方法、能够大大提高客户端的编写效率,编写如下:
BeanConfiguration .java:

@Configuration
public class BeanConfiguration {

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

创建接口,在接口中调用user/hello接口:
ArticleController.java:

@RestController
public class ArticleController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/article/callHello")
    public String callHello() {
        return restTemplate.getForObject("http://localhost:8081/user/hello" , String.class);
    }
}

然后执行App启动消费者服务,访问http://localhost:8082/article/callHello,页面会显示Hello字符串就证明调用成功。

2)、通过Eureka来消费接口

上面提到的方法是直接通过服务接口的地址来调用的,和我们之前的做法一样,完全没有用到Eureka带给我们的便利。既然用了注册中心,那么客户端调用的时候肯定是不需要关心有多少个服务提供接口,下面我们来改造之前的调用代码。

首先改造RestTemplate 的配置,添加一个@LoadBalanced注解,这个注解会自动构造 LoadBalancerClient接口的实现类并注册到Spring 容器中:
RestTemplate 负载均衡配置:

@Configuration
public class BeanConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

接下来就是改造调用代码,我们不再真接写固定地址,而是写成服务的名称,这个名称就是我们注册到Eurcka中的名称,是属性文件中的 spring.application.name:
ArticleController.java:

@GetMapping("/article/callHello2")
public String callHello2() {
    return restTemplate.getForObject(
            "http://eureka-client-user-service/user/hello", String.class
    );
}

5、开启Eureka认证

Eureeka自带了一个Web的管理页面,方便我们注册到上面的实例信息,但是有一个问题:如果在时间使用中心地址有公网IP的话,必然能直接访问到,这样是不是安全的,所以我们加个权限认证保证安全性。
例如:改造我们的eureka-server,通过集成Spring-Security的依赖包:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后application.properties加入认证的配置信息:

#用户名
spring.security.user.name=ygayddcxy
#密码
spring.security.user.password=123456

然后增加Security配置类:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        //关闭csrf
        httpSecurity.csrf().disable();
        //支持httpBasic
        httpSecurity.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();
    }
}

重新启动一下注册中心,访问http://127.0.0.1:8761/,此时游览器会提示输入你的用户名和密码:
在这里插入图片描述

在Eureka开启认证后,客户端注册的配置也要加上认证的用户名和密码信息:

eureka.client.serviceUrl.defaultZone=http://ygayddcxy:123456@localhost:8761/eureka

6、Eureka高可用搭建

前面我们搭建的注册中心只适合本地开发使用,在生产环境中必须搭建一个集群来保证高可用。Eureka的集群搭建方法很简单:每一台Eureka只需要在配置中指定另外多个Eureka的地址就可以实现一个集群的搭建了。下面我们以2个节点为例来说明搭建方式。假如我们有master和slaveone两台机器,需要做的就是:
1、将master注册到slaveone上面
2、将slaveone注册到master上面
若是三台机器或以上,以此类推即可。
下面便搭建一下项目测试一下吧:
创建一个新的项目eureka-server-cluster,配置的话和上面的eureka-server一样。
因为我们是要测试Eureka的高可用,所以需要在不同的环境中运行实例:
application-master.properties:

server.port=8761
#指向你的从节点的Eureka
eureka.client.serviceUrl.defaultZone=http://ygayddcxy:123456@localhost:8762/eureka/

增加:application-slaveone.properties:

server.port=8762
#指向你的主节点的Eureka
eureka.client.serviceUrl.defaultZone=http://ygayddcxy:123456@localhost:8761/eureka/

在application.properties:

spring.application.name=eureka-server-cluster
#由于该应用为注册中心,所以设置为false,代表不向注册中心注册自己
eureka.client.register-with-eureka=false
#由于注册中心的职责就是维护服务实例,并不需要检索服务,所以也设置为false
eureka.client.fetch-registry=false
spring.security.user.name=ygayddcxy
spring.security.user.password=123456
#指定不同环境
spring.profiles.active=master

以上便是我们的配置用例:
下面便设置不同的启动环境:
在这里插入图片描述
点击一下Edit设置,添加多一个服务启动,并且添加 –spring.profiles.active=slaveone
在这里插入图片描述
我们分别启动访问后:
在这里插入图片描述
在这里插入图片描述
应该可以看到master注册到了slaveone中,slaveone注册到了master中,无论谁出现问题,应用都能继续使用存活的注册中心。

在CSDN的其他博主的博文的评论区找到了一个源码级的讲解:

假设Server1和Server2,互为peer,且Client1只注册到Server1,Client2只注册到Server2(注意这个且字)。这个时候Server1和Server2上面都会有Client1和Client2。 假设Client1挂掉,会经过3次尝试也就是默认3*30,90S之后,Server1会希望将Client1移除掉,但是在默认设置的情况下,由于有自我保护机制的原因(3分钟内失败的客户端数量大于总数量的15%),目前只有三个Client(Client1、Client2、Server2这个时候都注册在Server1上,请确认理解这句话),达到了自我保护的阈值。Server1将不会移除Client。并且因为只有一个Client,再以后的三分钟也不会有其它Client失败会引起自我保护的取消,Client1将永远不会从Server1移除。 那什么情况下会移除,就不去算15%的什么服务器边界个数了,我们举个更大的例子,1、假设我们有100个客户端,Client1失败的时候,会在90S后移除。2、假设一开始只有Client1,开启保护了,然后又新注册了100个上来,会再下一个Client失败的时候,将该失败的Client和Client1一并移除。然后复制给Server2。 上面是客户端挂掉的情况,假设Server1挂掉,Server2从Server1同步服务列表的时候失败了,但它同样不会删除数据,对它来说同样是3个Client中断了两个。并且在将来也不会移除掉。 同样,假设服务比较多,就会在90S之后移除。 上面的Server1断掉的情况还没有说完,假设服务器比较多,在Server1断开之后发生了移除,那么Client1就变成孤立Client了,虽然它自身有其它服务的缓存,但是这个信息不再会更新了。并且其它服务下已经没有它的信息了。它只能成功调用那部分未发生变化的服务,这个时候的Zone并没有起到真正的容灾作用,继续。。。

之前在客户端中我们通过配置eureka.client.serviceUrl.defaultZone来指定对呀的注册中心,当我们的注册中心有多个节点后,就需要修改eureka.client.serviceUrl.defaultZone的配置为多个节点的地址,多个地址用英文逗号隔开即可:

eureka.client.serviceUrl.defaultZone=http://ygayddcxy:123456@localhost:8761/eureka/,http://ygayddcxy:123456@localhost:8762/eureka/

7、常用配置讲解

1)、关闭自我保护

保护模式主要在组客户端和Eureka Server之间存在网络分区场景时使用。一旦进人保护模式,Eureka Server将会尝试保护其服务的注册表中的信息,不再删除服务注册表中 的数据。当网络故障恢复后,该Eureka Server节点会自动退出保护模式。

可以通过下面的配置将自我保护模式关闭,这个配置是在eureka-server中:

eureka.server.enable-self-preservation=false

2)、自定义Eureka的InstanceID

客户端在注册时,服务的InstanceID的默认值的格式如下:

${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}

其实就是"主机名:服务名称:服务端口"。
例如一开始的案例,服务中心和服务提供者运行启动后,在Eureka的Web控制台查看:
在这里插入图片描述
我们可以点击服务的InstanceID进行跳转,而跳转的位置可以看图的左下角。

3)、自定义实例跳转链接

我们通过配置实现了用IP进行注册,当点击InstanceID进行跳转的时候,就可以用IP跳转了,跳转的地址默认是IP+Port/info。我们可以自定义这个跳转的地址:

eureka.instance.status-page-url=http://www.baidu.com

在这里插入图片描述
在左下角可以看到跳转的地址,点击的确是可以进行跳转的。

4)、快速移除已经失效的服务信息

在实际开发过程中,我们可能会不停地重启服务,由于Eureka有自己的保护机制,故 节点下线后,服务信息还会一直存在于 Eureka中。我们可以通过增加一些配置让移除的速度更快点,只推荐在开发环境下使用,生产环境下不推存使用。

首先在我们的eureka-server;中增加两个配置,分别是关闭自我保护和清理间隔:

# 关闭自我保护
eureka.server.enable-self-preservation=false
# 默认 60000 毫秒
eureka.server.eviction-interval-timer-in-ms=5000

然后在具体的客户端服务中配置下面的内容:

# 开启健康检查
eureka.client.healthcheck.enabled=true
# 默认 30 秒
eureka.instance.lease-renewal-interval-in-seconds=5
# 默认 90 秒
eureka.instance.lease-expiration-duration-in-seconds=5

eureka.client.healthcheck.enabled用于开启健康检查,需要在pom.xml引入actuator的依赖:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

解释:eureka.instance.lease-renewal-interval-in-seconds表示Eureka Client发送心跳给server端的频率。

eureka.instance.lease-expiration-duration-in-seconds表示Eureka Server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则移除该Instance。

更多的Instance配置信息可参考源码中的配置类:org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean。
更多的Server配置信息可参考源码中的配置类:org.springframework.cloud.netflix.eureka.EurekaServerConfigBean。

总结

Eureka作为注册中心,其本质是存储了每个客户端的注册信息,Ribbon在转发的时候会获取注册中心的服务列表,然后根据对应的路由规则来选择个服务给Feign来进行调用。如果我们不是Spring Cloud技术选型,也想用Eureka,可以吗?完全可以。
如果不是Spring Cloud技术栈,Zookeeper可以,当然用Eureka也是可以的,这样的话就会涉及如何注册信息、如何获取注册信息等操作。其实Eureka也考虑到了这点,提供了很多REST接口来给我们调用。

在最后来一道面试题:
Eureka和Zookeeper的区别?
要回答好这个问题,首先要先了解
什么是Eureka?
Eureka 是 Netflix 的一个子模块,也是核心模块之一。Eureka 是一个基于 REST(REpresentational State Transfer) 的服务,用于定位服务,以实现云端中间层服务器的负载均衡和故障转移。Eureka还附带了一个基于java的客户端组件——Eureka Client,它使得与服务的交互更加容易。Eureka Client 还有一个内置的负载均衡器,可以进行基本的循环负载均衡,在 Netflix,一个更加复杂的负载均衡器封装了 Eureka,可以根据流量、资源的使用情况、错误条件等因素根据自定义的权重来实现负载均衡,从而提供更好的弹性服务。对于服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。

什么是Zookeeper?
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,其主要功能包括:配置维护、域名服务、分布式同步、组服务管理等。ZooKeeper 的目标就是错综复杂的、易出错的服务封装起来,将简其单易用的接口和性能高效、功能稳定的系统服务暴露出来并提供给用户调用使用。

而他们的基本原理分别是什么呢?
Eureka 基本架构原理:

Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,则使用 Eureka Client 连接到 Eureka Server 并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。Spring Cloud 的一些其他子模块(例如 Gateway)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的业务逻辑。

Zooekeeper 基本原理:

ZooKeeper 是以 Paxos 算法为基础的,而Paxos 算法存在活锁的问题,即当有多个 proposer 交错提交时,有可能互相排斥导致没有一个 proposer 能提交成功,而 Paxos 作了一些优化,通过选举产生一个leader (领导者),只有 leader 才能提交 proposer。(Paxos 算法是一种基于消息传递的一致性算法,并且该算法被认为是类似算法中最有效的)

由此得出:

Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。Eureka作为单纯的服务注册中心来说要比zookeeper更加“专业”,因为注册服务更重要的是可用性,我们可以接受短期内达不到一致性的状况。

当然可以通过CAP的原则进行区别Eureka和Zookeeper。
以上便是我的学习记录,其实在Eureka后,还有一些扩展的使用,例如:Eureka REST API、元数据使用、EurekaClient使用、健康检查、服务上下线监控等等知识,此文章便记录到这里(✪ω✪)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值