为什么要有注册中心
注册中心很多时候都有听过,如何理解注册中心?在分布式系统中,倘若要找到一个服务的是哪里提供的是一件不容易的事情。在上千个节点中找到他光靠配置文件并不是一件靠谱的事情,假设是配置文件,某个节点异常挂掉了怎么办,这时候就需要用到注册中心了。
注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。
为什么需要注册中心
要了解为什么需要注册中心,那我们就需要知道注册中心解决了什么问题。理解了下面这些问题就知道为什么要注册中心了。
- 服务注册后,如何被及时发现?
- 服务宕机后,如何及时下线?
- 服务如何有效的水平扩展?
- 服务发现时,如何进行路由?
- 服务异常时,如何进行降级?
- 注册中心如何实现自身的高可用?
常见的注册中心有哪些
- Zookeeper(老牌注册中心,满足CP,后续详细介绍)
- Redis(很少以Redis做注册中心,dubbo可以支持)
-
Eureka(spring cloud的注册中心,Eurkea 2.x分支不再维护,满足AP)
市面上使用的最多,具体不细说了,各位可以baidu
-
etcd(灵感来源于Zookeeper,也是CP的)
- 更轻量级、更易用
- 高负载下的稳定读写
- 数据模型的多版本并发控制
- 稳定的watcher功能,通知订阅者监听值的变化
- 客户端协议使用gRPC协议,支持go、C++、Java等,而Zookeeper的RPC协议是自定制的,目前只支持C和Java
- 可以容忍脑裂现象的发生
-
Consul(K/V值存储)
- docker 实例的注册与配置共享
- coreos 实例的注册与配置共享
- vitess 集群
- SaaS 应用的配置共享
-
与 confd 服务集成,动态生成 nginx 和 haproxy 配置文件
- 使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft.
- 支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等. zookeeper 和 etcd 均不提供多数据中心功能的支持.
- 支持健康检查. etcd 不提供此功能.
- 支持 http 和 dns 协议接口. zookeeper 的集成较为复杂, etcd 只支持 http 协议.
- 官方提供web管理界面, etcd 无此功能.
- Nacos(Spring Cloud Eureka + Spring Cloud Config) 阿里开源的注册中心
开始我们的注册中心(zk)
- 准备工作,本地电脑上装个zookeeper(具体自己去baidu)
- 注册重要做什么事情,将其抽象成 抽象类或者接口
public abstract class RegisterCenter {
@Setter
private Map<String, String> registerParam = new HashMap<>();
public void start()
{
start(registerParam);
}
/**
* start
*/
public abstract void start(Map<String, String> param);
/**
* stop
*/
public abstract void stop();
/**
* register service, for mult
*
* @param keys service key
* @param value service value/ip:port
* @return
*/
public abstract boolean register(Set<String> keys, String value);
/**
* remove service, for mult
*
* @param keys
* @param value
* @return
*/
public abstract boolean remove(Set<String> keys, String value);
/**
* discovery services, for mult
*
* @param keys
* @return
*/
public abstract Map<String, TreeSet<String>> discovery(Set<String> keys);
/**
* discovery service, for one
*
* @param key service key
* @return service value/ip:port
*/
public abstract TreeSet<String> discovery(String key);
}
- 无论用什么注册中心,封装一下,实现这种接口就行了
基于zk作为存储介质,入口如下:
//开启注册中心 private void start(String zkAddress, String zkDigest, String env) { zkEnvPath = zkBasePath.concat("/").concat(env); yoyoZkClient = new YoyoZkClient(zkAddress, zkEnvPath, zkDigest, new ZkRegisterCenterWatcher(this)); yoyoZkClient.initClient(); refreshThread = new ZkRegisterCenterRefreshThread(this); refreshThread.setName("ZkRegisterCenterRefreshThread"); refreshThread.setDaemon(true); refreshThread.start(); log.info("yoyo-rpc, ZkRegisterCenter init success. [env={}]", env); }* ZkRegisterCenterRefreshThread: * 服务信息异常兜底方案(开启刷新线程,定时刷新) * YoyoZkClient: * zk的客户端操作封装,与服务信息的存储方式相关 * ZkRegisterCenterWatcher: * 远端服务信息发生了改变的一个Hook,刷新本地缓存。
具体代码可以在(https://github.com/tbkk/yoyo-rpc)看到
总结
这就是见到的注册中心,如果需要使用自研注册中心,实现以上接口即可。