框架篇-springcloud.erueka
定义电脑
微服务化后,服务将越来越多,已经云化动态分配IP,传统的手工配置 比如ngnix的ip配置将会变得越来越不满足要求,于是需要一个组件去管理服务,eureka就是来干这个的。
1.eureka作用是服务注册与发现中心,在springcloud中的作用可以和spring的IOC容器作为对比,是服务管理的基础组件
2.而管理服务需要几个基本能力:
a.服务注册表(服务端存储服务数据的地方 可以理解为表) 存数据的地方
b.服务发现 服务的注册与注销
c.健康监测 服务的续约
eureka就是在实现这三个能力进行开发
其实感觉大部分的组件都只是工具级别 都是可以自定义实现的
使用电脑
springcloud的组件用起来都比较简单,基本上就是三步走
a、导包
b、加注解
c、改配置
对于改配置这一点,是觉得springcloud还需要优化的地方,springboot将配置项变少,springcloud又回到配置了
服务端
a、导包
<dependency>
<!--eureka服务端-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
b、注解
@SpringBootApplication
@EnableEurekaServer//eureka服务端
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
c、配置application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
#是否向服务注册中心注册自己
registerWithEureka: false
#是否检索服务
fetchRegistry: false
serviceUrl:
#eureka服务端的位置 有需要用户名密码的形式 需要导Security包
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
客户端
a、导包
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--健康检查客户端包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
b、注解
@EnableDiscoveryClient
//@EnableEurekaClient//仅用于eureka作为服务治理中心
@Autowired
private DiscoveryClient discoveryClient;//可以通过这个获取服务实例信息
c、配置application.yml
eureka:
#eureka服务端地址
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#注册的实例信息 用于页面显示
instance:
instanceId: ${spring.application.name}:${spring.application.instance_id:${server.port}}
#开启健康检查
client:
healthcheck:
enabled: true
服务端高可用方案
注册信息和更新会被复制到其他Eureka 节点,来自任何区域的客户端科可以查找到注册中心信息,每30s发生一次复制来定位他们的服务,并进行远程调用 注册是服务端会通信
拆解电脑
如上所见 使用起来还是蛮简单的 现在我们来分析源码
客户端源码
当我们启动服务时,会发现服务端会出现一段日志,这是因为客户端调用了请求
客户端日志
com.netflix.discovery.DiscoveryClient : DiscoveryClient_AIS/ais:8081: registering service…
//….
com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
服务端日志
c.n.e.registry.AbstractInstanceRegistry : Registered instance AIS/ais:8081 with status UP (replication=false)
根据这个日志我们找到这个类
package com.netflix.discovery;
@Singleton//单例
public class DiscoveryClient implements EurekaClient
a、服务注册 注销->客户端启动时发送请求到服务端
我们看下客户端打这个日志的地方–>register()方法 其实就是发送了一个请求到服务端而已
boolean register();//服务注册 发送http请求到服务端
void getAndStoreFullRegistry();//本地服务缓存 发送http请求到服务端 然后存到本地
b、心跳 也可以叫续约->客户端开启定时任务发送请求到服务端
boolean renew();//调用register()注册方法 发送注册请求
定时任务那里来的
@Inject
DiscoveryClient(..){
//...
//构造函数里面做了很多初始化 其中就包括定时任务
this.initScheduledTasks();
}
private void initScheduledTasks() {
int renewalIntervalInSecs;
int expBackOffBound;
//是否服务获取 也就是eureka.client.fetch-registry=true 默认是ture
if (this.clientConfig.shouldFetchRegistry()) {
//定时任务 服务获取 默认每30s获取服务端服务
this.scheduler.schedule(new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.CacheRefreshThread()), (long)renewalIntervalInSecs, TimeUnit.SECONDS);
}
//是否注册服务
if (this.clientConfig.shouldRegisterWithEureka()) {
renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: renew interval is: {}", renewalIntervalInSecs);
//定时任务 心跳检测HeartbeatThread 频率配置同上
this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread()), (long)renewalIntervalInSecs, TimeUnit.SECONDS);
this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
//...
if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
}
//服务注册线程 类的是runnable类 run方法中会调用register方法
this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
} else {
logger.info("Not registering with Eureka server per configuration");
}
}
//心跳检测线程
private class HeartbeatThread implements Runnable {
private HeartbeatThread() {
}
public void run() {
// 续约成功 就更新下最后心跳的时间
if (DiscoveryClient.this.renew()) {
DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
服务端源码
服务端就是提供接口 可以跟踪到com.netflix.eureka.resources包下的内容 大体相同 以注册服务为例
就是ApplicationResource下的addInstance方法
@POST
@Consumes({"application/json", "application/xml"})
public Response addInstance(InstanceInfo info, @HeaderParam("x-netflix-discovery-replication") String isReplication) {
//注册
this.registry.register(info, "true".equals(isReplication));
return Response.status(204).build();
}
public void register(InstanceInfo info, boolean isReplication) {
int leaseDuration = 90;
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
//调用父类的注册方法
super.register(info, leaseDuration, isReplication);
//同步到其他集群的服务端
this.replicateToPeers(PeerAwareInstanceRegistryImpl.Action.Register, info.getAppName(), info.getId(), info, (InstanceStatus)null, isReplication);
}
拓展电脑
配置
配置项主要在于配置定时任务的频率 是否集群等
手写实现
比较电脑
erueka vs zk
服务治理目前比较流行的就是这两种了