spring cloud eureka 是 spring cloud netfix 为服务套件中的一部分,它基于Netflix eureka 做了二次封装,主要负责完成微服务架构中的服务治理功能
服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现
服务注册:在服务治理框架中,通常会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号,版本号,通信协议等一些附加信息告知注册中心,注册中心按服务名分类组织服务清单
服务发现:由于在服务治理框架下运作,服务间的调用不再通过指定具体的实例地址来实现,而是通过向服务名发起请求调用实现. 所以,服务调用方在调用服务提供方接口的时候,并不知道具体的服务实例位置。因此,调用方需要向服务注册中心咨询服务,并获取所有服务的实例清单,以实现对具体服务实例的访问
spring cloud eureka, 使用netfix eurefix 来实现服务注册与发现,它既包含了服务端组件,也包含了客户端组件
eureka 服务端,我们也称为服务注册中心。它同其他服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可以应对不同的故障场景。如果eureka 以集群模式部署,当集群中有分片出现故障时,那么eureka 就转入自我保护模式。它允许在分片故障期间继续提供服务的发现和注册,当故障分片恢复运行时,集群中的其他分片会把它们的状态再次同步回来
eureka 客户端,主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序时,eureka 客户端向注册中心注册自身提供的服务并周期性地发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性地刷新服务状态
spring boot 1.5.15.RELEASE
配置 注册中心
配置文件 application.properties |
server.port=1111 eureka.instance.hostname=localhost #由于该应用为注册中心,所有设置为false,代表不向注册中心注册自己 eureka.client.register-with-eureka=false #由于注册中心的职责就是维护服务实例,它并不需要去检索服务,所以也设置为false eureka.client.fetch-registry=false eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ |
启动 类 |
package springcloud.eurekaserver;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer // 注解启动一个服务注册中心 @SpringBootApplication public class EurekaServerApplication {
public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } |
启动应用访问 http://localhost:1111 就可以看到 eureka 信息面板
在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况,所以在生产环境中必须对各个组件进行高可用部署
eureka server 的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果
新建两个项目 分别配置:
peer1 节点 |
spring.application.name=eureka-server server.port=1111
eureka.instance.hostname=peer1 eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/ |
peer2 节点 |
spring.application.name=eureka-server server.port=1112
eureka.instance.hostname=peer2 eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/ |
host 文件 |
127.0.0.1 peer1 127.0.0.1 peer2 |
让serviceUrl 相互指向对方,启动类也加上 @EnableEurekaServer
启动后,http://localhost:1111, http://localhost:1112 就能看到 相互都在registered-replicas 与 available-replicase 栏目中
在设置了多节点的服务注册中心之后,服务提供方还需要做一些简单的配置才能将服务注册到eureka server集群中。
eureka。client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
我们将注册中心指向了之前我们搭建的peer1 与 peer2
若此时断开peer1,由于同时也向 peer2注册,因此在peer2上的其他服务依然能访问到,从而实现了服务注册中心的高可用
服务的提供者
配置文件 |
spring.application.name=hello-service eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
启动文件 主类中通过加上@EnableDiscoveryClient注解,激活Eureka中的DiscoveryClient实现 |
package springcloud.eureka_provider;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient @SpringBootApplication public class EurekaProviderApplication {
public static void main(String[] args) { SpringApplication.run(EurekaProviderApplication.class, args); } } |
编写controller 类 |
package springcloud.eureka_provider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController public class HelloController { @Autowired private DiscoveryClient client; @Qualifier("eurekaRegistration") @Autowired private org.springframework.cloud.client.serviceregistry.Registration eurekaRegistration;
@RequestMapping(value = "/hello",method = RequestMethod.GET) public String index(){ System.out.println("serviceId:"+eurekaRegistration.getServiceId()+" hostName:"+eurekaRegistration.getHost()); return "Hello World"; } } |
服务的消费者
服务发现的任务由eureka的客户端完成,而服务消费的任务由ribbon完成,ribbon是一个基于http和tcp的客户端负载均衡器,它可以在通过客户端中配置的ribbonServerList服务端列表去轮询访问以达到均衡负载的作用。当Ribbon 与 Eureka 联合使用时,Ribbon 的服务实例清单 会被重写
配置文件 服务消费方 配置的服务注册中心的位置 ,需要与 服务提供方一样,不然发现不了该服务 |
spring.application.name=ribbon-consumer server.port=9000 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
启动类 |
package springcloud.eureka_consumer;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient @SpringBootApplication public class EurekaConsumerApplication {
public static void main(String[] args) { SpringApplication.run(EurekaConsumerApplication.class, args); }
@Bean @LoadBalanced RestTemplate restTemplate(){ return new RestTemplate(); }
} |
controller |
package springcloud.eureka_consumer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;
@RestController public class ConsumerController { @Autowired RestTemplate restTemplate;
@RequestMapping(value = "/ribbon-consumer",method = RequestMethod.GET) public String helloConsumer(){
return restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody(); }
} |
eureka 实例 自动装配类
@ConfigurationProperties("eureka.instance")
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware
服务续约:
在注册完服务之后,服务提供者会维护一个心跳用来持续告诉eureka server: "我还活着",以防止eureka server的“剔除任务”将该服务实例从服务列表中排除出去,我们称该操作为服务续约
eureka.instance.lease-renewal-interval-in-seconds=
对应源码;
private int leaseRenewalIntervalInSeconds = 30;
参数用于定义服务续约任务的调用间隔时间,默认30秒
eureka.instance.lease-expiration-duration-in-seconds=
对应源码
private int leaseExpirationDurationInSeconds = 90;
参数用于定义服务失效的时间 默认90S
服务下线
在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心。服务端在接收到请求之后,将该服务状态置为下线(DOWN),并把下线事件传播出去
服务注册中心
失效剔除
有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出,网络故障等原因使得服务不能正常工作,而服务注册中心并未收到“服务下线”的请求。为了从服务列表中将这些无法提供服务的实例剔除,eureka server 在启动的时候回创建一个定时任务,默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除出去
以上出自 spring cloud 微服实战一书