Spring Cloud-Eureka

注:这个使用文章根据阅读 《spring cloud 微服务实战》在加上自己的一点理解。
如果想学习springCloud的话,要熟悉SpringBoot。

Spring Cloud 是一个基于SpringBoot实现的微服务开发工具。它为微服务架构中涉及的配置管理,服务治理,断路器,智能路由,微代理,控制总线,全局锁,决策竞选,分布式会话和集群状态管理等操作提供了一种简单的开发方式。(做为分布式框架,和Dubbo相比,SpringCloud更像是一个全家桶)

  • Eureka

Eureka服务端,我们也成为服务注册中心,它支持高可用的配置。相当于Dubbo框架中对Zookeeper的作用

Eureka客户端,主要处理服务中的注册与发现。

下边看一个eureka服务端的单机例子。

主类

/**
 * 通过@EnableEurekaServer注解启动一个服务注册中心提供给其他应用进行对话
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServiceApplication.class, args);
    }
}

配置文件

#端口号
server.port=1111
#名称
eureka.instance.hostname=localhost
#不向注册中心注册自己
eureka.client.register-with-eureka=false
#不需要检索服务
eureka.client.fetch-registry=false
#注册地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
  • 高可用注册中心

在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况,所以在生产环境中必须对各个组件进行高可用部署,对于微服务如此,对于注册中心也如此。

Eureka Service 的设计一开始就考虑到了高可用问题,在Eureka的服务治理设计中,所有的节点既是服务提供方,也是服务消费方,服务注册中心也不例外。
Eureka Service的高可用实际上就是自己作为服务向其他注册众生心注册自己,这样就可以形成一组互相注册的服务中心。

下边看一个双节点服务注册中心集群

配置文件

application-peer1.properties

spring.application.name=eureka-service
server.port=1111

eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://127.0.0.1:1112/eureka/

application-peer2.properties

spring.application.name=eureka-service
server.port=1112

eureka.instance.hostname=peer2
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/

启动的时候 ,利用spring profiles。
java -jar xxx.jar --spring.profiles.active=peer1
java -jar xxx.jar --spring.profiles.active=peer2

此时访问,http://localhost:1111 可以看到1112的分片,访问http://localhost:1112 可以看到1111的分片。

  • 提供者

主类

/**
 * 在主类上增加@EnableDiscoveryClient注解,激活Eureka中的
 * DiscoveryClient实现。让该应用注册为Eureka客户端。
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderServiceApplication.class, args);
    }
}

controller

@RestController
public class UserController {

    private final Logger logger = Logger.getLogger(getClass());

    @Autowired
    private DiscoveryClient client;

    @RequestMapping("/user")
    public String  index(){
        ServiceInstance instance = client.getLocalServiceInstance();
        logger.info("/user,host:"+instance.getHost()+",service_id:"+instance.getServiceId());
        return "this is userService";
    }
}

注册到上边Eureka集群中的配置文件

spring.application.name=user-service
#注册到多个eureka服务器
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/,http://127.0.0.1:1112/eureka/
  • 消费者

主类

/**
 * 在主类上增加@EnableDiscoveryClient注解,激活Eureka中的
 * DiscoveryClient实现。让该应用注册为Eureka客户端。
 * 同时,在该主类中创建RestTemplate的SpringBean实例,
 * 并通过@LoadBalanced注解开启客户端负载均衡
 */
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(RibbonConsumerApplication.class, args);
    }
}

controller

@RestController
public class ConsumerController {
    private final Logger logger = Logger.getLogger(this.getClass());

    /**
     * 通过RestTemplate来实现对user-service的接口调用。
     */
    @Autowired
    RestTemplate restTemplate;

    @RequestMapping("/rpc-user")
    public String helloConsumer(){
        logger.info("远程调用开始");
        return restTemplate.getForEntity("http://user-service/user",String.class).getBody();
    }
}

配置文件

server.port=3333

spring.application.name=user-consumer
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/,http://127.0.0.1:1112/eureka/

此时访问 http://localhost:1111 可以看到消费者和提供者的信息。
访问http://localhost:3333/rpc-user 也可以通过服务中心调用到提供者那里。

看图


Spring Cloud-Eureka_第1张图片
基础架构

下边看一下关于服务提供者,服务消费者,服务注册中心的一些概念,更好的理解上边这幅图

  • 服务提供者

服务注册:“服务提供者”在启动的时候回通过发送REST请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据,Eureka Server接收 到这个REST请求之后,将元数据信息存储在一个双层结构的Map中,第一层Map的Key是服务名,第二层的Key是具体服务的实例名。
在服务注册之时,要确认一下eureka.client.register-with-eureka=ture参数是否正确,默认为true,若为false将不会启动注册操作。

服务同步:如上图所示,这里的两个服务提供者分别注册到了两个不同的服务注册中心上,也就是说,他们的信息分别被两个服务注册中心维护,此时,由于服务注册中心之间因互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,他会将该请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两个服务注册中心中的任意一台获取到。

服务续约:在注册完服务之后,服务提供者会维护一个心跳来通知Eureka Service,以防止Eureka Service的“剔除任务”将该服务实例从服务列表中排除出去,我们称该操作为服务续约。
关于服务续约的两个配置

#该参数用于定义服务续约任务的调用时间间隔
eureka.instance.lease-renewal-interval-in-seconds=30
#该参数用于定义服务失效的时间
eureka.instance.lease-expiration-duration-in-seconds=90
  • 服务消费者

获取服务:当启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑。Eureka Server 会维护一份只读的服务清单来返回给客户端,同时,该缓存清单每隔30s更新一次。

#获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true .默认为true
eureka.client.fetch-registry=true
#若希望修改缓存清单的更新时间,可以通过该参数修改,默认为30s
eureka.client.registry-fetch-interval-seconds=30

服务调用:服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息,因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

服务下线:在系统运行过程中必然会面临关闭或重启的某个实例情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例,所以在客户端程序中,当服务实例进行正常关闭操作时,它会触发一个服务下线的REST请求给EurekaServer,告诉服务中心,我要下线了。服务端在收到请求后,将该服务状态置为下线,并把该下线时间传播出去。

  • 服务注册中心

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

自我保护:当我们在本地调试基于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.

实际上,该警告就是出发了EurekaServer的自我保护机制,之前我们介绍过,服务注册到EurekaServer之后,会维护一个心跳链接,告诉EurekaServer自己还活着,EurekaServer在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现这种情况,EurekaServer会讲当前实例注册保护起来,让这些实例不会过期。尽可能保护这些注册信息,但是,在这段保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的情况,所以客户端必须有容错机制,比如可以使用请求重试,断路器等机制。

由于本地调试很容易触发注册中心的保护机制。这会使得注册中心维护的服务实例不那么准确。所以,我们在本地进行开发的时候,可以使用下边的参数关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。

#关闭自我保护机制
eureka.server.enable-self-preservation=false

你可能感兴趣的:(Spring Cloud-Eureka)