實現一個分散式排程系統-LoadBalance和Ha策略
上一篇主要介紹了基於zookeeper的服務註冊實現:
對於我們的系統還需要一些策略,比如worker機器的選擇策略,請求失敗的策略,讓我們的系統更加的可靠。
客戶端負載均衡
對於loadbalance,主要是實現幾個方法,讓我們的manager客戶端進行worker機器進行合適的選擇。比如輪訓,隨機,或者權重。
具體實現
0-工具方法
private int getNextNonNegative() {
return MathUtil.getNonNegative(idx.getAndIncrement());
}
public static int getNonNegative(int originValue){
//透過二進位制位操作將originValue轉化為非負數
return 0x7fffffff & originValue;
}
1-隨機
@Override
public Endpoint doSelect(RequestPacket request) {
List<Endpoint> endpoints = getEndpoints();
int idx = (int) (ThreadLocalRandom.current().nextDouble() * endpoints.size());
for (int i = 0; i < endpoints.size(); i++) {
Endpoint ref = endpoints.get((i + idx) % endpoints.size());
//TODO 判斷是否存活
return ref;
}
return null;
}
2-輪訓
@Override
public Endpoint doSelect(RequestPacket request) {
List<Endpoint> endpoints = getEndpoints();
int index = getNextNonNegative();
for (int i = 0; i < endpoints.size(); i++) {
Endpoint ref = endpoints.get((i + index) % endpoints.size());
return ref;
}
return null;
}
3-低併發度優先: referer的某時刻的call數越小優先順序越高
低併發referer獲取策略:
由於Referer List可能很多,比如上百臺,如果每次都要從這上百個Referer或者最低並 發的幾個,效能有些損耗,因此 random.nextInt(list.size()) 獲取一個起始index,然後獲取最多不超過MAX_REFERER_COUNT的狀態是isAvailable的referer進行判斷activeCount.
protected Endpoint doSelect(RequestPacket request) {
List<Endpoint> endpoints = getEndpoints();
int refererSize = endpoints.size();
int startIndex = ThreadLocalRandom.current().nextInt(refererSize);
int currentCursor = 0;
int currentAvailableCursor = 0;
Endpoint endpoint = null;
while (currentAvailableCursor < MAX_REFERER_COUNT && currentCursor < refererSize) {
Endpoint temp = endpoints.get((startIndex + currentCursor) % refererSize);
currentCursor++;
currentAvailableCursor++;
if (endpoint == null) {
endpoint = temp;
} else {
if (compare(endpoint, temp) > 0) {
endpoint = temp;
}
}
}
return endpoint;
}
4 ......更多
Ha策略
這裡就簡單實現兩種:
1- FailfastHaStrategy 快速失敗
我們透過loadBalance選擇一個worker機器地址,然後發起請求,如果出現錯誤就立刻報錯失敗。
2- FailoverHaStrategy 會帶有重試功能
我們透過loadBalance會選擇一組worker機器,如果第一個失敗,會輪訓呼叫後面的機器,直到成功,或者全部失敗
實現
1-FailfastHaStrategy
//快速失敗策略
public ResponsePacket call(RequestPacket request, LoadBalance loadBalance) {
//獲取執行的服務
Endpoint endpoint = loadBalance.select(request);
log.info("{}FailfastHaStrategy start to call {},request:{}", Constants.LOG_PREFIX, endpoint.getHost(), request.toString());
//獲取nettyClient 傳送RPC請求
return request(endpoint, request);
}
2-FailoverHaStrategy
public class FailoverHaStrategy extends AbstractHaStrategy {
protected ThreadLocal<List<Endpoint>> endpointHolder = new ThreadLocal<List<Endpoint>>() {
@Override
protected java.util.List<Endpoint> initialValue() {
return new ArrayList<Endpoint>();
}
};
public ResponsePacket call(RequestPacket request, LoadBalance loadBalance) {
//根據規則獲取一組endpoint
List<Endpoint> endpointList = selectReferers(request, loadBalance);
if (endpointList.isEmpty()) {
throw new CommonException(999999, String.format("FailoverHaStrategy No Endpoint loadbalance:%s", loadBalance));
}
int tryCount = request.getRetries();//獲取使用者配置的重試次數
// 如果有問題,則設定為不重試
if (tryCount < 0) {
tryCount = 0;
}
for (int i = 0; i <= tryCount; i++) {
Endpoint endpoint = endpointList.get(i % endpointList.size());
log.info("{}FailoverHaStrategy start to call ......{},tryCount:{},request:{}", Constants.LOG_PREFIX, endpoint.getHost(), (i + 1), request.toString());
try {
//獲取nettyClient 傳送RPC請求
return request(endpoint, request);
} catch (RuntimeException e) {
// 對於業務異常,直接丟擲,不進行重試
if (e instanceof CommonException) {
throw e;
} else if (i >= tryCount) {
log.info("{}tryCount is over......throw e", Constants.LOG_PREFIX);
throw e;
}
log.info("{}try run ,tryCount:{}", Constants.LOG_PREFIX, (i + 1));
}
}
throw new CommonException(999999, "FailoverHaStrategy.call should not come here!");
}
protected List<Endpoint> selectReferers(RequestPacket request, LoadBalance loadBalance) {
List<Endpoint> endpoints = endpointHolder.get();
endpoints.clear();
loadBalance.selectToHolder(request, endpoints);
return endpoints;
}
}
總結
後續我們會繼續介紹一些核心功能,比如代理的實現和transport層的實現
完整程式碼見github:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/854/viewspace-2820356/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談分散式任務排程系統Celery的設計與實現分散式
- Quartz排程系統入門和排程高可用實現方案quartz
- Aloha:一個分散式任務排程框架分散式框架
- 系統設計:如何設計一個分散式作業排程器 ?- Rakshesh分散式
- 分散式任務排程系統設計小結分散式
- 分散式系統設計策略分散式
- 分散式任務排程分散式
- 實現一個任務排程系統,看這篇文章就夠了
- 開源分散式任務排程系統就選:DolphinScheduler分散式
- 【Python】輕量級分散式任務排程系統-RQPython分散式
- 一個簡單的基於 Redis 的分散式任務排程器 —— Java 語言實現Redis分散式Java
- Spring Boot Quartz 分散式叢集任務排程實現Spring Bootquartz分散式
- 分散式系統Session 實現方式分散式Session
- 分散式排程任務-ElasticJob分散式AST
- 實現一個 Redis 分散式鎖Redis分散式
- 大型分散式系統現場,阿里大牛帶你實戰分散式系統分散式阿里
- go實現簡易分散式系統Go分散式
- 新一代分散式任務排程框架分散式框架
- Zeus-Master-週期性排程策略實現AST
- 分散式系統架構之構建你的任務排程中心分散式架構
- Easy Scheduler 1.0.2 釋出,分散式工作流任務排程系統分散式
- LTS分散式任務排程部署分散式
- ZooKeeper分散式任務排程中心分散式
- 實現一個redis的分散式鎖Redis分散式
- Flink排程之排程器、排程策略、排程模式模式
- Elastic-job實戰(分散式作業排程框架)AST分散式框架
- haipproxy核心校驗和排程策略AI
- 冰激凌和分散式系統分散式
- 轉一個大牛對分散式系統和cqrs的反思文章分散式
- 一個輕量級的分散式定時任務排程平臺-Cloudtask分散式Cloud
- JavaScript 如何實現一個響應式系統JavaScript
- 想做個分散式叢集系統,不知道怎麼實現分散式
- 基於Redis實現一個分散式鎖Redis分散式
- 如何實現一個分散式RPC框架分散式RPC框架
- HA分散式叢集搭建分散式
- 07 系統排程
- APS高階計劃排程系統和生產排產系統
- Spark:一個高效的分散式計算系統Spark分散式