2、spring cloud服务治理之Eureka

spring cloud eureka

目录

  • spring cloud eureka
    • 是什么?
    • 为什么需要服务治理?
    • eureka server 和eureka client 示例图
    • 其他的服务注册与发现组件
  • 使用Eureka
    • 搭建一个Eureka Server 服务注册中心
    • 搭建一个Eureka client 端:service provider
    • server端和client端yaml配置的一些说明
    • 关于eureka控制台出现红字的几种情况
    • eureka server 添加认证
  • Eureka集群
    • 搭建高可用的Eureka Server
    • eureka-server 配置
    • eureka consumer搭建
    • 启动服务和测试eureka server的高可用
  • github源码地址
    • 地址
    • 代码所在模块

是什么?

spring cloud eureka是spring cloud Netflix微服务套件中的一部分,它基于Netflix做了二次封装,主要负责微服务架构中的服务治理功能,服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现。

为什么需要服务治理?

考虑当前有两个微服务实例A和B,A服务需要调用B服务的某个REST接口。假如某一天B服务迁移到了另外一台服务器,IP和端口也发生了变化,这时候我们不得不去修改A服务中调用B服务REST接口的静态配置。随着公司业务的发展,微服务的数量也越来越多,服务间的关系可能变得非常复杂,传统的微服务维护变得愈加困难,也很容易出错。所谓服务治理就是用来实现各个微服务实例的自动化注册与发现,在这种模式下,服务间的调用不再通过指定具体的实例地址来实现,而是通过向服务注册中心获取服务名并发起请求调用实现。

eureka server 和eureka client 示例图

eureka server和eureka client示例.png
  • Eureka Server:服务的注册中心,负责维护注册的服务列表。
  • Service Provider:服务提供方,作为一个Eureka Client,向Eureka Server做服务注册、续约和下线等操作,注册的主要数据包括服务名、机器ip、端口号、域名等等。
  • Service Consumer:服务消费方,作为一个Eureka Client,向Eureka Server获取Service Provider的注册信息,并通过远程调用与Service Provider进行通信。
  • Service Provider和Service Consumer不是严格的概念,Service Consumer也可以随时向Eureka Server注册,来让自己变成一个Service Provider。

其他的服务注册与发现组件

  • Consul
  • Zookeeper
  • Dubbo
  • Nacos

使用Eureka

搭建一个Eureka Server 服务注册中心

新建一个Spring Boot项目,artifactId填eureka-server,然后引入Greenwich.SR3和spring-cloud-starter-netflix-eureka-server:

    <!--spring cloud 版本 Greenwich.SR3 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
         <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</artifactId>
        </dependency>
    </dependencies>

启动类上加上注解@EnableEurekaServer表明这是一个Eureka Server端

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

yaml配置:

server:
  port: 8761 #指定端口为8761
spring:
  application:
    name: @artifactId@ #eureka服务的名字
eureka:
  instance:
    hostname: localhost #指定了eureka服务端的IP
  server:
    enable-self-preservation: false #用于开启Eureka Server自我保护功能,默认值为true,如果是true的话,eureka client在dev环境下会经常上线和下线,然后eureka server就认为client不是一个稳定的服务,不确定是否是真的可用还是不可用,就会报一串红色的警告。
  client:
    register-with-eureka: false #表示是否将服务注册到Eureka服务端,由于自身就是Eureka服务端,所以设置为false;
    fetch-registry: false #表示是否从Eureka服务端获取服务信息,因为这里只搭建了一个Eureka服务端,并不需要从别的Eureka服务端同步服务信息,所以这里设置为false;
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #指定Eureka服务端的地址,默认值为http://localhost:8761/eureka。

搭建一个Eureka client 端:service provider

新建一个Spring Boot项目,artifactId填eureka-server,然后引入Greenwich.SR3和spring-cloud-starter-netflix-eureka-client:

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

启动类上加上注解@EnableDiscoveryClient表明这是一个Eureka Client端

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

yaml配置:

server:
  port: 8762
spring:
  application:
    name: @artifactId@
eureka:
  client:
    enabled: true #是否启用Eureka Client
    fetch-registry: true #表示是否从Eureka Server获取注册的服务信息
    register-with-eureka: true #表示是否将自己注册到Eureka Server
    service-url:
      defaultZone: http://localhost:8761/eureka/ #配置Eureka Server地址,用于注册服务和获取服务
    registry-fetch-interval-seconds: 30 #默认值为30秒,即每30秒去Eureka Server上获取服务并缓存
    instance-info-replication-interval-seconds: 30 #更新实例信息的变化到Eureka服务端的间隔时间,单位为秒
    eureka-service-url-poll-interval-seconds: 300 #轮询Eureka服务端地址更改的间隔时间,单位为秒。
    healthcheck:
      enabled: false #默认Eureka Server是通过心跳来检测Eureka Client的健康状况的,通过置为true改变Eureka Server对客户端健康检测的方式,改用Actuator的/health端点来检测。
  instance:
    lease-renewal-interval-in-seconds: 30 #向Eureka Server发送心跳的间隔时间,单位为秒,用于服务续约
    lease-expiration-duration-in-seconds: 90 #定义服务失效时间,即Eureka Server检测到Eureka Client木有心跳后(客户端意外下线)多少秒将其剔除.
    prefer-ip-address: false #表示使用IP进行配置为不是域名
    hostname: localhost #指定了eureka服务端的IP
management:
  endpoints:
    web:
      exposure:
        include: "*" #暴露所有的actuator端点
  endpoint:
    health:
      show-details: always #健康检查展示所有详情:always

server端和client端yaml配置的一些说明

在上面的server端和client端的yaml配置,我把一些本来就是默认值得配置也写了进去(在项目里面可以按住ctrl+鼠标左键可以进源码看到是否为默认值),是因为显示的显示这些配置,并标注每个配置的使用含义,让配置更加直观。实际项目可以简化配置。下面是常用配置的表格:

常用配置 配置含义 默认值
eureka.client.enabled 是否启用Eureka Client true
eureka.client.register-with-eureka 表示是否将自己注册到Eureka Server true
eureka.client.fetch-registry 表示是否从Eureka Server获取注册的服务信息 true
eureka.client.serviceUrl.defaultZone 配置Eureka Server地址,用于注册服务和获取服务 http://localhost:8761/eureka
eureka.client.registry-fetch-interval-seconds 默认值为30秒,即每30秒去Eureka Server上获取服务并缓存 30
eureka.instance.lease-renewal-interval-in-seconds 向Eureka Server发送心跳的间隔时间,单位为秒,用于服务续约 30
eureka.instance.lease-expiration-duration-in-seconds 定义服务失效时间,即Eureka Server检测到Eureka Client木有心跳后(客户端意外下线)多少秒将其剔除 90
eureka.server.enable-self-preservation 用于开启Eureka Server自我保护功能 true
eureka.client.instance-info-replication-interval-seconds 更新实例信息的变化到Eureka服务端的间隔时间,单位为秒 30
eureka.client.eureka-service-url-poll-interval-seconds 轮询Eureka服务端地址更改的间隔时间,单位为秒。 300
eureka.instance.prefer-ip-address 表示使用IP进行配置为不是域名 false
eureka.client.healthcheck.enabled 默认Erueka Server是通过心跳来检测Eureka Client的健康状况的,通过置为true改变Eeureka Server对客户端健康检测的方式,改用Actuator的/health端点来检测。 false

其它配置参考:

  • org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean
  • org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
  • org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean
    修改一些默认配置需要注意的点:

官方:In production it's probably better to stick with the default because there are some computations internally in the server that make assumptions about the lease renewal period.

译:在生产中,最好坚持使用默认值,因为服务器内部有一些计算可以对租赁更新期进行假设。

关于eureka控制台出现红字的几种情况

1、在配置上,自我保护机制关闭(eureka.server.enable-self-preservation=false)

RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

2、自我保护机制开启了(
大致意思是Eureka已经进入了保护模式。微服务在部署之后可能由于网络问题造成Eureka客户端无法成功的发送心跳给Eureka服务端,这时候Eureka服务端认定Eureka客户端已经挂掉了,虽然实际上Eureka客户端还在正常的运行着。而保护模式就是为了解决这个问题,即当Eureka服务端在短时间内同时丢失了过多的Eureka客户端时,Eureka服务端会进入保护模式,不去剔除这些客户端。因为我们这里只部署了一个Eureka客户端服务,所以关闭客户端后满足“短时间内丢失过多Eureka客户端”的条件。

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.

3、在配置上,自我保护机制关闭了,但是一分钟内的续约数没有达到85% , 可能发生了网络分区,会有如下提示

THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

eureka server 添加认证

server端添加:

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

server端开启端点忽略:

  • You can secure your Eureka server simply by adding Spring Security to your server’s classpath via spring-boot-starter-security. By default when Spring Security is on the classpath it will require that a valid CSRF token be sent with every request to the app. Eureka clients will not generally possess a valid cross site request forgery (CSRF) token you will need to disable this requirement for the /eureka/** endpoints. For example:
  • 译:只需通过Spring boot starter Security将Spring Security添加到服务器的类路径中,就可以保护Eureka服务器。默认情况下,当Spring Security位于类路径上时,它将要求每次请求应用程序时都发送一个有效的CSRF令牌。Eureka客户端通常不会拥有有效的跨站点请求伪造(CSRF)令牌,您需要对/Eureka/**端点禁用此要求。例如:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

client端的配置也必须配置上用户名和密码,格式为:eureka.client.serviceUrl.defaultZone=http://{userName}:{password}@{hosetname}:{port}/eureka/,例如:

eureka:
  client:
    service-url:
      defaultZone: http://root:123456@localhost:8761/eureka/ #配置Eureka Server地址,用于注册服务和获取服务

Eureka集群

eureka server 高可用.png

搭建高可用的Eureka Server

Eureka服务端充当了重要的角色,所有Eureka客户端都将自己提供的服务注册到Eureka服务端,然后供所有服务消费者使用。如果单节点的Eureka服务端宕机了,那么所有服务都无法正常的访问,这必将是灾难性的。为了提高Eureka服务端的可用性,我们一般会对其集群部署,即同时部署多个Eureka服务端,并且可以相互间同步服务。

首先我们得检查这两个配置是否开启

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

这两个配置register-with-eureka=true是将自己注册到eureka服务端,然后fetch-registry是从服务端获取注册信息,搭建eureka server集群的话这两个得设置为true,才能各个eureka server之间相互发现。

下面来部署这几个服务:

服务名字 端口
eureka-server 8761
eureka-server 8762
eureka-server 8763
eureka-client-provider 8764
eureka-client-provider 8765
eureka-client-consumer 8766

eureka-server 配置

我们按照eureka集群的图来配置三个eureka server之间的互相通信,达成高可用的eureka server

peer1:

server:
  port: 8761 
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: peer1
  client:
    service-url:
      defaultZone: http://peer2:8762/eureka/,http://peer3:8763/eureka/
  server:
    enable-self-preservation: false

peer2:

server:
  port: 8762 
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: peer2
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer3:8763/eureka/
  server:
    enable-self-preservation: false

peer3:

server:
  port: 8763 
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: peer3
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
  server:
    enable-self-preservation: false

这里peer1、peer2、peer3和本地映射的关系建议使用工具switchhost配置下,没switchhost的找到hosts文件改下也可以。


switchhost本地映射关系.png

eureka consumer搭建

eureka-client-consumer配置:

server:
  port: 8766
spring:
  application:
    name: @artifactId@
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/
  instance:
    hostname: localhost

在启动类上加上负载均衡的注解等下测试eureka server 的高可用和 consumer调用provider默认采用均衡调用的规则

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

然后在consumer服务的controller写个调用provider服务的测试接口

@Slf4j
@RestController
@RequestMapping("/consumer")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ConsumerController {

    private final RestTemplate restTemplate;

    @RequestMapping("/getProviderInfo")
    public Integer getProviderInfo() {
        ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://eureka-client-provider/provider/findInstance", List.class);
        List list = responseEntity.getBody();
        log.info("调用provider服务获取到的信息为:{}", JSON.toJSONString(list));
        if (null != list) {
            return list.size();
        }
        return 0;
    }
}

然后在provider定义接口:

@Slf4j
@RestController
@RequestMapping("/provider")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ProviderController {
    private final DiscoveryClient discoveryClient;

    /**
     * 测试eureka-client-provider服务能找到eureka server。
     * @return
     */
    @GetMapping(value = "/findInstance", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public List<ServiceInstance> findInstance() {
        //测试 (eureka client) provider 是否可以找到eureka server
        List<ServiceInstance> instances = discoveryClient.getInstances("eureka-server");
        log.info("根据服务名eureka-server获取到的服务实例明细:{}", JSON.toJSONString(instances));
        return instances;
    }
}

启动服务和测试eureka server的高可用

启动三个eureka server、打开idea启动设置,运行多实例启动,启动两个provider服务,启动一个consumer服务,启动完成访问:http://localhost:8761/

五个服务启动完成.png

然后访问:http://localhost:8766/consumer/getProviderInfo

这时候可以观察到provider服务两个节点的控制台会被轮流访问。

然后干掉一个eureka server,继续访问你可以发现仍然是能通过其他两个eureka server 去调用到provider服务。

github源码地址

地址

https://gitee.com/zhouliangde/spring-project-learing

代码所在模块

代码模块.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容