重溫最少化集群搭建,我相信很多朋友都已經搭建出來,基於Watch機制也實現了出來,相信也有很多朋友有了自己的實現思路,但是,很多朋友有個疑問,我API和服務分離好了,怎么通過服務中心進行發現呢,這個過程是通過什么來實現的呢,本篇我們就來介紹這個“調用過程”。
本篇干貨較多,沒有代碼,閱讀請注意休息!
服務化引入
網站系統隨着不斷的發展,越來越復雜,架構的變遷也會從MVC—>SOA—>微服務,從簡單到復雜,從集中到分布,服務化框架的引入是SOA—>微服務過程必須要解決的問題。面對服務的增多,服務分布的部署,服務與服務之間相互的調用,不得不使用服務化框架去解決,著名的dubbo和spring cloud就是這樣產生的。
服務化框架介紹
服務化框架分為兩部分:遠程調用、注冊中心。
-
遠程調用:遠程調用的傳輸協議有很多種,可以走http、webservice、tcp等。facebook的thrift、google的grpc、alibaba的dubbo都是世界上主流的rpc框架。其重點在於安全、快速、跨語言。
-
注冊中心:用於存放,服務的ip地址和狀態信息等。比較好的存放服務信息的方案有:zookeeper、consul、etcd。其重點在於避免單點問題,並且好維護。
服務化框架原理和調用方式
根據上面圖,服務化原理可以分為3步:
-
服務端啟動並且向注冊中心發送服務信息,注冊中心收到后會定時監控服務狀態(常見心跳檢測);
-
客戶端需要開始調用服務的時候,首先去注冊中心獲取服務信息;
-
客戶端創建遠程調用連接,連接后服務端返回處理信息;
第3步又可以細分,下面說說遠程過程調用的原理:目標:客戶端怎么調用遠程機器上的公開方法:
-
客戶端發起調用,將需要調用的服務、方法、參數進行組裝;
-
序列化編碼組裝的消息,這里可以使用json,也可以使用xml,也可以使用protobuf,也可以使用hessian,幾種方案的序列化速度還有序列化后占用字節大小都是選擇的重要指標,對內筆者建議使用高效的protobuf,它基於TCP/IP二進制進行序列化,體積小,速度快。
-
傳輸協議,可以使用傳統的io阻塞傳輸,也可以使用高效的nio傳輸(Netty);
-
服務端收到后進行反序列化,然后進行相應的處理;
-
服務端序列化response信息並且返回;
-
客戶端收到response信息並且反序列化;
RESTful和RPC
RESTful : 嚴格意義上說接口很規范,操作對象即為資源,對資源的四種操作(post、get、put、delete),常見的http api都可以稱為Rest接口。
RPC :
我們常說的遠程方法調用,就是像調用本地方法一樣調用遠程方法,通信協議大多采用二進制方式。
Http vs 高性能二進制協議
http相對更規范,更標准,更通用,無論哪種語言都支持http協議。如果你是對外開放API,例如開放平台,外部的編程語言多種多樣,你無法拒絕對每種語言的支持,相應的,如果采用http,無疑在你實現SDK之前,支持了所有語言,所以,現在開源中間件,基本最先支持的幾個協議都包含RESTful。
RPC協議性能要高的多,例如Protobuf、Thrift、Kyro等,(如果算上序列化)吞吐量大概能達到http的二倍(甚至更高)。響應時間也更為出色。千萬不要小看這點性能損耗,公認的,微服務做的比較好的,例如,netflix、阿里,曾經都傳出過為了提升性能而合並服務。如果是交付型的項目,性能更為重要,因為你賣給客戶往往靠的就是性能上微弱的優勢。
RESTful筆者不做實際操作的介紹,程序員們個個都懂。
gRPC介紹
gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. It enables client and server applications to communicate transparently, and makes it easier to build connected systems.
gRPC是一種可以在任何地方運行的現代、開源、高性能遠程過程調用(RPC)框架,它使客戶端和服務端應用程序透明地通信,並使構建連接的系統更容易。
gRPC 一開始由 google 開發,是一款語言中立、平台中立、開源的遠程過程調用(RPC)系統。
在gRPC里客戶端應用可以像調用本地對象一樣直接調用另一台不同的機器上服務端應用的方法,使得您能夠更容易地創建分布式應用和服務。與許多 RPC 系統類似,gRPC 也是基於以下理念:定義一個服務,指定其能夠被遠程調用的方法(包含參數和返回類型)。在服務端實現這個接口,並運行一個 gRPC 服務器來處理客戶端調用。在客戶端擁有一個存根能夠像服務端一樣的方法。
基於HTTP/2
HTTP/2 提供了連接多路復用、雙向流、服務器推送、請求優先級、首部壓縮等機制。可以節省帶寬、降低TCP鏈接次數、節省CPU,幫助移動設備延長電池壽命等。gRPC 的協議設計上使用了HTTP2 現有的語義,請求和響應的數據使用HTTP Body 發送,其他的控制信息則用Header 表示。
IDL使用ProtoBuf
gRPC使用ProtoBuf來定義服務,ProtoBuf是由Google開發的一種數據序列化協議(類似於XML、JSON、hessian)。ProtoBuf能夠將數據進行序列化,並廣泛應用在數據存儲、通信協議等方面。壓縮和傳輸效率高,語法簡單,表達力強。
多語言支持(C, C++, Python, PHP, Nodejs, C#, Objective-C、Golang、Java)
gRPC支持多種語言,並能夠基於語言自動生成客戶端和服務端功能庫。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它語言的版本正在積極開發中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等語言,grpc-java已經支持Android開發。
與thrift,dubbo,motan等比較

使用gRPC的公司:
- Mochi中國
- 阿里OTS
- 騰訊部分部門
- Tensorflow項目中使用了grpc
- CoreOS — Production API for etcd v3 is entirely gRPC. etcd v3的接口全部使用grpc
- Square — replacement for all of their internal RPC. one of the very first adopters and contributors to gRPC.
- ngrok — all 20+ internal services communicate via gRPC 一個內網轉發產品
- Netflix
- Yik Yak
- VSCO
- Cockroach
gRPC的優點和缺點:
優點:
-
protobuf二進制消息,性能好/效率高(空間和時間效率都很不錯);
-
proto文件生成目標代碼,簡單易用;
-
序列化反序列化直接對應程序中的數據類,不需要解析后在進行映射(XML,JSON都是這種方式);
-
支持向前兼容(新加字段采用默認值)和向后兼容(忽略新加字段),簡化升級;
-
支持多種語言(可以把proto文件看做IDL文件);
-
Netty等一些框架集成;
缺點:
-
GRPC尚未提供連接池,需要自行實現;
-
尚未提供“服務發現”、“負載均衡”機制;
-
因為基於HTTP2,絕大部多數HTTP Server、Nginx都尚不支持,即Nginx不能將GRPC請求作為HTTP請求來負載均衡,而是作為普通的TCP請求。(nginx1.9版本已支持);
-
Protobuf二進制可讀性差(貌似提供了Text_Fromat功能,沒用過);
-
默認不具備動態特性(可以通過動態定義生成消息類型或者動態編譯支持);
protobuf的版本
PB具有三個版本:
1:Google官方版本:https://github.com/google/protobuf/tree/master/csharp(谷歌官方開發、比較晦澀和高大上,主庫名字:Google.ProtoBuf.dll)
2:.Net社區版本(一):https://github.com/mgravell/protobuf-net(.Net社區愛好者開發,寫法上比較符合.net上的語法習慣,主庫名字:protobuf-net.dll)
3:.Net社區版本(二):https://github.com/jskeet/protobuf-csharp-port(據說是由谷歌的.net員工為.net開發,在官方沒有出來csharp的時候開發,到發博文時還在維護,主庫名字:Google.ProtocolBuffers.dll)
至於選用那個版本,跨平台的需求不大的話,可以用版本二、大的話可以選用一或者三。(本文后續選用二為例)
gRPC服務發現與服務治理的方案
目前gRPC主流分布式方案有這么幾種: etcd, zookeeper, consul.
1、集中式LB(Proxy Model)
在服務消費者和服務提供者之間有一個獨立的LB,通常是專門的硬件設備如 F5,或者基於軟件如 LVS,HAproxy等實現。LB上有所有服務的地址映射表,通常由運維配置注冊,當服務消費方調用某個目標服務時,它向LB發起請求,由LB以某種策略,比如輪詢(Round-Robin)做負載均衡后將請求轉發到目標服務。LB一般具備健康檢查能力,能自動摘除不健康的服務實例。 該方案主要問題:
1、單點問題,所有服務調用流量都經過LB,當服務數量和調用量大的時候,LB容易成為瓶頸,且一旦LB發生故障影響整個系統;
2、服務消費方、提供方之間增加了一級,有一定性能開銷。
2、進程內LB(Balancing-aware Client)
針對第一個方案的不足,此方案將LB的功能集成到服務消費方進程里,也被稱為軟負載或者客戶端負載方案。服務提供方啟動時,首先將服務地址注冊到服務注冊表,同時定期報心跳到服務注冊表以表明服務的存活狀態,相當於健康檢查,服務消費方要訪問某個服務時,它通過內置的LB組件向服務注冊表查詢,同時緩存並定期刷新目標服務地址列表,然后以某種負載均衡策略選擇一個目標服務地址,最后向目標服務發起請求。LB和服務發現能力被分散到每一個服務消費者的進程內部,同時服務消費方和服務提供方之間是直接調用,沒有額外開銷,性能比較好。該方案主要問題:
1、開發成本,該方案將服務調用方集成到客戶端的進程里頭,如果有多種不同的語言棧,就要配合開發多種不同的客戶端,有一定的研發和維護成本;
2、另外生產環境中,后續如果要對客戶庫進行升級,勢必要求服務調用方修改代碼並重新發布,升級較復雜。
3、獨立 LB 進程(External Load Balancing Service)
該方案是針對第二種方案的不足而提出的一種折中方案,原理和第二種方案基本類似。
不同之處是將LB和服務發現功能從進程內移出來,變成主機上的一個獨立進程。主機上的一個或者多個服務要訪問目標服務時,他們都通過同一主機上的獨立LB進程做服務發現和負載均衡。該方案也是一種分布式方案沒有單點問題,一個LB進程掛了只影響該主機上的服務調用方,服務調用方和LB之間是進程內調用性能好,同時該方案還簡化了服務調用方,不需要為不同語言開發客戶庫,LB的升級不需要服務調用方改代碼。
該方案主要問題:部署較復雜,環節多,出錯調試排查問題不方便。
服務發現負載均衡實現
gRPC開源組件官方並未直接提供服務注冊與發現的功能實現,但其設計文檔已提供實現的思路,並在不同語言的gRPC代碼API中已提供了命名解析和負載均衡接口供擴展。
其基本實現原理:
1、服務啟動后gRPC客戶端向命名服務器發出名稱解析請求,名稱將解析為一個或多個IP地址,每個IP地址標示它是服務器地址還是負載均衡器地址,以及標示要使用那個客戶端負載均衡策略或服務配置。
2、客戶端實例化負載均衡策略,如果解析返回的地址是負載均衡器地址,則客戶端將使用grpclb策略,否則客戶端使用服務配置請求的負載均衡策略。
3、負載均衡策略為每個服務器地址創建一個子通道(channel)。
4、當有rpc請求時,負載均衡策略決定那個子通道即grpc服務器將接收請求,當可用服務器為空時客戶端的請求將被阻塞。
