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:服务的注册中心,负责维护注册的服务列表。
- 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:
org.springframework.cloud
spring-cloud-dependencies
Greenwich.SR3
pom
import
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter
启动类上加上注解@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:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-web
启动类上加上注解@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端添加:
org.springframework.boot
spring-boot-starter-security
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://{password}@{port}/eureka/,例如:
eureka:
client:
service-url:
defaultZone: http://root:123456@localhost:8761/eureka/ #配置Eureka Server地址,用于注册服务和获取服务
Eureka集群
搭建高可用的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文件改下也可以。
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 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 findInstance() {
//测试 (eureka client) provider 是否可以找到eureka server
List instances = discoveryClient.getInstances("eureka-server");
log.info("根据服务名eureka-server获取到的服务实例明细:{}", JSON.toJSONString(instances));
return instances;
}
}
启动服务和测试eureka server的高可用
启动三个eureka server、打开idea启动设置,运行多实例启动,启动两个provider服务,启动一个consumer服务,启动完成访问:http://localhost:8761/
然后访问:http://localhost:8766/consumer/getProviderInfo
这时候可以观察到provider服务两个节点的控制台会被轮流访问。
然后干掉一个eureka server,继续访问你可以发现仍然是能通过其他两个eureka server 去调用到provider服务。
github源码地址
地址
https://gitee.com/zhouliangde/spring-project-learing