服务治理中心
是微服务(分布式)架构中最基础,也是最核心的功能组件,它主要对各个服务实例进行管理,包括服务注册、服务发现,续约等。 服务治理组件有:Eurake,Dobbo,Consul,ZooKeeper等。
看到 Netflix的组件,需要留意下,可能已进入维护阶段,不再开发新功能或者最新的已不在开源使用。 下面会完整的搭建项目(后面其他的组件基于它,就不重复了),版本如下:
- IDEA 2020.2
- Maven 3.6.3
- SpringCloud Hoxton.SR9
- SpringBoot 2.3.6
- JDK8
Eureka是入门 SpringCloud微服务架构的必学组件,是学习所有其他组件的基础和基石。
Eureka(/juˈriːkə/ 音译‘尤瑞卡’)
是服务治理中心,它提供微服务的治理,服务提供方与 Eureka服务治理中心之间通过 “心跳” 机制进行监控,当某个服务提供方出现问题时,Eureka自然会把它从服务列表中剔除,从而实现了服务的自动注册、发现、状态监控,续约等功能。
主要功能是:
- 进行服务治理
- 定期检查服务状态
- 返回服务实例清单列表。
Eureka中的三个核心角色:
- 服务注册中心 指 Eureka服务端应用,提供服务注册,发现和续约等功能
- 服务提供者 提供服务的应用,可以是 SpringBoot应用,也可以是其它技术实现的应用。主要对外提供以 REST风格的服务节点被服务消费者调用。
- 服务消费者
- 消费应用从注册中心获取服务实例清单列表,保存到本地,然后通过特定的负载均衡的策略确定使用具体的实例,最后通过请求该实例获取数据。
注意:
服务提供者和服务消费者并不是对立的,一个微服务可以同时是服务提供者和服务消费者。
Eureka Server
即服务端 提供服务注册中心功能 管理所有服务 支持所有服务注册Eureka Client
即客户端 所有向Eureka注册中心注册的都是Eureka服务端,例如 用户服务 、商品服务、消息服务等等
高可用就是,在发生一定的不可控情况时,服务依然能用。
1、服务提供者和消费者的高可用
微服务是指完成某一业务功能的独立系统。 一个微服务可以有多个实例,实例是指一个具体的服务节点。 同一个微服务下的实例应该具备相同的业务功能。通过把微服务注册为多个实例,从而实现服务之间的高可用。
·2、Eureka的高可用
Eureka服务注册中心也是一个特殊的服务。 多个 Eureka服务注册中心之间也会相互注册为服务,当服务提供者注册到 Eureka Server集群中的某个节点时,该节点会把服务的信息同步到集群中的每一个节点中。从而实现数据同步。因此,无论客户端访问到哪个 Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
二、搭建单节点Eureka服务注册中心创建一个名为 springcloud-demo的maven项目,新建几个模块如下:
- eureka-server: 作为Eureka服务器。
- parent模块:添加 SpringBoot父坐标和统一管理其他组件的依赖版本。
- user用户微服务
- order订单微服务
添加 SpringBoot父坐标和统一管理其他组件的依赖版本。
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.6.RELEASE
com.example
parent
0.0.1-SNAPSHOT
pom
parent
Demo project for Spring Boot
1.8
Hoxton.SR9
8.0.22
1.2.72
com.alibaba
fastjson
${fastjson.version}
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
mysql
mysql-connector-java
${mysql.version}
org.springframework.cloud
spring-cloud-starter-config
org.springframework.boot
spring-boot-maven-plugin
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
注意
:通过 scope标签的 import
值,表示:可以继承 SpringBoot的依赖,也可继承 spring-cloud-dependencies工程中的依赖。
eureka-server 作为单节点Eureka服务端,需要配置自身不注册自己,否则启动日志为不断出现异常。 (1)pom.xml 引入 Eureka server依赖。
4.0.0
com.example
parent
0.0.1-SNAPSHOT
org.example
eureka-server
0.0.1-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
(2)yml配置文件
server:
# 项目端口
port: 8762
# 项目上下文路径
servlet:
context-path: /
spring:
application:
# 服务实例名
name: EUREKA-SERVER
eureka:
server:
# 取消 Eureka自我保护机制,不推荐
# enable-self-preservation: false
client:
# 是否注册服务,单节点自身就是服务治理中心,设置为fasle-取消注册
register-with-eureka: false
# 是否开启检索服务,单节点不需要开启,false-表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 注册中心地址,由注册中心ip和项目端口拼接/eureka
defaultZone: http://localhost:8762/eureka
instance:
# 注册中心的主机名
hostname: localhost
(3)启动类
启动类添加@EnableEurekaServer
注解,表示开启 Eureka服务端.
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
3. user服务
(1)pom.xml 引入Eureka Client依赖
4.0.0
com.example
parent
0.0.1-SNAPSHOT
org.example
user
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-test
test
(2)yml配置文件
server:
port: 18001
servlet:
context-path: /user
spring:
application:
# 服务实例名,每个服务名必须唯一
name: USER
eureka:
instance:
# 指定此实例的ip
ip-address: 192.xx.xx.xxx
# 使用ip地址,测试时ip+port访问不行,只能用服务实例名
prefer-ip-address: true
# 注册时使用ip,而不使用主机名
instance-id: ${eureka.instance.ip-address}:${server.port}
# 实例超时失效秒数,默认为 90秒,如果续约超时,该实例会被 Eureka剔除掉
lease-expiration-duration-in-seconds: 90
# 间隔对应的秒数执行一次续约服务,默认30秒
lease-renewal-interval-in-seconds: 30
client:
service-url:
# 指向 eureka注册中心地址
defaultZone: http://localhost:8762/eureka
(3)启动类
启动类添加 @EnableEurekaClient
注解,表示开启Eureka客户端,注册服务到注册中心。 使用 Ribbon 完成负载均衡。
@SpringBootApplication
@EnableEurekaClient
public class UserApplication {
// 负载均衡
@LoadBalanced
@Bean
public RestTemplate initRestTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
(4)conrtoller
@RestController
public class UserController {
@Value("${server.port}")
private String port;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getOrder/{id}")
public String getOrder(@PathVariable Long id){
String url = "http://ORDER/order/get/" + id;
String res = restTemplate.getForObject(url, String.class);
return res;
}
@GetMapping("/get/{id}")
public String get(@PathVariable Long id) {
return port + "--" + "user服务返回数据 >>>>>>> " + id;
}
}
4. order服务
order服务和 user服务操作同理, 这里使用下主机名,看一下区别。 (1)yml
server:
port: 18002
servlet:
context-path: /order
spring:
application:
name: ORDER
eureka:
instance:
# 服务主机名称
hostname: localhost
client:
service-url:
defaultZone: http://localhost:8762/eureka
(2)conrtoller
@RestController
public class OrderController {
@Value("${server.port}")
private String port;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getUser/{id}")
public String getUser(@PathVariable Long id){
String url = "http://USER/user/get/" + id;
// ip+port,会报错:java.lang.IllegalStateException: No instances available for 192.xx.xx.xxx
// String url = "http://192.xx.xx.xxx:18001/user/get/" + id;
String res = restTemplate.getForObject(url, String.class);
return res;
}
@GetMapping("/get/{id}")
public String get(@PathVariable Long id) {
return port + "--" + "order服务返回数据 >>>>>>> " + id;
}
}
注意:
- 不要使用 ip+port 的方式访问,取而代之的是应用名(不区分大小写)
- 这种方式发送的请求都会被ribbon拦截,Ribbon从eureka注册中心获取服务列表,然后采用均衡策略进行访问
(1)启动 eureka-server,然后启动 user, order服务。 访问:http://127.0.0.1:8762/ 到此,单节点 Eureka注册中心搭建完成。
(2)测试服务之间调用
从下面三个方法了解(图来自网络)
任何的微服务都可以对 Eureka服务治理中心(Eureka服务端)发送 REST风格的请求。
在 Eureka的机制中,一般是具体的微服务(Eureka客户端)来主动维持它们之间的关系。
Eureka客户端的请求类型包括注册、续约和下线。
(1)注册
设置 eureka.client.serviceUrl.defaultZone
属性的值来通过 REST风格的请求将微服务实例注册到 Eureka服务端。也可以通过 eureka.client.register-with-eureka
来设置是否注册服务。
eureka:
client:
# 是否注册服务
register-with-eureka: true
# 是否开启检索服务,默认true
fetch-registry: true
# 检索服务实例清单的时间间隔,单位秒,默认30秒
registry-fetch-interval-seconds: 30
service-url:
# 指向 eureka注册中心地址
defaultZone: http://localhost:8762/eureka/
当启动微服务时,并不会马上发送 REST请求,它会延迟 40秒才发起请求。
(2)续约 注册之后,微服务实例会按照一个频率对 Eureka服务端维持心跳,告诉 Eureka该实例是可用的,这样的行为被称为续约(Renew)。
Eureka通过续约来确认,对应的服务实例是否还能正常工作,如果不能工作就会被它及时的剔除掉。
续约存在两个配置:
eureka:
instance:
# 实例超时失效秒数,默认为 90秒,如果续约超时,该实例会被 Eureka剔除掉
lease-expiration-duration-in-seconds: 90
# 间隔对应的秒数执行一次续约服务,默认30秒
lease-renewal-interval-in-seconds: 30
(3)下线
在系统出现故障,或者停止/重启某个服务实例时,正常情况下,该实例会对 Eureka发送下线的 REST请求来告知服务治理中心,所以,客户端就不再请求该实例。
2. 服务治理中心Eureka可以有效管理具体的微服务实例,但是 Eureka本身也是服务,或者说也是Eureka客户端。
多个 Eureka服务之间如何进行注册和管理。
(1)互相复制 Eureka本身也可相互注册,来保证高可用和高性能。
各个 Eureka服务器之间会相互复制。Eureka服务器之间采用的是对等模式,即每一个 Eureka都是等价的。
(2)服务剔除
Eureka在启动时会创建一个定时任务,在默认情况下,每间隔 60秒就会更新一次微服务实例的清单,只要发现有超过 90秒没有完成续约的服务实例,就会将其剔除出去。
(3)自我保护
在本机测试时,会看到红色的警告,这就是 Eureka的自我保护机制。
在 Eureka运行期间,如果在 15分钟内低于 85%的情况下心跳测试失败,它就会出现红色警告。 可以配置取消,不推荐取消自我保护机制
eureka:
server:
# 取消 Eureka自我保护机制,不推荐
# enable-self-preservation: false
上面使用了 Ribbon 完成了负载均衡。这里说一下服务获取和调用。
(1)服务获取
服务获取是指微服务实例作为 Eureka的客户端,从 Eureka服务治理中心获取其他服务实例清单的功能。服务获取会将服务实例清单列表缓存到本地,并且按一定的时间间隔刷新。
eureka:
client:
# 是否开启检索服务,默认true
fetch-registry: true
# 检索服务实例清单的时间间隔,单位秒,默认30秒
registry-fetch-interval-seconds: 30
(2)服务调用
服务调用是指一个微服务调用另一个微服务的过程。服务调用的核心往往是负载均衡算法。
在 SpringCloud中,大部分都是采用 REST风格的请求。
Ribbon会根据请求的 URL知道调用的是哪个微服务,然后再服务获取的清单列表中,通过一种负载均衡的算法选择其中一个具体实例进行调用。默认情况下,Ribbon会采用轮询的策略。
四、搭建双节点Eureka服务注册中心双节点Eureka服务注册中心,让 Eureka服务端实现高可用,Eureka客户端在我们也启动多个服务实例。 这样,就可实现 Eureka服务端和Eureka客户端的集群搭建,更多Eureka服务注册中心节点搭建同理。
(1)eureka-server
修改YML,让 eureka-server注册服务,获取服务,默认是开始的,在上面单节点中注释掉就可以了。
eureka:
client:
service-url:
# eureka注册中心地址,由注册中心ip和项目端口拼接/eureka,如果是集群的话,使用逗号分隔
defaultZone: http://localhost:8762/eureka, http://localhost:8763/eureka
instance:
# 注册中心的主机名
hostname: localhost
在本地 启动 8762和8763端口得 Eureka服务端。
(2)user和order微服务
YML文件中服务注册地址配置成集群就可以了,其他不用变。启动多个服务实例。
# 指向 eureka注册中心地址
defaultZone: http://localhost:8762/eureka,http://localhost:8763/eureka
在本地 启动user和order微服务。
调用服务时会 轮询访问,注意端口得变化,说明高可用配置ok。
—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。