官方的靜態lb已經滿足大部分場景
缺點是全靜態,動態擴展能力不強
動態擴展有兩個方向
方式一 是聚焦於spring-cloud-gateway本身,實現一些自定義的方法
方式二 是依賴spring-cloud的生態,consul/nacos注冊中心,或config配置中心,bus事件隊列動態更新配置等
做es的網關依賴spring-cloud,太重,方案放棄了
個人一開始以為沒有靜態lb的支持,所以直接就看方式一,所實際這個需求,靜態基本就滿足,但也不算完全是白折騰,至少更熟悉了spring-cloud-gateway的代碼和機制
server:
port: 9208
spring:
cloud:
gateway:
enabled: true
discovery:
client:
simple:
instances:
es3[0]:
uri: http://127.0.0.1:19200
es3[1]:
uri: http://127.0.0.1:19201
es3[2]:
uri: http://127.0.0.1:19202
order: 1
spring-cloud-gateway 原生本地代理,配置resource即可
純靜態有兩個缺點
1 無法動態添加或刪除節點,如instances下 添加es[3] ,刪除可以自動檢測屏蔽,添加就不好做了
2 即使無法動態添加,手動更改配置,再重啟節點也滿足要求
自定義方式一
實現ServiceInstanceListSupplier
public class CustomServiceInstanceListSupplier implements ServiceInstanceListSupplier {
public CustomServiceInstanceListSupplier() {
}
private String aaaa;
@Override
public String getServiceId() {
return "es2";
}
@Override
public Flux<List<ServiceInstance>> get() {
List<ServiceInstance> sis=new ArrayList<>();
sis.add(0, new DefaultServiceInstance("instanceId-4","es2","127.0.0.1",9204,false));
sis.add(1, new DefaultServiceInstance("instanceId-5","es2","127.0.0.1",9205,false));
System.out.println("get()");
return Flux.defer(() -> {
return Flux.just(sis);
});
}
@Override
public Flux<List<ServiceInstance>> get(Request request) {
return get();
}
}
---
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withBase(new CustomServiceInstanceListSupplier())
// .withHints()
// .withHealthChecks()
.build(context);
}
自定義方式二,與方式一類似
實現DiscoveryClient 並結合DiscoveryClientServiceInstanceListSupplier
使用
public class CustomDiscoveryClient implements DiscoveryClient {
private List<ServiceInstance> instances;
private String myServiceId;
public CustomDiscoveryClient(List<ServiceInstance> instances) {
this.myServiceId=myServiceId;
this.instances=instances;
loadInstancesFromRemote();
}
public void loadInstancesFromRemote(){
List<ServiceInstance> serviceInstanceList2=new ArrayList<>();
serviceInstanceList2.add(0, new DefaultServiceInstance("instanceId-0","ces2","127.0.0.1",9200,false));
setInstances(serviceInstanceList2);
}
public String getMyServiceId() {
return myServiceId;
}
public void setInstances(List<ServiceInstance> instances) {
this.instances=instances;
}
@Override
public String description() {
return null;
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
return this.instances;
}
@Override
public List<String> getServices() {
return null;
}
}
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
CustomDiscoveryClient cdc2=new CustomDiscoveryClient(null);
DiscoveryClientServiceInstanceListSupplier listSupplier=new DiscoveryClientServiceInstanceListSupplier(cdc2,context.getEnvironment());
return ServiceInstanceListSupplier.builder()
.withBase(listSupplier)
.build(context);
}
再提供一個外部的webapi,添加或刪除節點,則一個基本的動態lb功能就完備了
添加lb節點,刪除lb節點,加載配置使lb變更生效
自定義方式三
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
return new RandomLoadBalancer(loadBalancerClientFactory
"es");
}
方式三功能最細致
簡而方式,方式一/方式二,都是注冊全局的ServiceInstanceListSupplier,全局生效
方式三,自定義返回 RandomLoadBalancer,構造函數包含ServiceInstanceListSupplier,可以在外層生成對應的ServiceInstanceListSupplier
public RandomLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
}
也可以完全不依賴官方的ServiceInstanceListSupplier,實現完全自定義的ReactorLoadBalancer