一零年代初,我还自己动手写过socket连接来做服务注册发现,后来有了zookeeper就方便多了,那时候zookeeper也直接做配置中心使用。后来出现了一些专门的服务注册发现组件如Eureka\etcd\consul,专门的配置中心比如spring cloud config\apollo。但是spring cloud全家桶后来又用nacos把注册发现和配置中心合在一起了。
为什么它们能合在一起用同一个服务提供?
因为本质上,注册中心和配置中心都是数据变化了,各个服务可以实时感知。对注册中心来说,服务状态作为了一种特殊的数据。它们核心都在做一件事:数据变化动态感知。
zookeeper采用的是基于会话的长连接,wacher监听机制,对变更事件进行发布监听。zookeeper能承载的连接数是可扩展的。咱们使用基于zookeeper的框架,比如dubbo\hadoop这些,都需要在客户端配置zookeeper集群节点,比如:
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
如果连服务端采用的是随机数算法,即随机选一台服务器进行长连接的话,服务端数量增加,可支持的客户端就可以增加。
但是zookeeper能承载的数据量因为数据模型类似于文件系统,是树状结构,不易于分割,所以受限于硬件。
配置中心在业务上是有约束的,它必须是一个CP的系统。就是说对数据一致性的要求是要高于可用性的。而zookeeper刚好是一个CP的系统。
为什么要将注册中心与配置中心分开?
zookeeper所谓的配置中心和etcd配置中心是一个道理。
将etcd拆开来看,ETC +D(distributed),也就是为分布式系统存储配置信息(这可能和小部分开发者认为的etcd的作用有些出入,很多人潜意识认为etcd就是用于服务发现、发布订阅等,其实这和配置信息没有冲突),当然这个配置信息功能又和业务侧使用的apolo等配置中心有些差异,apolo等配置中心主要用于最上层的业务开发的信息配置,而ETCD则是用于服务注册中心等基本架构的配置。
业务开发的信息配置相比较而言,虽然同样需要数据变更感知,但是数据结构上灵活性大,存储上也更灵活。所以出现了专门的配置中心,比如spring cloud config将数据存储在git仓库中,apollo存储在数据库中。但是它们依赖于注册发现,比如apollo架构上就依赖于eureka。
而只作为注册中心的Eureka不需要像zookeeper一样既可以注册永久节点又可以注册临时节点。Eureka只支持注册临时节点。它是一个AP的系统。
为什么spring cloud全家桶后来又用nacos把注册发现和配置中心合在一起了?
Nacos在注册时可以选择注册临时节点或者永久节点,如果在Nacos上注册临时节点,那么Nacos就是AP服务,保证高可用。如果Nacos上注册永久节点,那么Nacos就是CP服务,保证数据一致性。有了这个条件,距离配置中心,只差一个支持数据库这样的外部存储。
而现代微服务架构更倾向于一体化解决方案,同时兼顾高可用性、数据一致性、集群扩展性以及多地域部署和容灾支持,构建一个功能丰富、易于使用的平台。两个功能同时提供,总体成本更低,维护性更好。
总结
注册中心与配置中心核心都是数据变化动态感知,但使用场景不同。其演变过程经历了根据不同的开发场景进行针对性设计的过程,最终经过对前面设计的去粗取精,结合现代微服务架构的特点进行了一体化设计。
其他
在实际使用eureka的过程中出现过两次线上问题。两次线上问题的本质原因是eureka服务端资源不足,造成排队上下线。
第一次问题是在服务上线时,我猜测线程池队列应该已经溢出,任务直接丢弃了。当时有提过需要加大Eureka的资源,但是负责同学说资源够用,因为监控覆盖的原因,没有直接证据,所以当时没有处理。
第二次问题是在服务下线时,下线有延迟,之后自动恢复。当时的处理有减小缓存时间从默认30s改成10s。但客户端实际1分多才会真正下线,这个时间不是本质原因。本质还是资源不足,任务排队。后来负责同学找到了资源瓶颈点:JVM限制。进行扩容之后解决。在客户端也做了相应的容灾:如果下线失败,重新执行下线。