注册中心概述
假如我们在服务消费者端维护了一个服务提供者的列表,在没有注册中心的情况下,假如新增了一个服务提供者或者某一个提供者下线了,都要去更新服务消费者的配置文件。
引入注册中心之后,就可以实现分布式服务的注册与发现,注册中心是分布式系统的枢纽,其主要作用有如下几点:
- 动态加入。 一个服务提供者通过注册中心可以动态地把自己暴露给其他消费者, 无须消费者逐个去更新配置文件。
- 动态发现。 一个消费者可以动态地感知新的配置、 路由规则和新的服务提供者, 无须重启服务使之生效。
- 动态调整。 注册中心支持参数的动态调整, 新参数自动更新到所有相关服务节点。
- 统一配置。 避免了本地配置导致每个服务的配置不一致问题。
Dubbo注册中心
dubbo可以使用多种注册中心,比如nacos、redis、eureka、zookeeper等。
注册中心上保存的信息
无论使用哪一种注册中心的实现,都要在注册中心上保存四种类型的数据:
- providers: 服务提供者目录,记录着服务提供者的ip、端口等信息。
- consumers: 服务消费者目录,记录服务消费者的元数据信息,服务提供者并不会用到服务消费者的信息,这里要记录消费者的信息,是给服务治理中心(dubbo-admin)使用的。
- routers: 用于消费者路由策略元数据信息。
- configurators:用于服务者动态配置URL元数据信息。
比如,在zookeeper中,上述信息的数据结构如下:
以zookeeper作为注册中心
持久和临时节点
持久节点:节点会一直存在,就算建立该节点的会话断线,节点也会存在。
临时节点:会话存在,节点就存在;会话断开,节点就会被删除。
Watch机制
zookeeper节点发生变化(Znode本身的增加,删除,修改,以及子Znode的变化),zookeeper注册中心可以通过Watch机制通知到客户端。
路径说明
假如我们有一个BarService的服务注册到zookeeper注册中心上,其目录如下:
/dubbo/com.foo.BarService/provider
其中,provider是持久节点,之后会把BarService服务提供者的ip和端口等信息封装成临时节点注册到provider下。
dubbo为root根,我们可以修改服务的group来改变这个根(默认是dubbo)。
服务消费者的服务列表
每一个服务消费者都会在本地维持一张服务提供者的列表,在消费者第一次启动的时候,回去注册中心拉取一次完整的服务列表,然后通过watch机制监听routers、configuration、provider这三个目录的变化。如果新增了服务提供者,或者某一个提供者下线了,消费者就会收到通知,去更新自己的服务列表。
服务提供者的注册操作
当启动一个新的服务,会把服务的ip和端口注册provider下,作为一个临时节点,假如服务提供者宕机,由于是临时节点,所以节点会被删除,这样就可以触发watch机制,服务提供者启动后会监听configuration。
以Redis作为注册中心
pub/sub
Pub/Sub功能即发布及订阅功能。基于事件的系统中,订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。
数据结构
由于redis并没有像zookeeper那样的树形结构,所以redis用的key/Map结构来存储数据。key是/dubbo/com.foo.BarService/provider,对应一个Map,Map的key为URL,value为超时时间。
以Redis作为注册中心
pub/sub
Pub/Sub功能即发布及订阅功能。基于事件的系统中,订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。
数据结构
由于redis并没有像zookeeper那样的树形结构,所以redis用的key/Map结构来存储数据。key是/dubbo/com.foo.BarService/provider,对应一个Map,Map的key为URL,value为超时时间。
实现如watch机制一样的功能
由于redis是没有watch机制的,所以通过pub/sub实现了通知的功能,服务注册之后要发布一条消息,服务注销也要发布一条消息。
替代临时节点的方案
通过pub/sub机制,可以实现服务的注册和发现,但是假如服务宕机了,就无法通过pub/sub机制去通知了,因此redis记录了超时时间,服务提供者注册完成之后,要定时的去更新超时时间,不断的续约。
然而这还是没有解决宕机的问题,这时候就要服务治理中心介入了,服务治理中心需要定时调度,查看服务是否过期,如果过期就删除服务,同时发布通知。所以,以redis作为实现,最终各个组件的关系如下: