注册中心没那么玄乎,其实可以简单理解为:
提供一个存储介质,供服务提供者和服务消费者共同连接,而存储的主要信息就是这里的 URL。
一个完整的注册中心需要实现以下功能:
- 接收服务端的注册与客户端的引用,即将引用与消费建立关联,并支持多对多。
- 当服务端发生变化时,能及时更新状态,通知客户端。
- 当注册中心重启时,能自动恢复注册数据,以及订阅请求。
注册中心的角色分工
- Server端
a. 服务启动后向注册中心注册一个自己的实例。
b. 定期向注册中心发送心跳。
c. 服务关闭时向注册中心发起注销。 - Client端
a. 服务启动后向注册中心订阅所需的服务(Server),并缓存到实例列表。
b. 向服务(Server)发起调用时,从内存中对应的实例列表选择一个,进行远程调用。
c. 服务关闭时向注册中心取消订阅。 - 注册中心
a. Server端超过一定时间未提供心跳时,从服务的实例列表移除。
b. 服务的实例列表发生变化(新增或移除)时,通知订阅该服务的Client端去刷新本地缓存。(Eureka不提供此功能,Client定期轮询)
如何实现注册中心
服务注册接口
public interface RegistryService {
//1. 向注册中心注册服务
void register(URL url);
//2. 从注册中心摘除服务
void unregister(URL url);
//3. 将服务设置为可用,供客户端调用
void available(URL url);
//4. 禁用服务,客户端无法发现该服务
void unavailable(URL url);
//5. 获取已注册服务的集合
Collection<URL> getRegisteredServiceUrls();
}
服务发现接口
public interface DiscoveryService {
//1. 订阅服务
void subscribe(URL url, NotifyListener listener);
//2. 取消订阅
void unsubscribe(URL url, NotifyListener listener);
//3. 发现服务列表
List<URL> discover(URL url);
}
URL类定义
public class URL {
private String protocol;//协议名称
private String host;
private int port;
// interfaceName,也代表着路径
private String path;
private Map<String, String> parameters;
private volatile transient Map<String, Number> numbers;
}
注册中心实际存储了什么?
以dubbo+zookeeper举例
整个zookeeper的路径概览:
- /dubbo: root 目录, 持久化目录 (可通过 group=xxx 自定义root目录)
- /dubbo/xxx.xx.XxxService: 每个服务一个路径,持久化目录
- /dubbo/xxx.xx.XxxService/configurators: 配置存放路径,默认为空
- /dubbo/xxx.xx.XxxService/providers: 服务提供者目录,所有提供者以其子路径形式存储,持久化目录。
- /dubbo/xxx.xx.XxxService/consumers: 服务消费者目录, 持久化路径。
- /dubbo/xxx.xx.XxxService/routers: 路由配置信息,默认为空
示例Server服务端
dubbo://192.168.56.1:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-api-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=112756&release=&side=provider×tamp=1588548412331
将上述进行URLEncode,即为实际的节点
示例Client客户端
consumer://192.168.1.4/org.apache.dubbo.rpc.service.GenericService?application=dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&generic=true&interface=org.apache.dubbo.demo.DemoService&pid=139620&side=consumer&sticky=false×tamp=1588596195728
将上述进行URLEncode,即为实际的节点