目录
1. 创建项目spring_cloud_eureka_server_7001
1. 创建项目 spring_cloud_eureka_server_7002
1. 创建项目 spring_cloud_payment_8002
5,mapper,service,controller都复制一份
前面我们没有服务注册中心,也可以通过restTemplate服务间调用,为什么还要服务注册?
当服务很多时,单靠代码手动管理是很麻烦的,需要一个公共组件,统一管理多服务,包括服务是否正常运行,等等
Enreka基础知识
Eureka用于服务注册,目前官网已经停止更新
什么是服务治理?
Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务治理。
在传统的rpc远程调用框架中,管理每个服务与服务之间的依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
什么是服务注册与发现?
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。
这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息。比如服务地址、通讯地址等以别名方式注册到注册中心上。另一方(消费者-服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。
RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
Eureka两个组件
Eureka Server和Eureka Client
Eureka Server
Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所欲可用服务节点的信息,服务节点的信息可以在界面中直观看到。
Eureka Client
Eureka Client通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server 的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳。Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
单机Enreka构建步骤
1. 创建项目spring_cloud_eureka_server_7001
2. pom依赖
eurka最新的依赖变了,接下来看下1.X和2.X的pom对比
以前的老版本(当前使用2018)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
现在新版本(当前使用2020.2)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3. 配置文件
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/
4. 主启动类
添加@EnableEurekaServer 服务注册中心注解
package com.tudeen.learn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //代表我就是服务注册中心
public class EurekaMain {
public static void main(String[] args) {
SpringApplication.run(EurekaMain.class, args);
}
}
5. 启动当前项目
进入链接http://localhost:7001/ 展示如下:
6. 其他服务注册到eureka
比如此时pay模块加入eureka:
添加客服端注解
- 主启动类上,加注解@EnableEurekaClient,表示当前是eureka客户端
修改依赖
- 修改pom,引入Client的依赖
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改配置文件
eureka:
client:
#表示是否将自己注册进EurekaServer,默认为true。
register-with-eureka: true
#是否从Eureka Server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
支付模块重启
集群Eureka构建步骤
问题:微服务RPC远程服务调用最核心的是什么?
高可用,试想你的注册中心只有一个only one。它出了故障就呵呵了,会导致整个服务环境不可用,所以解决办法:搭建Eureka注册中心集群,实现负载均衡+故障容错
集群构建原理
互相注册,相互守望,对外暴露
搭建单点Eureka
Eureka : spring_cloud_eureka_server_7002
1. 创建项目 spring_cloud_eureka_server_7002
创建新的module
2. pom依赖
粘贴7001的即可
3. 配置文件
在写配置文件前,修改一下主机的hosts文件
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
首先修改之前的7001的eureka项目,因为多个eureka之间需要互相注册,相互观望
server:
port: 7001
eureka:
instance:
# hostname: localhost
hostname: eureka7001.com
#eureka服务端的实例名称
client:
# 不向euraka注册自己
register-with-eureka: false
# false表示自己端就是注册中心,我的职责就是维护实例,并不需要去检索服务
fetch-registry: false
service-url:
# 单机下配置
# 设置与Eurka Server交互端地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/ #注意:这里指定的是7002的地址
7002也是一样的,只不过端口和地址改一下
server:
port: 7002
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #注意:这里指定的是7001的地址
3. 主启动类
复制7001的即可
4. 启动运行
pay,order模块注册到eureka集群
eureka:
client:
#表示是否将自己注册进EurekaServer,默认为true。
register-with-eureka: true
#是否从Eureka Server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
#defaultZone: http://eureka7001.com:7001/eureka/
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
两个模块都修改上面的配置文件application.yml,保持配置文件都一致即可
先启动7001,7002,然后是pay模块8001,然后是order(80)
1. 创建项目 spring_cloud_payment_8002
创建新的module
2. pom文件,复制8001的
3. 配置文件复制8001的
端口修改一下,改为8002,其他不变
4.主启动类,复制8001的
5,mapper,service,controller都复制一份
然后就启动服务即可
此时访问order模块
我们通过订单模块远程调用支付模块的时候,http://localhost/consumer/payment/getId/31,发现端口号一直没变一直显示8001
发现并没有负载均衡到两个pay,模块中,而是只访问8001
虽然我们是使用RestTemplate访问的微服务,但是也可以负载均衡的
// private static final String PAYMENT_URL="http://localhost:8001";
public static final String PAYMENT_URL ="http://cloud-payment-service";
@Resource
// 改为微服务名称,这样每次访问.都去eureka中拿地址,就会轮询拿,就达到负载均衡效果了
private RestTemplate restTemplate;
但是现在又报错了,无语了,好烦,老是报错。
因为不知道是那台机器提供服务,需要让RestTemplate开启负载均衡注解,还可以指定负载均衡算法,默认轮询,如下
package com.tudeen.learn.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;
@Configuration
public class ApplicationContextConfig {
@Bean //applicationContext.xml <bean id="" class="">
@LoadBalanced //使用自定义负载
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
出来了,8002.
actuator微服务信息完善
主机名称与服务名称的修改
修改配置文件
instance:
instance-id: payment8002
prefer-ip-address: true #访问路径是否可以显示IP地址
修改为我们配置的实例id了
访问信息有IP地址提示
prefer-ip-address: true #访问路径是否可以显示IP地址
服务发现Discovery
对于注册进Eureka里面的微服务,可以通过服务发现来获得改服务的信息
以pay模块为例
1. 注入DiscoveryClient
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/payment/discovery")
public Object discovery(){
List<String> services = discoveryClient.getServices();//拿到所有注册的信息
services.forEach(System.out::println);
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");//拿到指定服务名称的所有服务的注册信息,比如pay模块,他们两个的名字都是一样的,所有这里返回的是一个list
for (ServiceInstance instance : instances) { log.info("instance:"+instance.getHost()+",port:"+instance.getPort()+","+"url:"+instance.getUri());
}
return this.discoveryClient;
}
2. 启动类添加注解
package com.tudeen.learn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
3. 点击执行
http://localhost:8001/payment/discovery 查看服务
eureka自我保护
概述
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册中的数据,也就是不会注销任何微服务
一句话:某个时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行
保存,属于CAP里面的AP分支
为什么会产生Eureka自我保护机制?
为了保证EurekaClient可以正常运行,与Eureka Server网络不通情况下EurekaServer不会立刻将EurekaClient服务剔除
什么是自我保护模式?
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。
但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了
因为微服务本身其实是健康的,此时本不应该注销这个微服务。
Eureka通过"自我保护模式"来解决这个问题
当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。
它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。
好死不如赖活
综上,自我保护模式就是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
自我保护机制
默认情况下EurekaClient定时向EurekaServer端发送心跳包。
如果EurekaServer端在一定时间内(默认90秒)没有收到EurekaClient发送心跳包,便会直接从服务注册列表中剔除该服务
但是在短时间内(90秒内)丢失了大量的服务实例心跳,这时候EurekaServer会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通,但是EurekaClient以为出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳,就会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)
eureka服务端配置
设置自我保护机制
出厂默认自我保护机制是开启的
server:
enable-self-preservation: false //可以禁用自我保护模式
设置接受心跳时间间隔
eviction-interval-timer-in-ms: 2000
现在修改支付模块的客户端心跳发送时间1s,服务端收到消息等待时间2S,此时启动erueka和pay.此时如果直接关闭了pay,那么eureka会直接删除其注册信息
eureka:
client:
register-with-eureka: true #表示是否将自己注册进EurekaServer,默认为true。
fetchRegistry: true #是否从Eureka Server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
# defaultZone: http://localhost:7001/eureka/
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
instance:
instance-id: payment8001
prefer-ip-address: true #访问路径是否可以显示IP地址
# Eureka客户端向服务端法发送心跳的时间间隔,默认30秒
lease-renewal-interval-in-seconds: 1
# Eureka服务端子收到最后一次心跳后等待时间上限,默认为90秒,单位为秒,超时将剔除服务
lease-expiration-duration-in-seconds: 2