Bugsnag(注:一家云端bug監(jiān)控服務(wù)商)每天處理數(shù)以億計(jì)的錯(cuò)誤信息,為了處理這些數(shù)據(jù)貌踏,考慮優(yōu)先構(gòu)建一個(gè)可擴(kuò)展十饥,性能強(qiáng)大的后端系統(tǒng),并從中學(xué)到很多有挑戰(zhàn)性的技術(shù)祖乳。最近逗堵,我們推出了新版本的儀表板,這個(gè)項(xiàng)目要求擴(kuò)展系統(tǒng)凡资,來處理服務(wù)呼叫的顯著增加砸捏,這些呼叫是跟蹤用戶發(fā)布和會話所需的。
儀表板的發(fā)布在進(jìn)行中隙赁,工程團(tuán)隊(duì)將Bugsnag的后端功能分解成稱之為管道(pipeline)的微服務(wù)體系垦藏。將管道擴(kuò)展到支持發(fā)布,意味著增加新的服務(wù)伞访,并修改現(xiàn)有服務(wù)掂骏,也可預(yù)見到許多新的服務(wù)器和客戶端的交互。為了處理上述架構(gòu)的變化厚掷,需要采用一致性的方式來設(shè)計(jì)弟灼,實(shí)施和集成企業(yè)的服務(wù)级解。Bugsnag是一家多語言的公司,服務(wù)是用Java田绑,Ruby勤哗,Go和Node.js等多語言編寫,因此企業(yè)需要一種與平臺無關(guān)的方法掩驱。
本文將介紹為什么我們最終選擇了gRPC作為Pipeline的默認(rèn)通信框架芒划。
達(dá)到REST API設(shè)計(jì)的極限
現(xiàn)有系統(tǒng)傳統(tǒng)上使用具有JSON有效載荷的REST API進(jìn)行同步通信。這種選擇是基于占壓倒性比例的成熟度欧穴、熟悉度和工具的可用性做出的民逼,但是隨著跨洲際工程團(tuán)隊(duì)的增長,企業(yè)需要設(shè)計(jì)一致的涮帘,基于RESTful API的工具拼苍。
不幸的是,這感覺就像試圖將簡單的方法調(diào)用變成一個(gè)數(shù)據(jù)驅(qū)動(dòng)的RESTful界面调缨。這滿足了RESTful接口的verb疮鲫,header,URL標(biāo)識符同蜻,資源的URL和有效載荷的神奇組合棚点,并做了一個(gè)清潔早处,簡單湾蔓,看起來幾乎不可能實(shí)現(xiàn)的功能界面。RESTful有很多規(guī)則和解釋砌梆,在大多數(shù)情況下會導(dǎo)致REST ish接口默责,這需要花費(fèi)額外的時(shí)間和精力來保持其純度。
最終咸包,考慮到RESTAPI的復(fù)雜性桃序,我們找到了替代方案。希望微服務(wù)盡可能相互隔離烂瘫,減少交互和解耦服務(wù)媒熊。它可以讓企業(yè)在很短的時(shí)間內(nèi)創(chuàng)造出一個(gè)可行的服務(wù),并防止跳過hoops坟比。
評估REST的替代方案
不要輕易選擇通信框架芦鳍。大型組織(如Netflix)可以擁有超過500+個(gè)微服務(wù)的后端系統(tǒng)。遷移這些服務(wù)以取代不充分的服務(wù)間通信會花費(fèi)大量時(shí)間葛账,從后勤和財(cái)務(wù)角度看這很不切實(shí)際柠衅。花時(shí)間從一開始就考慮正確的框架籍琳,可以省去很多未來的浪費(fèi)菲宴。
我們花了大量的時(shí)間來制定評估標(biāo)準(zhǔn)和研究贷祈、選擇。Bugsnag到底長什么樣子呢喝峦?
技術(shù)標(biāo)準(zhǔn)
在研究可用選項(xiàng)時(shí)势誊,使用了一些特定的標(biāo)準(zhǔn)來評估。要考慮的事情是基于微服務(wù)架構(gòu)的最有效的方法谣蠢。主要目標(biāo)是自由地使用通信键科,消除通信的復(fù)雜性,了解每項(xiàng)服務(wù)的責(zé)任所在漩怎。其中的一些技術(shù)問題是:
速度 - 對于大量的請求/響應(yīng)API調(diào)用勋颖,需要將調(diào)用本身的延遲作為性能和用戶響應(yīng)速度的最小因素。延遲的主要組成部分是連接成本勋锤,傳輸成本和消息編碼/解碼時(shí)間饭玲。
基礎(chǔ)架構(gòu)兼容性 - 框架在基礎(chǔ)架構(gòu)中扮演的角色如何?主要是關(guān)于負(fù)載平衡和自動(dòng)擴(kuò)展叁执?我們使用托管在Google云端平臺上的Kubernetes服務(wù)茄厘,因此需要框架來兼容這種環(huán)境。
開發(fā)工具 - 在實(shí)現(xiàn)框架時(shí)谈宛,提供盡可能小的摩擦將會使開發(fā)人員更快捷次哈。哪些工具可以幫助編碼,本地測試端點(diǎn)吆录,以及單元和集成測試的stubbing/mocking窑滞?當(dāng)事情出錯(cuò)時(shí),我們需要能夠看到包括內(nèi)容在內(nèi)的請求信息恢筝。消息格式等因素也可以使調(diào)試更容易依賴于工具哀卫,例如JSON消息是人可讀的,但是二進(jìn)制消息將需要額外的努力來解碼撬槽。
成熟度和采用 - 對于初創(chuàng)公司來說此改,資源是有限的,需要花費(fèi)在公司的核心業(yè)務(wù)上侄柔,而不是修復(fù)共啃,測試和增強(qiáng)第三方框架。諸如框架的普及暂题,大規(guī)模使用的例子移剪,社區(qū)的活躍程度以及框架本身的成熟度等因素都是穩(wěn)定性的良好指標(biāo)。需要強(qiáng)調(diào)的是敢靡,選擇一個(gè)解決具體問題的框架挂滓,而并非選擇最新最熱的。
多平臺支持 - 在真正的微服務(wù)思維中,使用最適合其目的的語言編寫企業(yè)的服務(wù)赶站,目前包括Java幔虏,Ruby,Go和Node贝椿∠肜ǎ框架是否為現(xiàn)有的語言選擇提供了一流的支持,同時(shí)提供了用其他語言編寫新服務(wù)的選項(xiàng)烙博?
代碼量 - 框架應(yīng)該有助于降低工程成本瑟蜈。企業(yè)需要編寫和維護(hù)多少代碼才能使其工作?與業(yè)務(wù)邏輯相比渣窜,這是多少樣板代碼铺根?
安全 - 所有的內(nèi)部通信都應(yīng)該被認(rèn)證和加密。我們需要能夠使用所有通信的SSL / TLS(或等價(jià)物)乔宿。
設(shè)計(jì)上的考慮位迂,并非都與技術(shù)有關(guān)
服務(wù)API是最重要的接口之一,因?yàn)樵陂_發(fā)過程中對設(shè)置服務(wù)期望至關(guān)重要详瑞。解決服務(wù)API的設(shè)計(jì)是一項(xiàng)艱巨的任務(wù)掂林,當(dāng)不同的團(tuán)隊(duì)負(fù)責(zé)所涉及的不同服務(wù)時(shí),該任務(wù)會被放大坝橡。最大限度地減少由于預(yù)期不匹配而浪費(fèi)的時(shí)間和精力眯勾,與縮短編碼時(shí)間一樣有價(jià)值嫂易。由于Bugsnag擁有跨地區(qū)的工程團(tuán)隊(duì)仁锯,因此溝通時(shí)間有限匙姜。必須通過簡化溝通,確保事情不用那么多解釋饲常,否則錯(cuò)誤很容易產(chǎn)生蹲堂,事情很容易被拖延狼讨。
以下是在選擇框架時(shí)的一些設(shè)計(jì)考慮因素:
強(qiáng)類型 - 消息是否是強(qiáng)類型的贝淤?如果通過服務(wù)邊界發(fā)送的消息清晰可見,那么可以消除由于類型而造成的設(shè)計(jì)和運(yùn)行時(shí)錯(cuò)誤政供。
打開解釋 - 能夠直接從服務(wù)API規(guī)范生成客戶端庫播聪,減少了誤解的問題。錯(cuò)誤條件 - 有一套明確定義的錯(cuò)誤代碼可以更容易一致地交流問題布隔。
文檔 - 服務(wù)API應(yīng)該是易讀易懂的离陶。定義服務(wù)API的格式應(yīng)該盡可能清楚,準(zhǔn)確地描述端點(diǎn)衅檀。
版本控制 - 更改是不可避免的招刨,這是一個(gè)很好的選擇,在某些時(shí)候哀军,服務(wù)API將需要修改沉眶。所使用的消息傳遞格式和服務(wù)定義可以影響修改API并將其部署到生產(chǎn)的容易程度打却。是否有明確的路徑來增加版本及其相應(yīng)的庫,并推出更改谎倔?
微服務(wù)最佳實(shí)踐柳击,為什么可擴(kuò)展性是重要的
除了上面列出的標(biāo)準(zhǔn)外,還需要選擇一個(gè)易于擴(kuò)展的框架片习。隨著微服務(wù)的發(fā)展捌肴,企業(yè)需要越來越多的“開箱即用”功能,發(fā)展的同時(shí)藕咏,為系統(tǒng)增加了更多的復(fù)雜性状知。因此企業(yè)希望的功能包括:
異常處理 - 在請求級別提供一個(gè)處理異常的機(jī)制。它允許捕獲有關(guān)請求的重要上下文元數(shù)據(jù)孽查,例如發(fā)出請求的用戶试幽,可以用例外報(bào)告。我們使用Bugsnag輕松地監(jiān)視這些異常卦碾。
智能重試 - 在特定條件下重試請求铺坞,例如僅在5xx狀態(tài)碼上。這包括支持各種退避策略洲胖,如指數(shù)退避济榨。
服務(wù)發(fā)現(xiàn)配置 - 將通信框架連接到流行的服務(wù)發(fā)現(xiàn)應(yīng)用程序(如Zookeeper,Eureka或Consul)的選項(xiàng)可以提供一種快速簡便的解決方案绿映,以繞過企業(yè)的架構(gòu)來請求路由擒滑。
度量、跟蹤和日志記錄 - 可觀察性對于復(fù)雜的分布式系統(tǒng)是必不可少的叉弦,但是應(yīng)該小心監(jiān)視的內(nèi)容丐一。在服務(wù)邊界自動(dòng)收集指標(biāo)和跟蹤信息可以快速回答常見問題,例如“我的服務(wù)對請求響應(yīng)緩慢嗎淹冰?”以及“請求失敗的頻率如何库车?”。
熔斷 - 這種模式可以通過自動(dòng)檢測問題和快速失敗來防止級聯(lián)服務(wù)故障樱拴。也可以由長時(shí)間緩慢的請求來觸發(fā)柠衍,以提供響應(yīng)降級的服務(wù)而不是不斷地超時(shí)。
緩存和批處理 - 通過使用緩存或批處理請求來加速請求晶乔。
大多數(shù)框架不會提供所有功能珍坊,但至少它們應(yīng)該是可擴(kuò)展的,以便在需要時(shí)添加正罢。
什么是gRPC和協(xié)議緩沖區(qū)阵漏?
沒有一個(gè)框架是萬能的。我們探索的一些選項(xiàng)包括Facebook的Thrift,Apache Hadoop的Avro履怯,Twitter的Finagle川无,甚至使用JSON模式。
我們的需求更接近于遠(yuǎn)程程序調(diào)用(RPC)虑乖,給予所需要的細(xì)粒度控制懦趋。使用RPC的另一個(gè)吸引力是使用接口描述語言或IDL。IDL允許以獨(dú)立于語言的格式描述服務(wù)API疹味,將接口與任何特定的編程語言分離仅叫。他們可以提供一系列的好處,包括服務(wù)API的一個(gè)單一的事實(shí)來源糙捺,并可能被用來生成客戶端和服務(wù)器代碼來與這些服務(wù)進(jìn)行交互诫咱。IDL的例子包括Thrift,Avro洪灯,CORBA坎缭,當(dāng)然還有ProtocolBuffers。
最后签钩,明確的獲勝者是基于協(xié)議緩沖區(qū)的gRPC掏呼。
什么是gRPC?
我們選擇了gRPC铅檩,因?yàn)樗鼭M足了我們的功能需求(包括未來的可擴(kuò)展性)憎夷,背后的活躍社區(qū)以及HTTP / 2框架的使用。
gRPC是由Google開發(fā)昧旨,設(shè)計(jì)用于傳統(tǒng)的RPC調(diào)用拾给。該框架使用最新的網(wǎng)絡(luò)傳輸協(xié)議HTTP / 2,主要用于通過使用流的單個(gè)TCP連接來實(shí)現(xiàn)低延遲和多路復(fù)用請求兔沃。與REST over HTTP / 1.1相比蒋得,gRPC非常快速和靈活乒疏。
gRPC的性能對于設(shè)置管道來處理儀表板發(fā)布的大量增加至關(guān)重要额衙。此外,HTTP / 2是下一個(gè)標(biāo)準(zhǔn)化的網(wǎng)絡(luò)協(xié)議缰雇,可以利用為HTTP / 2開發(fā)的工具和技術(shù)(如Envoy代理)入偷,并為gRPC提供一流的支持。由于多路復(fù)用流支持械哟,gRPC支持雙向通信,不限于簡單的請求/響應(yīng)呼叫殿雪。
什么是Protobufs(協(xié)議緩沖區(qū))暇咆?
Protocol Buffers或protobufs是定義和序列化結(jié)構(gòu)化數(shù)據(jù)為高效的二進(jìn)制格式的一種方式,也是由Google開發(fā)的。二者的有效結(jié)合爸业,也是我們選擇gRPC的主要原因之一其骄。
以前有許多與想修復(fù)的版本相關(guān)的問題。微服務(wù)意味著必須不斷更新扯旷,需要適應(yīng)并保持向前和向后兼容的接口拯爽,protobufs對此非常有用。由于是二進(jìn)制格式钧忽,所以它們也是通過wire快速發(fā)送的小型有效載荷毯炮。
Protobuf消息使用關(guān)聯(lián)的IDL進(jìn)行描述,它提供了一個(gè)緊湊的耸黑,強(qiáng)類型的桃煎,向后兼容的格式來定義消息和RPC服務(wù)。我們使用最新的proto3規(guī)范大刊,并在此處顯示protobuf消息的實(shí)際示例为迈。
所有字段proto3都是可選的。如果未設(shè)置字段缺菌,將始終使用默認(rèn)值葫辐。這與字段編號相結(jié)合提供了一個(gè)API,可以非常抵抗打破變化伴郁。通過遵循一些簡單的規(guī)則另患,向前和向后兼容性可以成為大多數(shù)API更改的默認(rèn)值。
protobuf格式還允許定義RPC服務(wù)本身蛾绎。服務(wù)端點(diǎn)與消息結(jié)構(gòu)共存昆箕,在單個(gè)protobuf文件中提供RPC服務(wù)的自包含定義。對于我們的跨洲際的工程團(tuán)隊(duì)來說租冠,這非常有用鹏倘,他們可以從一個(gè)文件中了解服務(wù)如何工作,生成客戶端并開始使用它顽爹。以下是我們的服務(wù)之一:
該框架能夠生成代碼來使用protobuf文件與這些服務(wù)進(jìn)行交互纤泵,這是另一個(gè)優(yōu)勢,它可以自動(dòng)生成需要的所有類镜粤。這個(gè)生成的代碼負(fù)責(zé)消息建模捏题,并提供一個(gè)存根類,其中包含與您的服務(wù)端點(diǎn)相關(guān)的重復(fù)方法調(diào)用肉渴。
支持多種語言公荧,包括C ++,Java同规,Python循狰,Go窟社,Ruby,C#绪钥,Node灿里,Android,Objective-C和PHP程腹。但是匣吊,使用protobuf文件維護(hù)和同步生成的代碼是個(gè)問題。我們已經(jīng)能夠通過使用Protobuf文件自動(dòng)生成客戶端庫來解決這個(gè)問題寸潦,會在即將發(fā)布的下一篇博客文章中分享更多的內(nèi)容色鸳。
gRPC最好的特性之一是支持中間件模式,被稱為攔截器甸祭。它允許擴(kuò)展所有的gRPC實(shí)現(xiàn)(這對企業(yè)來說很重要)缕碎,能夠輕松訪問所有請求,從而實(shí)現(xiàn)自己的微服務(wù)最佳實(shí)踐池户。gRPC還內(nèi)置了對一系列認(rèn)證機(jī)制的支持咏雌,包括SSL / TLS。
gRPC社區(qū)
我們正處于gRPC采用的開始階段校焦,期待社區(qū)提供更多的工具和技術(shù)赊抖。很高興能夠加入這個(gè)充滿活力的社區(qū),并對未來的項(xiàng)目有一些想法寨典,我們希望看到這些項(xiàng)目是開放源代碼或我們自己寫的氛雪。
gRPC工具的當(dāng)前狀態(tài)
gRPC比較新,缺乏可用的開發(fā)工具耸成,特別是與經(jīng)驗(yàn)豐富的REST over HTTP / 1.1協(xié)議相比报亩。搜索教程和示例時(shí),這一點(diǎn)尤其明顯井氢,因?yàn)橹挥猩贁?shù)有用的信息弦追。二進(jìn)制格式也使消息不透明,需要努力解碼花竞。雖然有一些選擇劲件,例如JSON代碼轉(zhuǎn)換器可以幫助,但預(yù)計(jì)需要做一些基礎(chǔ)工作约急,以便為gRPC提供順暢的開發(fā)體驗(yàn)零远。
我們喜歡用Apiary 來記錄外部API。使用服務(wù)協(xié)議緩沖區(qū)(protobuf)文件自動(dòng)生成交互式文檔的等價(jià)物厌蔽,將是理想的有效的內(nèi)部通信gRPCAPI牵辣。protobuf文件的靜態(tài)分析在運(yùn)行時(shí)能捕獲更多的bug。使用Checkstyle作為Java代碼躺枕,并且把它用作類似于protobuf的文件服猪。自定義攔截器可以提供跟蹤供填,日志記錄和錯(cuò)誤監(jiān)視功能拐云。我們希望開源我們的Bugsnag gRPC攔截器罢猪,以自動(dòng)捕獲并向Bugsnag報(bào)告錯(cuò)誤。gRPC的增長和采用
在過去幾年中叉瘩,gRPC的普及度大幅增長膳帕,Square,Lyft薇缅,Netflix危彩,Docker,Cisco和CoreOS等公司大規(guī)模采用泳桦。Netflix Ribbon是基于RPC調(diào)用使用REST的微服務(wù)通信框架的事實(shí)標(biāo)準(zhǔn)汤徽。今年,他們宣布灸撰,由于其多語言支持和更好的可擴(kuò)展性/可組合性谒府,他們正在向gRPC過渡。該框架最近也于2017年3月加入了CNCF基金會浮毯,支持重量級的Kubernetes和Prometheus完疫。gRPC社區(qū)非常活躍债蓝,與開源gRPC生態(tài)系統(tǒng) 列出了許多gRPC激動(dòng)人心的項(xiàng)目壳鹤。
另外,gRPC有我們認(rèn)同的原則
Lyft在轉(zhuǎn)向gRPC方面做了大量的討論饰迹,這與我們的經(jīng)驗(yàn)非常相似:使用Protocol Buffers和gRPC生成統(tǒng)一的API芳誓。值得一試。
gRPC現(xiàn)在還處于初期階段啊鸭,存在一些明顯的磨合問題锹淌,但未來前景光明±虻啵總的來說葛圃,我們對gRPC如何整合到后端系統(tǒng)非常樂觀,并且很高興見證這個(gè)框架的發(fā)展憎妙。
原文鏈接:
https://blog.bugsnag.com/grpc-and-microservices-architecture/?utm_source=tuicool&utm_medium=referral