抽空本身寫了個簡易版的rpc框架,想了下怎麼搞負載均衡, 最簡單的方式就是搞個配置文件放置服務地址,直接讀配置文件,轉而想到配置文件能夠放zk,至關於用zk來作配置中心或者服務發現。 優秀的dubbo項目就能夠這麼作,立刻參考了下谷歌的grpc,發現了一篇谷歌很棒的文章,拜讀了下(也借用了谷歌這篇文章的圖片),很不錯,想寫一些我本身的看法。nginx
rpc通訊自己並不複雜,只要定好協議怎麼處理問題不大,可是負載均衡的策略是值得推敲的。算法
通常狀況下,負載均衡的策略有如下兩種後端
1. 代理服務
客戶端並不知道服務端的存在,它全部的請求都打到代理服務,由代理服務去分發到服務端,而且實現公平的負載算法。 客戶機可能不可信,這種狀況經過用戶面向用戶的服務,相似於咱們的nginx將請求分發到後端機器。服務器
缺點: 客戶端不知道後端的存在,且客戶端不可信,延遲會更高且代理服務會影響服務自己的吞吐量cookie
優勢: 在中間層作監控等攔截操做特別棒。負載均衡
如圖: 框架
2. 客戶端負載均衡
客戶端知道有多個後端服務,由客戶端去選擇服務端,而且客戶端能夠從後端服務器中本身總結出一份負載的信息,實現負載均衡算法。 這種方式最簡單的實現就是我上面說的直接搞個配置文件,調用的時候隨機或者輪詢服務端便可。ide
如圖: 模塊化
優勢:
高性能,由於消除了第三方的交互微服務
缺點:
客戶端會很複雜,由於客戶端要跟蹤服務器負載和健康情況,客戶端實現負載均衡算法。多語言的實現和維護負擔也很麻煩,且客戶端須要被信任,得是靠譜的客戶端。
以上是介紹了兩種負載均衡的方案,下面要說的就是使用代理方式負載均衡的幾種詳細的方案
代理方式的負載均衡有不少種
代理負載平衡能夠是 L3/L4(傳輸級別)
或 L7(應用程序級別)
。
在 L3/L4
中,服務器終止TCP鏈接並打開另外一個鏈接到所選的後端。
L7
只是在客戶端鏈接到服務端端鏈接之間搞一個應用來作中間人。
L3/L4
級別的負載均衡按設計只作不多的處理,與L7級別的負載均衡相比的延遲會更少,並且更便宜,由於它消耗更少的資源。
在L7(應用程序級)負載平衡中,負載均衡服務終止並解析協議。負載均衡服務能夠檢查每一個請求並根據請求內容分配後端。這就意味監控攔截等操做能夠很是方便快捷的作在這裏。
L3/L4 vs L7
正確的打開方式有一下幾種
- 這些鏈接之間的RPC負載變化很大: 建議使用L7.
- 存儲或計算相關性很重要 :建議使用L7,並使用cookie或相似的路由請求來糾正服務端.
- 設備資源少(缺錢): 建議使用 L3/L4.
- 對延遲要求很嚴格(就是要快): L3/L4.
下面要說的就是客戶端實現負載均衡方式的詳細方案:
public class Test
{
public class InnerClass
{
public int getSum(int x,int y)
{
return x+y;
}
}
public static void main(String[] args)
{
Test.InnerClass testInner =new Test().new InnerClass();
int i = testInner.getSum(2/3);
System.out.println(i); //輸出5
}
}
實例內部類
實例內部類是指沒有用 static 修飾的內部類
public class Outer
{
class Inner
{
//實例內部類
}
}
在外部類的靜態方法和外部類之外的其餘類中,必須經過外部類的實例建立內部類的實例,若是有多層嵌套,則內部類能夠訪問全部外部類的成員
public class Outer
{
class Inner{}
Inner i=new Inner(); //類內部不須要建立外部類實例
public void method0()
{
Inner j=new Inner(); //類內部不須要建立外部類實例
}
public static void method1()
{
Inner r=new Outer().new inner(); //靜態方法須要建立外部類實例
}
class Inner1
{
Inner k=new Inner(); //不須要建立外部類實例
}
}
class OtherClass
{
Outer.Inner i=new Outer(yongshi123.cn).new Inner(); //其餘類使用時須要建立外部類實例
}
靜態內部類
靜態內部類是指使用 static 修飾的內部類
public class Outer
{
static class Inner
{
//靜態內部類
}
}
在建立靜態內部類的實例時,不須要建立外部類的實例
public class Outer
{
static class Inner{}
}
class OtherClass
{
Outer.Inner oi=new Outer.Inner();
}
局部內部類
局部內部類是指在一個方法中定義的內部類
public class Test
{
public void method()
{
class Inner
{
//局部內部類
}
}
}
局部內部類與局部變量同樣,不能使用訪問控制修飾符(public、private 和 protected)和 static 修飾符修飾,局部內部類只在當前方法中有效,局部內部類中能夠訪問外部類的全部成員
public class Test
{
Inner i=new Inner(www.hnxinhe.cn); //編譯出錯
Test.Inner ti=new Test.Inner(); //編譯出錯
Test.Inner ti2=new Test().new Inner(); //編譯出錯
public void method()
{
class Inner{}
Inner i=new Inner();
}
}
匿名類
匿名類是指沒有類名的內部類,必須在建立時使用 new 語句來聲明類
new<類或接口>()
{
//類的主體
};
這種形式的 new 語句聲明一個新的匿名類,它對一個給定的類進行擴展,或者實現一個給定的接口。使用匿名類可以使代碼更加簡潔、緊湊,模塊化程度更高
匿名類有兩種實現方式:
繼承一個類,重寫其方法。
實現一個接口(能夠是多個),實現其方法。
public class Out
{
void show()
{
System.out.println("調用 Out 類的 show() 方法");
}
}
public class TestAnonymousInterClass
{
//在這個方法中構造一個匿名內部類
private void show(www.xgjrfwsc.cn)
{
Out anonyInter=new Out()
{
//獲取匿名內部類的實例
void show()
{
System.out.println("調用匿名類中的 show() 方法");
}
};
anonyInter.show();
}
public static void main(String[] args)
{
TestAnonymousInterClass test=new TestAnonymousInterClass();
test.show();
}
1. 笨重的客戶端
這就意味着客戶端中實現負載平衡策略,客戶端負責跟蹤可用的服務器以及用於選擇服務器的算法。 客戶端一般集成與其餘基礎設施(如服務發現、名稱解析、配額管理等)通訊的庫,這就很複雜龐大了。
2. Lookaside 負載均衡 (旁觀?)
旁觀式負載平衡也稱爲外部負載平衡,使用後備負載平衡,負載平衡的各類功能智能的在一個單獨的特殊的負載均衡服務中實現。客戶端只須要查詢這個旁觀式的負載均衡服務, 這個服務就能給你最佳服務器的信息,而後你拿這個數據去請求那個服務端。 就像我一開說的好比把服務端的信息註冊到zk,由zk去作負載均衡的事情,客戶端只須要去zk取服務端數據,拿到了服務端地址後,直接向服務端請求。
如圖:
以上說了這麼多,到底服務間的負載均衡應該用哪一個,總結如下幾點:
-
客戶端和服務器之間很是高的流量,且客戶端是可信的,建議使用‘笨重’的客戶端 或者 Lookaside 負載均衡
-
傳統設置——許多客戶端鏈接到代理背後的大量服務,須要服務端和客戶端之間有一個橋樑,建議使用代理式的負載均衡
-
微服務- N個客戶端,數據中心有M個服務端,很是高的性能要求(低延遲,高流量),客戶端能夠不受信任,建議使用 Lookaside 負載均衡