SpringCloud(一)之小徐的Eureka初体验

新的任务

“我们现有的系统太笨重了,要拆成多个小系统来进行重构,系统之间通过Http通信交换数据......”架构师一上午噼里啪啦说了一堆事情,大家都哈欠都打到天上去了。“小徐,你这边负责一下各个系统的配置信息。”架构师大锤看了一眼角落里刚毕业的小徐。“哦,好的,没问题。”小徐满满自信,因为这不很简单么,一共才拆成三个服务能有多少信息。

几天后,小徐整理了下面的一个文件发给了各个小组。

刚开始的时候还没什么问题,之后突然有一天CustService服务调不通了,排查了好久的问题才发现CustService的端口变了,之后每当有变动的时候各个小组就把变动发给小徐,小徐修改完之后,再发给各个小组。一来二去,也挺麻烦的,有的时候也会不小心发错文件T__T。更要命的是在开会讨论之后,又新增了10个服务,这下可把小徐整懵逼了。还是问下大锤吧,大锤笑了笑,让小徐先自己整理存在问题,顺便想一套解决的方案,进行自动化管理。

需要解决的问题

  1. 新服务可以自动加入服务列表并且其他服务能够及时响应
  2. 已有服务信息变化时自动更新服务列表并且其他服务能够及时响应
  3. 服务正常下线之后,通知服务列表,剔除该服务
  4. 服务异常下线,服务列表能够短时间内觉察到,剔除该服务
  5. 各个开发小组手上总是有一份最新的服务列表

解决方案

核心方案:建立一个新的中心服务用来管理服务列表,其他服务作为客户端进行通信,如下:

注册中心
  1. 建立一个注册中心,注册中心进行各个服务信息的维护,由于考虑高可用,所以注册中心为HA,那么就要考虑文件的一致性,考虑使用Zookeeper作为注册元信息的存储。
  2. 注册中心开放接口允许其他服务(也可以有鉴权)进行更新注册信息
  3. 注册中心开放接口允许其他服务进行注册服务的下线
  4. 注册中心定时和其他服务检测心跳,对无响应的服务进行服务的下线
  5. 注册中心开放接口允许服务进行所有注册列表信息的拉取
其他服务
  1. 工程启动时向注册中心进行服务信息的注册
  2. 工程正常下线时向注册中心发起下线申请
  3. 定时向注册中心发送心跳
  4. 定时拉取服务注册列表,使用新的注册列表信息

反馈

小徐使出了浑身解数,整理了以上的内容,大锤看过之后说:“不错,就交给你开发了”。“啊?!”小徐一脸错愕,这下牛皮吹大了,不得了了。“不用你写,有现成的,你去了解下Spring Cloud的Eureka吧。”大锤摸了摸秃秃的头顶。

如何使用Eureka

Eureka Server
  1. 引入pom文件(根据实际需要选择适当的版本)
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
  1. 启动类加入@EnableEurekaServer注解
@EnableEurekaServer
@SpringBootApplication
public class CenterBootstrap {

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

}
  1. application.yml配置文件中加入相应的配置
spring:
    application:
        name: Venus-Center
server:
  #启动端口
  port: 8761

eureka:
    instance:
        preferIpAddress: true
    client:
        # 表示是否将自己注册的eureka,由于当前节点就是注册中心所以为false default=true
        registerWithEureka: false
        # 是否从Eureka Server拉取注册列表,单点的Eureka Server不需要,default=true
        fetchRegistry: false
    server:
        enable-self-preservation: false
Eureka Client
  1. 引入pom文件
        <!--eureka客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
  1. 启动类加入@EnableEurekaClient注解(新版本中不加入此注解也可以,只要引入jar包设置eureka.client.enabled=true,默认为true)或者@EnableDiscoveryClient注解,两者的区别是注册中心有很多实现,比如zookeeper、eureka等。如果注册中心使用eureka推荐使用EnableEurekaClient,如果是其他实现使用EnableDiscoveryClient。
@SpringBootApplication
@EnableEurekaClient
public class AresOrderBootstrap {
    public static void main(String[] args) {
        SpringApplication.run(AresOrderBootstrap.class, args);
    }
}
  1. application.yml配置文件中加入相应的配置
spring:
  application:
    name: ares-order
server:
  port: 10000
eureka:
    client:
        registerWithEureka: true
        fetchRegistry: true
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/

常见配置

以上只是常见的一些配置,Spring Cloud本身提供了一套最简配置,使用者也可以进行配置。比如注册中心可以配置多个以达到高可用;比如注册中心可以配置鉴权(也支持用户个性化),客户端只有通过鉴权才能进行注册;比如可以根据Region以及Zone,注册中心位于不同的机房,而客户端服务注册到离其最近的注册中心,服务与服务之间进行Ribbon调用时也会优先物理上同处于一个Zone的服务......

服务基本配置
  • spring.application.name
    应用名称会展示在eureka界面上​
  • server.port
    服务所占用端口号
eureka.instance
  • appname
    服务名,默认取 spring.application.name 配置值(此配置的优先级更高),如果没有则为 unknown
  • instance-id
    实例ID,这个值决定了eureka界面上的显示值
  • hostname
    应用实例主机名
  • prefer-ip-address(false)
    客户端在注册时使用自己的IP而不是主机名,false时采用hostname的值,为true时有限用ip-address地址,其为空时根据当前网络环境选择第一个非回环IP地址进行注册
  • ip-address
    应用实例IP
  • lease-expiration-duration-in-seconds(90)
    服务失效时间,失效的服务将被剔除。单位:秒
  • lease-renewal-interval-in-seconds(30)
    服务续约(心跳)频率,单位:秒
  • status-page-url-path(/info)
    状态页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置
  • health-check-url-path(/health)
    健康检查页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置
eureka.client
  • service-url.defaultZone(http://localhost:8761/eureka)
    Eureka服务器的地址,类型为HashMap,缺省的Key为 defaultZone;如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。 ​
  • register-with-eureka(true)
    是否向注册中心注册自己
  • fetch-registry(true)
    是否从Eureka获取注册信息​
  • registry-fetch-interval-seconds(30)
    客户端拉取服务注册信息间隔,单位:秒
  • health-check.enabled(true)
    是否启用客户端健康检查
  • eureka-server-connect-timeout-seconds(5)
    连接Eureka服务器的超时时间,单位:秒
  • eureka-server-read-timeout-seconds(8)
    从Eureka服务器读取信息的超时时间,单位:秒
  • filter-only-up-instances(true)
    获取实例时是否只保留状态为 UP 的实例
  • eureka-connection-idle-timeout-seconds(30)
    Eureka服务端连接空闲时的关闭时间,单位:秒
  • eureka-server-total-connections(200)
    从Eureka客户端到所有Eureka服务端的连接总数
  • eureka-server-total-connections-per-host(50)
    从Eureka客户端到每个Eureka服务主机的连接总数

源码导读

Eureka Server

入口类@EnableEurekaServer

@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {

}

继续看EurekaServerMarkerConfiguration

/**
 * Responsible for adding in a marker bean to activate
 * {@link EurekaServerAutoConfiguration}
 *
 * @author Biju Kunjummen
 */
@Configuration
public class EurekaServerMarkerConfiguration {

    @Bean
    public Marker eurekaServerMarkerBean() {
        return new Marker();
    }

    class Marker {
    }
}

这里注入了一个Marker,仔细一看Marker类还是空的,我当时就在想是不是逗我呢,看作者上面的注释,加入一个marker bean目的是去激活{@link EurekaServerAutoConfiguration},so 我们就去看这个类

@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
        InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter{
......
}

@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)的意思就是如果Spring上下文中存在EurekaServerMarkerConfiguration.Marker的Bean的话就会注入EurekaServerAutoConfiguration否则不进行注入,看到这里先不往下看了,后面我们再仔细的去看。

Eureka Client

Eureka client找入口可就费劲了,我使用的是@EnableEurekaClient注解,打开这个类:

/**
 * Convenience annotation for clients to enable Eureka discovery configuration
 * (specifically). Use this (optionally) in case you want discovery and know for sure that
 * it is Eureka you want. All it does is turn on discovery and let the autoconfiguration
 * find the eureka classes if they are available (i.e. you need Eureka on the classpath as
 * well).
 *
 * @author Dave Syer
 * @author Spencer Gibb
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableEurekaClient {

}

不知道是我英文水平不好,还是咋滴,这个注释是没看出门道。通过一番查阅资料之后也没有找到,只好自己进行摸索。
打开我们经常引用的@SpringBootApplication注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}

着重看@EnableAutoConfiguration,这个注解会引入当前jar下/META-INF/spring.factories下的配置类,具体原理可以参考SpringBoot之@EnableAutoConfiguration注解

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

一眼就看到了EurekaClientAutoConfiguration这个类,看起来特别像

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@Import(DiscoveryClientOptionalArgsConfiguration.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
        CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
        "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
        "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"})
public class EurekaClientAutoConfiguration {
}

@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)这一句是,如果application.yml(代指配置文件,可能不是这个名称)文件中存在eureka.client.enabled=true的话就注入这个类,默认是true
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)这一句是,如果存在EurekaDiscoveryClientConfiguration.Marker注入的话就注入这个类

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
public class EurekaDiscoveryClientConfiguration {
.......
}

可以看到这个类注入的条件也有eureka.client.enabled属性,上面的@ConditionalOnClass(EurekaClientConfig.class)是指jar包中存在EurekaClientConfig这个类的情况。
其中关于@Conditional注解的内容可以参考SpringBoot重点详解--@Conditional注解

至此,我们貌似已经找到了源码的入口,下面我们会有时间继续进行源码的阅读,在源码中找到我们原始构想的实现。

Stay hungry,stay foolish.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342