關於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); }