1:pom.xl
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.0.3</version>
</dependency>
2.FeignLoadBalancerConfig
/**
* 是有缓存的,默认是35s,如修改缓存时间,可做如下配置
* spring.cloud.loadbalancer.cache.ttl=5s
*/
@ConditionalOnDiscoveryEnabled
public class FeignLoadBalancerConfig {
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new HashLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
3.FeignConfig
public class FeignConfig {
@Bean
public Retryer getRetryBean() {
return Retryer.NEVER_RETRY;
// return new Retryer.Default();// 可将服务端设置超时,可看到多次进入服务端请求
}
}
4.HashLoadBalancer
@Slf4j
public class HashLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final String serviceId;
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private final AtomicInteger position;
public HashLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));
}
public HashLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.position = new AtomicInteger(seedPosition);
}
@SuppressWarnings("rawtypes")
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(request, supplier, serviceInstances));
}
private Response<ServiceInstance> processInstanceResponse(Request request, ServiceInstanceListSupplier supplier,
List<ServiceInstance> serviceInstances) {
Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(request, serviceInstances);
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
}
return serviceInstanceResponse;
}
private Response<ServiceInstance> getInstanceResponse(Request request, List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
// 节点实例
if (null != request.getContext() && request.getContext() instanceof RequestDataContext) {
// 获取请求头sharding属性值
List<String> sharingIds = ((RequestDataContext) request.getContext()).getClientRequest().getHeaders().get(ClientConstant.sharingId);
String shardingId = Optional.ofNullable(sharingIds).map(m -> m.get(0)).orElse(null);
if (null != shardingId) {
if (log.isDebugEnabled()) {
log.debug("getInstanceResponse shardingId = {} instances = {}", shardingId, instances.stream().map(e -> e.getInstanceId()).collect(Collectors.toList()));//todo
}
return new DefaultResponse(instances.get(HashKeyUtil.getIndex(shardingId, instances.size())));
}
}
// instance为空说明未配置sharingId,走默认路由规则
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
return new DefaultResponse(instances.get(pos % instances.size()));
}
}
5:HashKeyUtil
public class HashKeyUtil {
//@Autowired
//private DiscoveryClient discoveryClient;
// discoveryClient.getInstances("service-name"); 获取在线服务
public static int getIndex(String key, int serviceSize) {
return 0 == serviceSize ? 0 : hashLh(key) % serviceSize;
}
public static int hashLh(String key) { // 耗时和均布,相对适中
int h;
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
return hash & Integer.MAX_VALUE;
}
public static int hashLong(String key) {
return (int) (Long.parseLong(key) / 10);
}
public static int hashOnly(String key) {
return key.hashCode() & Integer.MAX_VALUE;
}
}
6:DemoClient
@FeignClient(name = ExchangeCoreClientConstants.SERVICE_NAME, path = "/inner/exchange/core/asset", configuration = FeignConfig.class)
@LoadBalancerClient(value = ExchangeCoreClientConstants.SERVICE_NAME, configuration = FeignLoadBalancerConfig.class)
public interface DemoClient {
@PostMapping(value = "/transfer-in")
ResponseResult transferIn(@RequestBody RequestCommon<TransferTraceAccountInDTO> toDto, @RequestHeader(ClientConstant.sharingId) long sharingId);
}