一. 什么是服务注册?
即将指定服务的 ip:port 注册到集中的注册服务中心,例如,用户服务有6台服务器,我们需要将6台服务器的 ip:port 统一注册到注册服务中心的 ‘UserService’ 下,伪代码如下:
//给User服务申请1个独有的专属名字
UserNameServer = NameServer->apply('UserService');
//User服务下的6台服务器启动后,都去注册自己
UserServer1 = {ip: 192.178.1.1, port: 3445}
UserNameServer->register(UserServer1);
......
UserServer6 = {ip: 192.178.1.6, port: 3445}
UserNameServer->register(UserServer6);
二. 什么是服务发现?
当其他服务(例如订单服务)需要调用用户服务时,可以直接去注册服务中心获取所有用户服务的 ip:port 列表。
//服务发现,获取User服务的列表
list = NameServer->getAllServer('User');
//list的内容
[
{
"ip": "192.178.1.1",
"port": 3445
},
{
"ip": "192.178.1.2",
"port": 3445
},
......
{
"ip": "192.178.1.6",
"port": 3445
}
]
拿到用户服务 ip:port 列表后,订单服务就可以随机或者按照一定的负载均衡算法,取出其中一个用户服务进行访问,
当然,也有些注册服务软件,本身也提供了一定的DNS解析或者负载均衡功能(例如:Eureka),它会直接返回一个可用的IP,直接调用就可以了,不用自己再去选择。
三. 为什么需要服务注册与发现?它的应用场景是什么?
我们先来看下数据请求模型的进化史:
1. WEB1.0 数据请求模型架构
在传统的数据请求架构中,其实是没有什么服务注册和发现之说的。因为请求模型足够的简单。下图是传统的服务请求模型图:
各个客户端请求server服务器,所有的业务逻辑都是在这个server端内完成,这是常见的网络请求模型架构,对于小型的服务而已,这个架构是最合适的,因为它稳定且简单。server服务器的更新和维护也很简单。
2. WEB2.0 数据请求模型架构
后期,随着我们的用户数渐渐变多,单台服务器的压力扛不住的时候,我们就要用到负载均衡技术,增加多台服务器来抗压,后端的数据库也可以用主从的方式来增加并发量,模型如下图所示:
然而这个时候,依然没有服务发现和注册的影子,因为这个架构依然足够的简单和清晰。只要不断的增加后端的server服务器的数量,那么我们的整体稳定性就会得到保证。各个server服务器的更新和维护也依旧很简单。
那么啥时候才需要用到服务注册和发现呢?答案是分布式微服务时代。
3. 微服务时代的服务管理
在微服务时代,我们所有的服务都被劲量拆分成最小的粒度,原先所有的服务都在混在1个server里,现在就被按照功能或者对象拆分成N个服务模块,这样做的好处是深度解耦,1个模块只负责自己的事情就好,能够实现快速的迭代更新。坏处就是服务的管理和控制变得异常的复杂和繁琐,人工维护难度变大。还有排查问题和性能变差(服务调用时的网络开销)
比如还是上面的模型架构,在微服务时代就会变成这样子:
各个微服务相互独立,每个微服务,由多台机器或者单机器不同的实例组成,各个微服务之间错综复杂的相互关联调用。
在不用服务注册之前,我们可以想象一下,怎么去维护这种复制的关系网络呢?答案就是:写死!
例如,上图的订单服务,需要把 用户服务、商品服务、查询服务的所有服务器写死在订单服务的代码中,相应的,如果修改了订单服务的服务器列表,其他服务的配置表也要相应作出修改。
4. 那么,把所有服务器配置在数据库中,实现一个简单的服务注册是否可以呢?
虽然也可以实现服务注册与发现的功能,但是要考虑到高可用性,因为各个服务每次需要调用其他服务时,都需要去服务发现,这会导致高并发,数据库容易成为瓶颈。而且数据库挂了会导致整个服务不可用。
而且服务注册有一个很重要的功能 健康检测
。
四. 什么是服务注册中心的健康检测?
简而言之,就是服务注册中心需要保证注册在自己这里的服务可用性,例如某一台服务器挂了,需要自动把它下线,不再被服务发现。
Eureka 的实现方式是,每个注册在 Service 的 Client 默认每隔30秒会自动像 Service 发送心跳,Service 若是一定周期内,没有接收到某个 Client 的心跳,就会将他自动下线(默认是3个周期,所以手动将某个 Client 服务关闭后,在 90~120秒内,Service 才会将这个服务下线)
五. 什么是 Eureka
Erurka 是 Netflix开发的服务发现框架,遵循的是 CAP原则中的 AP 原则。
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得
1. Eureka 的两大组件
Eureka Service
提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到
Eureka Client
EurekaClient是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳。
1. Eureka 的三个角色
Eureka Service
提供服务注册与发现。
Service Provider
服务提供方,将自身服务注册到Eureka Server,从而使服务消费者能够找到。
Service Customer
服务消费方,从Eureka Server上获取注册服务列表,从而能够消费服务。
Eureka 架构图
当启用多个 Eureka Service 时,不论我们向那个 Eureka Service 进行注册,最终 Eureka 都会自动同步到所有 Eureka Servie(可能不及时,因为 Eureka 不是强一致性)
Eureka Client 既是服务提供者,又是服务消费者
一方面,它将服务注册到 Eureka Service,同时查找其它服务。
另一方面,它对外提供了服务调用。
六. 作为服务注册中心,Eureka 相比于 Zookeeper 优势在哪?
Zookeeper 遵循的是 CAP原则 中的 CP原则,即强调高一致性和分区容错性。
而作为服务注册中心,更需要强调的是可用性,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。
例如,Zookeeper 会出现这样一种情况,当 Master 节点挂掉后,剩余的节点会重新进行 leader 选举,这个时间在 30 ~ 120 秒之前,在选举完成之前,整个注册服务都是不可用的。
而 Eureka 优先保证的就是可用性,首先,各个 Service 节点之间是平等的,即使挂掉了几个节点,剩余节点依然可以注册和服务发现,当 Client 向某个 Service 节点注册或者查询时,发现连接失败,会自动切换至其他 Servie 节点,等其他 Service 节点恢复后,注册信息会自动同步。
另外,Eureka 还有一个自动保护机制,即在一段时间内,发现大范围的失去 Client 节点心跳,就认为是 Client 和 Service 之间发生了网络故障,此时会出现以下几种情况:
- Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
- 当网络稳定时,当前实例新的注册信息会被同步到其它节点中,因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。