前言:Spring Cloud Ribbon 是一个基于HTTP和TCP的客户端负载均衡工具,基于Netflix Ribbon 实现。经过Spring cloud的封装可以将REST请求转换成客户端负载均衡的服务调用。鉴于微服务的服务间的调用的所以Ribbon存在于所有服务中。后续还有一种基于Ribbon实现的工具 Feign。
1、了解负载均衡
负载均衡:缓解网络压力 ,提高处理能力保证系统服务的高可用。
服务端负载均衡分类:硬负载和软负载。硬负载:指的是在服务器节点之间安装专门用于负载均衡的设备,如F5。软负载:指的是在服务器上安装具有负载均衡功能的软件来完成请求分发,如Nginx。硬负载和软负载都属于服务端负载均衡。
客户端负载均衡:功能类似于服务端负载均衡,其区别在于维护的服务清单都各自维护着自己的访问清单(服务注册中心,如Euraka)。
2、实现客户端负载步骤:(Spring cloud)
1、服务在服务中心上进行注册;
2、服务消费者通过调用被@LoadBalanced修饰过的RestTemplate来实现面向服务的接口调用。
3、spring Cloud Ribbon自动实现接口
1、IClientConfig:Ribbon的客户端配置,默认采用:com.netflix.client.config.DefaultClientConfigImpl。
2、IRule:Ribbon的负载均衡策咯,默认采用:com.netflix.loadbalancer.ZoneAvoidanceRule,该策略能够在多区域环境下选出最佳区域的实例进行访问。
3、IPing:Ribbon的实例检查策咯,默认采用:com.netflix.loadbalancer.NoOpPing,该策略并不会去检查服务实例的可用性,而是默认多有服务都是可用的,始终返回true。
4、ServerList<Server>:服务实例清单的维护机制,默认采用:com.netflix.loadbalancer.ConfigurationBasedServerList
5、ServerListFilter<Server>:服务实例清单过滤机制,默认采用:org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter实现,该策略能够优先过滤出与请求调用方法处于同一区域的服务实例。
6、ILoadBalancer:负载均衡器,默认采用:com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,具备区域感知能力。
备注:以上几点是在没有和Euraka进行结合时的实现。
同时引用Spring Cloud Euraka和Spring Cloud Ribbon后变化项:
1、ServerList<Server>:服务实例清单的维护机制,被 com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
覆盖,将服务清单交给Euraka的服务治理机制进行维护。
2、IPing:Ribbon的实例检查策咯,被 com.netflix.niws.loadbalancer.NIWSDiscoveryPing 覆盖。
Ribbon调用流程:
LoadBalancerAutoConfiguration类会创建了一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡;会创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器;会维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。
RestTemplate被@LoadBalance注解后,其在ClientHttpRequestExecution调用的过程中被名为LoadBalancerInterceptor的ClientHttpRequestInterceptor拦截器截获,进而交给负载均衡器LoadBalancerClient去处理。
LoadBalancerClient只是一个抽象的负载均衡器接口,核心功能交给了ILoadBalancer实现类来处理。ILoadBalancer实现类通过配置IRule、IPing等信息,通过ConsulClient获取注册列表的信息并定时检查服务器健康状态,得到注册列表后,ILoadBalancer实现类就可以根据IRule的策略进行负载均衡。
4、准备工作
两个服务提供着,一个服务消费者。
1、服务提供者可用之前的服务发现工程,添加一个controller。创建两个同样的工程,修改一下服务的端口号就可以。
@RestController
@RequestMapping("/test")
public class DemoController {
@Autowired
private DiscoveryClient discoveryClient;
/**
* @author:XingWL
* @description:测试接口
* @date: 2019/2/22 10:29
*/
@ResponseBody
@RequestMapping(value = "/testRibbonProducer",method = RequestMethod.GET)
public String testRibbon(){
ServiceInstance instance=discoveryClient.getLocalServiceInstance();
String hostMsg="";
try {
hostMsg= "Producer: host-"+instance.getHost()+",service_id-"+instance.getServiceId()+",Url-"+instance.getUri();
} catch (Exception e) {
e.printStackTrace();
hostMsg="异常";
}
return hostMsg;
}
}
2、创建一个服务消费者服务
pom.xml里添加Ribbon依赖引用。
<!--Ribbon 负载均衡-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
启动类添加注解,及给RestTemplate加上注解@LoadBalanced
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class DemoApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
添加一个controller调用服务(服务调用)
@RestController
@RequestMapping(value = "/test")
public class DemoController {
@Autowired
private RestTemplate restTemplate;
/**
* @author:XingWL
* @description:测试Ribbon负载均衡
* @date: 2019/1/28 18:07
*/
@ResponseBody
@RequestMapping(value = "/testRibbonConsummer",method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "myFallback")
public String testInf(){
String result=restTemplate.getForEntity("http://PRODUCER/producer/test/testRibbonProducer",String.class).getBody();
return result;
}
/**
* @author:XingWL
* @description:回调
* @date: 2019/2/26 18:14
*/
public String myFallback(){
String msg="断路保护";
return msg;
}
}
效果:多次请求会在两个服务间进行轮询。
SpringCloudRibbon默认实现了区域亲和策略,对服务进行区域划分
#区域划分
eureka.instance.metadata-map.zone=xxx
#断开Eureka对Ribbon服务实例的维护实现
ribbon.eureka.enabled=false
重试机制:spring cloud Eureka 实现的服务治理机制强调的是CAP原理(一致性c、可用性a、可靠性p)中的AP,zookeeper是(CP);而Eureka会因为超过85%的s实例丢失心跳而触发保护机制,注册中心会保留此时所有节点,以保证系统大多数的服务正常使用。
##开启重试机制,默认关闭状态
spring.cloud.loadbalancer.retry.enabled=true
Ribbon调优:
Ribbon默认使用ZoneAwareLoadBalancer进行负载,查看实现类DynamicServerListLoadBalancer,其中接口
ServerListUpdater的实现类PollingServerListUpdater控制ribbon缓存服务列表的更新。
调优入口配置参考:
com.netflix.client.config.CommonClientConfigKey包含相关配置,使用方式:
全局:ribbon.配置=value
部分应用:clientName.ribbon.配置=value
如:
ribbon.ServerListRefreshInterval=1000
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> NFLoadBalancerStatsClassName = new CommonClientConfigKey<String>("NFLoadBalancerStatsClassName") {
};
public static final IClientConfigKey<String> NIWSServerListClassName = new CommonClientConfigKey<String>("NIWSServerListClassName") {
};
public static final IClientConfigKey<String> ServerListUpdaterClassName = new CommonClientConfigKey<String>("ServerListUpdaterClassName") {
};
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") {
};