分类: LINUX
2016-08-25 08:44:52
服务发现是大多数分布式系统以及面向服务架构(SOA)的一个核心组成部分。这个难题,简单来说,可以认为是:当一项服务存在于多个主机节点上时,client端如何决策获取相应正确的IP和port。
在传统情况下,当出现服务存在于多个主机节点上时,都会使用静态配置的方法来实现服务信息的注册。但是当大型系统中,需要部署更多服务的时候,事情就显得 复杂得多。在一个实时的系统中,由于自动或者人工的服务扩展,或者服务的新添加部署,还有主机的宕机或者被替换,服务的location信息可能会很频繁 的变化。
在这样的场景下,为了避免不必要的服务中断,动态的服务注册和发现就显得尤为重要。
关于服务发现的话题,已经很多次被人所提及,而且也的确不断的在发展。现在,笔者介绍一下该领域内一些open-source或者被经常被世人广泛讨论的 解决方案,尝试理解它们到底是如何工作的。特别的是,我们会较为专注于每一个解决方案的一致性算法,到底是强一致性,还是弱一致性;运行时依 赖;client的集成选择;以后最后这些特性的折中情况。
本文首先从几个强一致性的项目于开始,比如Zookeeper,Doozer,Etcd,这些项目主要用于服务间的协调,同时又可用于服务的注册。
随后,本文将讨论一些在服务注册以及发现方面比较有意思的项目,比如:Airbnb的SmartStack,Netflix的Eureka,Bitly的NSQ,Serf,Spotify and DNS,最后是SkyDNS。
Zookeeper是一个集中式的服务,该服务可以维护服务配置信息,命名空间,提供分布式的同步,以及提供组化服务。Zookeeper是由Java语言实现,实现了强一致性(CP),并且是使用在ensemble集群之间协调服务信息的变化。
Zookeeper在ensemble集群中运行3个,5个或者7个成员。众多client端为了可以访问ensemble,需要使用绑定特定的语言。这种访问形式被显性的嵌入到了client的应用实例以及服务中。
服务注册的实现主要是通过命令空间(namespace)下的。ephemeral nodes只有在client建立连接后才存在。当client所在节点启动之后,该client端会使用一个后台进程获取client的位置信息,并完成自身的注册。如果该client失效或者失去连接的时候,该ephemeral node就从树中消息。
服务发现是通过列举以及查看具体服务的命名空间来完成的。Client端收到目前所有注册服务的信息,无论一个服务是否不可用或者系统新添加了一个同类的服务。Client端同时也需要自行处理所有的负载均衡工作,以及服务的失效工作。
Zookeeper的API用起来可能并没有那么方便,因为语言的绑定之间可能会造成一些细小的差异。如果使用的是基于JVM的语言的话,Curator Service Discovery Extension可能会对你有帮助。
由于Zookeeper是一个CP强一致性的系统,因此当网络分区(Partition)出故障的时候,你的部分系统可能将出出现不能注册的情况,也可能 出现不能找到已存在的注册信息,即使它们可能在Partition出现期间仍然正常工作。特殊的是,在任何一个non-quorum端,任何读写都会返回 一个错误信息。
Doozer是一个一致的分布式数据存储系统,Go语言实现,通过来实现共识的强一致性系统。这个项目开展了数年之后,停滞了一段时间,而且现在也关闭了一些fork数,使得fork数降至160 。.不幸的是,现在很难知道该项目的实际发展状态,以及它是否适合使用于生产环境。
Doozer在集群中运行3,5或者7个节点。和Zookeeper类似,Client端为了访问集群,需要在自身的应用或者服务中使用特殊的语言绑定。
Doozer的服务注册就没有Zookeeper这么直接,因为Doozer没有那些ephemeral node的概念。一个服务可以在一条路径下注册自己,如果该服务不可用的话,它也不会自动地被移除。
现有很多种方式来解决这样的问题。一个选择是给注册进程添加一个时间戳和心跳机制,随后在服务发现进程中处理那些超时的路径,也就是注册的服务信息,当然也可以通过另外一个清理进程来实现。
服务发现和Zookeeper很类似,Doozer可以罗列出指定路径下的所有入口,随后可以等待该路径下的任意改动。如果你在注册期间使用一个时间戳和心跳,你就可以在服务发现期间忽略或者删除任何过期的入口,也就是服务信息。
和Zookeeper一样,Doozer是一个CP强一致性系统,当发生网络分区故障时,会导致同样的后果。
是一个高可用的K-V存储系统,主要应用于共享配置、服务发现等场景。Etcd可以说是被Zookeeper和Doozer催生而出。整个系统使用Go语言实现,使用Raft算法来实现选举一致,同时又具有一个基于HTTP+JSON的API。
Etcd,和Doozer和Zookeeper相似,通常在集群中运行3,5或者7个节点。client端可以使用一种特定的语言进行绑定,同时也可以通过使用HTTP客户端自行实现一种。
服务注册环节主要依赖于使用一个key TTL来确保key的可用性,该key TTL会和服务端的心跳捆绑在一起。如果一个服务在更新key的TTL时失败了,那么Etcd会对它进行超时处理。如果一个服务变为不可用状 态,client会需要处理这样的连接失效,然后尝试另连接一个服务实例。
服务发现环节设计到罗列在一个目录下的所有key值,随后等待在该目录上的所有变动信息。由于API接口是基于HTTP的,所以client应用会的Etcd集群保持一个long-polling的连接。
由于Etcd使用, 故它应该是一个强一致性系统。Raft需要一个leader被选举,然后所有的client请求会被该leader所处理。然而,Etcd似乎也支持从 non-leaders中进行读取信息,使用的方式是在读情况下提高可用性的未公开的一致性参数。在网络分区故障期间,写操作还是会被leader处理, 而且同样会出现失效的情况。
关于作者:
孙宏亮,软件工程师。两年来在云计算方面主要研究PaaS领域的相关知识与技术。坚信轻量级虚拟化容器的技术,会给PaaS领域带来深度影响,甚至决定未来PaaS技术的走向。