1. 程式人生 > 其它 >關於Java效能優化的幾點建議,實戰案例

關於Java效能優化的幾點建議,實戰案例

Ribbo介紹原文連線

1.Ribbon簡介

Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。

簡單的說,Ribbon是Netflix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法,將Netflix的中間層服務連線在一起。Ribbon客戶端元件提供一系列完善的配置項如連線超時,重試等。簡單的說,就是在配置檔案中列出Load Balancer(簡稱LB)後面所有的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連線等)去連線這些機器。我們也很容易使用Ribbon實現自定義的負載均衡演算法。

負載均衡

LB,即負載均衡(Load Balance),在微服務或分散式叢集中經常用的一種應用。

負載均衡簡單的說就是將使用者的請求平攤的分配到多個服務上,從而達到系統的HA。

常見的負載均衡有軟體Nginx,LVS,硬體 F5等。

相應的在中介軟體,例如:dubbo和SpringCloud中均給我們提供了負載均衡,SpringCloud的負載均衡演算法可以自定義。

集中式LB

即在服務的消費方和提供方之間使用獨立的LB設施(可以是硬體,如F5, 也可以是軟體,如nginx), 由該設施負責把訪問請求通過某種策略轉發至服務的提供方;

程序內LB

將LB邏輯整合到消費方,消費方從服務註冊中心獲知有哪些地址可用,然後自己再從這些地址中選擇出一個合適的伺服器。

Ribbon就屬於程序內LB,它只是一個類庫,集成於消費方程序,消費方通過它來獲取到服務提供方的地址。

2.Ribbo架構

3.IRule的預設演算法

IRule:根據特定演算法中從伺服器列表中選取一個要訪問的服務,Ribbon預設的演算法為輪詢演算法;

Ribbon中的7中負載均衡演算法:

(1)RoundRobinRule:輪詢;

(2)RandomRule:隨機;

(3)AvailabilityFilteringRule:會先過濾掉由於多次訪問故障而處於斷路器狀態的服務,還有併發的連線數量超過閾值的服務,然後對剩餘的服務列表按照輪詢策略進行訪問;

(4)WeightedResponseTimeRule:根據平均響應時間計算所有服務的權重,響應時間越快的服務權重越大被選中的概率越大。剛啟動時如果統計資訊不足,則使用RoundRobinRule(輪詢)策略,等統計資訊足夠,會切換到WeightedResponseTimeRule;

(5)RetryRule:先按照RoundRobinRule(輪詢)策略獲取服務,如果獲取服務失敗則在指定時間內進行重試,獲取可用的服務;

(6)BestAvailableRule:會先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然後選擇一個併發量最小的服務;

(7)ZoneAvoidanceRule:複合判斷Server所在區域的效能和Server的可用性選擇伺服器;

3.負載規則替換

3.1配置類

注意:不要被@ComponentScan掃描到

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author 26414
 */
@Configuration
public class MySelfRule {

  @Bean
  public IRule myRule(){
    //隨機
    return new RandomRule();
  }

}

3.2在主啟動類上添加註解

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)

4.輪詢演算法原理

4.1rest介面請求次數 % 伺服器叢集總數量 = 實際呼叫伺服器下標,每次伺服器重啟後rest介面請求次數從1開始。

4.2手寫輪詢演算法

4.2.1服務提供者Controller程式碼

 @Value("${server.port}")
  private String serverPort;

 @GetMapping(value = "/payment/lb")
  public String getPaymentLB()
  {
    return serverPort;
  }

4.2.2服務消費者程式碼

1.介面

package com.fly.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

/**
 * @author 26414
 */
public interface LoadBalancer {

  /**
   * 初始化
   * @param serviceInstances 例項
   * @return ServiceInstance
   */
  ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

2.實現類

package com.fly.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 26414
 */
@Component
public class MyLB implements LoadBalancer {

  private AtomicInteger atomicInteger = new AtomicInteger(0);

  private final int getAndIncrement(){
    int current;
    int next;
    do {
      current = this.atomicInteger.get();
      next = current > 2147483647 ? 0 : current + 1;
    }while (!this.atomicInteger.compareAndSet(current,next));
    System.out.println("next = " + next);
    return next;
  }

  @Override
  public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
    int index = getAndIncrement() % serviceInstances.size();
    return serviceInstances.get(index);
  }
}

3.呼叫

 @GetMapping(value = "/consumer/payment/lb")
  public String getPaymentLB()
  {
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    if(instances == null || instances.size() < 0){
      return null;
    }
    ServiceInstance serviceInstance = loadBalancer.instances(instances);
    URI uri = serviceInstance.getUri();
    return restTemplate.getForObject(uri + "/payment/lb",String.class);
  }