負載均衡在架構設計中是常常提到的一種方案,用以提升系統處理量。今天用幾句代碼實現Round Robin方式,用白話文說就是有活你們輪着幹。在看了Ribbion源碼以後,確實是幾行代碼。安全
private List<String> serverList = new LinkedList<>(); public RoundRibbon() { serverList.add("http://server.01"); serverList.add("http://server.02"); serverList.add("http://server.03"); serverList.add("http://server.04"); serverList.add("http://server.05"); }
int nextServerIndex = (currentIndex + 1) % serverList.size();
在 Netflix/ribbon 的 RoundRobinRule 中實現代碼以下:架構
public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { //獲取可用的server列表 List<Server> reachableServers = lb.getReachableServers(); List<Server> allServers = lb.getAllServers(); int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } //核心實現,獲取server索引 int nextServerIndex = incrementAndGetModulo(serverCount); server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } //是這種 if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next. server = null; } //重試十次以後,沒有獲取到可用的服務,警告日誌 if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; } /** * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * @return The next value. */ private int incrementAndGetModulo(int modulo) { for (;;) { //獲取當前的服務索引值 int current = nextServerCyclicCounter.get(); //經過取餘的方式計算下一個索引值 int next = (current + 1) % modulo; //經過 CAS 設置下一個搜索引值(解決併發索引值可能重複的問題) if (nextServerCyclicCounter.compareAndSet(current, next)) return next; } }
輪詢方式實現很簡單,關鍵難點就是解決線程安全問題。例子中經過使用CAS解決,效率會高一些。也能夠使用鎖。併發