白话SpringCloud | 第三章:服务注册与发现-高可用配置(Eureka)-下

前言

上一章节,讲解了在单机模式下的服务注册与发现的相关知识点及简单示例。而在实际生产或者在这种微服务架构的分布式环境中,须要考虑发生故障时,各组件的高可用。而其实高可用,个人简单粗俗理解就是,经过系统的冗余进行高可用,或者是进行集群部署,保证一台服务不可用时,会进行自动转移至可用的服务中。今天的章节,就来讲说关于Eureka的高可用吧。html

一点知识

讲解前,咱们先来聊聊在使用Dubbo时耳闻能详的ZookeeperEureka之间的区别吧。java

CAP原则

根据百度百科的定义,CAP定理又称CAP原则,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),最多只能同时三个特性中的两个,三者不可兼得。git

在分布式领域,你们应该对CAP理论不陌生了吧(了解但也是没有深刻了解过⊙﹏⊙‖∣)。github

如下摘至百度百科:web

● 一致性(C):在分布式系统中的全部数据备份,在同一时刻是否一样的值。(等同于全部节点访问同一份最新的数据副本)spring

● 可用性(A):在集群中一部分节点故障后,集群总体是否还能响应客户端的读写请求。(对数据更新具有高可用性)api

● 分区容错性(P):以实际效果而言,分区至关于对通讯的时限要求。系统若是不能在时限内达成数据一致性,就意味着发生了分区的状况,必须就当前操做在C和A之间作出选择。浏览器

至于为什么不能同时知足,以上在分区容错性也有简单的说明了,通常来讲,分区容错没法避免,所以能够认为CAPP老是成立,而对于一致性可用性为什么不能同时知足,简单来讲就是:存在可能通讯失败状况,即:出现分区容错,至于更详细具体的,你们能够看下大佬阮一峰的这篇文章:CAP 定理的含义。这里就不阐述了,不是很了解~缓存

Eureka与Zookeeper区别

对于Eureka而言,其是知足AP的,而Zookeeper而言,是知足CP的。安全

Eureka是知足AP的:

  • 优先保证可用性
  • 各个节点都是平等的,几个节点挂掉不会影响正常节点的工做,剩余的节点依然能够提供注册和查询服务
  • 在向某个Eureka注册时若是发现链接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)

Zookeeper是知足AP的:

  • 任什么时候刻对ZooKeeper的访问请求能获得一致的数据结果,同时系统对网络分割具有容错性
  • 不能保证每次服务请求的可用性
  • 当master节点由于网络故障与其余节点失去联系时,剩余节点会从新进行leader选举
  • 选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就致使在选举期间注册服务瘫痪

个人简单理解:因为Zookeeperloader选举策略,使其能够保证数据的一致性。而Eureka,本事没有选举策略,各服务是独立运行的,至少在某一时刻,各服务之间的数据是不一致的,而在可用性方面,Zookeeper也是因为选举策略缘由,在选举期间是,整个zookeeper是不可用的,会形成短暂(看选举时长)的服务不可用。而对于Eureka而言,服务是独立运行的,因此不会由于某台服务不可用致使了其余服务不可用状况。感受上面有点绕,简单来讲,就是Zookeeper经过选举策略保证数据的一致性,但缺失了可用性,Eureka因为服务独立运行,经过心跳等通讯策略进行数据同步,存在数据不一致性,但保证了服务的可用性

因此,综上所述,做为服务注册中心而言,可用性原则是比数据一致性更重要的,同时上一章节也有说过,因为Eureka自我保护模式,可保护服务注册表中的信息不被剔除,因此Eureka能够很好的应对因网络故障致使节点失去联系的状况

Eurkea高可用介绍及示例

Eureka的高可用

官网中,关于Eureka的高可用部分是这么描述的:

High Availability, Zones and Regions

Peer Awareness

因此能够获悉,Eureka Server能够运行多个实例来构建集群,解决单点问题,Eureka Server采用的是Peer to Peer对等通讯。这是一种去中心化的架构,无master/slave区分,每个Peer都是对等的。在这种架构中,节点经过彼此互相注册来提升可用性,每一个节点须要添加一个或多个有效的serviceUrl指向其余节点。每一个节点均可被视为其余节点的副本。

若是某台Eureka Server宕机,Eureka Client的请求会自动切换到新的Eureka Server节点,当宕机的服务器从新恢复后,Eureka会再次将其归入到服务器集群管理之中。当节点开始接受客户端请求时,全部的操做都会进行replicateToPeer(节点间复制)操做,将请求复制到其余Eureka Server当前所知的全部节点中。

因此,简单来讲,Eureka Server的高可用,实际上就是将本身也做为服务向其余服务注册中心进行注册,这样就能够造成一组相互注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。

另外,从官网文档中有提到ZonesRegionsRegionZone(或者Availability Zone)均是AWS的概念。在非AWS环境下,咱们能够先简单地将region理解为Eureka集群,zone理解成机房。下图就能够理解为一个Eureka集群被部署在了zone1机房和zone2机房中。

Eureka集群

对这些概念的其余相关知识,也深刻了解,你们感兴趣,可自行搜索下吧。

示例前,先看看集群模式下,Eureka的架构图。

集群模式

  1. Service Provider会向Eureka Server作Register(服务注册)、Renew(服务续约)、Cancel(服务下线)等操做。
  2. Eureka Server之间会作注册服务的同步,从而保证状态一致
  3. Service Consumer会向Eureka Server获取注册服务列表,并消费服务

具体的原理分析,能够看看这篇比较早的文章:https://nobodyiam.com/2016/06/25/dive-into-eureka/,虽然是比较早的文章,但写的比较详细,能够看看。

接下来,以官网文档demo,示例下。

Eureka服务端高可用

经过点对点配置,注册中心经过相互注册来实现高可用配置。如下构建一个双节点的集群模式。

修改spring-cloud-eureka-server项目。

0.建立一个application-ha.properties配置文件,同时修改application.properties文件。

application-ha.properties

spring.application.name=eureka-service-ha
# 修改端口
server.port=1001

# 实例的主机名称
eureka.instance.hostname=myPeer2

## 不要向注册中心注册本身
#eureka.client.register-with-eureka=false
## 表示不去检索其余的服务,由于服务注册中心自己的职责就是维护服务实例,它也不须要去检索其余服务
#eureka.client.fetch-registry=false

# 指定服务注册中心地址
eureka.client.service-url.defaultZone=http://myPeer1:1000/eureka

application.properties

spring.application.name=eureka-service-ha
# 修改端口
server.port=1000

# 实例的主机名称
eureka.instance.hostname=myPeer1

## 不要向注册中心注册本身
#eureka.client.register-with-eureka=false
## 表示不去检索其余的服务,由于服务注册中心自己的职责就是维护服务实例,它也不须要去检索其余服务
#eureka.client.fetch-registry=false

# 指定服务注册中心地址
eureka.client.service-url.defaultZone=http://myPeer2:1000/eureka

#spring.profiles.active=ha

1.因为是在同一台进行模拟,首先修改hosts文件,当浏览器请求一个地址时,首先会今后文件选择对应对应的IP地址,找不到时才请求CDS域名解析服务器进行解析

‪C:\Windows\System32\drivers\etc\hosts文件:

127.0.0.1 myPeer1
127.0.0.1 myPeer2

友情提示:若提示无修改权限,可根据如下网址进行相应修改:编辑hosts文件没法保存怎么办

2.启动应用,咱们这里直接启动两个,可经过修改spring.profiles.active值来启动不一样环境的应用,或者使用-jar xx.jar --spring.profiles.active=xx来启动。

访问:http://myPeer1:1000

myPeer1

访问:http://myPeer2:1001

myPeer2

题外话:第一个启动的应用,后台会报错Connection refused: connect,等第二个应用启动后,就正常了~

Eureka客户端注册至集群上

客户端只须要经过修改配置文件的eureka.client.service-url.defaultZone值便可。

修改spring-cloud-eureka-client项目

0.修改配置文件application.properties

spring.application.name=eureka-client
server.port=2000

# 注册中心地址
eureka.client.service-url.defaultZone=http://myPeer1:1000/eureka,http://myPeer2:1001/eureka
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
eureka.instance.prefer-ip-address=true
# 实例名称  最后呈现地址:ip:2000
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

固然,也可只注册到某个节点上,其余的节点也会有此服务列表的,通常建议以集群方式进行配置,即多注册中心配置。避免单点故障,Eureka在搜索注册中心时,根据defaultZone列表,找到一个可用的,以后就不会继续去下一个注册中心地址拉取服务列表了,此时若其中一个注册中心挂了,这个时候客户端会继续去第二个注册中心拉取服务列表的。

启动后,能够看见eureka-client注册上去了。

如今咱们中止一个应用,能够看出不可用的服务列表中已经有相关信息了

高可用测试

为了验证高可用性是否成功,建立一个spring-cloud-eureka-server-ha-test项目,做为服务消费者使用RestTemplate+ribbon进行调用spring-cloud-eureka-client的服务。

建立spring-cloud-eureka-server-ha-test项目 0.引入pom依赖

<!-- 客户端依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>    
    <!-- 引入web,提供一个简单的api接口 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

1.配置文件,配置注册中心地址

spring.application.name=eureka-ha-test
server.port=8888

#指定注册中心地址
eureka.client.serviceUrl.defaultZone=http://myPeer1:1000/eureka/,http://myPeer2:1001/eureka/
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
eureka.instance.prefer-ip-address=true
# 实例名称  最后呈现地址:ip:2000
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

2.启动类,配置RestTemplateBean类,同时加入@LoadBalanced注解实现服务调用。

@SpringCloudApplication
@EnableDiscoveryClient
@Slf4j
public class EurekaServiceHaApplication {
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(EurekaServiceHaApplication.class, args);
        log.info("spring-cloud-eureka-server-ha-test启动!");
    }
    
    //加入负载均衡能力
    //同时可根据applicationName 来访问服务
    //如http://EUREKA-CLIENT/add
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

3.编写一个控制类,简单调用EUREKA-CLIENT服务方法。

/**
 * 调用简单示例
 * @author oKong
 *
 */
@RestController
public class DemoController {

    @Autowired
    private RestTemplate testTemplate;
    
    @GetMapping("/")
    public String index() {
        //访问服务提供者
        return testTemplate.getForObject("http://EUREKA-CLIENT/", String.class);
    }
}

4.启动应用类,访问注册中心和http://127.0.0.1:8888

注册中心

远程调用

可看见输出spring-cloud-eureka-client!代表调用成功。在控制台也能够看见,从注册中心拉取了EUREKA-CLIENT的服务地址:

这个时候,能够试着中止其中一个甚至所有的Eureka Server,再继续访问,能够看见服务仍是能够调用的,但要知道此时调用方是多是根据本地的缓存列表中直接获取地址的,而不是从注册服务中心,等待下次心跳机制时间到时,才会去进行拉取最新的服务列表的。


关于RestTemplateRibbon相关知识点,会在下一章节进行阐述的,这里就不敞开了。


一点疑问

第一次看官网文档进行demo时,还在想经过设置端口号不就能够了吗,为什么还须要指定eureka.instance.hostname呢,多麻烦?尝试下使用ip或者不配置试试看。

  • 修改eureka.instance.hostnamelocalhost或者127.0.0.1时,

localhost

能够看见,在DS Replicas中是空的,说明没有可复制的服务,registered-replicasavailable-replicas都是空的。

客户端配置eureka.client.service-url.defaultZone

eureka.client.service-url.defaultZone=http://127.0.0.1:1001/eureka,http://127.0.0.1:1000/eureka

会发现,在1001服务上有注册上去,1000服务没有服务信息。(客户端注册是按顺序进行优先注册和获取服务列表的)

1001服务:

1001服务

1000服务:

1000服务

这说明集群模式是没有生效的,注册中心之间没有相互复制服务列表。

  • 修改配置文件,一个修改为127.0.0.1,另外一个修改为localhost或者实际内网ip地址

说明下: 1001对应hostname为:127.0.0.1 1000对应hostname为:192.168.81.1

1001服务:

1001服务

1000服务:

1000服务服务

会发现,集群模式成功了。 接着咱们启动客户端。

1000服务: 1000服务

1001服务: 1001服务

能够看见,和上面设置myPeer1myPeer2效果是同样的,都有被复制了。

集群配置的一点浅谈

从上面能够大体获悉,Eureka互相注册要求各个Eureka server实例的eureka.instance.hostname不一样,若是相同,则会被Eureka标记为unavailable-replicas(像本地设置为127.0.0.1,干脆就不显示了,具体不明。。⊙﹏⊙‖∣),以前的同步就失效了。而对于客户端的defaultZone配置而言,是优先从第一个开始注册和拉取服务的,成功联通后就不会再继续找下一个注册服务了。


综上所述:

  • 如果一台服务器,部署多个Eureka server服务时,设置每一个服务 的hostname不一致,同时要设置eureka.instance.prefer-ip-addressfalse,不使用IP地址进行注册。
  • 如果多台服务器部署时,设置hostname为本机的ip地址,可以使用spring.cloud.client.ip-address变量进行赋值。同时设置eureka.instance.prefer-ip-addresstrue。这样的话,客户端使用ip进行链接就方便了,否则还要去配置host有点坑了。
  • 对于客户端的defaultZone建议仍是配置多个注册中心地址。就算自己集群模式无效,好歹其中一个不可用了,还能连其余的注册中心呀。

在最后收尾时,搜索到一篇文章,也是大体的意思,你们能够点击看一看:构建高可用Eureka注册中心

其源码地址:https://github.com/wangfei0904306/eureka-HA

以上可能理解有误差,还但愿知道的同窗能不吝赐教下,谢谢了!


Eureka注册中心访问认证

默认状况下,访问注册中心页面是匿名访问的,不须要一些认证。在生产中,为了安全性,可加入身份认证功能。

添加认证很简单,官网文档也有说明:

Securing The Eureka Server

0.加入pom依赖:

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

1.修改配置文件,设置用户名和密码及集群状态下,注册至其余服务中心时,加入用户名和密码:

# 设置账号密码
# 若不设置 默认账号是user,密码随机,启动时会打印在控制台上
spring.security.user.name=oKong
spring.security.user.password=123456

# 加入用户名和密码
eureka.client.service-url.defaultZone=http://oKong:123456@127.0.0.1:1001/eureka

友情提示:不设置name和password时,默认用户是user,密码是随机的,启动时会打印在控制台上的:

默认密码

2.修改启动类,根据官网的提示,关闭/eureka/**的CSRF的令牌。

/**
 * Eureka服务端
 * @author oKong
 *
 */
@SpringBootApplication
@EnableEurekaServer
@Slf4j
public class EureakServiceApplication {
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(EureakServiceApplication.class, args);
        log.info("spring-cloud-eureka-service启动!");
    }
    
    /**
     * 忽略此路径下的CSRF令牌
     * @author oKong
     *
     */
    @EnableWebSecurity
    static class WebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().ignoringAntMatchers("/eureka/**");
            super.configure(http);
        }
    }    
}

3.启动应用。再次访问:http:127.0.0.1:1000 时,就须要输入用户名和密码了。

4.客户端也是相似的,修改defaultZone加入用户名和密码便可:

eureka.client.service-url.defaultZone=http://oKong:123456@127.0.0.1:1001/eureka,http://oKong:123456@127.0.0.1:1000/eureka

参考资料

  1. https://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#spring-cloud-eureka-server

  2. https://nobodyiam.com/2016/06/25/dive-into-eureka/

  3. http://tech.lede.com/2017/03/15/rd/server/SpringCloud1/

  4. https://blog.csdn.net/wangfei0904306/article/details/79056083

总结

本章节主要是Eureka服务的高可用进行了简单的介绍了下。对于集群模式下的一些最佳实践仍是有待商讨的,还但愿你们能说说自个的方案!至于一些其余的特性,如元数据配置等,这里就不阐述了,用的很少。同时,本章节利用RestTemplate+ribbon进行了简单的服务调用,没有敞开说,下一章节就是开始讲解服务消费者相关知识点,应该也会分红两章节来描述,由于涉及到了RibbonFeign相关知识点。我一直以为使用都是很简单的,只有理解里面的原理之类的,这样才是一通百通吧,加深印象!使用起来也能比较顺利。

最后

目前互联网上大佬都有分享SpringCloud系列教程,内容可能会相似,望多多包涵了。原创不易,码字不易,还但愿你们多多支持。若文中有错误之处,还望提出,谢谢。

老生常谈

  • 我的QQ:499452441
  • 微信公众号:lqdevOps

公众号

我的博客:http://blog.lqdev.cn

源码示例:https://github.com/xie19900123/spring-cloud-learning

原文地址:http://blog.lqdev.cn/2018/09/09/SpringCloud/chapter-three/

相关文章
相关标签/搜索