服务发现

服务化的普及,令软件系统得以通过分布于网络中不同机器的互相协作来复用功能

最早的服务发现可以直接依赖DNS将一个全限定名翻译为一至多个IP地址或者SRV等其他类型的记录便可

但进入微服务时代后,服务宕机 上线下线变得更加频繁 DNS就力不从心了。

服务注册与发现的实现是随zk-eureka-nacos/consul这条线过来的

服务发现原理

批注 2020-07-03 083637

自理式服务发现

202259211731

代理式服务发现

202259211826

服务发现共性设计

在真实系统中,服务发现中心是整个系统的基础架构 如果它一挂 整个系统就完全崩溃了 所以必须进行高可用支持

20201119145641

服务发现中心有以Eureka的AP注册中心 也有以Consul为代表的CP注册中心

当然也有AP CP随时转换的Nacos

AP在出现在系统出现网络分区也能继续对外提供服务 不会影响系统操作的正确性场景下 是十分有用的

服务注册中心的实现

AP实现

2022614162525

Eureka

Eureka是Netflix开发的服务发现框架,Eureka包含两个组件: Eureka Server和Eureka Client.

各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息

在应用启动后,将会 向Eureka Server发送心跳,默认周期为30秒

保证AP,eureka在设计时优先保证可用性,每一个节点都是平等的,一部分节点挂掉不会影响到正常节点的工作,不会出现类似zk的选举leader的过程

202034165552

批注 2020-07-03 085520批注 2020-07-03 085612

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
spring.application.name=eureka-serverserver.port=8001#是否将自己注册到注册中心eureka.client.register-with-eureka=false#是否从注册中心获取注册信息eureka.client.fetch-registry=falseeureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
@SpringBootApplication@EnableEurekaServerpublic class EurekaServerApplication {    public static void main(String[] args) {        SpringApplication.run(EurekaServerApplication.class, args);    }}

服务注册

服务续约

eureka:  instance:    lease-expiration-duration-in-seconds: 10 # 10秒即过期    lease-renewal-interval-in-seconds: 5 # 5秒一次心跳

批注 2020-07-03 091553

失效剔除与自我保护

有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障等原因使得服务不能正常工作,而服务注册中心并未收到“服务下线”的请求。为了从服务表中将这些无法提供服务的实例剔除,Eureka Server 在启动的时候会创建一个定时任多默认每隔一一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务除出去

默认情况下,EurekaClient会定时向EurekaServer端发送心跳,如果EurekaServer在一定时间内没有收到EurekaClient发送的心跳,便会把该实例从注册服务列表中剔除(默认是90秒),为了防止只是EurekaClient与EurekaServer之间的网络故障,在短时间内丢失大量的实例心跳,这时候EurekaServer会开启自我保护机制,EurekaServer不会踢出这些服务

在开发中,由于会重复重启服务实例,所以经常会出现以下警告:

EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.

所以开发时需要关闭自我保护

eureka:  server:    enable-self-preservation: false # 关闭自我保护模式(缺省为打开)    eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间(缺省为60*1000ms)

服务下线

Eureka集群

Eureka 满足AP 牺牲了 C

# eureka1spring.application.name=spring-cloud-eurekaserver.port=8001eureka.client.serviceUrl.defaultZone=http://localhost:8002/eureka/
# eureka2spring.application.name=spring-cloud-eurekaserver.port=8002eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
eureka.client.service-url.defaultZone=http://localhost:8001/eureka,http://localhost:8002/eureka

集群同步

Consul

https://www.consul.io/downloads.html
consul agent -dev

生产者配置

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency>
spring.application.name=consul-producerserver.port=8503spring.cloud.consul.host=localhostspring.cloud.consul.port=8500#注册到consul的服务名称spring.cloud.consul.discovery.serviceName=producer

消费者

spring.application.name=consul-consumerserver.port=8504spring.cloud.consul.host=127.0.0.1spring.cloud.consul.port=8500#设置不需要注册到 consul 中spring.cloud.consul.discovery.register=false
@RestControllerpublic class ServiceController {    @Autowired    LoadBalancerClient loadBalancerClient;    @Autowired    DiscoveryClient discoveryClient;    // 获取相关服务实例    @RequestMapping("/services")    public Object services(){        return discoveryClient.getInstances("producer");    }    // 自动选择服务实例    @RequestMapping("/discover")    public Object discover(){        return loadBalancerClient.choose("producer").getUri().toString();    }    @RequestMapping("/hi")    public String hi(){        ServiceInstance instance = loadBalancerClient.choose("producer");        return new RestTemplate().getForObject(instance.getUri().toString()+"/hi",String.class);    }}

zookeeper

保证CP,即任何时刻对zookeeper的访问请求能得到一致性的数据结果,同时系统对网络分割具备容错性,但是它不能保证每次服务的可用性

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId></dependency>
server.port=8101spring.application.name=zk-producerspring.cloud.zookeeper.connect-string=127.0.0.1:2181
@EnableDiscoveryClient

Nacos

概念

屏幕截图 2020-09-23 163728

架构

屏幕截图 2020-09-23 163102

注册中心

使用
<dependency>    <groupId>com.alibaba.cloud</groupId>    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
spring.application.name=providerspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
@FeignClient("provider")public interface ProviderClient {    @GetMapping("/name")    String name();}@RestControllerpublic static class Api {    @Autowired    private ProviderClient client;    @GetMapping("/")    public String home() {        return client.name();    }}
vs Zookeeper & Eureka

不同点:

最主要的是Eureka集群中的各个节点是对等的,而Nacos则有主从之分