Skip to content

eureka: When the service Metadata is not empty, multiple endpoint registration causes "Endpoints" PC caller to report Zero endpoint found #3818

@mrlaojia

Description

@mrlaojia

问题描述

当服务同时满足以下两个条件时,会触发此 Bug:

  1. 设置了非空的 Metadata,例如 kratos.Metadata(map[string]string{"weight": "10"})
  2. 注册了多个 endpoint,例如同时注册 grpc://http://

register.go 中的 Endpoints() 函数在循环构建 Eureka 实例时,将 service.Metadata引用(而非副本)赋给了每个 Eureka Endpoint 结构体的 MetaData 字段。导致每次循环都在同一个 map 上写入 metadata["Endpoints"],后一次覆盖前一次,最终所有注册到 Eureka 的实例的"Endpoints" 元数据均为最后一个 endpoint 的值

消费方(如 system-perm)通过服务发现解析时,gRPC resolver 找不到grpc:// scheme 的地址,打印如下警告并拒绝更新地址列表:

[resolver] Zero endpoint found,refused to write, instances:
[service-name-id service-name-id]

后续 gRPC 调用因无可用地址而等待超时,最终报错:

rpc error: code = DeadlineExceeded desc = context deadline exceeded   

复现步骤

  1. 启动服务端,同时注册 gRPC 和 HTTP 两个 endpoint,并设置非空
    Metadata:
kratos.Metadata(map[string]string{"weight": "10"}),
kratos.Endpoint(
    grpcURL,  // grpc://192.168.1.100:9000
    httpURL,  // http://192.168.1.100:8000
)
  1. 启动消费方,通过 discovery:///service-name
    方式调用上述服务(gRPC)。

  2. 发起任意 gRPC 调用。

实际结果: rpc error: code = DeadlineExceeded desc = context deadline exceeded

根本原因

register.goEndpoints() 函数:

// https://github.com/go-kratos/kratos/blob/main/contrib/registry/eureka/register.go#L113-L116
for _, ep := range service.Endpoints {
    metadata := make(map[string]string)
    if len(service.Metadata) > 0 {
        metadata = service.Metadata  // ← 仅复制引用,非 deep copy    
    }
    // ...
    metadata["Endpoints"] = ep  // 第1轮: "grpc://..."
                                 // 第2轮: "http://..." →覆盖了第1轮!
    res = append(res, Endpoint{
        MetaData: metadata,      // 所有 Endpoint 共享同一个底层 map  
    })
}

service.Metadata 非空时,所有循环迭代均指向同一个map,"Endpoints" 键的最终值始终为 slice 中最后一个 endpoint(即 http://),gRPC 消费方因此无法发现 grpc:// 地址。

期望行为

每个生成的 Eureka Endpoint 结构体应持有独立的 metadata map,并包含正确的 "Endpoints" 值。

修复方案

metadata := maps.Clone(service.Metadata) // deep copy,非引用复制     
if metadata == nil {
    metadata = make(map[string]string)
}

环境信息

  • github.com/go-kratos/kratos/contrib/registry/eureka/v2 v2.0.0-20260404020628-f149714c1d54
  • github.com/go-kratos/kratos/v2 v2.9.2
  • Go 1.24
  • Eureka Server:Spring Boot Eureka(标准 REST API,namespace: "eureka"

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions