微服务中的服务发现

微服务中的服务发现

什么是服务发现

服务发现是微服务架构中的关键机制,用于确定各个微服务的地址。例如,在一个 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.rhkb.cn/news/39023.html

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

相关文章

How to share files with Windows via samba in Linux mint 22

概述 Windows是大家日常使用最多的操作系统&#xff0c;在Windows主机之间&#xff0c;可以共享文件&#xff0c;那么如何在Windows主机与Linux主机之间共享文件呢&#xff1f; 要在Windows主机与Linux主机之间共享文件&#xff0c;我们可以借助Samba协议完成。借助Samba协议…

牛客周赛84 题解 Java ABCDE 仅供参考

A 小苯跑外卖 除一下看有没有余数 有余数得多一天 没余数正好 // github https://github.com/Dddddduo // github https://github.com/Dddddduo/acm-java-algorithm // github https://github.com/Dddddduo/Dduo-mini-data_structure import java.util.*; import java.io.*…

基于SpringBoot + Vue 的图书馆座位预约系统

SpringBoot 图书馆座位预约管理系统 自习室座位预约管理系统 javaSpringbootVUEredis 1. 开发环境&#xff1a; idea/eclipse、jdk1.8、maven、nodejs 2. 技术栈&#xff1a;java、springboot、Redis、mybatis、vue 3. 数据库&#xff1a; MySQL 有用户和管理员两个角色…

深入理解 lt; 和 gt;:HTML 实体转义的核心指南!!!

&#x1f6e1;️ 深入理解 < 和 >&#xff1a;HTML 实体转义的核心指南 &#x1f6e1;️ 在编程和文档编写中&#xff0c;< 和 > 符号无处不在&#xff0c;但它们也是引发语法错误、安全漏洞和渲染混乱的头号元凶&#xff01;&#x1f525; 本文将聚焦 <&#…

Vue 3 + TypeScript 实现视频播放与字幕功能:集成西瓜播放器 XGPlayer

文章目录 1. 前言&#xff1a;视频播放器的重要性2. 准备工作2.1 安装 Vue 3 项目2.2 安装 XGPlayer 和相关依赖 3. 实现视频播放3.1 初始化 XGPlayer 4. 添加字幕功能4.1 配置字幕 4.2 字幕文件格式5. 增加交互性完整的代码&#xff0c;仅供参考6. 总结 在现代 Web 开发中&…

Simple-BEV的bilinear_sample 作为view_transformer的解析,核心是3D-2D关联点生成

文件路径models/view_transformers 父类 是class BiLinearSample(nn.Module)基于https://github.com/aharley/simple_bev。 函数解析 函数bev_coord_to_feature_coord的功能 将鸟瞰图3D坐标通过多相机&#xff08;针孔/鱼眼&#xff09;内外参投影到图像特征平面&#xff0…

HTTP长连接与短连接的前世今生

HTTP长连接与短连接的前世今生 大家好&#xff01;作为一名在互联网摸爬滚打多年的开发者&#xff0c;今天想跟大家聊聊HTTP中的长连接和短连接这个话题。 记得我刚入行时&#xff0c;对这些概念一头雾水&#xff0c;希望这篇文章能帮助新入行的朋友少走些弯路。 什么是HTTP…

在Mac M1/M2芯片上完美安装DeepCTR库:避坑指南与实战验证

让推荐算法在Apple Silicon上全速运行 概述 作为推荐系统领域的最经常用的明星库&#xff0c;DeepCTR集成了CTR预估、多任务学习等前沿模型实现。但在Apple Silicon架构的Mac设备上&#xff0c;安装过程常因ARM架构适配、依赖库版本冲突等问题受阻。本文通过20次环境搭建实测…

c#知识点补充4

1.发布者订阅模式 发布者 订阅者 俩者直接的关联使用

3. 轴指令(omron 机器自动化控制器)——>MC_SetOverride

机器自动化控制器——第三章 轴指令 12 MC_SetOverride变量▶输入变量▶输出变量▶输入输出变量 功能说明▶时序图▶重启运动指令▶多重启动运动指令▶异常 MC_SetOverride 变更轴的目标速度。 指令名称FB/FUN图形表现ST表现MC_SetOverride超调值设定FBMC_SetOverride_instan…

Cocos Creator Shader入门实战(五):材质的了解、使用和动态构建

引擎&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 前面的几篇文章&#xff0c;讲述的主要是Cocos引擎对Shader使用的一些固定规则&#xff0c;这里汇总下&#xff1a; 一、Shader实现基础是OpenGL ES可编程渲染管线&#xff0c;开发者只需关注顶点着色器和…

体育直播模板nba英超直播欧洲杯直播模板手机自适应

源码名称&#xff1a;体育直播模板nba英超直播欧洲杯直播模板手机自适应帝国cms 7.5模板 开发环境&#xff1a;帝国cms7.5 空间支持&#xff1a;phpmysql 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无需人工操作&#xff01; 模板特点&#xff1a; 程序伪静态…

python基于spark的心脏病患分类及可视化(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;汽车数据分析平台当然不能排除在外。本次我所开发的心脏病患分类及可视化系统是在实际应用和软件工程的开发原理之上&#xff0c;运用Pyth…

SAP 附件增删改查与文件服务器交互应用

【需求背景】 非SAP标准附件应用&#xff0c;自定义一套&#xff0c;跟公司内部文档服务器交互&#xff0c;支持各个应用场景的附件增删改查等。 每个附件在文件服务器上都有一个文件唯一ID作为关键字。 应用分两块&#xff1a;SAP GUI端&#xff0c;跟WDA Portal端应用 GU…

Linux__之__基于UDP的Socket编程网络通信

前言 本篇博客旨在使用Linux系统接口进行网络通信, 帮助我们更好的熟悉使用socket套接字网络通信, 学会了socket网络通信, 就能发现所谓网络, 不过都是套路而已, 话不多说, 让我们直接进入代码编写部分. 1. 事先准备 今天我们先来模拟实现一个echo demo, 也就是客户端向服务…

【Agent】Dify Docker 安装问题 INTERNAL SERVER ERROR

总结&#xff1a;建议大家选择稳定版本的分支&#xff0c;直接拉取 master 分支&#xff0c;可能出现一下后面更新代码导致缺失一些环境内容。 启动报错 一直停留在 INSTALL 界面 我是通过 Docker 进行安装的&#xff0c;由于项目开发者不严谨导致&#xff0c;遇到一个奇怪的…

unity开发效率提升笔记

本文将记录提升Unity开发效率的若干细节&#xff0c;持续更新 一.VSCode文件标签多行显示 1.File->Preference->Settings (快捷键Ctrl 逗号) 2.搜索workbench.editor.wrapTabs 3.勾选上这个单选开关 若依然不是多行 4.搜索workbench.editor.tabSizing,选择fi…

python每日十题(6)

列表操作函数有&#xff08;假设列表名为ls&#xff09;&#xff1a; len(ls)&#xff1a;返回列表ls的元素个数&#xff08;长度&#xff09;。min(ls)&#xff1a;返回列表ls的最小元素。max(ls)&#xff1a;返回列表ls的最大元素。list(x)&#xff1a;将x转变为列表类型。使…

【Java】TCP网络编程:从可靠传输到Socket实战

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

使用HAI来打通DeepSeek的任督二脉

一、什么是HAI HAI是一款专注于AI与科学计算领域的云服务产品&#xff0c;旨在为开发者、企业及科研人员提供高效、易用的算力支持与全栈解决方案。主要使用场景为&#xff1a; AI作画&#xff0c;AI对话/写作、AI开发/测试。 二、开通HAI 选择CPU算力 16核32GB&#xff0c;这…