微服务中的服务发现

微服务中的服务发现

什么是服务发现

服务发现是微服务架构中的关键机制,用于确定各个微服务的地址。例如,在一个 API Server 服务中,我们可能需要调用 User 服务来处理用户注册、登录和信息查询,也可能需要 Product 服务来获取商品相关信息。那么,如何发现并访问这些服务呢?

传统服务发现方法

最简单的方式是使用数据库存储服务名称及其对应的地址。每当有新的服务实例启动时,我们将其地址注册到数据库中。客户端在访问该服务时,可以从数据库中查询到对应的地址并发起请求。

Kitex 框架中,我们通常使用 ETCD 作为服务注册与发现的数据库,下面通过一个示例演示如何实现。

在 ETCD 中注册服务

在服务启动前,我们需要将其注册到 ETCD 中,以便其他微服务能够发现并访问它:

func kitexInit() (opts []server.Option) {cfg := config.GetConfig()// RegistryAddress为etcd数据库地址r, _ := etcd.NewEtcdRegistry(cfg.Registry.RegistryAddress)// address为user服务的地址address := cfg.KitexConfig.Address + cfg.KitexConfig.Portaddr, _:= net.ResolveTCPAddr("tcp", address)// 保存server的配置信息。opts = append(opts,server.WithServiceAddr(addr),server.WithRegistry(r),server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: cfg.KitexConfig.Service,},),)return
}func main() {config.InitConfig()   // 初始化配置文件db.InitDB()           // 初始化dbopts := kitexInit()   // 初始化服务配置信息svr := user.NewServer(new(UserServiceImpl), opts...) //创建newservererr := svr.Run() // 开启server服务,并实时注册到etcd数据库中if err != nil {log.Println(err.Error())}
}

这样,我们就成功开启了一个服务,并且成功将其注册到etcd数据库中。使其他服务可以通过 ETCD 进行发现和访问。

通过客户端调用服务

在微服务架构中,我们需要使用客户端来调用 User 服务,并通过 ETCD 进行服务发现:

func initUserClient() userservice.Client {// 1. 创建 etcd 服务解析器(连接注册中心)r, err := etcd.NewEtcdResolver(registryAddr)if err != nil {log.Fatalln(r)}// 2. 配置客户端选项:声明使用 etcd 作为服务发现源opts := []client.Option{client.WithResolver(r),}// 生命etcd进行服务发现。userClient, err := userservice.NewClient("douyinec.user", opts...)if err != nil {log.Fatalln(err)}return userClient
}

处理多个服务实例的情况

每次调用userClient客户端时,client会向etcd查询,微服务地址,并发送请求。如果 etcd 里存储了多个 user service 的地址(即多个实例部署了 user service),那么 client 会从 etcd 获取所有可用的 user service 地址,并根据负载均衡策略选择一个进行调用。

Kitex 默认使用随机负载均衡,但可以通过 client.WithLoadBalancer() 设定不同的策略,比如轮询`(Round Robin)、最小连接数(Least Connection)等。

处理服务变更(崩溃或重启)

如果 User 服务实例不可用了,会发生什么?

  1. User 服务启动后,会通过etcd.NewEtcdRegistry(...)注册自身地址到 ETCD
  2. 在运行期间,Kitex 定期向 ETCD 发送心跳,用于维持服务的可用状态。
  3. 如果 User 服务崩溃或手动关闭:
  • 它将停止发送心跳信号
  • ETCD 发现心跳超时(例如 10s 内未收到心跳)
  • ETCD 自动将该 User 服务实例从注册列表中移除

如果 User 服务重新启动到了新的地址,客户端还能找到它吗?

客户端每次请求时都会向 ETCD 查询最新的 User 服务地址,不会缓存旧的地址。

User 服务重新启动并注册到新的地址时,客户端会自动获取最新的服务位置。

这样,无论 User 服务的实例数量如何变化,客户端始终能够找到可用的服务实例,实现了动态的服务发现和负载均衡。

k8s中服务发现的方法

Kubernetes(k8s)中,每个应用服务对应一个 Servicek8s通过service进行服务发现,它充当了访问 Pod 的稳定入口。Service 通过 Endpoint 关联到具体的 Pod,并按照一定的负载均衡策略将请求路由到后端的 Pod。

Service、Endpoint 与 Pod 的关系

在 Kubernetes 中,

  • Pod 是运行应用程序的最小单位,每个 Pod 可能包含一个或多个容器。
  • Service 提供了一个稳定的访问入口,它会自动发现符合标签选择器(selector)的 Pod,并将请求负载均衡地转发给它们。
  • Endpoint 记录了 Service 关联的 Pod 的实际 IP 和端口。

整个流程如下:

  • Service 负责管理和暴露一组 Pod。
  • Endpoint 维护了当前 Service 关联的 Pod 列表。
  • kube-proxy 监听 Service 变更,并基于 Endpoint 配置负载均衡规则。
  • 客户端访问 Service 时,kube-proxy 负责将请求转发给 Endpoint 中的 Pod。

查看当前 Kubernetes 集群中的 Service

我们可以通过kubectl get service -o wide查看当前存在的所有service。实例输出:

kubectl get service -o wide
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                       AGE    SELECTOR
kubernetes     ClusterIP      10.43.0.1       <none>           443/TCP                       297d   <none>
manager        NodePort       10.43.196.96    <none>           8090:32545/TCP                191d   app.oam.dev/component=manager
localstorage   NodePort       10.43.183.49    <none>           8189:30621/TCP                191d   app.oam.dev/component=localstorage
scheduler      NodePort       10.43.8.18      <none>           5525:31965/TCP                191d   app.oam.dev/component=scheduler
redis          NodePort       10.43.167.133   <none>           6379:32155/TCP                191d   app.oam.dev/component=redis

其中 redis 服务的 Cluster-IP 10.43.167.133,我们可以继续查询其 Endpoint。

查看 Service 关联的 Endpoints

使用以下命令查看 kubectl get endpoints redis -o wide。实例输出:

 kubectl get endpoints redis -o wide
NAME    ENDPOINTS         AGE
redis   10.42.0.18:6379   191d

从这里可以看到,redis 服务对应的 Pod 运行在 10.42.0.18:6379

查看 Service 详细信息

之后通过kubectl describe service redis查看详情。实例输出:

IP Families:              IPv4
IP:                       10.43.167.133
IPs:                      10.43.167.133
Port:                     redis  6379/TCP
TargetPort:               6379/TCP
NodePort:                 redis  32155/TCP
Endpoints:                10.42.0.18:6379
Session Affinity:         None
External Traffic Policy:  Local```,

这里,这里的 Endpoints 字段表明,该 Service 的流量被转发到了 10.42.0.18:6379 上运行的 Pod。其中IP字段标识ServiceClusterIPPort: redis 6379/TCP定义Service 的端口映射。TargetPort标识Service 关联的 Pod 实际监听的端口,流量会被转发到该端口。

Service 的服务发现机制

Kubernetes 主要通过两种方式实现服务发现:

  1. 环境变量
  • KubernetesPod 启动时,会为其关联的 Service 自动创建一组环境变量(处于同一namespaceService),例如 REDIS_SERVICE_HOST=10.43.167.133REDIS_SERVICE_PORT=6379,在同一命名空间中的pod可以通过这些环境变量连接 Service
  1. DNS 解析方式
  • Kubernetes 内置的 CoreDNS 服务会为 Service 自动创建 DNS 记录。例如,redis 服务的DNS 记录是 redis.default.svc.cluster.local,集群内部的 Pod 直接访问 redis:6379 即可连接。其中default是服务所在的命名空间

我们运行ping redis.default.svc.cluster.local,发现返回ip地址10.42.0.18,即redis service的地址。

redis.default.svc.cluster.local被称为 FQDN(Fully Qualified Domain Name,全限定域名)。

全限定域名信息存储在 Kubernetes 内部的 CoreDNS 组件中。其中Kubernetes API Server 监听 Service 资源的创建或删除。CoreDNS 通过 kube-dns 插件 监听这些变化,并在内部的 DNS 服务器 里维护这些 Service 的解析记录。当 Pod 需要访问 Service,会向 CoreDNS 查询 xxx.namespace.svc.cluster.localCoreDNS 解析出 ClusterIP 并返回给 Pod,这样 Pod 就能访问 Service 了。

Service 的负载均衡原理

当多个 Pod 运行同一个 Service 时,Kubernetes 通过 kube-proxy 进行负载均衡,主要有以下几种模式:

  • iptables(默认)kube-proxy 使用 iptables 规则将流量随机转发到 Endpoints

  • IPVS(更高效):使用 IP Virtual Server 进行流量分发,支持更多的负载均衡策略(如 rr 轮询、wrr 权重轮询、lc 最小连接数等)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/73166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#与西门子PLC的六大通信库

C#与西门子PLC的六大通信库&#xff1a; 一、S7.NET S7.NET是一款开源的S7协议通信库&#xff0c;支持西门子S7通信。 二、Sharp7 Sharp7与S7.NET一样&#xff0c;是一款.NET版本的S7通信库。 三、Snap7 Snap7是一个开源的C通信库&#xff0c;支持西门子S7通信。 四、Prodave P…

IOS接入微信方法

导入SDK 和配置 SDK 的不做介绍&#xff1b; 1 在IOS 开发者中心 Identifiers 打开‘Associated Domains’ 2 建立一个文件&#xff08;不带后缀的&#xff09;apple-app-site-association, teamid在 IOS 开发者中心的会员找&#xff0c;appid在 xcode里面找 {"applin…

DHCPv6 Stateless Vs Stateful Vs Stateless Stateful

DHCPv6常见配置模式 在 IPv6 网络中,DHCPv6 的 Stateless(无状态)、Stateful(有状态) 和 Stateless + Stateful(混合模式) 是三种常见的配置模式。它们的主要区别在于客户端如何获取 IPv6 地址和其他网络配置信息(如 DNS 服务器)。 Stateless(无状态)模式 Statele…

HTTPS协议—加密算法和中间攻击人的博弈

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…

Java替换jar包中class文件

在更新java应用版本的运维工作中&#xff0c;由于一些原因&#xff0c;开发没办法给到完整的jar包&#xff0c;这个时候&#xff0c;就可以只将修改后的某个Java类的class文件替换掉原来iar包中的class文件&#xff0c;重新启动服务即可&#xff1a; 1、将jar包和将要替换的cl…

【UI设计】一些好用的免费图标素材网站

阿里巴巴矢量图标库https://www.iconfont.cn/国内最大的矢量图标库之一&#xff0c;拥有 800 万 图标资源。特色功能包括团队协作、多端适配、定制化编辑等&#xff0c;适合企业级项目、电商设计、中文产品开发等场景。IconParkhttps://iconpark.oceanengine.com/home字节跳动…

【10】高效存储MongoDB的用法

目录 一、什么是MongoDB 二、准备工作 &#xff08;1&#xff09;安装MongoDB ​&#xff08;2&#xff09;安装pymongo库 三、连接MongoDB 四、指定数据库 五、指定集合 六、插入数据 &#xff08;1&#xff09; insert 方法 &#xff08;2&#xff09;insert_one(…

MATLAB+Arduino利用板上的按键控制板上Led灯

几年不使用&#xff0c;之前的知识都忘掉了。需要逐步捡起来。 1 熟悉按键的使用 2熟悉灯的控制 1 电路 我们将通过 MATLAB 的 Arduino 支持包与 Arduino 板通信&#xff0c;读取按键状态并控制 LED 灯的亮灭。 按键&#xff1a;连接到 Arduino 的数字引脚&#xff08;例如…

《深度学习》——YOLOv3详解

文章目录 YOLOv3简介YOLOv3核心原理YOLOv3改进YOLOv3网络结构 YOLOv3简介 YOLOv3&#xff08;You Only Look Once, version 3&#xff09;是一种先进的实时目标检测算法&#xff0c;由 Joseph Redmon 和 Ali Farhadi 开发。它在目标检测领域表现出色&#xff0c;具有速度快、精…

【项目设计】网页版五子棋

文章目录 一、项目介绍1.项目简介2.开发环境3.核心技术4.开发阶段 二、Centos-7.6环境搭建1.安装wget工具2.更换软件源(yum源)3.安装scl工具4.安装epel软件源5.安装lrzsz传输工具6.安装高版本gcc/g编译器7.安装gdb调试器8.安装git9.安装cmake10.安装boost库11.安装Jsoncpp库12.…

在coze工作流中将数据回写到飞书表格

在coze工作流中将数据回写到飞书表格

并查集(竞赛)

一、模型建立 本质就是一个数组&#xff0c;数组的下标对应节点的编号&#xff0c;数组的值对应对应编号的节点的父节点。规定根节点的父节点是自己。 规定三个集合的根节点分别是1 4 6 二、并查集操作并实现 并查集主要操作&#xff1a;查找一个节点的父节点&#xff0c;判…

Leetcode 刷题笔记1 图论part04

leetcode 110 字符串接龙 def judge(s1, s2):count 0for i in range(len(s1)):if s1[i] ! s2[i]:count 1return count 1if __name__ __main__:n int(input())begin_str, end_str map(str, input().split())if begin_str end_str:print(0)exit()strlist []for _ in ran…

从扩展黎曼泽塔函数构造物质和时空的结构-7

有了先前关于电荷之间吸引和排斥关系的频率分析图&#xff0c;我们可以按照类似的方法&#xff0c;对磁场做一样的分析&#xff0c;即分析磁体同极相斥&#xff0c;异极相吸的本质。 我们知道上图得以成立的原因在于磁感线&#xff0c;如下图所示的排布方式&#xff0c; 磁体的…

AI比人脑更强,因为被植入思维模型【18】万物系统思维模型

把事物看成链&#xff0c;看成网&#xff0c;看成生态。 定义 万物系统思维模型是一种将宇宙万物视为一个相互关联、相互作用的整体系统的思维方式。它强调从系统的角度去认识、分析和解决问题&#xff0c;认为系统中的各个要素之间存在着复杂的相互关系&#xff0c;这些关系不…

Qt-Q_ENUM宏和QMetaEnum类

Q_ENUM是一个宏定义&#xff0c;它的作用是将一个枚举类型注册到元对象系统&#xff0c;从而能够通过QMetaEnum类获得一些关于enum类型的一些信息&#xff0c;例如获取enum类型的名称字符串&#xff0c;enum值和字符串互相转换&#xff0c;enum类型保存在QVariant中&#xff0c…

MongoDB 配合python使用的入门教程

MongoDB 入门教程 1. 安装 MongoDB 首先&#xff0c;你需要在你的机器上安装MongoDB。你可以从 MongoDB官网 下载并安装 Community 版本。安装完成后&#xff0c;启动MongoDB服务。 # 在Linux/Mac上启动MongoDB mongod# 在Windows上&#xff0c;你可以通过Windows服务启动Mo…

【云馨AI-大模型】大模型的开发和应用中,Python、PyTorch和vLLM关系概括

说明 1. Python 定位&#xff1a;基础编程语言。作用&#xff1a;Python 是大模型生态系统的核心语言&#xff0c;几乎所有深度学习框架&#xff08;如 PyTorch、TensorFlow&#xff09;和工具链&#xff08;如 vLLM&#xff09;都通过 Python 接口提供服务。特点&#xff1a…

西门子200smart之modbus_TCP(做主站与第三方设备)通讯

西门子200smart做MODBUS_TCP主站通讯,只有一个指令。设置相关参数即可完成读写操作。整 个过程非常复杂,操作非常严谨。此次,我们使用汇川EASY系列PLC做从站,完成演示。关于汇川案例的演示,详见汇川EASY系列之以太网通讯(MODBUS_TCP做从站)-CSDN博客 关于主站和从站的介…

缓存设计模式

缓存设计模式&#xff08;Cache Design Pattern&#xff09;是一种用于存储和管理频繁访问数据的技术&#xff0c;旨在提高系统性能、降低数据库或后端服务的负载&#xff0c;并减少数据访问延迟。以下是几种常见的缓存设计模式&#xff0c;并用 Python Redis 进行示例代码实现…