目录
一、基础知识
1.什么是服务治理:
2.什么是服务注册与发现:
⚪ Eureka Server 和 Eureka Client(服务端和客户端)
二、单机版Eureka构建:
1.新建项目cloud-eureka-server-7001
2.修改pom.xml
3.创建application.yml
4.主启动类
5.测试
三、将支付微服务8001入驻进eurekaServer
1.修改pom
2.在yml中添加相关配置
3. 在主启动类中添加注解 @EnableEurekaClient
编辑4.测试
四、将订单微服务80入驻进eurekaServer
1.修改pom
2.在yml中添加相关配置
3. 在主启动类中添加注解 @EnableEurekaServer
4.测试
五、Eureka集群原理说明
六、Eureka集群环境构建
①新建cloud-eureka-server7002
②修改pom.xml,添加相关依赖
③修改映射配置
④application.yml
⑤主启动类
⑥测试
七、将订单支付两个微服务注册进eureka集群
1.将支付服务8001微服务发布到上面两台Eureka集群配置中
⭐修改application.yml
2.将支付服务80微服务发布到上面两台Eureka集群配置中
⭐修改application.yml
启动顺序
3.支付服务提供者8001集群环境构建(构建8002)
1.新建sloud-provider-payment8002
2.修改pom.xml
3.application.yml
4.主启动类
5.业务类
6.修改8001/8002的controller
7.测试
①访问eureka7001.com:7001
②访问eureka7002.com:7002
消费者如何访问由这两个提供者组成的集群?
添加注解@LoadBalanced —— 赋予RestTemplate负载均衡的能力
九、actuator微服务信息完善
1.主机名称:服务名称修改
2. actuator让Eureka显示ip
十、服务发现Discovery @EnableDiscoveryClient
十一、Eureka自我保护理论知识
1.Eureka 自我保护机制
2.为什么会产生Eureka自我保护机制?
3.什么是自我保护模式?
十二、怎么禁止自我保护
1. 在 Eureka Server 的模块中的 yml 文件进行配置:
2.修改 Eureka Client 模块的 心跳间隔时间:
3.eureka配置项解读:
(1)eureka.instance.lease-expiration-duration-in-seconds
(2)eureka.instance.lease-renewal-interval-in-seconds
(3)*eureka.client.registry-fetch-interval-seconds*
(4)*eureka.server.enable-self-preservation*
十三、Eureka停更
Eureka(服务发现框架)_百度百科 (baidu.com)
cloud2022
com.atxupt.springcloud
1.0-SNAPSHOT
4.0.0
cloud-eureka-server-7001
8
8
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
com.atxupt.springcloud
cloud-api-commons
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
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/
@SpringBootApplication
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
defaultZone: http://localhost:7001/eureka/
名称与application.yml中的配置一致
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
启动三个微服务
名称与application.yml中的配置一致
- 先启动eureka注册中心
- 启动服务提供者payment支付服务
- 支付服务启动后会把自身信息化 服务以别名方式注册进eureka
- 消费者order服务在要调用接囗时,使用服务别名去注册中心取实际的RPC远程调用地址
- 消费者获得调用地址后,底层实际是利用HttpClient技术实现远程调用
- 消费者获得服务地址后会存jvm内存中,默认每间隔30s更新一次服务调用地址
Eureka 集群700X
Eureka Server在设计的时候就考虑了高可用设计,在Eureka服务治理设计中,所有节点既是服务的提供方,也是服务的消费方,服务注册中心也不例外。
Eureka Server的高可用实际上就是将自己做为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
Eureka Server的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。可以采用两两注册的方式实现集群中节点完全对等的效果,实现最高可用性集群,任何一台注册中心故障都不会影响服务的注册与发现。
问题:微服务RPC远程服务调用最核心的是什么:
高可用,试想你的注册中心只有一个。onlyone,它出故障了那就呵呵了,会导致整个为服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错
Eureka 集群的原理:相互注册,互相守望。
每台Eureka服务器都有集群里其他Eureka服务器地址的信息
cloud-eureka-server7002:第二个 Eureka 服务注册中心
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
com.atxupt.springcloud
cloud-api-commons
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka 服务器的实例地址
client:
register-with-eureka: false
fetch-registry: false
service-url:
## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
defaultZone: http://eureka7002.com:7002/eureka/
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # eureka 服务器的实例地址
client:
register-with-eureka: false
fetch-registry: false
service-url:
## 一定要注意这里的地址 这是搭建集群的关键
defaultZone: http://eureka7001.com:7001/eureka/
eureka.instance.hostname 才是启动以后 本 Server 的注册地址,而 service-url 是 map 类型,只要保证 key:value 格式就行,它代表 本Server 指向了那些 其它Server 。利用这个,就可以实现Eureka Server 相互之间的注册,从而实现集群的搭建。、
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class,args);
}
}
上面配置了多个Eureka作为集群,接下来要配置的是提供者集群,让提供者高可用
为提供者cloud-provider-payment8001 模块创建集群,新建模块名为 cloud-provider-payment8002
即两个提供者8001和8002
其余配置都一致,需要配置集群的配置如下:
配置区别要点:
集群中多个提供者的spring:application:name:要一致
启动类添加@EnableDiscoveryClient或者@EnableEurekaClient
1,@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现;
2,@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用;
如果你的classpath中添加了eureka,则它们的作用是一样的。
消费者(一般需要连接其他微服务的服务或者gateway/zuul)
# 提供者
server:
port: 8001 # 端口号不一样
spring:
application:
name: cloud-provider-service # 这次重点是这里,两个要写的一样,这是这个集群的关键
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password:
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.dkf.springcloud.entities
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url: # 提供者注册到多个eureka中
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
注意在 Controller 返回不同的消息,从而区分者两个提供者的工作状态。(只是为了学习测试才这么做,生产环境直接复制即可)
在提供者的controller中
@Value("${server.port}")
private String serverPort;
server:
port: 80
spring:
application:
name: cloud-order-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: false
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机
#defaultZone: http://localhost:7001/eureka
# 集群
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
- 先启动EurekaServer,7001,7002服务
- 再启动服务提供者provider,8001
- 最后启动消费者,80
添加相关依赖
8
8
com.atxupt.springcloud
cloud-api-commons
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.apache.maven.plugins
maven-project-info-reports-plugin
3.4.0
org.springframework.boot
spring-boot-dependencies
2.2.2.RELEASE
pom
import
org.springframework.cloud
spring-cloud-dependencies
Hoxton.SR1
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.8.RELEASE
pom
import
mysql
mysql-connector-java
${mysql.version}
runtime
com.alibaba
druid
1.1.10
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
com.alibaba
druid-spring-boot-starter
1.2.1
junit
junit
${junit.version}
log4j
log4j
${log4j.version}
org.projectlombok
lombok
org.springframework.cloud
spring-cloud-config-server
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
8.0.16
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-maven-plugin
true
true
server:
port: 8002
spring:
application:
name: cloud-payment-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#数据库url
url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
# 数据库访问账户
username: root
# 数据库访问密码
password:
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.atxupt.springcloud.entities #所有Entity别名类所在包
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8002 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8002.class,args);
}
}
直接从8001的业务类复制粘贴(U•ェ•*U)
(两个的controller都要修改)
按顺序启动7001->7002->8001->8002->80
存在的问题:此时消费者一旦消费完之后,他以后访问的还是那台提供者。明显不对,原因在于消费者并没有去Eureka里找服务,而是自己找的
订单服务的地址不能写死
Eureka Server 上的提供者的服务名称如下:
@RestController
@Slf4j
public class OrderController {
// 重点是这里,改成 提供者在Eureka 上的名称,而且无需写端口号
public static final String PAYMENY_URL = "http://CLOUD-PROVIDER-SERVICE";//取决于我们在提供者出配置的name,CLOUD-PAYMENY-SERVICE,//同时要注意使用@LoadBalanced注解赋予RestTemplate负载均衡能力
@Resource
private RestTemplate restTemplate;
@PostMapping("customer/payment/create")
public CommonResult create (Payment payment){
return restTemplate.postForObject(PAYMENY_URL + "/payment/create", payment, CommonResult.class);
}
@GetMapping("customer/payment/{id}")
public CommonResult getPaymentById(@PathVariable("id")Long id){
return restTemplate.getForObject(PAYMENY_URL + "/payment/" + id, CommonResult.class);
}
}
添加注解@LoadBalanced —— 赋予RestTemplate负载均衡的能力
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //这个注解,就赋予了RestTemplate 负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
这时候,消费者消费的提供者多次访问就会变化了(这就是Ribbon的负载平衡功能)
为了在微服务Eureka控制台能看到我们的某个具体服务是在哪台服务器上部署的,我们需要配置一些内容。
修改 提供者在Eureka 注册中心显示的 主机名:即修改eureka:instance:instance-id:和eureka:instance:prefer-ip-address:
# 提供者
server:
port: 8001 # 端口号不一样
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 可以显示ip地址
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。
(即我们前面可视化页面的信息)
@Resource // 自动注入
private DiscoveryClient discoveryClient;
@GetMapping("/customer/discovery")
public Object discovery(){
//获得服务清单列表
List services = discoveryClient.getServices();
for(String service: services){
log.info("*****service: " + service);
}
// 根据具体服务进一步获得该微服务的信息
List instances = discoveryClient.getInstances("CLOUD-ORDER-SERVICE");
for(ServiceInstance serviceInstance:instances){
log.info(serviceInstance.getServiceId() + "\t" +
serviceInstance.getHost()+ "\t" +
serviceInstance.getPort() + "\t" +
serviceInstance.getUri());
}
return this.discoveryClient;
}
如果在Eureka Server的首页看到以下这段提示,则说明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
为了防止Eureka Client可以正常运行但是与Eureka Server网络不通情况下,Eureka Server不会立刻将Eureka Client服务剔除
自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。
使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7002.com:7002/eureka/
server: # 与client平行
# 关闭自我保护机制,保证不可用该服务被及时剔除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
# 提供者
server:
port: 8001 # 端口号不一样
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url: # 集群
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
instance: #重点,和client平行
instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
prefer-ip-address: true # 可以显示ip地址
# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
least-renewal-interval-in-seconds: 1
# Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
least-expiration-duration-in-seconds: 2
在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。
默认为90秒
如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
该值至少应该大于leaseRenewalIntervalInSeconds
leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
默认30秒
表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
是否开启自我保护模式,默认为true。
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。
Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
*eureka.server.eviction-interval-timer-in-ms*
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒
Eureka停更说明:
2.0后停更了。