閒魚在ServiceMesh的探索和實踐

  背景:安全

  

  在阿里服務端開發以Java爲主的大背景下,其餘異構語言業務如何調用現有Java服務,如何與集團中間件打通,就成爲使用非Java語言團隊必需要解決的首要問題。併發

  

  已有方案問題:框架

  

  在ServiceMesh方案成熟以前,咱們採用:經過Dart C/C++擴展方式調用各中間件客戶端SO庫(類JNI)。該方案在業務初期很好的解決了Dart服務端生態建設問題。可是該方案還存在如下幾個問題:運維

  

  運維耦合度高。業務代碼和客戶端SO庫代碼打包在一塊兒,運行在同一進程,一旦微服務框架須要升級,業務代碼也須要維護和重啓。dom

  

  複雜性:進程內的多個語言環境,跨語言數據表示和傳輸等問題,都會增長系統的複雜性,下降原有服務的性能。ide

  

  接入成本高函數

  

  新功能滯後微服務

  

  ServiceMesh方案:性能

  

  因爲現有方案存在的一些問題,咱們轉向ServiceMesh尋找解決問題的思路測試

  

  如上圖所示:與目前比較常見的微服務框架相比,ServiceMesh把微服務客戶端核心功能獨立出來,並做爲一個獨立Proxy進程部署在每個主機上,業務進程經過Proxy進程與外界通訊。這個獨立的Proxy進程就是ServiceMesh的核心: SideCar。

  

  業務進程和SideCar之間最多見的兩種通訊方案:1. 基於Iptables的流量攔截轉發方案,2. 業務進程經過輕量化Mesh客戶端直連SideCar。從實現原理上看,Iptables方案相比直連方案會有必定的性能損耗和延遲。咱們選擇的ALiMesh方案採用了輕量級Mesh客戶端方案。

  

  Mesh化以後,業務進程只包含業務代碼和輕量化的Mesh Client,代碼邏輯變得簡單,問題定位更清晰。業務同窗能夠更專一業務開發,而不用關注微服務龐雜的邏輯。微服務框架核心功能的開發維護擴展升級等工做由專門的Mesh團隊負責,獨立升級維護,與業務解耦,業務無感知。

  

  ServiceMesh方案解決了現有方案存在的:運維成本、接入成本問題,代碼複雜問題。 並且採用開源的Mesh方案,還能夠藉助開源的力量,不斷增長新的功能。

  

  ALiMesh接入:

  

  SideCar的引入,使得本來業務跟微服務之間的進程內通訊轉變成進程間的通訊,進出流量增長了一跳,那麼ServiceMesh的引入對業務性能帶來的影響具體怎麼樣?接下來咱們基於ALiMesh(Istio開源方案阿里版本)一塊兒分狀況看下。

  

  ALiMesh提供了2種接入方案:Http方式、HSF方式。其中Http方式又分爲Http1.0和Http2.0方式。

  

  AliMesh Http方案(快速接入方案):

  

  如圖所示,Http方式下:在數據面,業務進程與SideCar,SideCar與Service Provider之間採用Http協議交互,數據編碼採用Json。業務進程集成了基於Http協議的Mesh Client,Mesh SideCar經過泛化調用遠程調用Java HSF服務。

  

  而在控制面: ISTIO控制面同步ConfigServer的服務提供者列表數據,SideCar跟ISTIO pilot走原生的服務同步通道。

  

  因爲Http協議的通用性,該方案接入簡單,快速的驗證了Mesh方案的可行性,可是性能還達不到業務的線上要求,經測試,主要指標以下:

  

  備註:目前閒魚只使用了ServiceMesh OutBound功能。爲了模擬線上詳情頁真實流量狀況,每次上游請求處理過程會調用21次下游Java HSF服務, 因此圖中QPS換算成Mesh流量時,須要乘以21倍,如下測試都是如此

  

  如圖所示:Mesh方式相比直連方式,Consumer側CPU消耗增加一倍,每一次RPC調用RT增長了近2ms。且HSF Provider側CPU也有近40%的增長,這一點跟HSF同窗的測試結果基本吻合。通過分析,咱們初步定位引發CPU消耗增長的主要緣由是Http1.1協議的鏈接方式(已經使用了鏈接池)和數據編碼。

  

  爲了驗證該方案的問題所在,咱們測試接入了Http2.0方案。Http2.0相比Http1.x,在鏈接多路複用、數據格式、head壓縮等等方面具備自然的優點。通過測試,ALiMesh的性能也較Http1.x有了較大的提高。部分知足或者接近咱們的技術要求。詳細指標以下圖所示:

  

  如圖所示,優化後,業務進程Consumer側,CPU和RT消耗稍稍有些超標(CPU 增長不超過20%)。爲了探索更高性能,更低延遲的方案,咱們轉向了HSF私有協議方案。

  

  AliMesh HSF擴展協議方案(高性能方案):

  

  如圖所示,HSF方案下,HSF RPC協議實現爲Mesh SideCar的一個擴展協議。在數據面:業務進程與SideCar,SideCar與Service Provider 之間採用HSF 2.0私有協議,數據編碼採用Hessian 1.0。業務進程集成了Mesh化改造的HSFCPP SO庫做爲MeshClient,負責與Mesh SideCar通訊。而在控制面:SideCar與Configsvr直連,同步服務提供者列表和配置信息,採用差量同步方式,以下降控制面板的CPU消耗。詳細測試數據以下:

  

  通過不斷優化,最終成功將Mesh CPU增加控制在20%之內,每跳RPC調用RT增長控制在1ms之內。

  

  ServiceMesh在閒魚的應用:

  

  目前Dart+ALiMesh方案在閒魚服務端已經穩定運行八個月+,服務於閒魚詳情頁、猜你喜歡,租房首頁等業務, 期間Mesh屢次進行優化、升級、擴展功能等運維工做,業務進程都無感,正常對外提供服務,業務同窗不須要參與。

  

  ALiMesh引入後,對線上業務RT的影響以下圖所示:橙色的曲線是Mesh化後的業務RT監控曲線,藍色的曲線是Mesh化前一週業務RT監控曲線,排除線上環境平常的波動後,ALiMesh的引入對線上業務RT的影響至關小。

  

  

int num = 1;

List<int> list = new List<int>(www.yishengyule158.com);

for (int i = 1; i <= 2000; www.xcdeyiju.com++)

{

list.Add(www.boyunylpt1.com);

}

Console.WriteLine($"num初始值爲:" + num.ToString());

list.AsParallel().ForAll(n =>

{

num++;

});

Console.WriteLine($"不加鎖,併發{list.Count}次後爲:" + num.ToString());

Console.ReadKey(www.jujinyule.com );

複製代碼

這段代碼是讓一個變量執行2000次自增,正常結果應該是2001,但實際結果以下:

 

 

 

有經驗的同窗,立馬能想到須要加鎖了,C#內置了不少鎖對象,如lock 互斥鎖,Interlocked 內部鎖,Monitor 這幾個比較常見,lock內部實現其實就是使用了Monitor對象。對變量自增,Interlocked對象提供了,變量自增,自減、或者相加等方法,咱們使用自增方法Interlocked.Increment,函數定義爲:int Increment(ref int num),該對象提供原子性的變量自增操做,傳入目標數值,返回或者ref num都是自增後的結果。 在以前的基礎上咱們增長一些代碼:

 

複製代碼

num = 1;

Console.WriteLine($"num初始值爲:" + num.ToString());

list.AsParallel(www.huichengtxgw.com).ForAll(n =>

{

Interlocked.Increment(ref num);

});

Console.WriteLine($"使用內部鎖,併發{list.Count}次後爲:" + num.ToString());

Console.ReadKey();

複製代碼

咱們來看運行結果:

 

 

 

加了鎖以後ID重複算是解決了,其實別高興太早,因爲正常的環境有了ID咱們還有用這些ID來構建對象呢,因而又寫了寫代碼,用集合來添加這些ID,爲了更真實的模擬生產環境,我在forAll裏面又加了一層循環代碼以下:

 

複製代碼

num = 1;

Random random = new Random();

var total = 0;

var m = new ConcurrentBag<int>();

list.AsParallel(www.yacuangyl.com).ForAll(n =>

{

var c = random.Next(1, 50);

Interlocked.Add(ref total, c);

for (int i = 0; i < c; i++)

{

Interlocked.Increment(ref num);

m.Add(num);

}

});

Console.WriteLine($"使用內部鎖,併發+內部循環{list.Count}次後爲:" + num.ToString());

Console.WriteLine($"實際值爲:{total + 1}");

var l = m.GroupBy(n => n).Where(o => o.Count() > 1);

Console.WriteLine($"併發裏面使用安全集合ConcurrentBag添加num,集合重複值:{l.Count()}個");

Console.ReadKey();

  

  ServiceMesh方案,將微服務邏輯和服務間通訊這些與業務無關的邏輯從業務應用中解耦出來,讓業務應用瘦身,讓業務同窗更專一於業務開發。同時也讓異構語言可以低成本的創建服務端生態,接入現有系統。

  

  固然對於性能損失,我的認爲整體利大於弊。業務團隊能夠根據本身業務實際狀況進行測試評估,權衡利弊是否要接入ServiceMesh。

  

  接下來咱們會進一步擴大AliMesh在閒魚的應用,並與ALiMesh合做,推進AliMesh在Dart Faas落地,適配更多的中間件。

相關文章
相關標籤/搜索