spring-cloud-gateway(三)自定義lb實現
官方的靜態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