<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          『每周譯Go』Uber 的 API 網(wǎng)關(guān)架構(gòu)

          共 6882字,需瀏覽 14分鐘

           ·

          2021-06-08 07:19


          原文地址:https://eng.uber.com/architecture-api-gateway/

          原文作者:Madan Thangavelu, Abhishek Parwal, Rohit Patali

          本文永久鏈接:https://github.com/gocn/translator/blob/master/2021/w22_uber_architecture_api_gateway.md

          譯者:咔嘰咔嘰

          校對(duì):Fivezh

          近些年來(lái),API 網(wǎng)關(guān)一直是微服務(wù)架構(gòu)的一個(gè)組成部分。API 網(wǎng)關(guān)為我們的應(yīng)用程序提供了一個(gè)單一的入口點(diǎn),并提供了一個(gè)接口來(lái)訪問(wèn)后端微服務(wù)的數(shù)據(jù)、邏輯或功能。它還提供了一個(gè)集中的地方來(lái)實(shí)現(xiàn)許多高層次的職責(zé),包括路由、協(xié)議轉(zhuǎn)換、限速、削減負(fù)載、豐富報(bào)頭并傳播、數(shù)據(jù)中心親和性的執(zhí)行、安全審計(jì)、用戶鑒權(quán)、移動(dòng)客戶端的代碼生成等等。

          在上一篇文章中,我們講述了 Uber 的 API 網(wǎng)關(guān)的演變以及我們?cè)诿總€(gè)階段的設(shè)計(jì)選擇。在這篇文章中,我們將更深入地探討自助 API 網(wǎng)關(guān)系統(tǒng)的技術(shù)組件。

          在最抽象的層面上,網(wǎng)關(guān)是通過(guò) API 提供數(shù)據(jù)的另一種服務(wù)。網(wǎng)關(guān)有很多種類,涵蓋的范圍也很廣,從作為 API 網(wǎng)關(guān)的低級(jí)負(fù)載均衡,到功能非常豐富的應(yīng)用級(jí)負(fù)載均衡,在這些 API 中操作請(qǐng)求和響應(yīng)的有效載荷。在 Uber,我們開發(fā)了一個(gè)功能豐富的 API 網(wǎng)關(guān),能夠?qū)缍鄥f(xié)議的傳入和傳出的數(shù)據(jù)載荷進(jìn)行復(fù)雜操作。

          API 管理

          一個(gè)功能豐富的應(yīng)用程序需要通過(guò)與不同功能的后端服務(wù)進(jìn)行互動(dòng)來(lái)實(shí)現(xiàn)的。而這些互動(dòng)都要通過(guò)一個(gè)共同的應(yīng)用網(wǎng)關(guān)層。API 管理是指這些網(wǎng)關(guān) API 的創(chuàng)建、編輯、刪除和版本管理。

          工程師在用戶界面中配置他們的 API 參數(shù),并將功能性 API 發(fā)布到互聯(lián)網(wǎng)上,供所有 Uber 應(yīng)用使用。配置規(guī)范了 API 的行為:路徑、請(qǐng)求數(shù)據(jù)類型、響應(yīng)類型、允許的最大調(diào)用量、允許的應(yīng)用程序、通信協(xié)議、調(diào)用的具體微服務(wù)、允許的報(bào)頭、可觀察性、字段映射驗(yàn)證等等。

          一旦配置被發(fā)布,網(wǎng)關(guān)基礎(chǔ)設(shè)施將這些配置轉(zhuǎn)換為有效的和功能性的 API,可以為我們應(yīng)用程序的流量提供服務(wù)。網(wǎng)關(guān)基礎(chǔ)設(shè)施還為應(yīng)用程序生成客戶端 SDK,以消費(fèi)這些 API。

          所有與網(wǎng)關(guān)系統(tǒng)的互動(dòng)都是通過(guò)一個(gè)用戶界面進(jìn)行的,它引導(dǎo)用戶一步一步地創(chuàng)建一個(gè) endpoint。用戶界面簡(jiǎn)化了這一過(guò)程,并對(duì) API 的各個(gè)方面進(jìn)行了各種驗(yàn)證。此外,這也是配置請(qǐng)求超時(shí)、監(jiān)控和警報(bào)的地方。

          管理系統(tǒng)提供了一些輔助功能,比如在發(fā)布新的配置變化之前的審查機(jī)制和存儲(chǔ)會(huì)話以共享或恢復(fù) API 管理。下面的屏幕截圖顯示了允許添加中間件的 UI 步驟:

          請(qǐng)求生命周期中的組件

          為了解釋網(wǎng)關(guān)的各個(gè)組成部分,比較重要的是了解一個(gè)請(qǐng)求是如何在網(wǎng)關(guān)運(yùn)行時(shí)流動(dòng)的。一個(gè)傳入的請(qǐng)求包含一個(gè)路徑,該路徑被映射到一個(gè)為其服務(wù)的處理程序。在一個(gè)請(qǐng)求的生命周期中,它流經(jīng)以下組件:協(xié)議管理器、中間件、數(shù)據(jù)驗(yàn)證、處理程序和后端客戶端。請(qǐng)求生命周期中的所有組件都是作為一個(gè)棧來(lái)實(shí)現(xiàn)的。

          下面詳細(xì)描述的每個(gè)組件都在傳入時(shí)對(duì)請(qǐng)求對(duì)象進(jìn)行操作,而在響應(yīng)對(duì)象傳出時(shí)以相反的順序運(yùn)行相同的組件。

          協(xié)議管理器是棧的第一層。它包含網(wǎng)關(guān)所支持的協(xié)議的反序列化器和序列化器。該層提供了實(shí)現(xiàn) API 的能力,這些 API 可以接收任何類型的相關(guān)協(xié)議載荷,包括 JSON、Thrift 或 Protobuf。它還能方便地接收傳入的 JSON 請(qǐng)求,并以 proto 編碼的響應(yīng)來(lái)回應(yīng)。

          中間件層是一個(gè)抽象,它在調(diào)用 endpoint 處理程序之前實(shí)現(xiàn)可組合的邏輯。中間件實(shí)現(xiàn)面向切面的關(guān)注點(diǎn),如認(rèn)證、授權(quán)、速率限制等。每個(gè) endpoint 可以選擇配置一個(gè)或多個(gè)中間件。除了可選的中間件,該平臺(tái)還包括一組總是為每個(gè)請(qǐng)求執(zhí)行的強(qiáng)制中間件。單個(gè)中間件不需要同時(shí)實(shí)現(xiàn) requestMiddleware 以及 responseMiddleware 方法。如果一個(gè)中間件執(zhí)行失敗,調(diào)用將使棧的其余部分?jǐn)嗦罚虚g件的響應(yīng)將被返回給調(diào)用者。在某些情況下,中間件可以是無(wú)操作的,這取決于請(qǐng)求上下文。

          endpoint 處理程序是負(fù)責(zé)請(qǐng)求驗(yàn)證、載荷轉(zhuǎn)換以及將 endpoint 請(qǐng)求對(duì)象轉(zhuǎn)換為客戶端請(qǐng)求對(duì)象的層。當(dāng)對(duì)響應(yīng)對(duì)象進(jìn)行操作時(shí),endpointHandler 將后端服務(wù)響應(yīng)轉(zhuǎn)換為 endpoint 響應(yīng),對(duì)響應(yīng)對(duì)象進(jìn)行轉(zhuǎn)換,基于 schema 的響應(yīng)驗(yàn)證和序列化。

          客戶端向后端服務(wù)發(fā)出請(qǐng)求??蛻舳丝勺R(shí)別協(xié)議,并根據(jù)配置期間選擇的協(xié)議生成。用戶可以配置客戶端的內(nèi)部功能,如請(qǐng)求和響應(yīng)轉(zhuǎn)換、schema 驗(yàn)證、熔斷和重試、超時(shí)和截止期限管理、以及錯(cuò)誤處理。

          配置組件

          協(xié)議管理器、中間件、處理程序和客戶端有許多行為,可以用配置來(lái)控制。管理 API 的用戶不需要修改任何代碼,只需修改配置即可確定網(wǎng)關(guān)上的預(yù)期 endpoint 行為。為了便于配置,這些配置是通過(guò)用戶界面管理的,并由 Git 倉(cāng)庫(kù)提供支持。

          每個(gè)組件的配置都在 Thrift 和/或 YAML 文件中捕獲。YAML 文件為組件提供信息,并作為它們之間的粘合劑。Thrift 文件定義了有效載荷和協(xié)議語(yǔ)義。

          網(wǎng)關(guān) thrift 文件大量使用了thrift IDL中的注釋的功能,以便為各種功能和協(xié)議提供一個(gè)單一的真實(shí)來(lái)源。在下面的章節(jié)中,我們將深入探討每個(gè)組件的配置。

          協(xié)議管理器

          協(xié)議管理器需要理解在協(xié)議上下文中請(qǐng)求的數(shù)據(jù)的形狀和類型。對(duì)于響應(yīng),也應(yīng)該知道類似的參數(shù)。

          下面的三行 YAML 配置提供了協(xié)議類型、Thrift 文件路徑和協(xié)議管理器用來(lái)處理傳入請(qǐng)求的方法:

          上面的配置表明新的 API 是 “HTTP” 協(xié)議類型,關(guān)于 schema 和協(xié)議的其他細(xì)節(jié)都在下面的 apiSample.thrift 文件中提供。

          Thrift 文件 apiSample.thrift 功能豐富,它描述了 JSON 請(qǐng)求和響應(yīng)載荷的數(shù)據(jù)類型、HTTP 路徑和 HTTP 謂詞。HTTP 協(xié)議是在 Thrift schema 中使用 Thrift 的注釋功能定義的。

          并非所有 API 調(diào)用都會(huì)成功。下面的示例 schema 將一個(gè)處理程序的錯(cuò)誤響應(yīng)提供給適當(dāng)?shù)?HTTP 協(xié)議。這是使用如下所示的注解完成的:

          還有十幾個(gè)其他的注解,幫助協(xié)議管理器管理使用 thrift 注解的 HTTP 請(qǐng)求的行為。

          中間件

          中間件是棧中最靈活且功能最豐富的組件。它允許網(wǎng)關(guān)平臺(tái)向 API 網(wǎng)關(guān)用戶暴露更高階的功能。我們將在解鎖功能部分介紹由中間件提供的詳細(xì)功能。在這里,我們將重點(diǎn)討論 YAML 文件中的中間件配置。

          在上面的配置中,將 authentication 中間件添加到 API 中。authentication 中間件將從 header.x-user-uuid 的值中接收配置的路徑參數(shù)。上面配置的第二個(gè)中間件是 transformRequest 中間件,它被指示從傳入的請(qǐng)求中復(fù)制 regionID 到調(diào)用后端服務(wù)中。在開發(fā)新的中間件時(shí),它為 API 開發(fā)者需要提供的可配置參數(shù)定義了一個(gè) schema。

          處理程序

          支持處理程序的配置主要是驗(yàn)證和將傳入請(qǐng)求映射到后端客戶端的請(qǐng)求參數(shù)。

          上面的配置提供了處理程序理解請(qǐng)求應(yīng)該映射到的后端客戶端所需的輸入。如果傳入的請(qǐng)求字段與后端服務(wù)完全匹配,上述配置就足夠了。如果字段的名稱不同,則必須使用轉(zhuǎn)換請(qǐng)求中間件來(lái)映射它們。

          客戶端

          后端客戶端的配置分為 YAML 文件和 thrift 文件。在下面的示例中,使用 backendSample.thrift 文件中定義的請(qǐng)求和響應(yīng)定義配置了一個(gè)使用TChannel協(xié)議的新后端服務(wù),其中包含兩個(gè)可以調(diào)用的方法。

          請(qǐng)?jiān)俅巫⒁猓珺ackend::method 也可以真正成為 HTTP API,在 Thrift 規(guī)范中,借助注解可以用 /backend/method 這樣的路徑等價(jià)表示。

          可運(yùn)行的產(chǎn)物

          上一節(jié)描述的所有組件的 YAML 和 Thrift 配置是完整描述單個(gè) API 配置所必需的。自助網(wǎng)關(guān)負(fù)責(zé)確保這些組件配置一起提供網(wǎng)關(guān)運(yùn)行時(shí)。

          有兩種類型的網(wǎng)關(guān):一種采用配置并基于它們動(dòng)態(tài)提供API (非常類似于 Kong、Tyk 和反向代理,如 Envoy、Nginx);另一種是根據(jù)輸入的配置,使用代碼生成步驟生成一個(gè)構(gòu)建程序。在 Uber,我們選擇了后者,用代碼生成的方法來(lái)創(chuàng)建一個(gè)可運(yùn)行的構(gòu)建程序。

          生成 scheme 對(duì)象:所有的 scheme 文件都通過(guò)處理器運(yùn)行來(lái)為 thriftrw 和 protoc 輸出本地 golang 代碼。這對(duì)于序列化/反序列化和客戶端接口的代碼生成是必要的。

          生成自定義序列化:移動(dòng)應(yīng)用程序的 API 契約需要與 i64、枚舉類型和多種協(xié)議有關(guān)的自定義序列化。

          依賴性的 DAG:endpoint、后端客戶端和中間件的代碼是靜態(tài)生成的。它們?cè)诖a生成中存在固有的依賴性。而客戶端是獨(dú)立的,可以立即生成。中間件的功能可以依賴零個(gè)或多個(gè)客戶端。endpoint 可以依賴零個(gè)或多個(gè)中間件也可以依賴零個(gè)或一個(gè)客戶端。這個(gè)DAG(有向無(wú)環(huán)圖)會(huì)在構(gòu)建時(shí)被解決。

          由于客戶端是獨(dú)立于 endpoint 生成的,endpoint 可以是 HTTP,而后端服務(wù)可以是 gRPC。他們是在邊緣網(wǎng)關(guān)構(gòu)建的這一步驟中完成綁定的。

          API 生成:在這最后一步,對(duì) DAG 進(jìn)行迭代以生成所有的 endpoint。單個(gè)生成步驟如下:加載模板,生成端點(diǎn)請(qǐng)求到客戶端請(qǐng)求的映射(反之亦然),注入依賴項(xiàng),并使用請(qǐng)求-響應(yīng)轉(zhuǎn)換生成 IDL 對(duì)象。

          整個(gè)代碼的生成被抽象為一個(gè) Uber OSS 庫(kù),Zanzibar。

          解鎖功能

          中心化系統(tǒng)的一個(gè)優(yōu)勢(shì)是可以構(gòu)建令所有入駐用戶受益的功能。有了像邊緣網(wǎng)關(guān)這樣功能豐富的網(wǎng)關(guān),就有了多種途徑來(lái)構(gòu)建豐富的功能。

          下面是一些已經(jīng)開發(fā)的功能的例子,以及一些仍在醞釀中的功能。

          審計(jì)管道

          邊緣網(wǎng)關(guān)發(fā)出包含豐富元數(shù)據(jù)的訪問(wèn)日志,該日志被持久化以進(jìn)行審計(jì)。維護(hù)我們產(chǎn)品的所有 API 訪問(wèn)模式的審記記錄至關(guān)重要。當(dāng)惡意攻擊者試圖使用自動(dòng)化系統(tǒng)訪問(wèn)我們的 API 時(shí),它可以進(jìn)行安全審計(jì),并幫助建立跨版本、跨地域和跨應(yīng)用程序的各種產(chǎn)品的檔案。

          此管道有助于快速捕獲特定 SDK 版本、應(yīng)用程序、地理位置或互聯(lián)網(wǎng)提供商之間的錯(cuò)誤、問(wèn)題和異常。我們所有的應(yīng)用程序都啟用了審計(jì)管道。

          鑒權(quán)

          每個(gè)外部 API 請(qǐng)求都經(jīng)過(guò)身份驗(yàn)證 (AuthN) 和/或授權(quán) (AuthZ)。該平臺(tái)提供了幾種可重用的 AuthX 實(shí)現(xiàn),作為用戶可以從其 endpoint 選擇使用中間件。這消除了對(duì)如何實(shí)現(xiàn)這些 AuthN/AuthZ 的擔(dān)憂,并強(qiáng)制 endpoint 至少使用一種所提供的實(shí)現(xiàn)。平臺(tái)所有者可以無(wú)縫地對(duì)這些實(shí)現(xiàn)進(jìn)行更新,這些更新將自動(dòng)應(yīng)用于所有 endpoint。

          熔斷

          每個(gè)用于調(diào)用后端服務(wù)的客戶端都被包裹著一個(gè)斷路器。只要后端服務(wù)出現(xiàn)延遲或錯(cuò)誤率增加(可配置),斷路器就會(huì)啟動(dòng),從而防止級(jí)聯(lián)中斷。這為已經(jīng)惡化的服務(wù)提供了恢復(fù)的空間。

          限速

          endpoint 所有者可以選擇對(duì) API 進(jìn)行限速。所提供的實(shí)現(xiàn)的一些例子是基于用戶 ID、用戶代理、IP、請(qǐng)求的一些屬性的組合的限速,等等??梢曰趤?lái)自路徑/查詢參數(shù)、報(bào)頭或主體的特定字段來(lái)實(shí)施限速。這樣可以靈活地提供比簡(jiǎn)單的用戶級(jí) API 訪問(wèn)更精細(xì)的應(yīng)用感知型限速策略。每個(gè) endpoint 都可以獨(dú)立地動(dòng)態(tài)分配一個(gè)配額,而不需要重新部署。

          文檔

          YAML 和 Thrift 中的配置都完全描述了 API。這提供了以一致的方式自動(dòng)生成所有網(wǎng)關(guān) API 文檔的選項(xiàng)。

          手機(jī)客戶端 SDK 生成

          Uber 的所有移動(dòng)應(yīng)用都基于 Thrift IDL 生成服務(wù)和模型,與服務(wù)器交互。CI 工作從網(wǎng)關(guān)獲取所有的 endpoint IDL,并為各種模型運(yùn)行自定義的代碼生成。移動(dòng)代碼生成也依賴于各種自定義 Thrift 注解,如異常狀態(tài)代碼、URL 路徑和 HTTP 方法。對(duì) endpoint schema 的向后不兼容變更將被代碼生成審查的持續(xù)集成過(guò)程所阻止。

          響應(yīng)字段裁剪

          因?yàn)?API 的創(chuàng)建很容易,并且同一底層客戶端服務(wù)可以支持多個(gè) endpoint。我們能夠創(chuàng)建 API 來(lái)精細(xì)地選擇用戶體驗(yàn)所需的特定字段,而不是使用完整大小的后端響應(yīng)進(jìn)行響應(yīng)。

          數(shù)據(jù)中心親和性

          擁有冗余的數(shù)據(jù)中心和區(qū)域是目前大規(guī)模網(wǎng)絡(luò)公司的架構(gòu)。屬于不同業(yè)務(wù)部門或領(lǐng)域的 API 被托管在網(wǎng)關(guān)上,每個(gè)業(yè)務(wù)部門可以在多個(gè)數(shù)據(jù)中心定義他們的工作負(fù)載分片。邊緣網(wǎng)關(guān)提供了一個(gè)緩存,業(yè)務(wù)部門可以寫入其中,將用戶、區(qū)域或版本親和性配置到適當(dāng)?shù)臄?shù)據(jù)中心。然后,網(wǎng)關(guān)將遵守?cái)?shù)據(jù)中心的親和力信息,重新路由來(lái)自特定用戶、設(shè)備或應(yīng)用程序的傳入 API。

          短期用戶禁令

          帳戶級(jí)禁令是對(duì)付惡意行為者的有效手段。對(duì)于暫時(shí)濫用系統(tǒng)的用戶,網(wǎng)關(guān)提供了一個(gè)中心位置,可以在短時(shí)間內(nèi)阻止特定用戶訪問(wèn) API。這種方法類似于數(shù)據(jù)中心的親和性,其中網(wǎng)關(guān)可以提供外部緩存來(lái)存儲(chǔ)具有 TTL 的受阻用戶。欺詐和安全系統(tǒng)可以為用戶、應(yīng)用程序版本或其他標(biāo)識(shí)符提供攔截。邊緣網(wǎng)關(guān)將確保這些短期禁令的實(shí)施,以保護(hù)我們的用戶。

          挑戰(zhàn)和教訓(xùn)

          在網(wǎng)關(guān)的開發(fā)過(guò)程中,我們不得不在設(shè)計(jì)的多個(gè)方面做出選擇。一些選擇導(dǎo)致了非常令人興奮的結(jié)果,而另一些選擇則沒有提供預(yù)期的投資回報(bào)。我們將簡(jiǎn)要介紹幾個(gè)挑戰(zhàn)。

          語(yǔ)言

          在開發(fā)該網(wǎng)關(guān)的時(shí)候,我們的語(yǔ)言選擇是 Go 和 Java。我們之前的版本是用 Node.js。雖然那是一種非常適用于構(gòu)建 IO 密集型網(wǎng)關(guān)層的語(yǔ)言,但我們決定與 Uber 的語(yǔ)言平臺(tái)團(tuán)隊(duì)支持的語(yǔ)言保持一致。Go 提供了顯著的性能改進(jìn)。由于缺乏泛型,在構(gòu)建過(guò)程中產(chǎn)生了大量的代碼,以至于我們達(dá)到了 Go 鏈接器的極限。我們不得不在二進(jìn)制編譯期間關(guān)閉符號(hào)表和調(diào)試信息。Go (不是Thrift) 中的 ID、HTTP 和保留關(guān)鍵字等語(yǔ)言命名約定造成了向用戶暴露內(nèi)部實(shí)現(xiàn)細(xì)節(jié)的故障。

          序列化格式

          我們網(wǎng)關(guān)的協(xié)議管理器能夠?qū)崿F(xiàn)多種協(xié)議。這一功能暴露了復(fù)雜的兼容性問(wèn)題,例如在 JSON schema 與 Thrift schema 中表示 Union、Set、List 和 Map 的數(shù)據(jù)類型不匹配。我們不得不為這種映射制定自己的約定。

          配置存儲(chǔ)

          如前所述,用戶的配置被存儲(chǔ)在 Git 中。然而,其中一些配置是動(dòng)態(tài)的,如 API 限速。以前,這里的變化需要代碼生成和部署。這很耗費(fèi)時(shí)間,因此我們現(xiàn)在將用戶配置的動(dòng)態(tài)部分存儲(chǔ)在一個(gè)配置存儲(chǔ)中。

          網(wǎng)關(guān) UI

          在網(wǎng)關(guān) UI 中開發(fā)單個(gè) API 很容易,但在開發(fā)批處理編輯流時(shí)就變得難以管理了。當(dāng) Thrift 文件引用其他 Thrift 文件并且嵌套可以任意深時(shí),情況尤其如此。一旦用戶提供配置并由構(gòu)建系統(tǒng)接管,由于構(gòu)建系統(tǒng)獨(dú)立于 UI 而發(fā)展,將構(gòu)建失敗呈現(xiàn)給 UI 可能會(huì)很有挑戰(zhàn)性。在它們之間保持一致的契約來(lái)展現(xiàn)錯(cuò)誤是至關(guān)重要的。

          理解載荷

          大多數(shù)網(wǎng)關(guān)功能的開發(fā)不需要對(duì)傳入或傳出的載荷進(jìn)行反序列化。協(xié)議互操作性的用例迫使我們對(duì)載荷進(jìn)行反序列化。這增加了構(gòu)建系統(tǒng)的復(fù)雜性,也增加了運(yùn)行時(shí)的性能。如果后端和移動(dòng)端協(xié)議是相同的,限制網(wǎng)關(guān)只訪問(wèn)協(xié)議謂詞和報(bào)頭 (header) 而不反序列化正文 (body) 可能會(huì)有好處。然而,這將限制一些復(fù)雜的網(wǎng)關(guān)功能。

          一個(gè)豐富的網(wǎng)關(guān),像我們描述的那樣,是一項(xiàng)復(fù)雜的工作。如果你有興趣走同樣的路,zanzibar可以提供一個(gè)可擴(kuò)展的模塊,從那里啟動(dòng)。在 Uber,我們正在開發(fā)一種基于envoy的 API 網(wǎng)關(guān)運(yùn)行時(shí),用于從我們的應(yīng)用程序到后端服務(wù)的 gRPC 請(qǐng)求,而我們的自助用戶界面沒有明顯的用戶體驗(yàn)變化。如果你有興趣和熱情,就來(lái)和我們談?wù)劙?

          致謝

          如果沒有這么多參與網(wǎng)關(guān)開發(fā)的人的重大貢獻(xiàn),這項(xiàng)工作是不可能完成的。一些重要的致謝有:Abhishek Panda, Alex Hauser, Aravind Gopalan, Chao Li, Chuntao Lu, Gregory Trowbridge, Jake Verbaten, Karthik Karuppaiya, Maximiliano Benedetto, Michael Sindler, Olivia Zhang, Pavel Astakhov, Rena Ren, Steven Bauer, Tejaswi Agarwal, Uday Medisetty, and Zhenghui Wang。



          想和各位技術(shù)大佬們同臺(tái)見面嘛?


          那就趕快點(diǎn)擊下方「閱讀原文」報(bào)名參加呀!

          瀏覽 89
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产AV日韩AⅤ亚洲AV中文 | 啪啪啪啪啪啪网站 | 一道本无码免费视频 | 草草视频网站 | 91逼逼|