diff --git a/src/main/java/com/flagnote/gateway/GatewayApplication.java b/src/main/java/com/flagnote/gateway/GatewayApplication.java index 9569dc4..2fa16c9 100644 --- a/src/main/java/com/flagnote/gateway/GatewayApplication.java +++ b/src/main/java/com/flagnote/gateway/GatewayApplication.java @@ -2,10 +2,13 @@ package com.flagnote.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; + +import com.flagnote.gateway.config.BkrLoadBalancerConfiguration; @SpringBootApplication +@LoadBalancerClient(name = "noteCommonService", configuration = BkrLoadBalancerConfiguration.class) public class GatewayApplication { - public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } diff --git a/src/main/java/com/flagnote/gateway/config/BizKeyLoadBalancerClient.java b/src/main/java/com/flagnote/gateway/config/BizKeyLoadBalancerClient.java new file mode 100644 index 0000000..6464f1f --- /dev/null +++ b/src/main/java/com/flagnote/gateway/config/BizKeyLoadBalancerClient.java @@ -0,0 +1,91 @@ +package com.flagnote.gateway.config; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.DefaultResponse; +import org.springframework.cloud.client.loadbalancer.EmptyResponse; +import org.springframework.cloud.client.loadbalancer.Request; +import org.springframework.cloud.client.loadbalancer.RequestData; +import org.springframework.cloud.client.loadbalancer.RequestDataContext; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer; +import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; + +import com.flagnote.gateway.utils.BizKeyUtils; + +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Mono; + +@Slf4j +public class BizKeyLoadBalancerClient implements ReactorServiceInstanceLoadBalancer { + + private final String serviceId; + + private ObjectProvider serviceInstanceListSupplierProvider; + + public BizKeyLoadBalancerClient(ObjectProvider serviceInstanceListSupplierProvider, + String serviceId) { + this.serviceId = serviceId; + this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; + } + + @SuppressWarnings("rawtypes") + @Override + public Mono> choose(Request request) { + ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider + .getIfAvailable(NoopServiceInstanceListSupplier::new); + return supplier.get(request).next() + .map(serviceInstances -> processInstanceResponse(request, supplier, serviceInstances)); + } + + @SuppressWarnings("rawtypes") + private Response processInstanceResponse(Request request, ServiceInstanceListSupplier supplier, + List serviceInstances) { + Response serviceInstanceResponse = getInstanceResponse(request, serviceInstances); + if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) { + ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer()); + } + return serviceInstanceResponse; + } + + @SuppressWarnings("rawtypes") + private Response getInstanceResponse(Request request, List instances) { + if (instances.isEmpty()) { + if (log.isWarnEnabled()) { + log.warn("No servers available for service: " + serviceId); + } + return new EmptyResponse(); + } + + RequestDataContext rdContext = (RequestDataContext)request.getContext(); + RequestData rdata = rdContext.getClientRequest(); + String path = rdata.getUrl().getPath(); + + String pattern = "^/note/([abcdefhikmnopqstuvwxyz23456789]{16})(\\.txt|/noteMeta|/delete)?$"; + Pattern pt = Pattern.compile(pattern); + Matcher m = pt.matcher(path); + + //默认随机 + int index = ThreadLocalRandom.current().nextInt(instances.size()); + + //如果有key,则为key分配指定服务。 + if(m.find()) { + String mixKey = BizKeyUtils.mixKey(m.group(1)); + index = Math.abs(mixKey.hashCode())%instances.size(); + } + ServiceInstance instance = instances.get(index); + log.info("path:{},service:{}",path,instance.getUri().toString()); + return new DefaultResponse(instance); + } + +} diff --git a/src/main/java/com/flagnote/gateway/config/BkrLoadBalancerConfiguration.java b/src/main/java/com/flagnote/gateway/config/BkrLoadBalancerConfiguration.java new file mode 100644 index 0000000..03046ae --- /dev/null +++ b/src/main/java/com/flagnote/gateway/config/BkrLoadBalancerConfiguration.java @@ -0,0 +1,17 @@ +package com.flagnote.gateway.config; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; + +//@Configuration 必须注释掉 +public class BkrLoadBalancerConfiguration { + @Bean + public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { + String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); + return new BizKeyLoadBalancerClient(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 935aaa2..0230585 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -32,14 +32,19 @@ spring: client: simple: instances: - noteService: # 一定要带端口 + noteCommonService: # 一定要带端口 - uri: http://127.0.0.1:20000 -# - uri: http://94.103.5.10:20001 + - uri: http://127.0.0.1:20001 + keyMetaService: # 一定要带端口 + - uri: http://127.0.0.1:20000 + - uri: http://127.0.0.1:20001 + loadbalancer: configurations: health-check health-check: path: - noteService: /f2w8u47ie56edc93/actuator/health + noteCommonService: /f2w8u47ie56edc93/actuator/health + keyMetaService: /f2w8u47ie56edc93/actuator/health initial-delay: 0 interval: 5s inetutils: @@ -53,7 +58,7 @@ spring: # allowedMethods: "*" routes: - id: keyMeta - uri: lb://noteService + uri: lb://keyMetaService order: -1 predicates: - Path=/note/keyMeta @@ -91,7 +96,7 @@ spring: - id: noteMeta - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}}/noteMeta @@ -99,7 +104,7 @@ spring: filters: - ValidateNoteKey - id: getNote - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}} @@ -107,7 +112,7 @@ spring: filters: - ValidateNoteKey - id: saveNote - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}} @@ -115,7 +120,7 @@ spring: filters: - ValidateNoteKey - id: deleteNote - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}}/delete @@ -123,7 +128,7 @@ spring: filters: - ValidateNoteKey - id: secretKey - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}}/secretKey @@ -131,7 +136,7 @@ spring: filters: - ValidateNoteKey - id: getNoteTxt - uri: lb://noteService + uri: lb://noteCommonService order: -1 predicates: - Path=/note/{key:[abcdefhikmnopqstuvwxyz23456789]{16}}.txt @@ -160,6 +165,6 @@ management: logging: level: - org.springframework.cloud.gateway: trace - org.springframework.cloud.loadbalancer: trace - org.springframework.web.reactive: trace \ No newline at end of file + org.springframework.cloud.gateway: info + org.springframework.cloud.loadbalancer: info + org.springframework.web.reactive: info \ No newline at end of file