笔记:Spring Cloud Eureka

注册与发现

Eureka 服务注册和发现机制 和Spring Cloud无缝集成
集成Eureka Service

简化了分布式系统基础设施的开发,如服务注册、服务发现、配置中心、消息总线、负载均衡、断路器、数据监控等

• Eureka :服务注册中心,用于服务管理 。
• Ribbon :基于客户端的负载均衡组件 。
• Hystrix :容错框架,能够防止服务的雪崩效应 。
• Feign: Web 服务客户端,能够简化 Http 接口的调用 。
• Zuul: API 网关 ,提供路由转发、请求过滤等功能 。
• Config : 分布式配置管理。
• Sleuth :服务跟踪 。
• Stream :构建消息驱动的微服务应用程序的框架 。
• Bus :消息代理的集群消息总线。

Eureka 注册中心

主要用来实现服务治理功能
Spring Cloud Eureka 是一个基于 REST 的服务,并且提供了基于 Java 的客户端组件 , 能够非常方便地将服务注册到Spring Cloud Eureka 中进行统一管理

除了用 Eureka 作为注册中心外,我们还可以使用 Consul 、 Etcd 、 Zookeeper 等来作为服务的注册中心 。
Eureka 是基于 AP 原则构建的,而 ZooKeeper 是基于 CP 原则构建的 。 在分布式系统领域有个著名的 CAP 定理,即 C(Consistency ) 为数据一致性;
A (Availability )为服务可用性;
P (Partition tolerance)为服务对网络分区故障的容错性 。
这三个特性在任何分布式系统中都不能同时满足,最多同时满足两个 。
Consistency 和 Availability 之间是有矛盾的,因为可能通信失败(即出现分区容错)
在这里插入图片描述
如图G1和G2是两个不同分区的服务器,client是客户端,客户端可以访问两个服务器中的任何一个

如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性。

如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。

综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

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

一般来说,网页的更新不是特别强调一致性。短时期内,一些用户拿到老版本,另一些用户拿到新版本,问题不会特别大。当然,所有人最终都会看到新版本。所以,这个场合就是可用性高于一致性,但涉及金融方面的,例如银行转账等操作,买票等就是一致性高于可用性。总而言之,想要保证 AP 就要用 Eureka , 想要保证 CP 就要用 Zookeeper。

1.gradle中添加依赖

 	//spring boot
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.6.RELEASE'
    // 添加spring cloud Netflix Eureka Server 依赖
    //(这个是错误的已弃用)compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka-server', version: '1.4.7.RELEASE'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-server', version: '2.2.2.RELEASE'

2.创建一个启动类 Application
创建一个启动类 Application,启动类,跟我们之前 Spring Boot 几乎完全一样,只是多了一个@EnableEureka
Server 注解,表示开启 Eureka Server 。

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

3.向application.properties文件中写入配置信息

server.port=8761
spring.application.name=service-zwt
# 是否优先从文件系统加载template,以支持热加载,默认为true
spring.freemarker.prefer-file-system-access=false


eureka.instance.hostname=localhost
# 由于该应用为注册中心,所以设置为 false , 代表不向汪册中心注册自己
# 一定要配置为 false ,不然启动时会把自己当作客户端向自己注册,会报错 。
eureka.client.register-with-eureka=false
# 由于注册中心的职责就是维护服务实例 , 他并不需要去检索服务,所以也设置为 false
eureka.client.fetch-registry=false
# 指定服务注册中心地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

启动服务,浏览器中访问http://localhost/8761就能进入管理界面
在这里插入图片描述

问题1

遇到无法找到EnableEurekaServer关键字的错误,解决办法把 Eureka 包删了重新下载一下就好了
启动项目后保错
在这里插入图片描述
这个错失因为spring boot 和spring cloud的版本不一致导致的,但都是用的最新版的不因该啊,最后在maven仓库中看到:
在这里插入图片描述
由于我看的教材问题,书中使用的是spring-cloud-starter-eureka-server,这里用的spring boot 是 2.2.6.RELEASE 版本的,所以版本当然不一致,将依赖换成spring-cloud-starter-netflix-eureka-server最新的就行了

问题2

服务器启动成功了,也没有报什么错,但是浏览器访问 http://localhost:8761 时报404
在这里插入图片描述
解决办法:
1.检查gradle配置文件中的依赖是否加载正确
2.检查启动类是否添加了@EnableEurekaServer注解
3.配置文件错误

一般前两个不会出错,主要就是配置文件出错,网上找了半天,试过各种办法都不行,最后一个大神告诉我在配置文件中添加一个配置

spring.freemarker.prefer-file-system-access=false

添加后居然成了,不明觉厉啊,找了半天也没有找到解释,只知道这个配置是:是否优先从文件系统加载template,以支持热加载,默认为true

问题3

配置属性没有defaultZone的提示,到service-url就没有了
本来配置属性都有自动提示的,会发现defaultZone并不会提示,service-url的配置内容是map,map的内容是可以自己发挥的,只要是key: value格式就行。有很多map类型的配置,比如availabilityZones,metadata-map都是的,内容虽然是key: value格式,但是都是可以自由发挥。其中metadata-map比较特殊,里面有个zone的属性,会被eureka client解析,当成客户端默认指向的zone来处理。
在这里插入图片描述

Spring boot的属性解析器 会自动把驼峰、下划线和连字符的同名属性关联起来。换句话,说 default-zone defaultZone default_zone 是等价的

服务提供者

与Eureka服务器类似,书中用的是spring-cloud-starter-eureka已经弃用,用新的spring-cloud-starter-netflix-eureka-client
1.gradle中添加依赖

 // Spring Boot
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.2.6.RELEASE'
    // https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client
    // 添加spring cloud Netflix Eureka Client依赖
	//(已弃用)compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka', version: '1.4.7.RELEASE'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-client', version: '2.2.2.RELEASE'

2.创建一个启动类 Application
创建一个启动类,启动类的方法与之前没有多大区别,就是注解变了,换成@EnableDiscoveryClient ,这个表示当前服务是一个 Eureka 的客户端 。

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

3.向application.properties文件中写入配置信息

spring.application.name=hello-client
# 应用服务web访问端口
server.port=8080

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

eureka.client.service-url.defaultZone 的地址就是我们之前启动的 Eureka 服务的地址,在启动的时候需要将自身的信息注册到 Eureka 中去 。
4.启动 Eureka 服务器,再启动刚刚写好的Eureka客户端,浏览器访问http://localhost:8761就能看到新注册的服务信息
在这里插入图片描述

编写提供接口

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

@RestController
@RequestMapping("/house")
public class Hello {
    @GetMapping("/hello")
    public String hello() {
        return "Hello";
    }
}

服务消费者

先创建一个 gradle项目, 然后添加依赖,依赖和服务提供者的一样启动类也是一样的,唯一不同的是配置文件,配置文件也只是更改一下端口号防止冲突

spring.application.name=hello-consumer-client
server.port=8082

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

RestTemplate 是 Spring 提供的用于访问 Rest 服务的 客户端, RestTemplate 提供了多种便捷访问远程 Http 服务的方法
需要通过配置RestTemplate 来调用接口,这个在spring boot中有讲到,当时是添加了Httpclient依赖org.apache.httpcomponents:httpclient:4.5.12这里在spring-cloud-starter-netflix-eureka-client中已经包含了Httpclient所以直接使用就行

package com.zwt.helloconsumer.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * Rest配置类
 * @since 2020-4-13RestTemplate
 * @author zwt
 */
@Configuration
public class RestConfiguration {
    @Autowired
    private RestTemplateBuilder builder;
    @Bean
    public RestTemplate restTemplate(){
        return builder.build();
    }
}

创建接口,在接口中调用 服务提供者的house/hello 接口

@RestController
public class ConsumerHello {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/callhello")
    public String callHello(){
        return restTemplate.getForObject("http://localhost:8080/house/hello", String .class);
    }
}

最后运行项目,在浏览器中输入 http://localhost: 8082/callHello 就能看到8080端口服务器返回的字符串

通过 Eureka 来消费接口

但上面的是通过http请求的方式获得另一个服务器上的服务提供的数据的,客户端需要关心有多少个服务提供接口,以及每个接口的ip和端口,完全没有用到 Eureka 带给我们的便利,实际上根本不用启动Eureka 服务器就能完成数据的交换。

1.RestTemplate 的配置,添加一个 @LoadBalanced 注解,这个注解会自动构造LoadBalancerClient 接口的实现类并注册到 Spring 容器中

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

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

@RestController
public class Hello {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/callhello")
    public String callHello(){
    	// 这里的hello-client是服务提供者应用的名称
        return restTemplate.getForObject("http://hello-client/house/hello", String .class);
    }
}

开启 Eureka 认证

在知道注册中心ip地址和端口的话,必然能直接访问到,这样是不安全的 。所以需要对 Eureka 进行改造,加上权限认证来保证安全性。
在 Eureka 服务器的项目中添加依赖

compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.2.6.RELEASE'

然后在 application .properties 中加上认证的配置信息:

# 登录用户名
spring.security.user.name=root
# 登录密码
spring.security.user.password=root

之后访问 http://localhost:8761 会跳转到 http://localhost:8761/login 登录界面
在这里插入图片描述
注意添加认证之后客户端注册的配置也要加上认证的用户名和密码信息

eureka.client.service-url.defaultZone=http://用户名:密码@localhost:8761/eureka/

启动客户端的时候出现问题
在这里插入图片描述
这是因为 eureka开启安全策略后,在新版本的security中,添加了csrf过滤,任何一次服务请求默认都需要CSRF 的token,而Eureka-client不会生成该token,csrf将微服务的注册也给过滤了!故启动时会报如上错误。 此时则需要在注册中心中增加配置,将csrf过滤机制屏蔽

服务端自己重写WebSecurityConfigurerAdapter,客户端配置不变。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configure HttpSecurity as needed (e.g. enable http basic).
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        // 禁用CSRF保护
        http.csrf().disable();
        // 注意:为了可以使用 http://${user}:${password}@${host}:${port}/eureka/ 这种方式登录,所以必须是httpBasic,如果是form方式,不能使用url格式登录
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }
}

Eureka 高可用搭建

在生产环境中肯定需要搭建一个集群来保证高可用 。 Eureka 的集群搭建方法很简单:每一台 Eureka 只需要在配置中指定另外多个Eureka 的地址就可以实现一个集群的搭建了
复制一份Eureka 服务器 ide打开,其他的不变,只需要更改配置文件
在这里插入图片描述
这里有个坑,localhost(域名)和127.0.0.1(ip)是不一样的,使用localhost会发现两边的 Eureka 服务器没有相互注册,而使用127.0.0.1就可以。
如果采用域名的方式,要设置不同的hostname才可以配置集群成功,既第一个Eureka 服务器设置成了 localhost 第二个Eureka 服务器就不能叫 localhost 了,只能设置成其他的域名,在host文件(C:\Windows\System32\drivers\etc)中添加即可。

分别启动两台Eureka-server服务实例,启动第一台服务器时会报错,两两都启动之后,都找得到对方,则不会再报错。
在这里插入图片描述

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

eureka.client.service-url.defaultZone=http://root:root@localhost:8761/eureka/,http://root:root@localhost:8762/eureka/

常用配置

自我保护
保护模式主要用于一组客户端和 Eureka Server 之间存在网络分区场景时 。 一旦进入保护模式, Eureka Server 将会尝试保护其服务的注册表中的信息,不再删除服务注册表中的数据 。当网络故障恢复后,该 Eureka Server 节点会自动退出保护模式 。
可以通过下面的配置将自我保护模式关闭:

#关闭自我保护,为true则开启,为false则关闭
eureka.server.enable-self-preservation=false

自定义 Eureka 的 Instance ID
现在想用“服务名称:服务所在 IP :服务端口 的格式来定义:
只需要在配置文件中定义:

#eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}
# 注意:spring cloud Finchley.RC2及以后版本spring.cloud.client.ipAddress改为了spring.cloud.client.ip-address
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
# 使用 IP 进行注册,这样点击Instance ID 进行跳转,跳转的链接变成ip地址,不然还是主机名
eureka.instance.prefer-ip-address=true

在这里插入图片描述
健康检查
默认情况下, Eureka 客户端是使用心跳和服务端通信来判断客户端是否存活, Spring Boot Actuator 提供了 /health 端点,该端点可展示应用程序的健康信息, 可以将健康信息传递给 Eureka 服务端 。 通过配置如下内容开启健康检查

在客户端添加依赖

// 健康检查,注意版本应该和spring boot的版本一样,不然可能会出错
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.2.6.RELEASE'

添加依赖后启动项目,访问http://localhost:8080/actuator查看,你应该能看到如下列表

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/actuator", 
            "templated": false
        }, 
        "health-path": {
            "href": "http://localhost:8080/actuator/health/{*path}", 
            "templated": true
        }, 
        "health": {
            "href": "http://localhost:8080/actuator/health", 
            "templated": false
        }, 
        "info": {
            "href": "http://localhost:8080/actuator/info", 
            "templated": false
        }
    }
}

访问/actuator获取到的是当前已开启的endpoints列表,有一些文档说很多endpoints是默认开启的,但从Spring Boot2.0之后,因为安全原因,大部分的endpoints都是默认关闭的了,默认只开启了 health 和 info 节点,其他节点开放需要在配置文件中手动开启。

# Actuator访问端口,不指定与客户端端口相同
management.server.port=8080
management.endpoints.jmx.exposure.include=*
# 开放节点(与之相反的是exclude),*表示开放所有节点,
# 如果想单独操作某个端点可以使用management.endpoint.端点.enabled属性进行启用或禁用例如:management.endpoint.health.enabled=false  禁用health节点
management.endpoints.web.exposure.include=*
# health是比较重要的一个endpoint,因为它本身自带了许多健康检查,可以对我们的线上监控起到非常重要的作用,health默认只返回一个简单的UP或DOWN的status信息,想要看到全部数据,需要如下配置
management.endpoint.health.show-details=always

访问http://localhost:8080/actuator/health:

{
    "status": "UP", 
    "components": {
        "discoveryComposite": {
            "status": "UP", 
            "components": {
                "discoveryClient": {
                    "status": "UP", 
                    "details": {
                        "services": [
                            "hello-client"
                        ]
                    }
                }, 
                "eureka": {
                    "description": "Remote status from Eureka server", 
                    "status": "UP", 
                    "details": {
                        "applications": {
                            "HELLO-CLIENT": 1
                        }
                    }
                }
            }
        }, 
        "diskSpace": {
            "status": "UP", 
            "details": {
                "total": 377598504960, 
                "free": 62304329728, 
                "threshold": 10485760
            }
        }, 
        "hystrix": {
            "status": "UP"
        }, 
        "ping": {
            "status": "UP"
        }, 
        "refreshScope": {
            "status": "UP"
        }
    }
}

参考文档:https://blog.csdn.net/weixin_42674359/article/details/105208421
服务上下线监控
在某些特定的需求下,我们需要对服务的上下线进行监控,上线或下线都进行邮件通知, Eureka 中提供了事件监听的方式来扩展 。
常用事件:
EurekaInstanceCanceledEvent 服务下线事件
EurekaInstanceRegisteredEvent 服务注册事件
EurekaInstanceRenewedEvent 服务续约事件
EurekaRegistryAvailableEvent Eureka注册中心启动事件
EurekaServerStartedEvent Eureka Server启动事件
在每个节点编写 Eureka 监听器类

@Component
public class EurekaStateChangeListener {
    @EventListener
    public void listen(EurekaInstanceCanceledEvent event) {
        System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服务下线");
    }

    @EventListener
    public void listen(EurekaInstanceRegisteredEvent event) {
        InstanceInfo instanceInfo = event.getInstanceInfo();
        System.err.println(instanceInfo.getAppName() + "进行注册");
    }

    @EventListener
    public void listen(EurekaInstanceRenewedEvent event) {
        System.err.println(event.getServerId() + "\t" + event.getAppName() + " 服务进行续约");
    }

    @EventListener
    public void listen(EurekaRegistryAvailableEvent event) {
        System.err.println("注册中心 启动");
    }

    @EventListener
    public void listen(EurekaServerStartedEvent event) {
        System.err.println("Eureka Server 启动");
    }
}

在这里插入图片描述
注意:在 Eureka 集群环境下,每个节点都会触发事件,这个时候需要控制下发送通知的行思为,不控制的话每个节点都会发送通知 。
元数据使用
Eureka 的元数据有两种类型,分别是框架定好了的标准元数据和用户自定义元数据
标准元数据指的是主机名、 IP 地址 、 端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用
自定义元数据就是自定义配置,可以为每个 Eureka Client 定义一些属于自己的配置 ,这个配置不会影 响 Eureka 的功能

自定义元数据可以使用 eureka.instance.metadataMap 进行配置 。
在这里插入图片描述
然后通过 Eureka 提供的 REST API 来查看刚刚配置的元数据是否 已经存在于 Eureka 中(具体接口信息可以查看官方文档https://github.com/Netflix/eureka/wiki/Eureka-REST-operations)
访问:http://localhost:8762/eureka/apps/hello-client 其中 hello-client 是应用名称,也就是 spring.application.name
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值