Spring Cloud系列学习: 微服务注册与发现之Eureka

服务发现

1. 为什么使用服务发现(痛点)

每一服务实例都会在特定位置(主机与端口)通过HTTP/REST或者Thrift等方式发布一个远程API。

服务端实例的具体数量及位置会发生动态变化。

虚拟机与容器化部署通常会被分配动态IP地址。

服务实例的数量会发生动态变化。例如,EC自动伸缩组会根据负载情况随时调整实例数量。

2. 解决方案 Eureka

Eureka 是基于AP 的服务注册发现

服务提供者:向注册中心发送请求,发送信息

服务消费者:向注册中心发送请求,获取信息

注册中心:

  • 提供接口给服务发现客户端调用
  • 维护服务实例信息集合
  • 集群之间信息同步

在这里插入图片描述

Eureka 自我保护机制

首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行。

默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。

  • 官方对于自我保护机制的定义:

自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。

  • 自我保护机制的工作机制是:

如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:

Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。

Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。

当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

因此也很有可能出现 服务故障缺没有移除的情况

  • 自我保护开关

Eureka自我保护机制,通过配置 eureka.server.enable-self-preservation 来true打开/false禁用自我保护机制,默认打开状态,建议生产环境打开此配置。
eviction-interval-timer-in-ms: 设定检测周期

Eureka server 单机版

spring-cloud-demo-eureka-server 工程提供 eureka server ,分三步

1. 引入pom文件

        <!--    这个是重点 ,引入eureka  -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </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>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</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>

2. 配置 application.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    # 不注册自己
    register-with-eureka: false
    # 维护 不检索
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: false
    # 清理无效节点的时间间隔,默认60000毫秒,即60秒
    eviction-interval-timer-in-ms: 10
spring:
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

3. 写启动类 EurekaServerApplication

@EnableEurekaServer 重点就是这个

package top.freshgeek.springcloud.eureka;

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

/**
 * @author chen.chao
 * @version 1.0
 * @date 2020/4/29 11:31
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}

启动日志

最后就可以启动了,可以在控制台看到很多日志打印,如下:

2020-11-30 20:29:19.185  INFO 33572 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry  : Running the evict task with compensationTime 0ms
2020-11-30 20:29:19.196  INFO 33572 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry  : Running the evict task with compensationTime 1ms
2020-11-30 20:29:19.207  INFO 33572 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry  : Running the evict task with compensationTime 0ms
2020-11-30 20:29:19.218  INFO 33572 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry  : Running the evict task with compensationTime 1ms

这是正常的检测,在检测不正常的节点剔除,如果不想看到可以调整日志级别屏蔽,如:

logging:
  level:
    com:
      netflix:
        eureka:
          registry: warn

Eureka 服务方-调用方 配置使用

那么单机服务就搭建成功了,启动微服务的消费者-生产者测试:

  • spring-cloud-demo-provider-payment (提供支付服务,生产者)
  • spring-cloud-demo-consumer-order (订单调用支付服务,消费者)

同样分为三步:

1. 引入pom

需要连接eureka-server 那么就要引用 eureka client 的 依赖

服务发现使用一个即可,其他几个后面文章介绍

 <!--eureka 注册中心   选一-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
                </dependency>
        <!--eureka 注册中心   选一-->

2. 修改application.yml

  • spring-cloud-demo-provider-payment 生产者

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    # 当前数据源操作类型
    type: com.alibaba.druid.pool.DruidDataSource
    # mysql驱动类
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://data.keepon.site:3306/springcloud-payment?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    username: springcloud
    password: springcloud
    # 这里用了jpa 省得写dao了
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

eureka:
  client:
    # 注册进eureka
    register-with-eureka: true
    # 要不要去注册中心获取其他服务的地址
    fetch-registry: true
    # 这里需要配置一下eureka 服务器的 host域名
    service-url:
      defaultZone: http://eureka01:8761/eureka/

  • spring-cloud-demo-consumer-order 消费者

server:
  port: 80
eureka:
  client:
    register-with-eureka: false
    fetch-registry: true
    service-url:
      defaultZone: http://eureka01:8761/eureka/
spring:
  application:
    name: cloud-consumer-order

这里需要把eureka server 启动的地址和端口对应上
如果没有域名可以自己在host 里面添加一条

其实两个也都差不多,主要就是两个配置参数

  • eureka.client.register-with-eureka 是否注册入eureka ,别人需要调用开
  • eureka.client.fetch-registry 是否拉取服务列表,需要调用别人开

3.添加主启动类

  • spring-cloud-demo-provider-payment

package top.freshgeek.springcloud.payment;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author chen.chao
 * @version 1.0
 * @date 2020/4/28 21:05
 * @description 启动类
 */
@EnableSwagger2
// 在eureka 环境下才加@EnableEurekaClient
@EnableEurekaClient
@SpringBootApplication
@EntityScan("top.freshgeek.springcloud.payment.entity")
public class ProviderPaymentApplication {

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


  • spring-cloud-demo-consumer-order
package top.freshgeek.springcloud.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author chen.chao
 * @version 1.0
 * @date 2020/4/28 21:05
 * @description 启动类
 */
@EnableSwagger2
// eureka
@EnableEurekaClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ConsumerOrderApplication {

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

4. 编写业务类

  • spring-cloud-demo-provider-payment (生产者就不解释了,curd)
  • spring-cloud-demo-consumer-order 消费者,怎么调用

我们可以在 http://eureka01:8761/ 看到已经出现了 CLOUD-PAYMENT-SERVICE

因此我们可以使用一个配置,然后使用服务名CLOUD-PAYMENT-SERVICE 调用它

RestTemplate 配置

package top.freshgeek.springcloud.order.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author chen.chao
 * @version 1.0
 * @date 2020/4/29 10:29
 * @description
 */
@Configuration
public class RestConfig {

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

package top.freshgeek.springcloud.order.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import top.freshgeek.springcloud.common.payment.CommonResult;
import Payment;

import javax.annotation.Resource;

/**
 * @author chen.chao
 * @version 1.0
 * @date 2020/4/29 10:28
 * @description
 *
 * 使用rest template + ribbon 结合 使用
 *
 */
@Slf4j
@RequestMapping("/consumer/")
@RestController
public class OrderTemplateController {

    static final String PAYMENT = "http://"+PAY_SERVICE;

    @Resource
    private RestTemplate restTemplate;


    @GetMapping("payment/get/{id}")
    public CommonResult getPayment(@PathVariable("id") int id) {
        return restTemplate.getForObject(PAYMENT + "/payment/get/" + id, CommonResult.class);
    }

    @PostMapping("payment/create")
    public CommonResult getPayment(Payment payment) {
        return restTemplate.postForObject(PAYMENT + "/payment/create",
                payment, CommonResult.class);
    }

}

这样我们就完成了微服务的注册和发现了,可以测试调用

如:启动配置 single-eureka-productor-consumer

Eureka 集群

作为微服务,如果是单体server,那肯定不行,必须上集群。

Eureka 集群 是把每一台节点作为服务提供者注册进其他eureka server 实例中相互守望

Eureka Server 集群配置引入服务提供者和生产者,pom不用变,只是需要修改eureka server 多启动几个实例即可,同时在服务注册和调用方配置多个eureka地址即可

第一步:复制多端口 eureka 配置文件

复制多份application.yml , 这里复制两个:

  • application-cluster-01.yml
  • application-cluster-02.yml

注意: 这里是1注册进2 , 2 注册进 1
如果三个的话:1注册进23, 2注册进13 , 3注册进12

application-cluster-01.yml

server:
  port: 8761
eureka:
  instance:
    hostname: eureka01
  client:
    # 不注册自己
    register-with-eureka: true
    # 维护 不检索
    fetch-registry: true
    service-url:
      defaultZone: http://eureka02:8762/eureka/

application-cluster-02.yml

server:
  port: 8762
eureka:
  instance:
    hostname: eureka02
  client:
    # 不注册自己
    register-with-eureka: true
    # 维护 不检索
    fetch-registry: true
    service-url:
      defaultZone: http://eureka01:8761/eureka/

第二步:启动eureka集群

因为是本机启动,所以端口和实例名没有重复,

启动动时指定在idea 的 config中指定springboot 的active profile cluster-01 cluster-02 即可

在这里插入图片描述

启动完成后可以访问(同样需要配置hosts):

在这里插入图片描述

在这里插入图片描述

达成相互守望效果(这里我启动了生产者,在下一步)

第三步:配置启动微服务 生产者-消费者

只需要在生产和消费者配置两个eureka 地址即可

如 启动配置 eureka-cluster-productor-consumer


      defaultZone: http://eureka01:8761/eureka/,http://eureka02:8762/eureka/

然后再启动生产消费者,调用消费者接口,可以返回数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木秀林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值