【微服务】(三)—— Eureka
本期介绍🍖
目录
一、Eureka概述
1、背景
(1)netflix公司与AWS的ELB
(2)eureka诞生
(3)ELB和eureka搭配使用
2、eureka优势
(1)提供完成的服务注册和服务发现实现
(2)与spirngcloud无缝集成
(3)采用AP而非CP
(4)开源
3、eureka和zk作为注册中心比较
二、eureka架构设计
1、设计理念
(1)AP由于CP
(2)Peer to Peer设计
(3)Zone和region的设计
(4)self preservation设计
2、组件调用关系设计
(1)服务提供者
(2)服务消费者
(3)服务注册中心
3、数据存储结构
(1)数据存储层
(2)二级缓存层
1、客户端高可用原理
2、服务端高可用原理
四、代码实操
1、Eureka服务器
(1) maven
(2)创建启动类
(3)创建配置文件 application.yml
2、Eureka客户端
(1)maven 导入
(2)代码引入
3、展示效果
一、Eureka概述
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。
SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
1、背景
(1)netflix公司与AWS的ELB
netflix是世界上最大的流媒体视频网站,其公司的架构师基于AWS云开发的。在AWS中使用的负载均衡器是ELB(Elastic Load Balancing),即弹性负载均衡通过流量分发扩展应用系统对外的服务能力(类似阿里云SLB服务)。理论上是可以通过ELB对内部进行负载均衡的,但是如果这样就会暴露到外网,存在安全性问题;另外ELB是基于传统的代理的负载均衡解决方案,无法直接基于服务元数据信息定义负载均衡算法。也就是说使用ELB有一定的限制,无法根据复杂的生产环境提供更为复杂的负载均衡方案,且存在一定的安全隐患。
(2)eureka诞生
netflix鉴于自己的生产环境,设计出了eureka,一方面给内部服务做服务发现,另一方面可以结合ribbon组件提供各种个性化的负载均衡算法。ELB亦是传统的基于代理实现的负载均衡解决方案而Eureka则与之不同,Eureka属于客户端发现模式,客户端负责决定相应服务实例的网络位置,并且对请求实现负载均衡。客户端从一个服务注册服务中查询所有可用服务实例的库,并缓存到本地。
(3)ELB和eureka搭配使用
在生产中如果是使用AWS等云服务,可以结合eureka一起使用(以AWS为例),ELB用来对客户端或者终端设备进行请求负载均衡,而eureka用来对中间层的服务做服务发现,配合其他组件提供负载均衡的能力。
2、eureka优势
(1)提供完成的服务注册和服务发现实现
首先是提供了完整的服务注册和服务发现实现,并且也经受住了Netflix自己的生产环境考验,相对使用起来会比较省心。
(2)与spirngcloud无缝集成
我们的项目本身就使用了Spring Cloud和Spring Boot,同时Spring Cloud还有一套非常完善的开源代码来整合Eureka,所以使用起来非常方便。另外,Eureka还支持在我们应用自身的容器中启动,也就是说我们的应用启动完之后,既充当了Eureka的角色,同时也是服务的提供者。这样就极大的提高了服务的可用性
(3)采用AP而非CP
eureka是在部署AWS的背景下面设计的,其设计认为,在云端,特别是大规模部署情况下面,失败是不可以避免的,可能是因为eureka自身部署失败或者网络分区等情况导致服务不可用,这些问题是不可以避免的,要解决这个问题就需要eureka在网络分区的时候,还能够正常提供服务,因此eureka选择满足availability这个特性。
eureka选择了A也就必须放弃C,也就是说在eureka中采用最终一致性的方式来保证数据的一致性问题,因此实例的注册信息在集群的所有节点之间的数据都不是强一性的,需要客户端能支持负载均衡算法及失败重试等机制。
(4)开源
代码是开源的,所以非常便于我们了解它的实现原理和排查问题。需要的话还可以在上面进行二次开发。
3、eureka和zk作为注册中心比较
Zookeeper |
Eureka |
|
设计原则 |
CP |
AP |
优点 |
数据强一致 |
服务高可用 |
缺点 |
网络分区会影响Leader选举,超过阈值后集群不可用 |
服务节点间的数据可能不一致; Client-Server间的数据可能不一致; |
适用场景 |
单机房集群,对数据一致性要求较高 |
云机房集群,跨越多机房部署;对注册中心服务可用性要求较高 |
二、eureka架构设计
1、设计理念
(1)AP由于CP
(2)Peer to Peer设计
一般而言在分布式系统的数据有多个副本之间的复制方式,可以分为主从复制和对等复制
- 主从复制:
Master-Slave模式,一个主副本和多个从副本,所有数据的写操作都是提交到主副本,最后由主副本更新到其他的从副本(常采用异步更新),通常写是整个系统的瓶颈所在。对等复制:副本之间不分主从,任何的副本都可以接受写数据,然后副本之间进行数据更新。在对等复制中,由于每一个副本都可以进行写操作,各个副本之间的数据同步及冲突处理是一个比较难解决的问题。
eureka中的对等复制机制
1、客户端:在客户端中配置相应的服务端的多个peer节点,在客户端实际操作中有如下几点规律;
- (1)有多个分区时候,优先选择与应用实例所在分区一样的其他服务实例,如果没有的话选择默认是defaultZone
- (2)客户端会维护一个可用的server列表,请求的时候优先从可用的列表中进行选择,如果请求失败切换到下一个server进行重试,重试次数为3次
- (3)为了防止客户端请求服务端的节点不均匀现象,客户端有一个定时任务来刷新并随机化eureka server的列表。
2、服务端:server本身依赖于客户端,也就是每一个server是作为其他server的客户端存在。在一个server启动的时候,有一个synvUp操作,通过客户端请求其他的server节点中的一个节点获取注册的应用实例信息,然后复制到其他的peer节点。eureka中采用版本号(lastDirtyTimestamp)和心跳机制(renewLease从新租约方式)的方式来解决数据复制过程中的冲突问题。
(3)Zone和region的设计
- 使用region来代表一个独立的地理区域,比如us-east-1、us-east-2,、us-west-1等。在每一个region下面还分为多个AvailabilityZone,一个region对应多个AvailabilityZone,不同的region之间相互隔离。默认情况下面资源只是在单个region之间的AvailabilityZone之间进行复制,跨region之间不会进行资源的复制。
AvailabilityZone看成是region下面的一个一个机房,各个机房相对独立,主要是为了region的高可用考虑的,一个region下面的机房挂了,还有其他的机房可以使用。
一个AvailabilityZone可以设置多个server实例,他们之间构成peer节点,然后采用peer to peer的复制模式进行数据复制。
(4)self preservation设计
在分布式系统设计中,通常需要对应用实例的存活进行健康检验,这里比较难处理的就是网络偶尔抖动或者短暂不可用而造成的误判。因此eureka设计了self preservation机制。server和client之间有一个租约,client定期发送心跳来维护这个租约,表示心跳还活着,eureka通过当前注册的实例数量,去计算每分钟应用从应用实例接受到的心跳数量,如果近一分钟接受到的租约的次数小于等于指定的阈值,则关闭租约失效剔除,禁止定时任务剔除失效的实例,从而保护注册信息。
2、组件调用关系设计
(1)服务提供者
- 1、启动后,向注册中心发起 register 请求,注册服务
- 2、在运行过程中,定时向注册中心发送 renew 心跳,证明“我还活着”。
- 3、停止服务提供者,向注册中心发起 cancel 请求,清空当前服务注册信息。
(2)服务消费者
- 1、启动后,从注册中心拉取服务注册信息
- 2、在运行过程中,定时更新服务注册信息。
- 3、服务消费者发起远程调用:
- a> 服务消费者(北京)会从服务注册信息中选择同机房的服务提供者(北京),发起远程调用。只有同机房的服务提供者挂了才会选择其他机房的服务提供者(青岛)。
- b> 服务消费者(天津)因为同机房内没有服务提供者,则会按负载均衡算法选择北京或青岛的服务提供者,发起远程调用。
(3)服务注册中心
- 1、启动后,从其他节点拉取服务注册信息。
- 2、运行过程中,定时运行 evict 任务,剔除没有按时 renew 的服务(包括非正常停止和网络故障的服务)。
- 3、运行过程中,接收到的 register、renew、cancel 请求,都会同步至其他注册中心节点
3、数据存储结构
-
Eureka 的数据存储分了两层:数据存储层和缓存层。
Eureka Client 在拉取服务信息时,先从缓存层获取(相当于 Redis),如果获取不到,先把数据存储层的数据加载到缓存中(相当于 Mysql),再从缓存中获取。值得注意的是,数据存储层的数据结构是服务信息,而缓存中保存的是经过处理加工过的、可以直接传输到 Eureka Client 的数据结构。
(1)数据存储层
第一层的 key 是spring.application.name,value 是第二层 ConcurrentHashMap;第二层 ConcurrentHashMap 的 key 是服务的 InstanceId,value 是 Lease 对象;Lease 对象包含了服务详情和服务治理相关的属性。
更新一级缓存:
Eureka Server 内置了一个 TimerTask,定时将二级缓存中的数据同步到一级缓存(这个动作包括了删除和加载)。
(2)二级缓存层
Eureka 实现了二级缓存来保存即将要对外传输的服务信息,数据结构完全相同。
- 一级缓存:ConcurrentHashMap readOnlyCacheMap,本质上是 HashMap,无过期时间,保存服务信息的对外输出数据结构。
- 二级缓存:Loading readWriteCacheMap,本质上是 guava 的缓存,包含失效机制,保存服务信息的对外输出数据结构。
既然是缓存,那必然要有更新机制,来保证数据的一致性。下面是缓存的更新机制:
更新机制包含删除和加载两个部分,上图黑色箭头表示删除缓存的动作,绿色表示加载或触发加载的动作。
-
删除二级缓存:
1、Eureka Client 发送 register、renew 和 cancel 请求并更新 registry 注册表之后,删除二级缓存;
2、Eureka Server 自身的 Evict Task 剔除服务后,删除二级缓存;
3、二级缓存本身设置了 guava 的失效机制,隔一段时间后自己自动失效;
- 加载二级缓存:
1、Eureka Client 发送 getRegistry 请求后,如果二级缓存中没有,就触发 guava 的 load,即从 registry 中获取原始服务信息后进行处理加工,再加载到二级缓存中。
2、Eureka Server 更新一级缓存的时候,如果二级缓存没有数据,也会触发 guava 的 load。
更新一级缓存:
Eureka Server 内置了一个 TimerTask,定时将二级缓存中的数据同步到一级缓存(这个动作包括了删除和加载)。
关于缓存的实现参考 ResponseCacheImpl
三、eureka高可用原理分析
前面讲了eureka是基于AWS开发出来的框架,因此eureka天生的支持region和availabilityZone的概念。
1、默认情况下面不同region是相互隔离的,region之间的数据是不会复制的,但是eureka client提供了fetch-remote-regions-registry配置,作用是拉取远程的注册信息到本地
2、availabilityZone,eureka中默认eureka-client-prefer-zone-eureka配置为true,也就是拉取serverUrl时候,默认选取和应用实例同一个zone的eureka server列表。
1、客户端高可用原理
(1)在client启动之前,如果没有eureka server,则通过配置eureka.client.back-registry-impl从备份的registry读取关键服务的信息。
(2)在client启动后,如果运行时候server全部挂掉了,本地内存有localRegion之前获取的数据。
(3)如果是server部分挂了。如果预计恢复时间比较长,可以人工介入,通过配置中心人工摘除服务(但是基本不用这样做)。在client中会维护一份不可用的server列表,一旦心跳时候失败,当该列表的大小超过指定的阈值时候就会进行重新清空,重新清空后,client会进行重试(默认3次)
2、服务端高可用原理
服务端采用peer to peer的架构模式,原则上就是高可用的。同时服务端还可以通过配置remoteRegionUrlsWithName来支持拉取远程的region实例,如果当前的region挂了,会自动fallback到远程的region获取数据
同时服务端采用renew租约和定时心跳的方式保护注册信息(self preservation机制)
四、代码实操
1、Eureka服务器
(1) maven
org.springframework.cloud spring-cloud-starter-netflix-eureka-server
(2)创建启动类
package com.cloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/** * @author :jizhibing * @date :Created in 2022/4/17 * @description: */@EnableEurekaServer@SpringBootApplicationpublic class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); }}
(3)创建配置文件 application.yml
server: port: 10010spring: application: name: eurekaservereureka: client: service-url: defaultZone: http://127.0.0.1:10010/eureka
2、Eureka客户端
(1)maven 导入
org.springframework.cloud spring-cloud-starter-netflix-eureka-server
(2)代码引入
由之前代码写死具体 ip+端口 的URL 改为 服务名访问。
例:http://localhost:8881/user/ 改为 http:/userserver/user/
package com.cloud.order.service;import com.cloud.order.mapper.OrderMapper;import com.cloud.order.pojo.Order;import com.cloud.order.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;@Servicepublic class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private RestTemplate restTemplate ; public Order queryOrderById(Long orderId) { // 1.查询订单 Order order = orderMapper.findById(orderId); //2.利用restTemplate 发起http请求,查询用户// String url = "http://localhost:8881/user/"+order.getId(); String url = "http://userserver/user/"+order.getId(); User user = restTemplate.getForObject(url,User.class); //3.设置用户信息 order.setUser(user); // 4.返回 return order; }}
(3)application.yml 添加Eureka服务器地址信息
eureka: client: service-url: defaultZone: http://127.0.0.1:10010/eureka
3、展示效果
代码资源下载:
https://pan.baidu.com/s/169SFtYEvel44hRJhmFTRTQ
提取码:1234参考:
重新定义springcloud
深度剖析服务发现组件Netflix Eureka
其他资料