Solon v4.1.1

LoadBalance、服务发现与节点选择

</> markdown
2026年9月14日 上午5:29:45

服务发现回答“有哪些实例”,负载均衡回答“本次选哪一个”。在 Solon 中,LoadBalance 是一个很小的适配接口,Nami 和 HTTP 工具都可以通过它获得上游地址。

1、 读取服务名对应的节点

import org.noear.solon.core.LoadBalance;

LoadBalance balance = LoadBalance.get("userapi");
String server = balance.getServer();

带分组:

LoadBalance balance = LoadBalance.get("demo", "userapi");
String server = balance.getServer();

当前源码中:

  • get(String service) 等价于空 group。
  • getServer() 默认调用 getServer(0)。
  • getServer(int port) 是接口必须实现的方法。
  • 找不到底层负载器时,包装器可能返回 null;调用前要做好配置和空值检查。

2、 parse 的两类输入

LoadBalance.parse("userapi");
LoadBalance.parse("lb://userapi");
LoadBalance.parse("http://localhost:9001");

源码会把不含 :// 的字符串当服务名;lb:// 表示从负载均衡器取得节点;普通 http:// 则包装成固定 server。不要把任意业务 URL 当成服务名。

3、 自定义负载均衡器

最小实现:

import org.noear.solon.core.LoadBalance;

public class MyLoadBalance implements LoadBalance {
    @Override
    public String getServer(int port) {
        if (port > 0) {
            return "http://127.0.0.1:" + port;
        }
        return "http://127.0.0.1:9001";
    }
}

如果要按轮询、权重或健康状态选择多个地址,应在实现内部维护节点列表和策略;不要在 getServer 中每次无条件返回同一个地址却把它称为负载均衡。

4、 工厂接入

一般不这么做,避免破坏 Solon Cloud Discovery/LoadBalance 插件的接入

public class MyLoadBalanceFactory implements LoadBalance.Factory {
    @Override
    public LoadBalance create(String group, String service) {
        if ("demo".equals(group) && "userapi".equals(service)) {
            return new MyLoadBalance();
        }
        return null;
    }
}

Factory 的签名是 create(String group, String service)。未匹配的服务应返回 null,让其他工厂或默认机制处理;不要返回一个错误实例导致所有未知服务都指向错误地址。具体注册方式取决于应用容器,可作为 Solon Bean 注册。

5、 与 Nami 配合

UserService service = Nami.builder()
    .name("userapi")
    .group("demo")
    .path("/rpc/v1/user")
    .create(UserService.class);

普通项目优先使用 Solon Cloud 的 Discovery/LoadBalance 插件。只有需要特殊节点来源、灰度规则或自定义权重时,才实现自己的 LoadBalance.Factory。

6、不要混淆三层配置

solon.app.name       → 当前应用注册名
NamiClient.name      → 要调用的服务名/负载名称
@Mapping             → 服务的 HTTP 路径

三者可以文字相同,但语义不同。排查多实例调用时按“服务名 → group → 节点 URL → path”逐项打印和核对。