www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 公眾號精選 > 架構師社區(qū)
[導讀]背景在Netflix,我們大量使用gRPC來實現(xiàn)后端到后端的通信。當我們處理請求時,知道調用者對哪些字段感興趣以及忽略哪些字段通常是有益的。某些響應字段的計算成本可能很高,某些字段可能需要遠程調用其他服務。遠程調用都是有代價的;它們會帶來額外的延遲,增加出錯的可能性,并消耗網絡帶...



背景



在 Netflix,我們大量使用 gRPC 來實現(xiàn)后端到后端的通信。當我們處理請求時,知道調用者對哪些字段感興趣以及忽略哪些字段通常是有益的。某些響應字段的計算成本可能很高,某些字段可能需要遠程調用其他服務。遠程調用都是有代價的;它們會帶來額外的延遲,增加出錯的可能性,并消耗網絡帶寬。那么該如何知道響應中哪些字段不需要提供給調用者,從而避免進行不必要的計算以及遠程調用?使用 GraphQL,這是通過使用字段選擇器來實現(xiàn)的。在 JSON:API 標準中,類似的技術稱為稀疏字段集[1]。在設計 gRPC API 時,我們如何實現(xiàn)類似的功能?我們在 Netflix Studio Engineering 中使用的解決方案是 protobuf FieldMask[2]。


Protobuf FieldMask



Protocol Buffers[3],或簡稱為 protobuf,是一種數(shù)據(jù)序列化機制。默認情況下,gRPC 使用 protobuf 作為其 IDL(接口定義語言)和數(shù)據(jù)序列化協(xié)議。FieldMask 是一個 protobuf 消息。當此消息出現(xiàn)在 RPC 請求中時,有關如何使用此消息有許多實用工具(utilities)和約定。FieldMask 消息包含一個名為 paths 的字段,它用于指定字段,這些字段可以由讀操作返回或由更新操作來修改。message FieldMask {
// The set of field mask paths.
repeated string paths = 1;
}



案例:Netflix Studio Production



假設有一個 Production 服務來管理 Studio Content Productions(在電影和電視行業(yè)中,術語 production[4] 是指制作電影的過程,而不是運行軟件的環(huán)境)。// Contains Production-related information
message Production {
string id = 1;
string title = 2;
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
// ... more fields
}

service ProductionService {
// returns Production by ID
rpc GetProduction (GetProductionRequest) returns (GetProductionResponse);
}

message GetProductionRequest {
string production_id = 1;
}

message GetProductionResponse {
Production production = 1;
}


GetProduction 通過唯一 ID 返回 Production 消息。一個 production 包含多個字段,例如:標題、格式、日程安排日期、腳本又名劇本、預算、劇集等,但讓我們保持這個例子簡單,并在請求 production時重點過濾日程安排日期和腳本。
讀取 Production 詳細信息
假設我們想要使用 GetProduction API 獲取特定 production 的信息,例如“La Casa De Papel”。雖然 production 有許多字段,但其中一些字段是從其他服務返回的,例如來自 Schedule 服務的 schedule 或來自 Script 服務的 scripts。



每次調用 GetProduction 時,Production 服務都會向 Schedule 和 Script 服務發(fā)出 RPC,即使客戶端忽略響應中的 schedule 和 scripts 字段。如上所述,遠程調用是有代價的。如果服務知道哪些字段對調用者很重要,它可以在是否進行昂貴的調用、啟動資源密集型計算和/或調用數(shù)據(jù)庫這些事中做出明智的決定。在這個例子中,如果調用者只需要標題和格式兩個字段,Production 服務可以避免遠程調用 Schedule 和 Script 服務。
此外,請求大量字段會使響應負載變得龐大。對某些應用程序來說可能是個問題,例如,在網絡帶寬有限的移動設備上。在這些情況下,消費者只請求他們需要的字段是一種很好的做法。
一個比較笨的解決方法是添加額外的請求參數(shù),例如 includeSchedule 和 includeScripts:// Request with one-off "include" fields, not recommended
message GetProductionRequest {
string production_id = 1;
bool include_format = 2;
bool include_schedule = 3;
bool include_scripts = 4;
}


這種方法需要為每個昂貴的響應字段添加一個自定義的 includeXXX 字段,并且不適用于嵌套字段。它還增加了請求的復雜性,最終使維護和支持更具挑戰(zhàn)性。
將 FieldMask 添加到請求消息中
API 設計者可以將 field_mask 字段添加到請求消息中,而不是創(chuàng)建一次性的“包含”字段:import "google/protobuf/field_mask.proto";

message GetProductionRequest {
string production_id = 1;
google.protobuf.FieldMask field_mask = 2;
}


消費者可以為他們希望在響應中收到的字段設置路徑。如果消費者只對標題和格式感興趣,他們可以設置帶有“title”和“format”路徑的 FieldMask:FieldMask fieldMask = FieldMask.newBuilder()
.addPaths("title")
.addPaths("format")
.build();

GetProductionRequest request = GetProductionRequest.newBuilder()
.setProductionId(LA_CASA_DE_PAPEL_PRODUCTION_ID)
.setFieldMask(fieldMask)
.build();





請注意,即使本博文中的代碼示例是用 Java 編寫的,演示的概念也適用于任何支持 protocol buffers 的其他語言。
如果消費者只需要最后一個更新日程表的人的標題和電子郵件,他們可以設置不同的字段掩碼:FieldMask fieldMask = FieldMask.newBuilder()
.addPaths("title")
.addPaths("schedule.last_updated_by.email")
.build();

GetProductionRequest request = GetProductionRequest.newBuilder()
.setProductionId(LA_CASA_DE_PAPEL_PRODUCTION_ID)
.setFieldMask(fieldMask)
.build();


按照慣例,如果請求中不存在 FieldMask,則應返回所有字段。
Protobuf 字段名稱與字段編號
你可能會注意到 FieldMask 中的路徑是使用字段名稱指定的,而在傳輸中,編碼的 protocol buffers 消息僅包含字段編號,而不包含字段名稱。這(以及其他一些技術,如用于簽名類型的 ZigZag[5] 編碼)會讓 protobuf 消息節(jié)省空間。
為了理解字段編號和字段名稱之間的區(qū)別,讓我們詳細了解一下 protobuf 是如何編碼和解碼消息的。
我們的 protobuf 消息定義(.proto 文件)包含一個具有五個字段的 Production 消息。每個字段都有一個類型、名稱和編號。// Message with Production-related information
message Production {
string id = 1;
string title = 2;
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
}


當 protobuf 編譯器(protoc)編譯此消息定義時,它會以你選擇的語言(在我們的示例中為 Java)創(chuàng)建代碼。這個生成的代碼包含定義消息的類,以及消息和字段描述符。描述符包含將消息編碼和解碼為其二進制格式所需的所有信息。例如,它們包含字段編號、名稱、類型。消息生產者使用描述符將消息轉換為傳輸格式。為提高效率,二進制消息僅包含字段數(shù)值對。不包括字段名稱。當消費者收到消息時,它通過引用編譯的消息定義將字節(jié)流解碼為一個對象(例如,Java 對象)。



如上所述,F(xiàn)ieldMask 列出字段名稱,而不是數(shù)字。在 Netflix,我們使用字段編號并使用 FieldMaskUtil.fromFieldNumbers()[6] 方法將它們轉換為字段名稱。此方法利用編譯的消息定義將字段編號轉換為字段名稱并創(chuàng)建 FieldMask。FieldMask fieldMask = FieldMaskUtil.fromFieldNumbers(Production.class,
Production.TITLE_FIELD_NUMBER,
Production.FORMAT_FIELD_NUMBER);

GetProductionRequest request = GetProductionRequest.newBuilder()
.setProductionId(LA_CASA_DE_PAPEL_PRODUCTION_ID)
.setFieldMask(fieldMask)
.build();


但是,有一個容易忽略的限制:使用 FieldMask 會限制你重命名消息字段的能力。重命名消息字段通常被認為是一種安全操作,因為如上所述,字段名稱不會被傳輸發(fā)送的,而是使用消費者端的字段編號派生的。使用 FieldMask,字段名稱會在消息負載中被發(fā)送出去(在路徑字段值中)并且還是很重要的部分。
假設我們要將字段 title 重命名為 title_name 并發(fā)布消息定義的 2.0 版:// version 2.0, with title field renamed to title_name
message Production {
string id = 1;
string title_name = 2;       // this field used to be "title"
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
}





在此圖表中,生產者(服務器)使用新的描述符,字段編號 2 名為 title_name。傳輸發(fā)送的二進制消息包含字段編號及其值。消費者仍然使用原始描述符,其中字段編號 2 作為標題。它仍然能夠通過字段號對消息進行解碼。
如果消費者不使用 FieldMask 來請求字段,那倒是沒問題。如果消費者使用 FieldMask 字段中的“title”路徑進行調用,生產者將無法找到該字段。生產者在其描述符中沒有名為 title 的字段,因此它不知道消費者請求的字段編號為 2。



如我們所見,如果一個字段被重命名,后端應該能夠支持新舊字段名稱,直到所有調用者都遷移到新字段名稱(向后兼容性問題)。
有多種方法可以處理此限制:
  • 使用 FieldMask 時切勿重命名字段。這是最簡單的解決方案,但并非總是可行


  • 要求后端支持所有舊的字段名稱。這解決了向后兼容性問題,但需要后端額外的代碼來跟蹤所有歷史字段名稱


  • 棄用舊字段并創(chuàng)建新字段而不是重命名。在我們的示例中,我們將創(chuàng)建 title_name 字段編號 6。此選項比前一個有一些優(yōu)點:它允許生產者繼續(xù)使用生成的描述符而不是自定義轉換器;此外,棄用一個字段在消費者端影響更大


message Production {
string id = 1;
string title = 2 [deprecated = true];  // use "title_name" field instead
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
string title_name = 6;
}


無論采用哪種解決方案,重要的是要記住 FieldMask 使字段名稱成為 API 合約中不可或缺的一部分。
在生產者(服務器)端使用 FieldMask
在生產者(服務器)端,可以使用 FieldMaskUtil.merge()[7] 方法(8 和 9 行)從響應負載中刪除不必要的字段:@Override
public void getProduction(GetProductionRequest request,
StreamObserverresponse) {

Production production = fetchProduction(request.getProductionId());
FieldMask fieldMask = request.getFieldMask();

Production.Builder productionWithMaskedFields = Production.newBuilder();
FieldMaskUtil.merge(fieldMask, production, productionWithMaskedFields);

GetProductionResponse response = GetProductionResponse.newBuilder()
.setProduction(productionWithMaskedFields).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}


如果服務端代碼還需要知道請求哪些字段以避免進行外部調用、數(shù)據(jù)庫查詢或昂貴的計算,則可以從 FieldMask 路徑字段中獲取此信息:private static final String FIELD_SEPARATOR_REGEX = "\\.";
private static final String MAX_FIELD_NESTING = 2;
private static final String SCHEDULE_FIELD_NAME =                                // (1)
Production.getDescriptor()
.findFieldByNumber(Production.SCHEDULE_FIELD_NUMBER).getName();

@Override
public void getProduction(GetProductionRequest request,
StreamObserverresponse) {

FieldMask canonicalFieldMask =
FieldMaskUtil.normalize(request.getFieldMask());                         // (2)

boolean scheduleFieldRequested =                                             // (3)
canonicalFieldMask.getPathsList().stream()
.map(path -> path.split(FIELD_SEPARATOR_REGEX, MAX_FIELD_NESTING)[0])
.anyMatch(SCHEDULE_FIELD_NAME::equals);

if (scheduleFieldRequested) {
ProductionSchedule schedule =
makeExpensiveCallToScheduleService(request.getProductionId());       // (4)
...
}

...
}


此代碼僅在schedule 字段被請求時調用 makeExpensiveCallToScheduleService 方法(第 21 行)。讓我們更詳細地探索這個代碼示例。
  1. SCHEDULE_FIELD_NAME 常量包含字段的名稱。此代碼示例使用消息類型 Descriptor[8] 和 FieldDescriptor[9] 通過字段編號查找字段名稱。protobuf 字段名稱和字段編號之間的區(qū)別在上面的 Protobuf 字段名稱與字段編號部分進行了描述。


  2. FieldMaskUtil.normalize()[10] 返回具有按字母順序排序和去重的字段路徑(又名規(guī)范形式)的 FieldMask。


  3. scheduleFieldRequestedvalue 表達式(第14 - 17 行)采用 FieldMask 路徑流,將其映射到頂級(top-level)字段流,如果頂級字段包含 SCHEDULE_FIELD_NAME 常量的值,則返回 true。


  4. 僅當 scheduleFieldRequested 為真時才檢索 ProductionSchedule。



如果你決定將 FieldMask 用于不同的消息和字段,請考慮創(chuàng)建可重用的實用封裝方法。例如,基于 FieldMask 和 FieldDescriptor 返回所有頂級字段的方法,如果字段存在于 FieldMask 中則返回的方法等。


發(fā)布預編譯的 FieldMask



某些訪問模式可能比其他訪問模式更常見。如果多個消費者對同一字段子集感興趣,API 生產者可以提供帶有 FieldMask 的客戶端庫,用于最常用的字段組合。public class ProductionFieldMasks {
/**
* Can be used in {@link GetProductionRequest} to query
* production title and format
*/
public static final FieldMask TITLE_AND_FORMAT_FIELD_MASK =
FieldMaskUtil.fromFieldNumbers(Production.class,
Production.TITLE_FIELD_NUMBER, Production.FORMAT_FIELD_NUMBER);

/**
* Can be used in {@link GetProductionRequest} to query
* production title and schedule
*/
public static final FieldMask TITLE_AND_SCHEDULE_FIELD_MASK =
FieldMaskUtil.fromFieldNumbers(Production.class,
Production.TITLE_FIELD_NUMBER,
Production.SCHEDULE_FIELD_NUMBER);

/**
* Can be used in {@link GetProductionRequest} to query
* production title and scripts
*/
public static final FieldMask TITLE_AND_SCRIPTS_FIELD_MASK =
FieldMaskUtil.fromFieldNumbers(Production.class,
Production.TITLE_FIELD_NUMBER, Production.SCRIPTS_FIELD_NUMBER);

}


提供預編譯的字段掩碼可以簡化最常見場景的 API 使用,并使消費者能夠靈活地為更具體的用例構建自己的字段掩碼。


限制



  • 使用 FieldMask 會限制重命名消息字段的能力(在 Protobuf 字段名稱與字段編號部分中描述)


  • 重復字段只允許出現(xiàn)在路徑字符串的最后一個位置。這意味著你不能在列表內的消息中選擇(屏蔽)單個子字段。這在可預見的未來可能會發(fā)生變化,因為最近批準的 Google API 改進提案 AIP-161 字段掩碼[11]包括對重復字段的通配符的支持。



總結



Protobuf FieldMask 是一個簡單但功能強大的概念。它可以幫助使 API 更健壯,服務實現(xiàn)更高效。
這篇博文介紹了 Netflix Studio Engineering 如何以及為何將其用于讀取數(shù)據(jù)的 API。第 2 部分將闡明使用 FieldMask 進行更新和刪除操作。


本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉