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

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



背景



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


Protobuf FieldMask



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



案例:Netflix Studio Production



假設(shè)有一個(gè) Production 服務(wù)來(lái)管理 Studio Content Productions(在電影和電視行業(yè)中,術(shù)語(yǔ) production[4] 是指制作電影的過(guò)程,而不是運(yùn)行軟件的環(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 通過(guò)唯一 ID 返回 Production 消息。一個(gè) production 包含多個(gè)字段,例如:標(biāo)題、格式、日程安排日期、腳本又名劇本、預(yù)算、劇集等,但讓我們保持這個(gè)例子簡(jiǎn)單,并在請(qǐng)求 production時(shí)重點(diǎn)過(guò)濾日程安排日期和腳本。
讀取 Production 詳細(xì)信息
假設(shè)我們想要使用 GetProduction API 獲取特定 production 的信息,例如“La Casa De Papel”。雖然 production 有許多字段,但其中一些字段是從其他服務(wù)返回的,例如來(lái)自 Schedule 服務(wù)的 schedule 或來(lái)自 Script 服務(wù)的 scripts。



每次調(diào)用 GetProduction 時(shí),Production 服務(wù)都會(huì)向 Schedule 和 Script 服務(wù)發(fā)出 RPC,即使客戶端忽略響應(yīng)中的 schedule 和 scripts 字段。如上所述,遠(yuǎn)程調(diào)用是有代價(jià)的。如果服務(wù)知道哪些字段對(duì)調(diào)用者很重要,它可以在是否進(jìn)行昂貴的調(diào)用、啟動(dòng)資源密集型計(jì)算和/或調(diào)用數(shù)據(jù)庫(kù)這些事中做出明智的決定。在這個(gè)例子中,如果調(diào)用者只需要標(biāo)題和格式兩個(gè)字段,Production 服務(wù)可以避免遠(yuǎn)程調(diào)用 Schedule 和 Script 服務(wù)。
此外,請(qǐng)求大量字段會(huì)使響應(yīng)負(fù)載變得龐大。對(duì)某些應(yīng)用程序來(lái)說(shuō)可能是個(gè)問(wèn)題,例如,在網(wǎng)絡(luò)帶寬有限的移動(dòng)設(shè)備上。在這些情況下,消費(fèi)者只請(qǐng)求他們需要的字段是一種很好的做法。
一個(gè)比較笨的解決方法是添加額外的請(qǐng)求參數(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;
}


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

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


消費(fèi)者可以為他們希望在響應(yīng)中收到的字段設(shè)置路徑。如果消費(fèi)者只對(duì)標(biāo)題和格式感興趣,他們可以設(shè)置帶有“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();





請(qǐng)注意,即使本博文中的代碼示例是用 Java 編寫(xiě)的,演示的概念也適用于任何支持 protocol buffers 的其他語(yǔ)言。
如果消費(fèi)者只需要最后一個(gè)更新日程表的人的標(biāo)題和電子郵件,他們可以設(shè)置不同的字段掩碼: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();


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


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



如上所述,F(xiàn)ieldMask 列出字段名稱,而不是數(shù)字。在 Netflix,我們使用字段編號(hào)并使用 FieldMaskUtil.fromFieldNumbers()[6] 方法將它們轉(zhuǎn)換為字段名稱。此方法利用編譯的消息定義將字段編號(hào)轉(zhuǎn)換為字段名稱并創(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();


但是,有一個(gè)容易忽略的限制:使用 FieldMask 會(huì)限制你重命名消息字段的能力。重命名消息字段通常被認(rèn)為是一種安全操作,因?yàn)槿缟纤?,字段名稱不會(huì)被傳輸發(fā)送的,而是使用消費(fèi)者端的字段編號(hào)派生的。使用 FieldMask,字段名稱會(huì)在消息負(fù)載中被發(fā)送出去(在路徑字段值中)并且還是很重要的部分。
假設(shè)我們要將字段 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;
}





在此圖表中,生產(chǎn)者(服務(wù)器)使用新的描述符,字段編號(hào) 2 名為 title_name。傳輸發(fā)送的二進(jìn)制消息包含字段編號(hào)及其值。消費(fèi)者仍然使用原始描述符,其中字段編號(hào) 2 作為標(biāo)題。它仍然能夠通過(guò)字段號(hào)對(duì)消息進(jìn)行解碼。
如果消費(fèi)者不使用 FieldMask 來(lái)請(qǐng)求字段,那倒是沒(méi)問(wèn)題。如果消費(fèi)者使用 FieldMask 字段中的“title”路徑進(jìn)行調(diào)用,生產(chǎn)者將無(wú)法找到該字段。生產(chǎn)者在其描述符中沒(méi)有名為 title 的字段,因此它不知道消費(fèi)者請(qǐng)求的字段編號(hào)為 2。



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


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


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


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;
}


無(wú)論采用哪種解決方案,重要的是要記住 FieldMask 使字段名稱成為 API 合約中不可或缺的一部分。
在生產(chǎn)者(服務(wù)器)端使用 FieldMask
在生產(chǎn)者(服務(wù)器)端,可以使用 FieldMaskUtil.merge()[7] 方法(8 和 9 行)從響應(yīng)負(fù)載中刪除不必要的字段:@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();
}


如果服務(wù)端代碼還需要知道請(qǐng)求哪些字段以避免進(jìn)行外部調(diào)用、數(shù)據(jù)庫(kù)查詢或昂貴的計(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 字段被請(qǐng)求時(shí)調(diào)用 makeExpensiveCallToScheduleService 方法(第 21 行)。讓我們更詳細(xì)地探索這個(gè)代碼示例。
  1. SCHEDULE_FIELD_NAME 常量包含字段的名稱。此代碼示例使用消息類(lèi)型 Descriptor[8] 和 FieldDescriptor[9] 通過(guò)字段編號(hào)查找字段名稱。protobuf 字段名稱和字段編號(hào)之間的區(qū)別在上面的 Protobuf 字段名稱與字段編號(hào)部分進(jìn)行了描述。


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


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


  4. 僅當(dāng) scheduleFieldRequested 為真時(shí)才檢索 ProductionSchedule。



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


發(fā)布預(yù)編譯的 FieldMask



某些訪問(wèn)模式可能比其他訪問(wèn)模式更常見(jiàn)。如果多個(gè)消費(fèi)者對(duì)同一字段子集感興趣,API 生產(chǎn)者可以提供帶有 FieldMask 的客戶端庫(kù),用于最常用的字段組合。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);

}


提供預(yù)編譯的字段掩碼可以簡(jiǎn)化最常見(jiàn)場(chǎng)景的 API 使用,并使消費(fèi)者能夠靈活地為更具體的用例構(gòu)建自己的字段掩碼。


限制



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


  • 重復(fù)字段只允許出現(xiàn)在路徑字符串的最后一個(gè)位置。這意味著你不能在列表內(nèi)的消息中選擇(屏蔽)單個(gè)子字段。這在可預(yù)見(jiàn)的未來(lái)可能會(huì)發(fā)生變化,因?yàn)樽罱鷾?zhǔn)的 Google API 改進(jìn)提案 AIP-161 字段掩碼[11]包括對(duì)重復(fù)字段的通配符的支持。



總結(jié)



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


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

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

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

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

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

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

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

關(guān)鍵字: 騰訊 編碼器 CPU

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

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

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

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

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

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

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

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

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

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉