Feign结合Ribbon原生调用学习笔记
1概述
在项目开发中,除了考虑正常的调用之外,负载均衡和故障转移也是关注的重点,这也是feign + ribbon(通常我们作为请求中间件来看)的优势所在。
1.1Ribbon参数配置
Ribbon所有的配置均交由IClientConfig统一管理,并提供统一的入口、出口,其它核心组件如IClient、ILoadBalancer均会读取此配置来控制其行为。
public abstract class CommonClientConfigKey<T> implements IClientConfigKey<T> {
public static final IClientConfigKey<String> AppName = new CommonClientConfigKey<String>("AppName") {
};
public static final IClientConfigKey<String> Version = new CommonClientConfigKey<String>("Version") {
};
public static final IClientConfigKey<Integer> Port = new CommonClientConfigKey<Integer>("Port") {
};
public static final IClientConfigKey<Integer> SecurePort = new CommonClientConfigKey<Integer>("SecurePort") {
};
public static final IClientConfigKey<String> VipAddress = new CommonClientConfigKey<String>("VipAddress") {
};
public static final IClientConfigKey<Boolean> ForceClientPortConfiguration = new CommonClientConfigKey<Boolean>("ForceClientPortConfiguration") {
};
public static final IClientConfigKey<String> DeploymentContextBasedVipAddresses = new CommonClientConfigKey<String>("DeploymentContextBasedVipAddresses") {
};
public static final IClientConfigKey<Integer> MaxAutoRetries = new CommonClientConfigKey<Integer>("MaxAutoRetries") {
};
public static final IClientConfigKey<Integer> MaxAutoRetriesNextServer = new CommonClientConfigKey<Integer>("MaxAutoRetriesNextServer") {
};
public static final IClientConfigKey<Boolean> OkToRetryOnAllOperations = new CommonClientConfigKey<Boolean>("OkToRetryOnAllOperations") {
};
public static final IClientConfigKey<Boolean> RequestSpecificRetryOn = new CommonClientConfigKey<Boolean>("RequestSpecificRetryOn") {
};
public static final IClientConfigKey<Integer> ReceiveBufferSize = new CommonClientConfigKey<Integer>("ReceiveBufferSize") {
};
public static final IClientConfigKey<Boolean> EnablePrimeConnections = new CommonClientConfigKey<Boolean>("EnablePrimeConnections") {
};
public static final IClientConfigKey<String> PrimeConnectionsClassName = new CommonClientConfigKey<String>("PrimeConnectionsClassName") {
};
public static final IClientConfigKey<Integer> MaxRetriesPerServerPrimeConnection = new CommonClientConfigKey<Integer>("MaxRetriesPerServerPrimeConnection") {
};
public static final IClientConfigKey<Integer> MaxTotalTimeToPrimeConnections = new CommonClientConfigKey<Integer>("MaxTotalTimeToPrimeConnections") {
};
public static final IClientConfigKey<Float> MinPrimeConnectionsRatio = new CommonClientConfigKey<Float>("MinPrimeConnectionsRatio") {
};
public static final IClientConfigKey<String> PrimeConnectionsURI = new CommonClientConfigKey<String>("PrimeConnectionsURI") {
};
public static final IClientConfigKey<Integer> PoolMaxThreads = new CommonClientConfigKey<Integer>("PoolMaxThreads") {
};
public static final IClientConfigKey<Integer> PoolMinThreads = new CommonClientConfigKey<Integer>("PoolMinThreads") {
};
public static final IClientConfigKey<Integer> PoolKeepAliveTime = new CommonClientConfigKey<Integer>("PoolKeepAliveTime") {
};
public static final IClientConfigKey<String> PoolKeepAliveTimeUnits = new CommonClientConfigKey<String>("PoolKeepAliveTimeUnits") {
};
public static final IClientConfigKey<Boolean> EnableConnectionPool = new CommonClientConfigKey<Boolean>("EnableConnectionPool") {
};
/** @deprecated */
@Deprecated
public static final IClientConfigKey<Integer> MaxHttpConnectionsPerHost = new CommonClientConfigKey<Integer>("MaxHttpConnectionsPerHost") {
};
/** @deprecated */
@Deprecated
public static final IClientConfigKey<Integer> MaxTotalHttpConnections = new CommonClientConfigKey<Integer>("MaxTotalHttpConnections") {
};
public static final IClientConfigKey<Integer> MaxConnectionsPerHost = new CommonClientConfigKey<Integer>("MaxConnectionsPerHost") {
};
public static final IClientConfigKey<Integer> MaxTotalConnections = new CommonClientConfigKey<Integer>("MaxTotalConnections") {
};
public static final IClientConfigKey<Boolean> IsSecure = new CommonClientConfigKey<Boolean>("IsSecure") {
};
public static final IClientConfigKey<Boolean> GZipPayload = new CommonClientConfigKey<Boolean>("GZipPayload") {
};
public static final IClientConfigKey<Integer> ConnectTimeout = new CommonClientConfigKey<Integer>("ConnectTimeout") {
};
public static final IClientConfigKey<Integer> BackoffInterval = new CommonClientConfigKey<Integer>("BackoffTimeout") {
};
public static final IClientConfigKey<Integer> ReadTimeout = new CommonClientConfigKey<Integer>("ReadTimeout") {
};
public static final IClientConfigKey<Integer> SendBufferSize = new CommonClientConfigKey<Integer>("SendBufferSize") {
};
public static final IClientConfigKey<Boolean> StaleCheckingEnabled = new CommonClientConfigKey<Boolean>("StaleCheckingEnabled") {
};
public static final IClientConfigKey<Integer> Linger = new CommonClientConfigKey<Integer>("Linger") {
};
public static final IClientConfigKey<Integer> ConnectionManagerTimeout = new CommonClientConfigKey<Integer>("ConnectionManagerTimeout") {
};
public static final IClientConfigKey<Boolean> FollowRedirects = new CommonClientConfigKey<Boolean>("FollowRedirects") {
};
public static final IClientConfigKey<Boolean> ConnectionPoolCleanerTaskEnabled = new CommonClientConfigKey<Boolean>("ConnectionPoolCleanerTaskEnabled") {
};
public static final IClientConfigKey<Integer> ConnIdleEvictTimeMilliSeconds = new CommonClientConfigKey<Integer>("ConnIdleEvictTimeMilliSeconds") {
};
public static final IClientConfigKey<Integer> ConnectionCleanerRepeatInterval = new CommonClientConfigKey<Integer>("ConnectionCleanerRepeatInterval") {
};
public static final IClientConfigKey<Boolean> EnableGZIPContentEncodingFilter = new CommonClientConfigKey<Boolean>("EnableGZIPContentEncodingFilter") {
};
public static final IClientConfigKey<String> ProxyHost = new CommonClientConfigKey<String>("ProxyHost") {
};
public static final IClientConfigKey<Integer> ProxyPort = new CommonClientConfigKey<Integer>("ProxyPort") {
};
public static final IClientConfigKey<String> KeyStore = new CommonClientConfigKey<String>("KeyStore") {
};
public static final IClientConfigKey<String> KeyStorePassword = new CommonClientConfigKey<String>("KeyStorePassword") {
};
public static final IClientConfigKey<String> TrustStore = new CommonClientConfigKey<String>("TrustStore") {
};
public static final IClientConfigKey<String> TrustStorePassword = new CommonClientConfigKey<String>("TrustStorePassword") {
};
public static final IClientConfigKey<Boolean> IsClientAuthRequired = new CommonClientConfigKey<Boolean>("IsClientAuthRequired") {
};
public static final IClientConfigKey<String> CustomSSLSocketFactoryClassName = new CommonClientConfigKey<String>("CustomSSLSocketFactoryClassName") {
};
public static final IClientConfigKey<Boolean> IsHostnameValidationRequired = new CommonClientConfigKey<Boolean>("IsHostnameValidationRequired") {
};
public static final IClientConfigKey<Boolean> IgnoreUserTokenInConnectionPoolForSecureClient = new CommonClientConfigKey<Boolean>("IgnoreUserTokenInConnectionPoolForSecureClient") {
};
public static final IClientConfigKey<String> ClientClassName = new CommonClientConfigKey<String>("ClientClassName") {
};
public static final IClientConfigKey<Boolean> InitializeNFLoadBalancer = new CommonClientConfigKey<Boolean>("InitializeNFLoadBalancer") {
};
public static final IClientConfigKey<String> NFLoadBalancerClassName = new CommonClientConfigKey<String>("NFLoadBalancerClassName") {
};
public static final IClientConfigKey<String> NFLoadBalancerRuleClassName = new CommonClientConfigKey<String>("NFLoadBalancerRuleClassName") {
};
public static final IClientConfigKey<String> NFLoadBalancerPingClassName = new CommonClientConfigKey<String>("NFLoadBalancerPingClassName") {
};
public static final IClientConfigKey<Integer> NFLoadBalancerPingInterval = new CommonClientConfigKey<Integer>("NFLoadBalancerPingInterval") {
};
public static final IClientConfigKey<Integer> NFLoadBalancerMaxTotalPingTime = new CommonClientConfigKey<Integer>("NFLoadBalancerMaxTotalPingTime") {
};
public static final IClientConfigKey<String> NIWSServerListClassName = new CommonClientConfigKey<String>("NIWSServerListClassName") {
};
public static final IClientConfigKey<String> NIWSServerListFilterClassName = new CommonClientConfigKey<String>("NIWSServerListFilterClassName") {
};
public static final IClientConfigKey<Integer> ServerListRefreshInterval = new CommonClientConfigKey<Integer>("ServerListRefreshInterval") {
};
public static final IClientConfigKey<Boolean> EnableMarkingServerDownOnReachingFailureLimit = new CommonClientConfigKey<Boolean>("EnableMarkingServerDownOnReachingFailureLimit") {
};
public static final IClientConfigKey<Integer> ServerDownFailureLimit = new CommonClientConfigKey<Integer>("ServerDownFailureLimit") {
};
public static final IClientConfigKey<Integer> ServerDownStatWindowInMillis = new CommonClientConfigKey<Integer>("ServerDownStatWindowInMillis") {
};
public static final IClientConfigKey<Boolean> EnableZoneAffinity = new CommonClientConfigKey<Boolean>("EnableZoneAffinity") {
};
public static final IClientConfigKey<Boolean> EnableZoneExclusivity = new CommonClientConfigKey<Boolean>("EnableZoneExclusivity") {
};
public static final IClientConfigKey<Boolean> PrioritizeVipAddressBasedServers = new CommonClientConfigKey<Boolean>("PrioritizeVipAddressBasedServers") {
};
public static final IClientConfigKey<String> VipAddressResolverClassName = new CommonClientConfigKey<String>("VipAddressResolverClassName") {
};
public static final IClientConfigKey<String> TargetRegion = new CommonClientConfigKey<String>("TargetRegion") {
};
public static final IClientConfigKey<String> RulePredicateClasses = new CommonClientConfigKey<String>("RulePredicateClasses") {
};
public static final IClientConfigKey<String> RequestIdHeaderName = new CommonClientConfigKey<String>("RequestIdHeaderName") {
};
public static final IClientConfigKey<Boolean> UseIPAddrForServer = new CommonClientConfigKey<Boolean>("UseIPAddrForServer") {
};
public static final IClientConfigKey<String> ListOfServers = new CommonClientConfigKey<String>("listOfServers") {
};
1.2Ribbon负载均衡策略IRule(7种)
// 1.随机策略
RandomRule
// 2.简单的轮询,交替访问,没有实现权重的策略(Ribbon默认策略,按照顺序选择server,ribbon默认策略)
RoundRobinRule
// 3.重试策略(在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server)
RetryRule
// 4.最低并发策略(逐个考察server,如果server断路器打开,则忽略,再选择其中并发链接最低的server)
BestAvailableRule
// 5.可用过滤策略 过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值)
AvailabilityFilteringRule
// 6.响应时间加权重策略 根据server的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。响应时间越短,
// 权重越高,被选中的概率越高,这个策略很贴切,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间
ResponseTimeWeightedRule
// 7.区域权重策略 综合判断server所在区域的性能,和server的连接数可用性
// 使用ZoneAvoidancePredicate:判断判定一个zone的运行性能是否可用,
// 和AvailabilityPredicate:用于过滤掉连接数过多的Server
// 轮询选择server并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server
ZoneAvoidanceRule
1.3Ribbon配置文件
#1.重试机制(对第一次请求的服务的重试次数)
#由于使用的ribbon,所以feign不再需要配置超时时长,重试策略
myimportsvr.ribbon.MaxAutoRetries=1
#2.要重试的下一个服务的最大数量(不包括第一个服务)
myimportsvr.ribbon.MaxAutoRetriesNextServer=1
#3.对所有请求都重试,get可以(post需事先幂等,否则危险)
myimportsvr.ribbon.OkToRetryOnAllOperations=false
#4.服务列表刷新机制
myimportsvr.ribbon.ServerListRefreshInterval=2000
#5.请求链接超时(这里配置的ConnectTimeout和ReadTimeout是当HTTP客户端使用的是HttpClient才生效)
myimportsvr.ribbon.ConnectTimeout=3000
#6.请求处理超时时间(这里配置的ConnectTimeout和ReadTimeout是当HTTP客户端使用的是HttpClient才生效)
myimportsvr.ribbon.ReadTimeout=3000
#7.服务列表
myimportsvr.ribbon.listOfServers=127.0.0.1:8085,127.0.0.1:8086
#8.EnablePrimeConnections
myimportsvr.ribbon.EnablePrimeConnections=false
#配置说明:
# <clientName>.<nameSpace>.<propertyName>=<value>
#1>.clientName正对某个服务的服务名称,如:myimportsvr,如果没有clientName,则是对所有的client都有效
#2>.nameSpace是命名空间,默认是ribbon
2代码实战
2.1Ribbon
2.1.1client
2.1.1.1maven依赖
<!--3.3.feign-ribbon-->
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-ribbon -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-ribbon</artifactId>
<version>9.6.0</version>
</dependency>
2.1.1.2远程服务接口
// 负载均衡访问示例
@Headers({"Content-Type: application/json", "Accept: application/json"})
@RequestLine("POST /myspringbootdemo/myfeign/getRibbonValue")
JSONObject getRibbonValue(JSONObject req);
2.1.1.3调用测试
private static void feignWithRibbonTest() throws IOException {
// // 1.ConfigurationManager的引用太复杂,换做代码实现DefaultClientConfigImpl
// ConfigurationManager.loadPropertiesFromResources("myribbon/myribbon.properties");
// 2.设置策略类型
RibbonClient ribbonClient = RibbonClient.builder().lbClientFactory(new LBClientFactory() {
@Override
public LBClient create(String clientName) {
// IClientConfig默认的实现类:DefaultClientConfigImpl
IClientConfig config = ClientFactory.getNamedConfig(clientName);
// 1.重试机制(对第一次请求的服务的重试次数)
IClientConfigKey<Integer> maxAutoRetries = CommonClientConfigKey.MaxAutoRetries;
config.set(maxAutoRetries, 1);
// 2.要重试的下一个服务的最大数量(不包括第一个服务)
IClientConfigKey<Integer> maxAutoRetriesNextServer = CommonClientConfigKey.MaxAutoRetriesNextServer;
config.set(maxAutoRetriesNextServer, 1);
// 3.对所有请求都重试,get可以(post需事先幂等,否则危险)
IClientConfigKey<Boolean> okToRetryOnAllOperations = CommonClientConfigKey.OkToRetryOnAllOperations;
config.set(okToRetryOnAllOperations, false);
// 4.服务列表刷新机制,定时ping任务,从server刷新服务列表
IClientConfigKey<Integer> serverListRefreshInterval = CommonClientConfigKey.ServerListRefreshInterval;
config.set(serverListRefreshInterval, 2000);
// 5.请求链接超时(这里配置的ConnectTimeout和ReadTimeout是当HTTP客户端使用的是HttpClient才生效)
IClientConfigKey<Integer> connectTimeout = CommonClientConfigKey.ConnectTimeout;
config.set(connectTimeout, 3000);
// 6.请求处理超时时间(这里配置的ConnectTimeout和ReadTimeout是当HTTP客户端使用的是HttpClient才生效)
IClientConfigKey<Integer> readTimeout = CommonClientConfigKey.ReadTimeout;
config.set(readTimeout, 3000);
// 7.服务列表
IClientConfigKey<String> listOfServers = CommonClientConfigKey.ListOfServers;
config.set(listOfServers, "127.0.0.1:8085,127.0.0.1:8086");
// 8.enablePrimeConnections
IClientConfigKey<Boolean> enablePrimeConnections = CommonClientConfigKey.EnablePrimeConnections;
config.set(enablePrimeConnections, false);
ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
ZoneAwareLoadBalancer zb = (ZoneAwareLoadBalancer) lb;
// zb.setRule(new RoundRobinRule()); // 设置策略类型:简单轮询
// zb.setRule(new RandomRule()); // 设置策略类型:随机
return LBClient.create(lb, config);
}
}).build();
// 3.发起服务请求
RemoveServiceImpl removeService = Feign.builder()
// Feign对象获得 Ribbon特性
.client(ribbonClient)
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
// myimportsvr服务地址会被拼接并动态代理
.target(RemoveServiceImpl.class, "http://myimportsvr");
JSONObject req = new JSONObject();
req.put("userName", "kikop");
JSONObject result = removeService.getRibbonValue(req);
System.out.println(result.getString("userName") + ":" + result.getString("remotePort"));
}
IntStream.range(0, 10).parallel().forEach(currentValue -> {
System.out.println(currentValue + "@" + Thread.currentThread().getName() + ":" + Thread.currentThread().getId());
try {
feignWithRibbonTest();
} catch (IOException e) {
e.printStackTrace();
}
});
2.1.2server(辅助测试)
2.1.2.1后台服务接口
@RequestMapping(value = "/getRibbonValue", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public JSONObject getRibbonValue(HttpServletRequest request, @RequestBody JSONObject user) throws InterruptedException {
System.out.println("getObjectValue..." + request.getLocalPort());
JSONObject result = new JSONObject();
result.put("success", true);
result.put("userName", user.getString("userName").toUpperCase());
result.put("remotePort", request.getLocalPort());
System.out.println("getObjectValue!");
TimeUnit.SECONDS.sleep(10);
return result;
}
网友评论