Eureka简介
Eureka与覆盖网络
Eureka在IP网络的基础上提供了覆盖网络(Overlay Network),所谓覆盖网络,实际上就是在网络上的网络,比如VoIP,DNS,DHT,VxN协议甚至热炒的区块链,它们的特点就是节点间通信与下层IP协议解藕(比如地址,端口,协议等): A用户给B用户打电话,只需要知道对方的电话号码,而不需要对方的IP地址,这里的“电话号码”就可以看作一个NodeId,而电话连线的过程对用户是透明的。
在Eureka中,通过VIP(Virtual IP,同义词,非真正的VIP协议)来表示一个节点集群的ID,节点间通信只需要考虑VIP,而不用考虑其下层网络的属性(是否可用,IP是否又变了等)。
Eureka的数据结构
Eureka实际就是维护了一个远程中心化的Map,key为Virtual IP,也就是Application的名称,Value为可用服务实例列表(Instance)
Map<String, List<ServiceInstance>>
它的函数原型大致如下
void put(KEY vip, List<ServiceInstance> services); // 发送实例到中心服务器
List<ServiceInstance> get(KEY vip); // 通过VIP获取实例
因此,当你看到“云”,“微服务”时,千万不要产生胆怯心理,也不要被忽悠了。Eureka相比于Dubbo等RPC框架简单了许多,更比通信领域简单了太多。普通开发可以在一下午上手,中级开发看完本书后即可了解70%的流程。
与其他组件的对比
从客户端的角度
如果说让我来做个类比的话,那么DNS中的特例“HTTP DNS”就是Eureka最好的类比。HTTP DNS在Android等客户端中广泛使用,客户端向DNS发送域名,服务端返回了一串解析后的IP列表
# 下为OpenDNS的例子
$ curl http://119.29.29.29/d?dn=gitbook.com
104.25.212.20;104.25.213.20
而Eureka也一样,通过向EurekaServer发送VIP(Virtual IP,你可以把它看作内网域名)名称,也返回一串地址,Java代码中对应的请求是
# api-prod-sz1就是vip,它对应了很多Server实例
$ curl localhost:8761/eureka/vips/api-prod-sz1
返回了如下(以XML为例)
<applications>
<versions__delta>-1</versions__delta>
<apps__hashcode>UP_1_</apps__hashcode>
<application>
<name>API-PROD-SZ1</name>
<instance>
<instanceId>10.0.0.4:api-prod-sz1</instanceId>
<hostName>10.0.0.4</hostName>
<app>API-PROD-SZ1</app>
<ipAddr>10.0.0.4</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8080</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
...
</leaseInfo>
<metadata>
<management.port>8080</management.port>
<jmx.port>53894</jmx.port>
</metadata>
...
<vipAddress>api-prod-sz1</vipAddress>
</instance>
</application>
</applications>
因此从客户端黑盒的角度来看,Eureka与HTTP DNS没有很大的差别
Eureka | HTTP DNS | |
---|---|---|
实例粒度 | 节点级 | 节点级 |
侵入式 | 有,也可以使用RESTfulAPI | 无 |
短板 | 老项目不好改 | 需要跨防火墙,维护成本高,背后隐藏着Nginx(upsource等) |
控制域 | 与命名服务直连 | 与命名服务直连 |
用户域 | P2P | P2P |
传输语法 | HTTP | HTTP |
抽象语法 | 按照Wiki的几个API来搞 | 发送一个QueryString即可 |
所以千万不要畏惧Eureka这样的新技术,它们的使用并不需要非常高的编码水平。
网上有很多文章拿Eureka与Nginx进行对比,我认为这个是不公平的,Nginx本身定位是位于防火墙前面向客户的,而Eureka用于内部PRC的。对于我个人来说,Nginx/DNS这一套折腾下来最麻烦的就是防火墙的各种开通,需要各种跳板去调试配置,分析定位速度非常慢。
从CAP的角度
根据CAP定律,C——数据一致性,A——服务可用性,P——服务对网络分区故障的容错性,这三个无法同时满足,因此各个微服务框架均侧重选了2个
Zookeeper | Eureka | |
---|---|---|
C(Consistence) | Y | N |
A(Avaliabilty) | N | Y |
上面说的只是理论问题,实际上Zookeeper在真正生产使用时,稍微请求多一点就跪了,雪崩(连接数太多)直接导致所有服务无法使用,比如在生产环境用遇到过
- 断电(没想到吧) -> Zk持久化EOF错误了 -> 无法启动 -> 负载压到少数机器 -> 慢慢变慢最终爆掉
- 负载过多 -> 连接数下不来 -> 线程卡在Netty的NIO等待,没法更新树->最终爆掉
此外还有Zk难以抓包定位,无可视化界面等问题,这些都需要自己维护定制工具
与Dubbo的关系
- 正如上面的Curl例子所示,Eureka的命名服务主要是通过VIP帮你找到IP,不支持方法级服务的注册发现,因此比基于zk的Dubbo更简化(但是可以用Swagger+Feign来实现)。
- Eureka的增量更新不是原子操作,但是保证最终一致性
- 基于Eureka的RPC一般是HTTP调用,也就是服务端开一个RestController就可以了,比Dubbo等微服务框架侵入性更低
与SpringCloudFunction的关系
Eureka与Spring Cloud Function(FAAS)没有任何关系。Spring的FAAS开源实现目前还不成熟,内部直接用文件做的全局共享,不存在分布式特性
Eureka的主要概念
在Eureka中,Netflix基于AWS设计出了很多Java类
-
EurekaServer: 服务注册发现的实现,你可以把它看作Zookeeper, etcd等
-
EurekaClient: 一个对Eureka的RESTful规范的实现,心跳,注册等流程均通过这里以HTTP请求的形式发出,你暂时可以把它理解为轮询HTTP请求发生器。
-
VIP(Virtual IP): 虚拟IP,命名服务中的Key,类似于域名
-
Feign: 注解形式的HTTP客户端,API基本与Retrofit一致,内部通过动态代理拼装HTTP请求,我之前也写Retrofit的文章,这里就多不介绍了。
-
SpringCloud-xxx: 对上面的包装,重点在于它的AutoConfiguration帮你干了很多重复工作,此外Maven的依赖问题也帮你解决了(老项目的工作量就在这了)