定制小程序开发费用Ribbon配置和实现原理

负载均衡 

        定制小程序开发费用负载均衡是一种基础的网络服务,定制小程序开发费用它的核心原理是按照指定的,定制小程序开发费用将请求分配到后端服务集群上,定制小程序开发费用从而为系统提供并行处定制小程序开发费用理和高可用的能力。定制小程序开发费用提到负载均衡,定制小程序开发费用你可能想到nginx。定制小程序开发费用对于负载均衡,定制小程序开发费用一般分为服务端负载均衡和客户端负载均衡。

  • 服务端负载均衡:在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的负载均衡器,比如 F5,也有软件,比如 Nginx。
  • 客户端负载均衡:所谓客户端负载均衡,就是客户端根据自己的请求情况做负载,本文介绍的Netflix Ribbon就是客户端负载均衡的组件。而Ribbon是一个客户端实现负载均衡的框架,主要用户客户端调用远端服务实现负载均衡。目前Ribbon使用的是spring-cloud-starter-netflix-ribbon这个依赖。

1.实现负载均衡

    RestTemplate使用负载均衡,只需要给RestTemplate增加@LoadBalanced注解

  1. @LoadBalanced
  2. @Bean
  3. public RestTemplate restTemplate() {
  4. return new RestTemplate();
  5. }

 2.负载均衡策略配置

          BestAvailableRule:在过滤掉故障服务后,它会基于过去30分钟的统计结果选取当前并发量最小的服务节点,也就是最“闲”的节点作为目标地址。如果统计结果尚未生成,则采用的方式选定节点

       ZoneAvoidanceRule: 包含了组合过滤条件,分别是Zone级别和可用性级别,Zone级别过滤为在Eureka注册中一个服务节点有Zone, Region和URL三个身份信息,其中Zone可以理解为机房大区(未指定则由Eureka给定默认值),而这里会对这个Zone的健康情况过滤其下面所有服务节点。可用性级别过滤和AvailabilityFilteringRule的验证非常像,会过滤掉当前并发量较大,或者处于熔断状态的服务节点

       AvailabilityFilteringRule:这个规则底层依赖RandomRobinRule来选取节点,但并非来者不拒,必须要满足它的最低要求的节点才会被选中(节点处于非熔断状态和当前活跃请求数量不能超过阈值)。如果节点满足了要求,无论其响应时间或者当前并发量是什么,都会被选中

       WeightedResponseTimeRule:这个Rule继承自RoundRibbonRule,他会根据服务节点的响应时间计算权重,响应时间越长权重就越低,响应越快则权重越高,权重的高低决定了机器被选中概率的高低。也就是说,响应时间越小的机器,被选中的概率越大  

       ResponseTimeWeightedRule:作用同 WeightedResponseTimeRule,ResponseTime-Weighted Rule 后来改名为 WeightedResponseTimeRule

       RoundRobinRule默认策略,轮询选择,轮询 index,选择 index 对应位置的 Server

       RandomRule:随机选择一个 Server

       RetryRule:对选定的负载均衡策略机上重试机制,也就是说当选定了某个策略进行请求负载时在一个配置时间段内若选择 Server 不成功,则一直尝试使用 subRule 的方式选择一个可用的 Server

2.1 配置负载均衡策略

  方式1:代码方式

  1. @Configuration
  2. public class RibbonConfiguration {
  3. @Bean
  4. public IRule defaultLBStrategy() {
  5. return new RandomRule();
  6. }

 方式2:配置文件方式

ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule

2.2指定单个服务的负载均衡策略

方式1:代码方式

        只需要在启动类或者配置类上增加注解

  1. #这里的name指的是serviceId
  2. @RibbonClient(name = "producer-one", configuration = com.netflix.loadbalancer.RoundRobinRule.class)

方式2:配置文件方式

producer-one.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule

如果同时应用了以上两种方式去配置负载均衡,注解的优先级更高,因为配置文件的加载顺序在注解之前,后加载的配置会覆盖先前配置。

3.饥饿加载配置 

          Ribbon是在第一次方法调用的时候才去初始化LoadBalancer。这样看来,第一个方法请求不仅仅包含HTTP连接和方法的响应时间,还包括了LoadBalancer的创建耗时。假如你的方法本身就比较耗时的话,而且超时时间又设置的比较短,那么很大可能这第一次http调用就会失败。其实还有很多框架也实现了类似的懒加载功能,比如Hibernate的lazy-fetch,懒加载在大部分情况下可以节省系统资源开销,但某些情况下反而导致服务响应时间被延长。

  1. #开启Ribbon的饥饿加载模式
  2. ribbon.eager-load.enabled=true
  3. #指定需要饥饿加载的服务名,若有多个则用逗号隔开
  4. ribbon.eager-load.clients=producer-one

4.其他配置

4.1  脱离Eureka,单独使用ribbon

  1. # 禁用 Eureka
  2. ribbon.eureka.enabled=false
  3. # 禁用 Eureka 后手动配置服务地址
  4. producer-one.ribbon.listOfServers=localhost:50000,localhost:50001

禁用了 Eureka 之后,就不能使用服务名称去调用接口了,必须指定服务地址。

4.2 其他配置

  1. #控制ribbon下面的配置是否生效,默认true
  2. ribbon.http.client.enabled=false
  3. # 请求连接的超时时间
  4. ribbon.ConnectTimeout=2000
  5. # 请求处理的超时时间
  6. ribbon.ReadTimeout=2000
  7. #不指定Ribbon默认使用轮询进行重试
  8. ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RetryRule
  9. # 在所有HTTP Method进行重试
  10. ribbon.OkToRetryOnAllOperations=true
  11. # 每台机器最大重试次数
  12. ribbon.MaxAutoRetries=2
  13. # 可以再重试几台机器
  14. ribbon.MaxAutoRetriesNextServer=2
  15. #也可以为每个Ribbon客户端设置不同的超时时间, 通过服务名称进行指定:
  16. #producer-one.ribbon-config-demo.ribbon.ConnectTimeout=2000
  17. #producer-one.ribbon-config-demo.ribbon.ReadTimeout=500

 ConnectTimeout创建会话的连接时间,注意,不是服务的响应时间,而是本机与服务建立会话的时间。

ReadTimeout当连接建立好之后,如果对方服务没有在规定时间内返回,则直接进行重试。

最大超时时间计算公式:MAX(Response Time) = (ConnectTimeout + ReadTimeout) * (MaxAutoRetries + 1) * (MaxAutoRetriesNextServer + 1) 

5@LoadBalanced 注解原理

 Spring Cloud 给我们做了大量的底层工作,我们使用RestTemplate实现负载均衡只需要加一个@LoadBalanced 就可以了,主要的逻辑就是给 RestTemplate 增加拦截器,在请求之前对请求的地址进行替换,或者根据具体的负载策略选择服务地址,然后再去调用。(可以查看源码org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration)。这里自定义一个@LoadBalanced来实现负责均衡。

1.新建一个拦截类MyLoadBalancerInterceptor

  1. public class MyLoadBalancerInterceptor implements ClientHttpRequestInterceptor {
  2. private LoadBalancerClient loadBalancer;
  3. private LoadBalancerRequestFactory requestFactory;
  4. public MyLoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
  5. this.loadBalancer = loadBalancer;
  6. this.requestFactory = requestFactory;
  7. }
  8. public MyLoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
  9. this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
  10. }
  11. @Override
  12. public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
  13. final ClientHttpRequestExecution execution) throws IOException {
  14. final URI originalUri = request.getURI();
  15. String serviceName = originalUri.getHost();
  16. System.out.println("进入自定义的请求拦截器中" + serviceName);
  17. Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
  18. return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
  19. }
  20. }

2.增加一个注解

  1. @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @Qualifier
  6. public @interface MyLoadBalanced {
  7. }

3.增加一个自动配置类,将拦截器对象放入Spring中

  1. @Configuration
  2. public class MyLoadBalancerAutoConfiguration {
  3. @MyLoadBalanced
  4. @Autowired(required = false)
  5. private List<RestTemplate> restTemplates = Collections.emptyList();
  6. @Bean
  7. public MyLoadBalancerInterceptor myLoadBalancerInterceptor(final LoadBalancerClient loadBalancer) {
  8. return new MyLoadBalancerInterceptor(loadBalancer);
  9. }
  10. @Bean
  11. public SmartInitializingSingleton myLoadBalancedRestTemplateInitializer(MyLoadBalancerInterceptor myLoadBalancerInterceptor) {
  12. return new SmartInitializingSingleton() {
  13. @Override
  14. public void afterSingletonsInstantiated() {
  15. for (RestTemplate restTemplateTemp : MyLoadBalancerAutoConfiguration.this.restTemplates) {
  16. List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplateTemp.getInterceptors());
  17. list.add(myLoadBalancerInterceptor);
  18. restTemplateTemp.setInterceptors(list);
  19. }
  20. }
  21. };
  22. }
  23. }

4.只需要将原来的@LoadBalanced替换成@MyLoadBalanced就可以了

 

参考:

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发