服务注册/发现-Eureka-微服务核心组件【分布式微服务条记02】
服务注册/发现-Eureka
目前主流的服务注册&发现的组件是Nacos, 但是Eureka 作为一个老牌经典的服务注册&发现技能照旧有必要学习一下, 缘故原由:
- 一些早期的分布式微服务项目使用的是Eureka,在工作中, 完全有大概遇到.
- 后期的服务注册&发现组件/技能, 都参考了Eureka 设计和理念, 学习了Eureka 后, 我们上手Nacos 容易很多,而且明白的更深刻.
引出Eureka
在不使用 服务注册/发现-Eureka 时,通常我们的项目架构是:
服务消费方 ------利用restTemplate (直接调用) ---->服务提供方
如下:- @RestController
- @RequestMapping("/member/consumer")
- @Slf4j
- public class MemberConsumerController {
- //定义MEMBER_SERVICE_PROVIDER_URL 基础url地址
- public static final String MEMBER_SERVICE_PROVIDER_URL = "http://localhost:10001";
- @Autowired
- private RestTemplate restTemplate;
- //接口
- /***
- * 添加member;
- * member :通过restTemplate 发出的请求携带的数据;
- * Result.class :返回对象的类型;
- */
- @PostMapping("/save")
- public Result<Member> save(Member member) {
- return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
- }
- //根据id 调用服务接口 返回member
- @GetMapping("/get/{id}")
- public Result<Member> getMemberById(@PathVariable("id") Long id) {
- return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
- }
- }
复制代码 但这样简朴的项目结构有肯定的缺陷:
- 在企业级项目中,服务消费访问请求会存在高并发
- 如果只有一个会员中心-提供服务,可用性差
- 以是,提供服务方往往是一个集群,也就是说会有多个提供服务微服务模块
- 那么这个时间,就存在一个标题就是服务消费方,不能写死这些url,那怎么去发现可以使用的服务(引出服务发现)
- 当服务消费方,发现了可以使用的服务后(大概是多个,又存在一个标题就是到底调用A服务,照旧B 服务的标题,这就引出了服务注册和负载平衡)
- Eureka 就可以解决上述标题
引入Eureka后项目
使用 服务注册/发现-Eureka 后,通常我们的项目架构是:
- 服务提供方【大概是一个集群】------将自己注册到/renew/cancel---->Eureka Server【大概是一个集群】
- 服务消费方 ------将自己注册到/发现服务---->Eureka Server【大概是一个集群】 ---->
- 服务消费方 ------远程调用 remote call---->服务提供方
分析:
- 会员中心-提供服务的,在项目中,会做成集群,提供高可用
- Eureka Server 有必要的话,也可以做成集群,保证单个Eureka Server 宕机,保证高可用
- Eureka 包含两个组件∶Eureka Server 和 Eureka Client
- Eureka Server 提供注册服务, 各个微服务节点【服务消费方、服务提供方】通过配置启动后,会在Eureka Server 中进
行注册,这样EurekaServer 中的服务注册表中将会存储全部可用服务节点的信息,服务节点的信息可以在界面【Eureka 提供的界面】中直观看到。
- EurekaClient 通过注册中心进行访问, 是一个Java 客户端,用于简化Eureka Server 的交互,客户端同时也具备一个内置的、使用轮询(round-robin) 负载算法的负载平衡器。在应用启动后,将会向Eureka Server 发送心跳(默认周期为30 秒)【确定微服务模块还在运行】。如果Eureka Server 在多个心跳周期内没有接收到某个节点的心跳【宕机了】,EurekaServer 将会从服务注册表中把这个服务节点移除(默认90 秒)
服务治理
- Eureka实现了服务治理
- 在传统的rpc(Remote Procedure Call) 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理困难,以是需要治理服务之间依赖关系
- 服务治理实现服务调用、负载平衡、容错等,实现服务发现与注册
服务注册和服务发现
- Eureka采用了CS【client-server】的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
- 系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接,通过Eureka Server 来监控系统中各个微服务是否正常运行。
- 在服务注册与发现中,有一个注册中心。当服务器启动的时间,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。
- 服务消费者或者服务提供者,以服务别名的方式去注册中心上获取到实际的服务提供者通讯地址,然后通过RPC调用服务
Eureka-Server 【非集群】代码实现
- pom.xml引入 eureka-server starter场景启动器
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
- </dependency>
复制代码 - 配置application.yml
- #配置端口号
- server:
- port: 9001
- #配置eureka-server
- eureka:
- instance:
- #服务实例名
- hostname: localhost
- #当 eureka-server是一个集群时,需要互相注册,变成了 client
- client:
- #配置不向注册中心注册自己
- register-with-eureka: false
- #表示自己就是注册中心,作用: 维护注册服务实例,不需要去检索服务
- fetch-registry: false
- service-url:
- #设置与 eureka-server 交互的模块,查询服务和注册服务都需要依赖这个地址
- defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
复制代码 - 编写主启动类
- @EnableEurekaServer //表示该程序作为Eureka-server,并且监听端口
- @SpringBootApplication
- public class EurekaApplication {
- public static void main(String[] args) {
- SpringApplication.run(EurekaApplication.class, args);
- }
- }
复制代码 Eureka-Client 【非集群 】代码实现
- 引入 eureka-client 场景启动器 starter
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
复制代码 - 配置application.yml
- #配置端口号
- server:
- port: 10001
- spring:
- application:
- name: member-service-provider-10001 #配置应用的名称
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
- username: root
- password: zy
- #配置mybatis
- mybatis:
- mapper-locations: classpath:mapper/*.xml #指定mapper。xml文件
- type-aliases-package: com.zy88.springcloud.entity #实体类 别名引用
- #配置eureka-client
- eureka:
- client:
- # 将自己注册到eureka-server
- register-with-eureka: true
- # 表示从 Euraka-Server 抓取注册信息,如果不是集群,可以不配置。
- # 如果是集群,设置成true才能配合Ribbon使用负载均衡
- fetch-registry: true
- #表示将自己注册到哪个eureka-server
- service-url:
- defaultZone: http://localhost:9001/eureka
复制代码 - 编写主启动类
- @EnableEurekaClient//表示该程序作为Eureka-Client,并且监听端口
- @SpringBootApplication
- public class MemberApplication {
- public static void main(String[] args) {
- SpringApplication.run(MemberApplication.class, args);
- }
- }
复制代码 Eureka自我保护模式
- 默认环境下EurekaClient定时向EurekaServer端发送心跳包
- 如果Eureka在server端在肯定时间内(默认90秒)没有收到EurekaClient发送心跳包,便会直接从服务注册列表中剔除该服务
- 如果Eureka 开启了自我保护模式/机制, 那么在短时间(90秒中)内丢失了大量的服务实例心跳,这时间EurekaServer会开启自我保护机制,不会剔除该服务(该现象大概出现在如果网络不通或者阻塞) 因为客户端还能正常发送心跳,只是网络耽误标题,而保护机制是为相识决此标题而产生的
- 自我保护是属于CAP 里面的AP 分支, 保证高可用和分区容错性
- 自我保护模式是—种应对网络非常的安全保护措施。它的架构哲学是宁可同时保留全部微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式, 可以让Eureka 集群更加的健壮、稳固。
- 参考:https://blog.csdn.net/wangliangluang/article/details/120626014
- 禁用Eureka自我保护模式【实际生产不推荐!】
- eureka:
- server:
- #禁用自我保护模式
- enable-self-preservation: false
复制代码 Eureka-Server 【集群】代码实现
为什么需要集群?
- 微服务RPC 远程服务调用最核心的是实现高可用
- 如果注册中心只有1 个,它出故障,会导致整个服务环境不可用
- 解决办法∶搭建Eureka 注册中心集群,实现负载平衡+故障容错
代码实现:
- 修改application.yml
- server:
- port: 9001
- #配置eureka-server
- eureka:
- instance:
- #服务实例名
- hostname: eureka9001.com
- #当 eureka-server是一个集群时,需要互相注册,变成了 client
- client:
- #配置不向注册中心注册自己
- register-with-eureka: false
- #表示自己就是注册中心,作用: 维护注册服务实例,不需要去检索服务
- fetch-registry: false
- service-url:
- #集群需要相互注册 , 注册到eureka9001
- defaultZone: http://eureka9002.com:9002/eureka/
复制代码 - 修改hosts文件
文件地址:C:\Windows\System32\drivers\etc\hosts
Eureka-Client-提供方 【集群 】代码实现
修改 eureka-client 的 application.yml即可- server:
- port: 10001
- spring:
- application:
- name: member-service-provider #配置应用的名称
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
- username: root
- password: zy
- #配置mybatis
- mybatis:
- mapper-locations: classpath:mapper/*.xml #指定mapper。xml文件
- type-aliases-package: com.zy88.springcloud.entity #实体类 别名引用
- #配置eureka-client
- eureka:
- client:
- # 将自己注册到eureka-server
- register-with-eureka: true
- # 表示从 Euraka-Server 抓取注册信息,如果不是集群,可以不配置。
- # 如果是集群,设置成true才能配合Ribbon使用负载均衡
- fetch-registry: true
- #表示将自己注册到哪个eureka-server
- service-url:
- # 注册到集群,多个eureka,使用逗号间隔
- defaultZone: http://eureka9001.com:9001/eureka,http://eureka9002.com:9002/eureka
复制代码
- 以集群提供服务,需要将spring.application.name 同一,这样消费方通过同一的别名进行负载平衡调用
- spring:
- application:
- name: member-service-provider #配置应用的名称,如果是集群保持一致
复制代码
Eureka-Client-消费方【集群 】代码实现
- 需要修改MemberConsumerController
- @RestController
- @RequestMapping("/member/consumer")
- @Slf4j
- public class MemberConsumerController {
- //定义MEMBER_SERVICE_PROVIDER_URL 基础url地址
- //MEMBER-SERVICE-PROVIDER 表示服务提供方【集群】,注册到Eureka-server的别名
- //就是服务提供方【集群】,对外暴露的名称MEMBER-SERVICE-PROVIDER
- public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
- @Autowired
- private RestTemplate restTemplate;
- //接口
- /***
- * 添加member;
- * member :通过restTemplate 发出的请求携带的数据;
- * Result.class :返回对象的类型;
- */
- @PostMapping("/save")
- public Result<Member> save(Member member) {
- return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
- }
- //根据id 调用服务接口 返回member
- @GetMapping("/get/{id}")
- public Result<Member> getMemberById(@PathVariable("id") Long id) {
- return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
- }
- }
复制代码 - 在配置类,CustomizationBean 中增加一个注解@LoadBalanced 赋予 restTemplate 负载平衡的本领,也就是说根据负载平衡算法【默认轮询算法,也可以配置负载平衡的算法】来选择某个服务去访问
- //配置注入 RestTemplate
- @Configuration
- public class CustomizationBean {
- @LoadBalanced //赋予 restTemplate 负载均衡 的能力
- @Bean
- public RestTemplate getRestTemplate() {
- return new RestTemplate();
- }
- }
复制代码
- 轮询交替访问member 服务说明:
- 注解@LoadBalanced 底层是Ribbon 支持算法
- Ribbon 和Eureka整合后consumer 直接调用服务而不用再关心地址和端标语,且该服务还有负载功能
DiscoveryClient-获取Eureka Server 服务注册信息
获取到Eureka Server 服务注册信息,可以使用 DiscoveryClient
- 需要加上 @EnableDiscoveryClient , 启用服务发现
- 装配 DiscoveryClient
- 编写接口discovery( )
- @EnableDiscoveryClient //启用服务发现
- @RestController
- @RequestMapping("/member/consumer")
- @Slf4j
- public class MemberConsumerController {
-
- public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
- @Autowired
- private RestTemplate restTemplate;
- //装配 DiscoveryClient
- @Autowired
- private DiscoveryClient discoveryClient;
- @GetMapping("/discovery")
- public Object discovery(){
- List<String> services = discoveryClient.getServices();
- //遍历服务
- for (String service : services) {
- log.info("服务名= {}",service);
- //获取服务名对应的实例
- List<ServiceInstance> instances = discoveryClient.getInstances(service);
- for (ServiceInstance instance : instances) {
- log.info("id= {},host= {},port= {},uri= {}",
- instance.getServiceId(),instance.getHost(),instance.getPort(),instance.getUri());
- }
- }
- return discoveryClient;
- }
-
- @PostMapping("/save")
- public Result<Member> save(Member member) {
- return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
- }
- @GetMapping("/get/{id}")
- public Result<Member> getMemberById(@PathVariable("id") Long id) {
- return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
- }
- }
复制代码 访问 http://localhost/member/consumer/discovery 获取Eureka Server 服务注册信息:
本文学习内容来自韩顺平老师的课程
仅供个人参考学习
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |