SpringCloud 服务注册中心Eureka、zookeeper

本篇文章是在B站看的周阳老师的SpringCloud的教学视频做的笔记,有感兴趣的同学可以B站看阳哥的视频进一步学习https://www.bilibili.com/video/BV18E411x7eT?p=1

服务注册中心

Eureka服务注册与发现

Eureka基础

什么是服务治理

​ Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务治理

​ 在传统的rpc远程调用框架中,管理每个服务于服务之间依赖关系比较复杂,所以需要使用服务治理,管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

什么是服务注册与发现

​ Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,他是服务注册中心,而系统中的其他微服务,使用Eureka Server并维持心跳连接,这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行

​ 在服务注册与发现中,有个注册中心。当服务器启动时,会把当前自己服务器的信息,比如服务地址通讯地址等以别名方式注册到注册中心上,另一方(消费者|服务提供者)以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心。因为使用注册中心管理每个服务与服务之间的依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))

Eureka的两个组件
Eureka Server(提供服务注册服务)

​ 各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储多有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

Eureka Client(通过注册中心进行访问)

​ 是一个Java客户端,用于简化Eureka Server的交互,可u段同时具备了一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer会从服务注册表中将这个服务节点移除(默认60秒)

搭建单机Eureka

Eureka Server

1、建moudle

创建名为cloud-eureka-server7001模块

2、改pom

说明:

1.X版本(当前使用2018)

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

2.X版本(当前使用2020.2)

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

完整的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>cn.yz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7001</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--引入公共模块坐标-->
        <dependency>
            <groupId>cn.yz.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

3、写yml

#端口号
server:
  port: 7001
eureka:
  instance:
    hostname: localhost  #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

4、主启动

@SpringBootApplication
//标记为Eureka服务注册中心
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class,args);
    }
}

5、启动

访问:http://localhost:7001

访问页面:
Eureka Server

改造8001和80为Eureka Client(只示范8001)

1、修改pom

pom版本说明:

老版本:(导入的依赖无法区分是服务端还是客户端)

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

新本版:

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

2、修改yml

#端口号
server:
  port: 8001

#微服务名称
spring:
  application:
    name: cloud-payment-servcie
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource      #当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

#mybatis
mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entities    # 所有Entity别名类所在包

#Eureka
eureka:
  client:
    #表示是否将自己注册进EurekaServer,默认为true
    register-with-eureka: true
    #表示是否从EurekaServer中抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能默认ribbon使用负载均衡
    fetch-registry: true
    service-url:
      #注册地址
      defaultZone: http://localhost:7001/eureka

3、标记为EurekaClient

@SpringBootApplication
//标记为EurekaClient
@EnableEurekaClient
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class);
    }
}

重新启动8001,在Eureka中界面如下:可以看到,CLOUD-PAYMENT-SERVCIE已经进入Eureka中(红字为Eureka的自我保护机制,重启Eureka服务器就会消失啦~)
EurekaClient注册进EurekaServer

搭建Eureka集群

微服务RPC远程服务调用最核心的是什么?高可用

解决方法:搭建Eureka注册中心集群,实现负载均衡+故障容错

Eureka集群原理

Eureka集群原理

1、建moudle

创建一个和

2、修改host配置

在C:\Windows\System32\drivers\etc目录下修改host文件,添加下列配置

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

修改hosts文件

3、修改yml

#端口号
server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com  #eureka服务端的实例名称,不能再以localhost命名
  client:
    #false表示不向注册中心注册自己
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址,在集群中,Eureka服务器相互注册,相互守望,因此地址设置为集群中其他的服务
      defaultZone: http://eureka7001.com:7001/eureka/

4、启动

当看到7001中注册有7002,说明集群搭建成功
eureka集群搭建成功

5、修改8001和80配置

由于eureka搭建了集群,因此要将8001和80微服务都发布到集群中(再yml中修改)

server:
  port: 80

#微服务名称
spring:
  application:
    #入驻进Eureka服务器的名称
    name: cloud-consumer-order

#Eureka
eureka:
  client:
    #表示是否将自己注册进EurekaServer,默认为true
    register-with-eureka: true
    #表示是否从EurekaServer中抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能默认ribbon使用负载均衡
    fetch-registry: true
    service-url:
      #注册地址
#      defaultZone: http://localhost:7001/eureka   #单机版
      defaultZone: http://eureka7002.com:7001/eureka,http://eureka7001.com:7002/eureka  #集群版

启动顺序:eureka服务器集群→8001→80

服务提供者集群

1、建moudle

创建一个和8001一样的模块,命名为cloud-provider-payment8002,修改其中的端口号。这样服务提供者集群算搭建完成。

2、修改80

因为eureka中注册了cloud-provider-payment8001和cloud-provider-payment8002两个服务提供者,而在80端口中,我们已经将访问的端口号写死了,只会访问那一个端口。如下图:
80中payment_URL

为了能使80能够随机访问注册在eureka的服务提供者,不能写端口号,要写服务名称。(eureka中相同的服务注册微服务名称是相同的)
80中写eureka中微服务名称

在修改完服务名称后,直接启动仍会报错,因为eureka的服务提供者有多个,不知道选用哪个,因此要在ApplicationContextConfig加入负载均衡机制。在ApplicationContextConfig中注册的RestTemplate Bean上添加@LoadBalanced注解。
负载均衡LoadBalanced

当通过80端口来查询payment信息时:http://localhost/consumer/payment/getPaymentById/1,8001和8002端口交替服务,避免了只有一个端口负载过重的现象。
负载均衡8001服务
负载均衡8002服务

actuator微服务信息完善:

主机名称修改和IP显示:

在8001和8002的yml下修改。在eureka下添加:(instance和client平齐)

  instance:
    instance-id: payment8001
    prefer-ip-address: true  #访问路径可以显示IP地址

服务发现Discovery

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。

以8001为例,在controller中通过discoveryClient实例来获取相关的信息。

@GetMapping("/payment/discovery")
public Object discovery(){
    //获得服务列表信息
    List<String> services = discoveryClient.getServices();
    for(String element:services){
        log.info("*********element:"+element+"*********");
    }
    //根据服务名称进一步获得服务相关信息
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVCIE");
    for(ServiceInstance instance:instances){
        log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
    }
    return this.discoveryClient;
}

在主程序类上加上@EnableDiscoveryClient注解来开启服务发现。
服务发现日志打印

Eureka的自我保护

故障现象

保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不在删除服务注册表中的数据,也就是不会注销任何微服务。

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 Server首页看到下面这段提示,说明Eureka进入了保护模式。

导致原因

为什么会产生Eureka自我保护机制?

为了防止EurekaClient可以正常运行,但是与EurekaServer网络不同的情况下,EurekaServer不会立刻将EurekaClient服务剔除

什么是自我保护模式?

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得十分危险,因为服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当Eureka节点短时间内丢失过多的客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。

自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加健壮、稳定。

关闭自我保护机制

EurrkaServer yml配置

Eureka的自我保护机制配置中默认为true
Eureka自我保护默认为true

eureka:
  server:
    #关闭自我保护机制,保证不可用服务被及时剔除
    enable-self-preservation: false
    #默认时间修改为2秒
    eviction-interval-timer-in-ms: 2000

关闭后重启EurekaServer,界面出现下列图示:
Eureka自我保护机制关闭

EurekaClient yml配置

eureka:
  instance:
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    lease-expiration-duration-in-seconds: 2	

修改后重新启动,能够成功注册进Eureka7001

当将8001服务停止,间隔2s后,将payment8001剔除(为了方便只启动了8001,未启动8002)
Eureka自我保护 8001宕机

Zookeeper服务注册与发现

springcloud整合Zookeeper代替Eureka

注册中心Zookeeper

Zookeeper是一个分布式协调工具,可以实现注册中心功能

安装Zookeeper

在周阳老师的视频教学中,在centOS中安装的Zookeeper,我这里图方便,使用docker安装的zookeeper
zookeeper docker

使用命令docker pull zookeeper安装
zookeeper dockerpull

启动zookeeper(请注意图中我标记的命令和id)
zookeeper docker启动

zookeeper启动成功
zookeeper docker启动成功

使用客户端连接
zookeeper 客户端

服务提供者

1、建moudle

创建名为cloud-provider-payment8004

2、改pom

除了基础要使用的依赖外,还要添加zookeeper的依赖

<!--SpringBoot整合zookeeper客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <!--排除自带的zookeeper-->
<!--            <artifactId>org.apache.zookeeper:zookeeper:3.5.3-beta</artifactId>-->
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--添加zookeeper3.4.9版本,可根据自己的zookeeper确定版本-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.9</version>
</dependency>

3、写yml

#8004表示注册到zookeeper服务器的直赋服务提供者端口号
server:
  port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 192.168.99.100:2181

4、主启动

@SpringBootApplication
//服务发现,用于向使用consul或者zookeeper作为注册中心是注册服务
@EnableDiscoveryClient
public class PaymentMain8004 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8004.class);
    }
}

5、业务类

@RestController
@Slf4j
public class PaymentController {

    @Value("$(server.port)")
    private String serverPort;

    @GetMapping("/payment/zk")
    public String paymentzk(){
        return ""+serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

6、启动

7、验证测试(未连接zookeeper)
zookeeper 验证1

刷新后不一样表示连接成功
zookeeper 验证2

8、验证测试

支付模块成功入驻进zookeeper
zookeeper service

8004服务注册详情
zookeeper docker 服务详情

思考:

在zookeeper中都以znode节点存储,zookeeper中的节点粗分可以分为四种节点,分为临时节点,带序号的临时节点,持久节点,带序号的持久节点。

服务8004在zookeeper上是什么节点?临时节点
zookeeper 服务注册临时节点.

重新启动8004服务后,会直接将服务注册进zookeeper,但是在zookeeper中的服务名称会被修改,随机生成(上一次是7e2ae571-304d-4660-b2d8-ea117cc39be9,这一次是c5381299-8d9a-47af-b0e5-d2818ce22cdb)

服务消费者

1、建moudle

创建名为cloud-consumerzk-order80的moudle

2、改pom

和8004一样的

3、写yml

#8004表示注册到zookeeper服务器的直赋服务提供者端口号
server:
  port: 80
#服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-consumer-order
  cloud:
    zookeeper:
      connect-string: 192.168.99.100:2181

4、主启动

@SpringBootApplication
//服务发现,用于向使用consul或者zookeeper作为注册中心是注册服务
@EnableDiscoveryClient
public class OrderZKMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderZKMain80.class);
    }
}

5、业务类

ApplicationContextConfig.java

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

PaymentController.java

@RestController
@Slf4j
public class PaymentController {

    public static final String INVOKE_URL = "http://CLOUD-PORVIDER_PAYMENT";

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/zk")
    public String paymentInfo(){
       String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
       return result;
    }
}

6、访问

http://localhost:8004/payment/zk和http://localhost/consumer/payment/zk均可访问

zookeeper中服务端和消费端都注册成功
zookeeper 服务端 消费端

Consul服务注册与发现

这一部分的操作和zookeeper大同小异,因此这一部分我没有实际操作,笔记也就略过了。

三个注册中心的异同点

组件名语言CAP服务健康检查对外暴露接口SpringCloud集成
EurekaJJavaAP(高可用)可配支持HTTP已集成
ConsulGoCP(数据一致)支持HTTP/DNS已集成
ZookeeperJavaCP(数据一致)支持客户端已集成

CAP是指CAP定理,指在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾
经典CAP理论图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值