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 也可以通过服务中心调用到提供者那里。

看图


基础架构

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

  • 服务提供者

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

推荐阅读更多精彩内容