实现一个注册中心咱们要怎么搞?搞些什么呢?缓存
主流的 IP 获取有这几种方法:安全
最简单粗暴的方式,手动配置须要注册的IP。固然这种方式基本没法在生产环境使用,由于微服务基本都是支持水平扩容多机部署的,在配置中写死 IP 地址的方式没法支持一份代码水平扩容,会给运维带来极大的成本。服务器
经过遍历网卡的方式去获取,找到第一个不为本地环回地址的 IP 地址。绝大多数状况下,这个方式比较好用,dubbo 等框架采用的就是这种方法。网络
在一些网络规划比较好的标准化机房中,咱们还能够经过手动指定网卡名,即 interfaceName 的方式来指定使用哪一块网卡所对应的 IP 地址进行注册。session
当上述三种方式都不能有效解决问题的时候,有一个方法就是直接与服务注册中心创建 socket 链接,而后经过socket.getLocalAddress() 这种方式来获取本机的 IP。负载均衡
端口的获取,没有标准化的方案。框架
若是是 RPC 应用,启动的时候都有一个配置来指定服务监听的端口, 注册的时候直接使用配置项的端口值。运维
传统的 WEB 容器所提供的 HTTP 的应用,一样也存在一个配置文件来配置容器的监听端口,注册时候直接使用配置项的端口值。socket
特别的,在 Java 应用的 Spring Boot 框架中,能够经过 EmbeddedServletContainerInitializedEvent. getEmbeddedServletContainer().getPort()来获取。(Spring Boot 版本为 1.x)。微服务
简单地将 IP 和 port 信息注册上去,能够知足基本的服务调用的需求,可是在业务发展到必定程度的时候,咱们还会有这些需求:
固然上述两种方式还不够优雅,由于不能确保不出现 kill -9 这种粗暴的中止方式,并且应用调用服务下线接口也是尝试去调用,对于网络不通等异常场景并无作异常处理。所以,调用客户端仍应该作好负载均衡与 failover 的处理。 更优雅的方式,先将即将中止的应用所对应的权重调成 0,此时上游将再也不调用此应用。这时候的中止应用的操做对服务订阅者彻底没有影响,固然这种场景须要订阅者实现按权重的负载均衡和运维部署工具深度结合。
健康检查分为客户端心跳和服务端主动探测两种方式。
客户端每隔必定时间主动发送“心跳”的方式来向服务端代表本身的服务状态正常,心跳能够是 TCP 的形式,也能够是 HTTP 的形式。 也能够经过维持客户端和服务端的一个 socket 长链接本身实现一个客户端心跳的方式。 ZooKeeper 并无主动的发送心跳,而是依赖了组件自己提供的临时节点的特性,经过 ZooKeeper 链接的 session 来维持临时节点。 可是客户端心跳中,长链接的维持和客户端的主动心跳都只是代表链路上的正常,不必定是服务状态正常。 服务端主动调用服务进行健康检查是一个较为准确的方式,返回结果成功代表服务状态确实正常。
因此如何取舍,仍是须要根据实际状况来决定,根据不一样的场景,选择不一样的策略。
在应用的配置文件中指定服务注册中心的地址,相似于 zookeeper 和 eureka。 指定一个地址服务器的地址,而后经过这个地址服务器来获取服务注册中心的地址,地址服务器返回的结果会随着服务注册中心的扩缩容及时更新。
很经典的 Push 和 Pull 问题。
Push 的经典实现有两种,基于 socket 长链接的 notify,典型的实现如 zookeeper;另外一种为 HTTP 链接所使用 Long Polling。 可是基于 socket 长链接的 notify 和基于 HTTP 协议的 Long Polling 都会存在notify消息丢失的问题。
因此经过 Pull 的方式定时轮询也必不可少,时间间隔的选择也很关键,频率越高服务注册中心所承受的压力也越大。须要结合服务端的性能和业务的规模进行权衡。
还有一种方式,真实的 Push,客户端开启一个 UDP server,服务注册中心经过 UDP 的方式进行数据推送,固然这个也受限于网络的连通性。
一个好的产品,用户使用体验和运维体验必须是优雅的,若是查看本机发布和订阅的服务,只能经过查看日志,甚至是 jmap 的方式来获取,显然体验很是糟糕。 服务注册中心应该提供了丰富的接口,支持根据应用名、IP、订阅服务名、发布服务名,来进行多层次的组合查询。 同时,客户端的内存里,一样也应该保留服务发布与订阅的各类信息,并提供方式供人方便地查询。
好比在 Java 中的 Spring Boot 的应用,能够结合 actuator endpoint,经过 HTTP 的方式来提供本机服务查询功能,查询此应用发布的服务,以及订阅的服务及各服务的对应节点。
当服务节点数愈来愈多时,服务注册中心的性能会成为瓶颈,这时候就须要经过水平扩容来提高服务注册中心集群的性能。
对于那些采用了类 Paxos 协议的强一致性的组件,如ZooKeeper,因为每次写操做须要过半的节点确认。水平扩容不能提高整个集群的写性能,只能提高整个集群的读性能。 而对于采用最终一致性的组件来讲,水平扩容能够同时提高整个集群的写性能和读性能。
首先,本地内存缓存,当运行时与服务注册中心的链接丢失或服务注册中心彻底宕机,仍能正常地调用服务。
而后,本地缓存文件,当应用与服务注册中心发生网络分区或服务注册中心彻底宕机后,应用进行了重启操做,内存里没有数据,此时应用能够经过读取本地缓存文件的数据来获取到最后一次订阅到的内容。
最后,本地容灾文件夹。正常的状况下,容灾文件夹内是没有内容的。当服务端彻底宕机且长时间不能恢复,同时服务提供者又发生了很大的变动时,能够经过在容灾文件夹内添加文件的方式来开启本地容灾。此时客户端会忽略原有的本地缓存文件,只从本地容灾文件中读取配置。
当有新节点加入集群时,节点启动后能自动添加到地址服务器中,并经过地址服务器找到其余节点,自动从其余节点同步数据,以达到数据的最终一致性。
当某个节点宕机时,此服务注册中心节点的信息会自动地址服务器中摘除,客户端能及时感知到此节点已下线。
服务端的无状态性保证了服务的容灾和高可用能够作的很薄。
链路安全,对于使用 HTTP 链接的服务注册中心,保护链路安全的最好方式是使用 HTTPS。而使用 TCP 链接的服务注册中心来讲,因为应用层协议通常使用的是私有协议,不必定存在现成的 TLS 支持方案。
在业务安全方面,应该在每一次的发布、订阅、心跳,都带上鉴权的信息就行验签和鉴权,确保业务信息的安全性。