{"id":45174480,"url":"https://github.com/xkeyideal/grpcbalance","last_synced_at":"2026-02-20T09:08:42.007Z","repository":{"id":64306069,"uuid":"351007456","full_name":"xkeyideal/grpcbalance","owner":"xkeyideal","description":"grpc-go load balancing","archived":false,"fork":false,"pushed_at":"2026-02-04T09:43:53.000Z","size":7950,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-04T14:25:41.435Z","etag":null,"topics":["grpc","grpc-client","grpc-go","load-balancer","random-weighted-round-robin","round-robin","weighted-round-robin"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xkeyideal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-03-24T08:47:01.000Z","updated_at":"2026-02-04T09:43:56.000Z","dependencies_parsed_at":"2023-01-15T10:45:37.440Z","dependency_job_id":"c3c488f0-f1be-4176-85fc-1c8ccb093a67","html_url":"https://github.com/xkeyideal/grpcbalance","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/xkeyideal/grpcbalance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xkeyideal%2Fgrpcbalance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xkeyideal%2Fgrpcbalance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xkeyideal%2Fgrpcbalance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xkeyideal%2Fgrpcbalance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xkeyideal","download_url":"https://codeload.github.com/xkeyideal/grpcbalance/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xkeyideal%2Fgrpcbalance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29646633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T08:48:14.886Z","status":"ssl_error","status_checked_at":"2026-02-20T08:45:26.777Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","grpc-client","grpc-go","load-balancer","random-weighted-round-robin","round-robin","weighted-round-robin"],"created_at":"2026-02-20T09:08:41.511Z","updated_at":"2026-02-20T09:08:42.002Z","avatar_url":"https://github.com/xkeyideal.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## gRPC-go load balancing\n\nThe gRPC-go Require\n\n* Go 1.25+\n* gRPC 1.78.0+\n\n### Version\n\nEach version corresponds to the corresponding version of GRPC-go.\n\nFor example, tag: v1.78.0 -\u003e grpc-go v1.78.0\n\n### Features\n\n- **多种负载均衡算法**: 轮询、加权轮询、随机加权轮询、最少连接、最小响应时间、P2C\n- **熔断器**: 自动隔离故障节点\n- **节点过滤**: 按版本、元数据、地址过滤节点（可选功能，需显式启用）\n- **子集选择**: 大规模部署时限制连接数量\n- **平滑切换**: Picker 更新时不丢失请求\n- **动态端点**: 运行时动态更新服务节点\n- **服务发现**: 支持静态、轮询、etcd、Consul 等多种服务发现方式\n\n### Cautions\n\nv1.45.0 \u0026 v1.46.0-dev running panic like this:\n\n```\npanic: runtime error: comparing uncomparable type MyAttribute\n\ngoroutine 1 [running]:\ngoogle.golang.org/grpc/attributes.(*Attributes).Equal(0xc00015e4b0, 0xc00013c140)\n        /project/vendor/google.golang.org/grpc/attributes/attributes.go:95 +0x194\ngoogle.golang.org/grpc/resolver.addressMapEntryList.find({0xc00013c1b8, 0x1, 0x8000102}, {{0xc00015e4c8, 0x13}, {0xc00015e4c8, 0xd}, 0xc00013c140, 0x0, 0x0, ...})\n        /project/vendor/google.golang.org/grpc/resolver/map.go:49 +0xb9\ngoogle.golang.org/grpc/resolver.(*AddressMap).Get(0xc00013c188, {{0xc00015e4c8, 0x13}, {0xc00015e4c8, 0xd}, 0xc00013c140, 0x0, 0x0, {0x0, 0x0}})\n        /project/vendor/google.golang.org/grpc/resolver/map.go:59 +0x94\nmesh-sidecar/grpclient_balancer/balancer.(*baseBalancer).UpdateClientConnState(0xc00013b500, {{{0xc000414380, 0x3, 0x3}, 0x0, 0x0}, {0x0, 0x0}})\n```\n\nYour `attribute` needs implement `Equal` function. https://github.com/grpc/grpc-go/blob/v1.46.0-dev/attributes/attributes.go#L91\n\n\n```go\ntype MyAttribute struct {\n    attr string\n}\n\nfunc (ma MyAttribute) Equal(o interface{}) bool {\n    return true\n}\n```\n\n### How it works\n\nThe gRPC client-side load balancing to work need to main components, the [naming resolver](https://github.com/grpc/grpc/blob/master/doc/naming.md) and the [load balancing policy](https://github.com/grpc/grpc/blob/master/doc/load-balancing.md)\n\n![load balancing work image](https://github.com/xkeyideal/grpcbalance/blob/master/examples/balancer.png)\n\nThe infra image source [itnext.io](https://itnext.io/on-grpc-load-balancing-683257c5b7b3)\n\n### gRPC naming resolver \u0026 load balancing working principle\n\n[On gRPC Load Balancing](https://itnext.io/on-grpc-load-balancing-683257c5b7b3)\n\n\n### Running the Example Application\n\nThe gRPC client and server applications used in the example are based on the [proto/echo]((https://github.com/grpc/grpc-go/blob/master/examples/features/proto/echo/echo.proto)) \u0026 [load_balancing](https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/README.md) examples found on the **gRPC-go examples** with the following modifications:\n\n* The [server](https://github.com/xkeyideal/grpcbalance/blob/master/examples/server/server.go) running with port args\n* The [client](https://github.com/xkeyideal/grpcbalance/blob/master/examples/client/client.go) used customized balance\n\n### Support Balance Strategy\n\n* round robin [balancer.RoundRobinBalanceName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/roundrobin.go#L11)\n* weighted round robin [balancer.WeightedRobinBalanceName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/weightedroundrobin.go#L11)\n* random weighted round robin [balancer.RandomWeightedRobinBalanceName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/randomweightedroundrobin.go#L11)\n* minimum connection number [balancer.MinConnectBalanceName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/minconnect.go#L11)\n* minimum response consume [balancer.MinRespTimeBalanceName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/minresptime.go#L11), keep 10 response consume time, remove maximum and minimum and then take the average value.\n* **P2C (Power of Two Choices)** [balancer.P2CBalancerName](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/balancer/p2c.go) - 随机选择两个节点，选择负载更低的那个，参考 Kratos 实现\n\n### Examples\n\n项目提供了丰富的使用示例，位于 `examples/` 目录：\n\n| 目录 | 说明 |\n|------|------|\n| [examples/basic](examples/basic) | 基本负载均衡算法使用示例 |\n| [examples/circuitbreaker](examples/circuitbreaker) | 熔断器功能使用示例 |\n| [examples/p2c](examples/p2c) | P2C 负载均衡算法示例 |\n| [examples/filter](examples/filter) | 节点过滤功能示例 |\n| [examples/subset](examples/subset) | 子集选择功能示例 |\n| [examples/graceful](examples/graceful) | 平滑切换 Picker 示例 |\n| [examples/dynamic](examples/dynamic) | 动态端点更新示例 |\n| [examples/discovery](examples/discovery) | 服务发现功能使用示例 |\n| [examples/comprehensive](examples/comprehensive) | 综合使用最佳实践 |\n\n### Configuration\n\n#### 主要配置项\n\n| 配置项 | 类型 | 说明 |\n|-------|------|------|\n| `Endpoints` | `[]string` | 服务端点列表 |\n| `BalanceName` | `string` | 负载均衡算法名称 |\n| `EnableCircuitBreaker` | `bool` | 是否启用熔断器 |\n| `EnableNodeFilter` | `bool` | 是否启用节点过滤功能（默认关闭） |\n| `Discovery` | `discovery.Discovery` | 服务发现实现（设置后 Endpoints 被忽略） |\n| `DiscoveryPollInterval` | `time.Duration` | 服务发现轮询间隔（默认 30s） |\n\n#### 快速开始\n\n```go\npackage main\n\nimport (\n    \"github.com/xkeyideal/grpcbalance/grpclient\"\n    \"github.com/xkeyideal/grpcbalance/grpclient/balancer\"\n)\n\nfunc main() {\n    cfg := \u0026grpclient.Config{\n        Endpoints:   []string{\"127.0.0.1:50051\", \"127.0.0.1:50052\"},\n        BalanceName: balancer.RoundRobinBalanceName,\n        EnableHealthCheck:     true,\n        \n        EnableCircuitBreaker: true, // 启用熔断器\n    }\n    \n    client, err := grpclient.NewClient(cfg)\n    if err != nil {\n        panic(err)\n    }\n    defer client.Close()\n    \n    conn := client.ActiveConnection()\n    // 使用 conn 创建 gRPC 客户端...\n}\n```\n\n#### 使用 P2C 负载均衡\n\n```go\nimport (\n    \"github.com/xkeyideal/grpcbalance/grpclient/balancer\"\n)\n\n// 先注册 P2C 负载均衡器\nbalancer.RegisterP2CBalance()\n\ncfg := \u0026grpclient.Config{\n    Endpoints:   addrs,\n    BalanceName: balancer.P2CBalancerName,\n    EnableHealthCheck:     true,\n}\n```\n\n#### 使用节点过滤\n\n节点过滤是**按请求**选择子集节点的能力，常用于灰度/多 AZ/多机房/租户隔离等场景。\n\n注意：`picker.MetadataFilterKey`（当前值为 `_x_grpc_metadata_`）是框架内部保留 key，用于在 `resolver.Address.Attributes` 中保存“整张 metadata map”。\n请不要在你的服务发现 metadata（例如 `discovery.Endpoint.Metadata`）里使用同名 key；该 key 会被忽略以避免覆盖内部结构。\n\n支持的过滤方式（可组合使用）：\n\n- `picker.LabelSelectorFilter(selector)`（推荐）：一条 selector 表达更复杂的条件\n- `picker.VersionFilter(version)` / `picker.VersionPrefixFilter(prefix)`：按版本过滤\n- `picker.MetadataFilter(key, value)` / `picker.MetadataExistsFilter(key)`：按 metadata 过滤\n- `picker.AddressFilter(addrs...)` / `picker.ExcludeAddressFilter(addrs...)`：按地址白/黑名单\n- `picker.HealthyFilter(checker)`：按自定义健康检查过滤\n\n使用前提：配置里必须显式打开 `EnableNodeFilter`。\n\n```go\nimport (\n    \"context\"\n\n    \"github.com/xkeyideal/grpcbalance/grpclient\"\n    \"github.com/xkeyideal/grpcbalance/grpclient/balancer\"\n    \"github.com/xkeyideal/grpcbalance/grpclient/picker\"\n)\n\ncfg := \u0026grpclient.Config{\n    Endpoints:        addrs,\n    BalanceName:      balancer.RoundRobinBalanceName,\n    EnableNodeFilter: true,\n    EnableHealthCheck:     true,\n}\n_ = cfg\n\n// 每次 RPC 调用时，把过滤器放进 ctx\nctx := picker.WithNodeFilter(context.Background(), picker.MetadataFilter(\"env\", \"prod\"))\n_ = ctx\n```\n\n##### 推荐：使用 Label Selector 过滤\n\n当你能把服务发现/注册中心的 metadata（比如 `env=prod`、`region=cn-north`、`lane=canary`、`version=2.1.0`）注入到 `resolver.Address.Attributes` 后，用 `LabelSelectorFilter` 通常是最省心也最强的写法。\n\n约定：\n- selector 优先读取 `Attributes[key]`（例如 `env`、`region`、`lane` 等）\n- 当 `Attributes[key]` 缺失时，会回退读取 `Attributes[picker.MetadataFilterKey]` 里的 map（仅当其类型为 `map[string]string`）\n\n```go\nimport (\n    \"context\"\n\n    \"github.com/xkeyideal/grpcbalance/grpclient/picker\"\n)\n\nf, err := picker.LabelSelectorFilter(\"env=prod, lane notin (dev), v@^1.1.0 || \u003e=2\")\nif err != nil {\n    // selector 解析失败时返回 error（不建议 panic）\n    return\n}\n\nctx := picker.WithNodeFilter(context.Background(), f)\nresp, err := client.SomeRPC(ctx, req)\n_ = resp\n_ = err\n```\n\n更多 selector 语法见 [label/README.md](label/README.md)。\n\n##### 其它简单过滤器示例\n\n```go\nctx := picker.WithNodeFilter(context.Background(),\n    picker.VersionPrefixFilter(\"v2.\"),\n    picker.MetadataFilter(\"env\", \"prod\"),\n    picker.ExcludeAddressFilter(\"127.0.0.1:50052\"),\n)\nresp, err := client.SomeRPC(ctx, req)\n_ = resp\n_ = err\n```\n\n#### 使用子集选择\n\n```go\nimport (\n    \"github.com/xkeyideal/grpcbalance/grpclient/resolver\"\n)\n\n// 从 100 个节点中选择 10 个\nselector := resolver.NewSubsetSelector(resolver.SubsetConfig{\n    SubsetSize: 10,\n    ClientKey:  \"my-service\",\n})\nsubset := selector.Select(allAddrs)\n```\n\n#### 使用服务发现\n\n```go\nimport (\n    \"github.com/xkeyideal/grpcbalance/grpclient\"\n    \"github.com/xkeyideal/grpcbalance/grpclient/discovery\"\n)\n\n// 静态发现\nstaticDiscovery := discovery.NewStaticDiscovery([]string{\n    \"127.0.0.1:8081\",\n    \"127.0.0.1:8082\",\n})\n\n// 轮询发现（自定义获取端点的函数）\npollingDiscovery := discovery.NewPollingDiscovery(\n    discovery.DiscoveryFunc(func(ctx context.Context) ([]discovery.Endpoint, error) {\n        return fetchEndpointsFromRegistry()\n    }),\n    30*time.Second,\n)\n\ncfg := \u0026grpclient.Config{\n    BalanceName: balancer.RoundRobinBalanceName,\n    Discovery:   pollingDiscovery, // 设置后 Endpoints 被忽略\n    EnableHealthCheck:     true,\n}\n```\n\n### Changelog\n\n详细的变更记录请参阅 [upgrade.md](upgrade.md)。\n\n### Customize Advanced Balancing Strategy\n\n1. Modify [naming resolver](https://github.com/xkeyideal/grpcbalance/blob/master/grpclient/resolver/resolver.go) with your requirements, first set [attributes.Attributes](https://github.com/grpc/grpc-go/blob/master/attributes/attributes.go) for per endpoint address, second when one endpoint attributes.Attributes changed then update subConn state.\n\n2. Implement yourself balancer \u0026 picker function, then based on [attributes.Attributes](https://github.com/grpc/grpc-go/blob/master/attributes/attributes.go) picker subConn in `Pick(balancer.PickInfo) (balancer.PickResult, error)`\n\n### License\n\nApache 2.0 license.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxkeyideal%2Fgrpcbalance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxkeyideal%2Fgrpcbalance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxkeyideal%2Fgrpcbalance/lists"}