Skip to main content
Version: v5.3

服务注册和服务发现

服务注册

服务为什么需要注册

在云原生环境下,服务的通信地址可能是不确定的,根据生命周期的变化而变化,同时其还有可能有多个运行实例。那么其他服务需要与去通信的前提是需要发现服务的通信地址,因此服务需要通过服务注册来将自己的通信地址和运行状态注册到服务注册中心,比如SpringCloud架构有eureka注册中心。

服务注册粒度和范围

Rainbond服务注册的粒度是端口级别,也就是说如果服务组件有多个端口它可以分别控制注册。同时为了区分服务是对外网提供服务(通过应用网关)还是对内网提供服务(通过ServiceMesh),Rainbond为服务的每个端口设置了两种注册范围。

服务注册方式

由于Rainbond不同于SpringCloud架构还提供了服务运行环境,因此Rainbond的服务注册是自动的,即服务实例启动就会注册到注册中心。但是需要用户指定注册范围,开启了对内服务或者对外服务。

服务发现

服务发现与服务注册是对应的概念,即服务A希望访问服务B时,需要先获取对方的服务地址。Rainbond提供了两种服务发现策略。

声明式服务发现

所谓声明式服务发现即服务A需要访问服务B时,需要显式的在Rainbond设置依赖关系,即A依赖B。当建立依赖关系以后,服务A的同一个网络空间内的Mesh服务会通过XDS协议从Rainbond服务注册中心获取服务B的所有运行健康的服务实例,从而建立本地的监听来对服务B进行负载均衡。 对于服务A来说,访问B的方式是固定的本地地址,比如访问服务B的8080端口,访问地址即是127.0.0.1:8080。此地址可以在代码中固定配置或通过相应的环境变量获取。 由此可以得出,Rainbond的服务发现是对业务层透明的,即用户的业务不需要处理服务发现的逻辑,Mesh层会自动完成。根据Mesh层的自定义路由配置和负载均衡算法配置,目前此方式主要支持无状态服务、单实例有状态服务和可以无差别多实例运行的有状态集群服务。

基于DNS的服务发现

除了上文提到的服务类型,还有一类服务通信比较特殊,比如以下场景:

  1. 集群化服务,支持水平扩容,实例之间需要通信。比如zookeeper、etcd等
  2. 主从集群服务,从实例需要与主实例通信。比如Mysql主从集群,Redis主从复制集群

对于上诉服务主要涉及到同一个服务的多个实例间通信。此类需求必须将服务类型设置为有状态服务

通过固定的DNS解析的方式进行服务发现:

对于已经部署的有状态服务,我们可以进入容器查看主机名,如下图:

从中你可以看到,服务实例的主机名是按照如下规则生成的:

服务别名-服务实例编号.服务别名.租户ID.svc.cluster.local

对于不同的服务涉及的变量主要如下:

  • 服务别名,可以通过获取环境变量SERVICE_NAME 获取
  • 服务实例编号,根据实例数量从0开始依次编号。它们的启动顺序和更新数据都会按照编号顺序进行,因此一般编号0会作为特殊实例,比如主从集群的主实例。
  • 租户ID,可以通过获取环境变量TENANT_ID 获取

通过上述分析你应该已经理解了,当你需要发现当前服务的所有已运行实例地址时,可以以DNS的nslookup方式获取服务别名.租户ID.svc.cluster.local域名的NS记录。此方式有很多现成的实现工具.比如参考: cockroachdb服务源码

如果需要与主节点通信,直接请求主节点的域名即可。比如 服务别名-0.服务别名.租户ID.svc.cluster.local