經驗分享:Grubhub是如何自己製造服務框架的?

經驗分享:Grubhub是如何自己製造服務框架的?

本文幫助你瞭解一個組織或公司內部的服務框架是什麼樣的,相比Spring Boot生態系統有什麼好處?

在SOA時期,Grubhub的工程師需要針對具體技術提供商和基礎設施配置推出大量代碼,每當您想要增加監控指標時,都需要客戶端庫調用Datadog。必須為每個新服務配置Splunk,以確保它包含適當的跟蹤和實例信息。此外,如果我們希望讓自己對這些集成的變化持開放態度,我們可能需要承擔將100多項服務調整為新集成模式的成本。這種情況很容易失控,我們希望在影響我們的業務之前避免這種情況。

在一些技術公司,特別是早期的技術公司,技術團隊並不急於圍繞他們的代碼強制執行許多標準,並且團隊可以自由地選擇如何與他們選擇的技術集成。雖然他們可能會將他們的組織限制為幾種語言、限制數據庫和雲提供商的選擇。

雖然讓團隊或代碼貢獻者在技術上做出獨立選擇可能具有吸引力,但公司經常發現自己因此放任政策而收到懲罰。團隊必須花更多時間編寫樣板文件以集成到其他服務和工具中。他們將花費更多時間來測試此代碼並解決集成中邊緣情況的問題。從一個代碼庫跳到另一個代碼庫的開發人員需要重新調整自己的位置,才能進行更改。最後,這可能成為一個devops噩夢,因為通常有更多的系統和語言來學習如何支持。

Grubhub想出了一個替代方案:我們開發了一個類似於Dropwizard的基於Java的服務框架。該框架允許我們開發同質化服務,自動掛鉤我們在數據存儲,消息傳遞,日誌記錄等方面支持的所有供應商集成。它使我們能夠接觸到最小的樣板代碼。在同質性方面,我們能夠更好地利用我們工程師過去的經驗,使他們更快地定向,同時更舒適地在我們的服務架構中的任何領域中發佈新功能。

管理RPC和API方法

該框架抽象出基礎技術,以便我們可以專注於功能開發。例如,我們使用JSON / HTTP執行RPC,但框架提供了一個Java包裝器,它不需要知道底層的序列化格式。如果我想創建一個接受某個RPC的服務(我們將其命名為handlePing),我會編寫一些如下所示的代碼:

經驗分享:Grubhub是如何自己製造服務框架的?

通過幾行設置,我的服務現在已準備好接受handlePingRPC - PingRequest並且PingResponse是其他地方定義的POJO(普通的舊Java對象)。該框架負責將POJO序列化到JSON和從JSON反序列化,並處理任何特定於傳輸的邏輯。我只需要添加我們在框架中定義的註釋 - RpcMethod並且RpcParam - 框架負責其餘部分。

調用RPC很簡單:

經驗分享:Grubhub是如何自己製造服務框架的?

因為序列化格式和傳輸不是由代碼決定的,所以如果我願意,我可以輕鬆地將它們切換出來。如果我這樣做,開發我的服務的開發人員就不必精通新的序列化格式和傳輸的細節,因為框架掩蓋了所有這些。他們必須熟悉的只是Java和我們定義的語義。只要框架以一致的方式與底層RPC解決方案集成,我就可以更少地擔心RPC框架的複雜性,這些複雜性可能各不相同。

記錄和指標

在直接使用RPC或API調用時,如果您沒有使用像Grubhub這樣的框架,您將經常被迫編寫滿足內部技術約束的庫以及您用於指標的任何提供程序日誌記錄。這可能會導致很多頭痛。例如,在記錄時,您可能沒有一致的方法來跟蹤一組請求,因此在調試問題時您可能無法將相關日誌綁定在一起。度量標準可能更加麻煩:當不同的開發人員圍繞代碼集成度量標準時,他們可能會對如何計算這些度量標準以及不同的命名方案提出不同的解釋。這些指標很難找到或解釋為結果。

Grubhub框架將這些RPC與我們的日誌管理提供程序(Splunk)集成在一起,在每個RPC上生成有用的日誌:

經驗分享:Grubhub是如何自己製造服務框架的?

請注意,這些日誌通過顯示的請求ID和跟蹤ID為調試目的提供服務跟蹤。該框架為RPC請求和API請求的每個請求週期添加新的請求ID,以及用於將更長的事件生命週期組合在一起的跟蹤ID。我是否需要跟蹤一系列服務調用以進行調試,我可以使用此請求ID查詢Splunk以拼湊此請求的歷史記錄。此外,RPC自動與Datadog集成以提供大量有用的統計信息:

  • rpc.MyService_handlePing.request_count
  • rpc.MyService_handlePing.response_time.min (also max, p50, p75, and p99)
  • rpc.client.MyService_handlePing.request_count
  • rpc.client.MyService_handlePing.response_time.min (also max, p50, p75, and p99)

我們的框架為REST API提供了類似的功能,加快了開發人員的工作效率。這些集成可以為開發人員實現無縫處理,而無需任何干預。作為一名開發人員,我很高興有這個框架可供我使用,因為我自己在檢測這些集成時經常遇到fencepost錯誤和其他小問題,這會分散對核心應用程序邏輯的影響。

服務間消息傳遞

消息傳遞可能會導致圍繞消息系統編寫樣板,日誌記錄和指標的所有相同的設置問題,但有時甚至可能更麻煩。許多解決方案在暴露重試,超時等方面提供的內容各不相同。如果您的組織不小心,與某些消息傳遞提供程序的集成將成為特定於供應商並且難以轉移。

在我們的服務框架中,我們以一種可以容納許多不同消息傳遞解決方案的方式抽象出消息傳遞實現。以類似於RPC的方式,我可以像這樣定義一個消息處理程序類:

經驗分享:Grubhub是如何自己製造服務框架的?

與RPC庫的情況一樣,語義允許我在不瞭解底層消息傳遞提供程序的情況下進行編碼。在框架的代碼庫中,有幾個支持消息傳遞提供程序的適配器(例如SQS),但很少有這些必須在使用該框架的服務的代碼庫中公開。我覺得有必要切換到不同的消息傳遞解決方案,我只需要與符合當前的API,而不是框架的新的集成在我們的新的集成服務。

工程友好的代碼

除了討論的功能之外,我們的框架還促進了諸如領導者選舉,斷路器等常見服務功能,使我們的服務與供應商無關並且易於適應。如果我們希望更改我們的度量提供程序或日誌記錄平臺,則不需要在我們的服務中進行任何代碼更改,並且不需要向我們的所有開發人員教授新的專業知識。

無需擔心實現服務功能,樣板文件幾乎沒有減少,開發人員大多隻關注功能開發。即使對於不熟悉底層技術的人來說,代碼也很簡單易讀。這加快了每個開發人員加入併為他或她尚未開展的服務做出貢獻的能力。故障排除變得更加容易。

框架的一致性使我們的SRE團隊的生活更加美好。它最大限度地減少了專門的部署,從而最大限度地降低了SRE團隊的工作量 - 提升新服務幾乎毫不費力。

顯然,我們框架的主要限制是它將我們與Java / JVM世界聯繫在一起。就個人而言,我並不一定認為這是一個缺點,因為許多流行的技術都有一流的支持和強大的Java客戶端庫。但即使JVM不是您的風格,您仍然可以創建一個框架或Golang,Ruby,Python或任何適合您團隊的偏好。無論您選擇哪種語言,編寫一個抽象實現細節和服務基礎設施瑣事的圖書館都可以幫助您更快地開始實施重要的事情。

最重要的是,結果不言而喻 - 該框架在過去三年中促進了100多項服務的開發和發佈。這種生產高質量服務的效率可能是不可能的。作為工程師,我們希望以最少的時間利用最高質量的輸出,我們的服務框架使我們能夠實現這一目標。

(banq注:公司內部搞一套服務中間件框架好處顯而易見,壞處也不容忽視,閉門造車會與Spring Boot等主流框架脫節,程序員因被所在公司技術鎖定而抱怨甚至跳槽,認為沒有學習到新技術,主要問題是技術發展方向無法把握,現在都是通過開源世界Github程序員自由投票發展路線,集全球聰明人的大腦,一個公司的力量如何與人類通天塔抗衡,最後中間件框架反而成為公司發展的瓶頸。)

寫在最後:

歡迎留言討論,如需Java方面的架構資料,我這裡剛好有一份,怎麼領取→→→關注+轉發 然後私信“架構資料” 即可領取

點關注,不迷路,持續更新!!!


分享到:


相關文章: