go实战案例:如何在 Go-kit 和 Service Meh 中进行服务注册与发现?

今天分享的是如何在Go-kit和ServiceMesh中进行服务注册与发现的案例。

在上文中,我们基于搭建好的 Consul 集群,通过 Consul 中提供的 HTTP API 实现了 register 的服务注册与发现功能。我们采用手动构造HTTP请求的方式,在服务启动时发送服务实例数据到Consul中完成服务注册,在服务关闭时向Consul请求服务注销,并通过Consul提供的服务发现接口根据服务名获取可用的服务实例信息列表。

在本文,我们将使用Go-kit提供的服务注册与发现工具包完成服务注册与发现,并介绍ServiceMesh中Istio是如何进行服务注册与发现的。

使用Go-kit服务注册与发现工具包

自主开发服务注册与发现客户端固然能够加深我们对微服务和服务注册与发现中心 交互流程的理解,但同样会增加开发人员的理解成本,比如要了解服务注册与发现中心对外提供的接口、提交数据的具体细节,以及在服务注册与发现中心版本升级迭代或者API发生更新时,还需要持续维护客户端代码以避免不可用情况的发生,等等。
Go-kit作为一套微服务工具集 ,意在帮助开发人员解决微服务开发中遇到的绝大多数问题,让他们更专注于业务开发。

Go-kit 提供了诸多服务注册与发现组件的客户端实现,支持包括 Consul、Etcd、ZooKeeper和 Eureka在内的多种服务注册与发现中心。下面我们以Consul为例,实践如何使用Go-kit的sd 包简化微服务服务注册与发现的实现
sd包中提供如下注册和注销接口,代码如下所示:

Go 复制代码
type Registrar interface {
    Register() //服务注册
    Deregister()//服务注销
}

在Go-kit中,我们根据选定的服务注册和发现组件,实例化 Registrar 接口对应的结构体实现,即可使用同样的接口进行服务注册和服务注销。接下来我们实例化sd/consul包下的Registrar用于完成与Consul的交互,实例化代码如下:

Go 复制代码
func NewDiscoveryclient(host string, port int, registration
*api.AgentServiceRegistration) (*Discoveryclient, error) {
    config := api.DefaultConfig()
    config.Address = host + ":" + strconv.Itoa(port)
    // 生成 hashicorp client
    client, err := api.Newclient(config)
    if err != nil{
        return nil, err
    }
    // 使用 hashicorp client 生成 sd consul client
    sdclient := consul.Newclient(client)
    return &Discoveryclient{
        client: sdclient,
        config: config,
        registration: registration,
        register: consul.NewRegistrar(sdclient, registration,
log.NewLogfmtLogger(os.Stderr)),
    }, nil
}

DiscoveryClient.register 即最终实例化的 Consul 注册器。从实例化的过程可以发现 Consul Registrar的实现依赖于 sd.consul.client, 而 sd.consul.client 实现依赖于 hashicorp client,即 Consul 的官方实现客户端。深入hashicorp client客户端中的服务注册与发现的实现,会发现它也是通过请求ConsulAgent 提供的HTTP API 完成的,实现的方式与我们在上一课时中的实践大同小异。

api.AgentServiceRegistration 结构体即需要提交到 Consul 中的服务实例信息,包含服务名、服务实例ID、服务地址和服务端口等基本信息。
然后我们的服务注册和服务注销实现就可以委托给Register执行,如下所示:

Go 复制代码
func (consulclient *Discoveryclient) Register(ctx context.Context) {
    consulclient.register.Register()
}
func (consulclient *Discoveryclient) Deregister(ctx context.Context) {
    consulclient.register.Deregister()
}

服务发现的实现也是直接调用sd.consul.client提供的相关方法。通过使用Go-kit提供的Consul 工具包,可以在不了解微服务与Consul具体交互逻辑的基础上,通过简单调用包中提供的方法即可完成服务注册与发现,大大减轻业务人员的开发工作。

Service Mesh 中 Istio 服务注册与发现

ServiceMesh作为下一代的微服务架构,它将服务间的通信从基础设施中抽离出来,达到交付更可靠的应用请求、监控和控制流量的目的。Service Mesh一般与应用程序一同部署,作为"数据平面"代理网络以及"控制平面"代替应用与其他代理交互。ServiceMesh的出现让业务开发人员从基础架构的底层细节中解放出来,从而把更多的精力放在业务开发上,提高需求迭代的效率。

**Istio作为ServiceMesh的落地产品之一,依托Kubernetes快速发展,已经成为最受欢迎的ServiceMesh之一。**Istio在逻辑上分为数据平面和控制平面。

  • 数据平面,由一组高性能的智能代理(基于Envoy 改进的istio-proxy)组成,它们控制和协调了被代理服务的所有网络通信,同时也负责收集和上报相关的监控数据。
  • 控制平面,负责制定应用策略来控制网络流量的路由。Istio由多个组件组成,核心组件及其作用为如下:
  • Ingressgateway,控制外部流量访问Istio 内部的服务。
  • Egressgateway,控制Istio 内部访问外部服务的流量。
  • Pilot,负责管理服务网格内部的服务和流量策略。它将服务信息和流量控制的高级路由规则在运行时传播给Proxy,并将特定平台的服务发现机制抽象为Proxy可使用的标准格式。
  • Citadel,提供身份认证和凭证管理。
  • Galley,负责验证、提取、处理和分发配置。
  • Proxy,作为服务代理,调节所有ServiceMesh 单元的入口和出口流量。

lstio Architecture

Istio 架构图

这其中 Proxy属于数据平面,以 Sidecar 的方式与应用程序一同部署到 Pod 中,而 Pilot、Citadel和Galley 属于控制平面。除此之外,Istio 中还提供一些额外的插件,如 grafana、istio-tracing、kiali和prometheus,用于进行可视化的数据查看、流量监控和链路追踪等。

Istio默认提供了以下几种安装profile形式,它们开启的组件配置如下表所示(+表示开启,空白表示未开启,-表示未知):

这其中,istiod 组件封装了Pilot、Citadel和 Galley等控制平面组件,将它们进行统一打包部署,降低多组件维护和管理的困难性。从上表可以看出,demo profile是功能最全的配置清单,适合于学习和功能演示。previewprofile将可能使用一些开发阶段的测试组件,开启的组件不定。官方推荐使用default profile进行安装,因为它在核心组件和插件上做到了最优的选择,比如组件只开启了Ingressgateway 和 istiod,插件只开启了 prometheus。

当然我们也可以根据实践的需求选择合适的profile进行安装启动,比如下面的安装命令我们使用的是demo profile:

Go 复制代码
istioctl manifest apply --set profile=demo

上述命令以demo profile部署Istio,该配置下的Istio能够通过可视化界面监控Istio 中应用的方方面面。Istio以 Sidecar 的方式在应用程序运行的Pod 中注入Proxy,全面接管应用程序的网络流入流出。我们可以通过标记Kubernetes命名空间的方式,让Sidecar 注入器自动将Proxy注入在该命名空间下启动的Pod中,开启标记的命令如下:

bash 复制代码
kubectl label namespace default istio-injection=enabled

上述命令中,我们将 default 命名空间标记为istio-injection。如果不想开启命令空间的标记,也可以通过 istioctl kube-inject 为 Pod 注入 Proxy Sidecar 容器。接下来,我们就为 register 服务所在的 Pod 注入Proxy,启动命令如下:

bash 复制代码
istioctl kube-inject -f register-service.yaml I kubectl apply -f -

register 服务的yaml 配置如下:

bash 复制代码
apiversion: apps/v1
kind: Deployment
metadata:
  name: register
  labels:
    name: register
spec:
  selector:
    matchLabels:
      name: register
  replicas: 1
  template:
    metadata:
      name: register
      labels:
        name: register
        app: register  #添加 app 标签
    spec:
      containers :
        - name: register
          image: register
          ports:
            - containerPort: 12312
          imagePullpolicy: IfNotPresent
          # ...省略环境配置
---
# 添加 Service 资源
apiversion: v1
kind: Service
metadata:
  name: register-service
  labels:
    name: register-service
spec:
  selector:
    name: register
  ports:
    - protocol: TCP
      port: 12312
      targetPort: 12312
      name: register-service-http

这主要的改动有:为register 服务添加 Deployment Controller,添加了新的标签 app,以及为register 添加相应的 Service 资源。如果在部署Istio 时启动了 kiali插件,即可在 kiali 平台中查看到register服务的相关信息,通过以下命令即可打开kiali控制面板,默认账户和密码都为 admin:

bash 复制代码
istioctl dashboard kiali

kiali 控制台

从上图可以看出在kiali控制台中存在多个维度查看Istio 中部署的应用:

  • Overview,网格概述,展示Istio内具有服务的所有命名空间;
  • Graph,服务拓扑图;
  • Applications,应用维度,识别设置了app 标签的应用;
  • Workloads,负载维度,检测 Kubernetes 中的资源,包括 Deployment、Job、DaemonSet等,无论这些资源有没有加入Istio 中都能检测到;
  • Services,服务维度,检测 Kubernetes 的 Service;
  • Istio Config,配置维度,查看Istio 相关配置类信息。

register 服务启动后,我们在 Applications、Workloads、Services 维度中均可查看到 register 的身影,如下 Applications 维度图所示:

kiali Applications 维度下的 register

Istio依托Kubernetes 的快速发展和推广,对Kubernetes 有着极强的依赖性,其服务注册与发现的实现也主要依赖于Kubernetes的 Service管理。我们可以通过以下这张图理解Istio的服务注册与发现

lstio Architecture

Istio服务注册与发现逻辑图

通过该逻辑图,我们可以看到Istio服务注册与发现主要有以下模块参与。

  • **ConfigController:**负责管理配置数据,包括用户配置的流量管理和路由规则。
  • **ServiceController:**负责加载各类ServiceRegistry,从ServiceRegistry 中同步需要在网格中管理的服务。主要包含:①KubeServiceRegistry,从 Kubernetes 同步 Service 和 Endpoint 到Istio;②ConsulServiceRegistry,从 Consul 中同步服务信息到Istio;③ExternalServiceRegistry,监听 ConfigController 中的配置变化,获取 ServiceEntry 和WorkloadEntry资源并封装成服务数据提供给ServiceController。
  • **DiscoveryServer:**负责将 ConfigController 中的路由配置信息和 ServiceController 中的服务信息封装成 Proxy 可以理解的标准格式,并下发到 Proxy 中。

Pilot 组件会从各个 Service Registry,比如 Kubernetes 中的 Service 和 Consul 中注册的服务,采集可用的服务数据到Istio 中,并将这些服务转换为Proxy可理解的标准服务格式,下发到Proxy,同时下发的还有用户预先配置的路由规则和流量控制策略。在被代理的应用根据服务标识发起 HTTP 通信时,

Proxy将会从拦截的网络请求中根据服务标识获取对应的服务数据,并根据下发的路由规则选择合适的实例转发请求。

基于Kubernetes 迅速发展的Istio 在服务注册与发现组件上支持最完善的自然也为Kubernetes,这依托于Kubernetes对 Pod、Service 等资源的监控,为服务之间的调用提供弹性、负载均衡、重试、熔断和限流等诸多保障。

而对第三方服务注册与发现组件的集成和支持,比如Consul等,Istio官方的实现仅仅是基本可用的级别,在性能和易用性方面仍需要不断进行打磨和测试。因此,在Istio的落地实践中,建议是与Kubernetes强绑定使用,以达到功能的最优化发挥。

小结

服务注册与发现是微服务架构落地实践的基石之一,因为有中心化的服务注册与发现中心管理大量动态变化的服务实例,使得应用服务可以在无太大压力的条件下进行微服务拆分和横向扩展,大大提升了微服务架构的灵活性和伸缩性。

在本文,我们首先介绍了Go-kit中服务注册与发现工具包,并使用其中的Consul工具包改善了register 服务的服务注册与发现的实现。接着我们介绍了 Service Mesh 中的依依者Istio,以及其服务注册与发现的实现。Istio 本身并不提供服务发现的能力,但是它可以依托Kubernetes 或者第三方的服务注册中心获取服务信息列表,并根据设定的路由规则进行有效的动态调用。

希望通过本文的学习,不仅能加深你对Go微服务中服务注册与发现的认识,也能了解到Istio是如何在代理层实现服务注册与发现。

相关推荐
卷毛的技术笔记8 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
isyangli_blog8 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008118 小时前
FastAPI APIRouter
开发语言·python
Benszen9 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆9 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木9 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
喵个咪9 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
杨充9 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~9 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6169 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang