精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

聊聊為什么 IDL 只能擴展字段而非修改

大數據 數據分析
本文聊聊 grpc proto 變更時的兼容問題,核心只有一條:對擴展開放,對修改關閉,永遠只增加字段而不修改。

[[439484]]

本文轉載自微信公眾號「董澤潤的技術筆記」,作者董澤潤  。轉載本文請聯系董澤潤的技術筆記公眾號。

前幾年業界流行使用 thrift, 比如滴滴。這幾年 grpc 越來越流行,很多開源框架也集成了,我司大部分服務都同時開放 grpc 和 http 接口

相比于傳統的 http1 + json 組合,這兩種技術都用到了 IDL, 即 Interface description language 接口描述語言,相當于增加了 endpoint schema 約束,不同語言只需要一份相同的 IDL 文件即可生成接口代碼。

很多人喜歡問:proto buf 與 json 比起來有哪些優勢?比較經典的面試題

IDL 文件管理每個公司不一樣,有的保存在單獨 gitlab 庫,有的是 mono repo 大倉庫。當業務變更時,IDL 文件經常需要修改,很多新手總是容易踩坑,本文聊聊 grpc proto 變更時的兼容問題,核心只有一條:對擴展開放,對修改關閉,永遠只增加字段而不修改

測試修改兼容性

本文測試使用 grpc-go example 官方用例,感興趣自查

  1. syntax = "proto3"
  2.  
  3. option go_package = "google.golang.org/grpc/examples/helloworld/helloworld"
  4. package helloworld; 
  5.  
  6. // The greeting service definition. 
  7. service Greeter { 
  8.   // Sends a greeting 
  9.   rpc SayHello (HelloRequest) returns (HelloReply) {} 
  10.  
  11. // The request message containing the user's name
  12. message HelloRequest { 
  13.   string name = 1; 
  14.  
  15. // The response message containing the greetings 
  16. message HelloReply { 
  17.   string message = 1; 
  18.   string additional = 2; 
  19.   int32 age = 3; 
  20.   int64 id = 4; 

每次修改后使用 protoc 重新生成代碼

  1. protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto 

Server 每次接受請求后,返回 HelloReply 結構體

  1. // SayHello implements helloworld.GreeterServer 
  2. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { 
  3.  log.Printf("Received: %v"in.GetName()) 
  4.  return &pb.HelloReply{ 
  5.   Message:    "Hello addidional " + in.GetName(), 
  6.   Additional: "this is addidional field"
  7.   Age:        10, 
  8.   Id:         12345, 
  9.  }, nil 

Client 每次只打印 Server 返回的結果

修改字段編號

將 HelloReply 結構體字段 age 編號變成 12, 然后 server 使用新生成的 IDL 庫,client 使用舊版本

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 22:23:38 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "id": 12345 

可以看到 client 沒有讀到 age 字段,因為 IDL 是根據序號傳輸的,client 讀不到 seq 3, 所以修改序號不兼容

修改字段 name

修改 HelloReploy 字段 id, 變成 score 類型和序號不變

  1. // The response message containing the greetings 
  2. message HelloReply { 
  3.   string message = 1; 
  4.   string additional = 2; 
  5.   int32 age = 3; 
  6.   int64 score = 4; 

重新編譯 server, 并用舊版本 client 訪問

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 22:29:18 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "age": 10, 
  7.  "id": 12345 

可以看到,雖然修改了字段名,但是 client 仍然讀到了正確的值 12345, 如果字段含義不變,那么只修改名稱是兼容的

修改類型

有些類型是兼容的,有些不可以,而且還要考慮不同的語言。這里測試三種

1.字符串與字節數組

  1. // The response message containing the greetings 
  2. message HelloReply { 
  3.   string message = 1; 
  4.   bytes additional = 2; 
  5.   int32 age = 3; 
  6.   int64 id = 4; 

我們將 additional 字段由 string 類型修改為 bytes

  1. // The response message containing the greetings 
  2. type HelloReply struct { 
  3.  Message    string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"
  4.  Additional []byte `protobuf:"bytes,2,opt,name=additional,proto3" json:"additional,omitempty"
  5.  Age        int32  `protobuf:"varint,3,opt,name=age,proto3" json:"age,omitempty"
  6.  Id         int64  `protobuf:"varint,4,opt,name=id,proto3" json:"id,omitempty"

可以看到 go 結構體由 string 變成了 []byte, 我們知道這兩個其實可以互換

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 22:35:43 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "age": 10, 
  7.  "id": 12345 

最后結果也證明 client 可以正確的處理數據,即修改成兼容類型沒有任何問題

2.int32 int64 互轉

  1. message HelloReply { 
  2.   string message = 1; 
  3.   string additional = 2; 
  4.   int64 age = 3; 
  5.   int64 id = 4; 

這里我們將 age 由 int32 修改成 int64 字段,位數不一樣,如果同樣小于 int32 最大值沒有問題,此時我們在 server 端將 age 賦于 2147483647 + 1 剛好超過最大值

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 22:43:32 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "age": -2147483648, 
  7.  "id": 12345 

我們可以看到 age 變成了負數,如果業務剛好允許負值,那么此時一定會出邏輯問題,而且難以排查 bug, 這其實是非常典型的向上向下兼容問題

3.非兼容類型互轉

  1. message HelloReply { 
  2.   string message = 1; 
  3.   string additional = 2; 
  4.   string age = 3; 
  5.   int64 id = 4; 

我們將 age 由 int32 變成 string 字符串,依舊使用 client 舊版本測試

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 22:55:21 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "id": 12345 
  7. 2021/12/08 22:55:21 message:"Hello addidional world" additional:"this is addidional field" id:12345 3:"this is age" 
  8. 2021/12/08 22:57:56 r.Age is 0 

可以看到結構體 json 序列化打印時不存在 Age 字段,但是 log 打印時發現了不兼容的 3:"this is age", 注意 grpc 會保留不兼容的數據

同時 r.Age 默認是 0 值,即非兼容類型修改是有問題的

刪除字段

  1. message HelloReply { 
  2.   string message = 1; 
  3.   string additional = 2; 
  4.   // string age = 3; 
  5.   int64 id = 4; 

刪除字段 age 也就是說序號此時有空洞,運行 client 舊版本協義

  1. zerun.dong$ ./greeter_client 
  2. ...... 
  3. 2021/12/08 23:02:12 Greeting: { 
  4.  "message""Hello addidional world"
  5.  "additional""this is addidional field"
  6.  "id": 12345 
  7. 2021/12/08 23:02:12 message:"Hello addidional world"  additional:"this is addidional field"  id:12345 
  8. 2021/12/08 23:02:12 0 

沒有問題,打印 r.Age 當然是默認值 0, 即刪除字段是兼容的

為什么 required 在 proto3 中取消了?

  1. message SearchRequest { 
  2.   required string query = 1; 
  3.   optional int32 page_number = 2; 
  4.   optional int32 result_per_page = 3; 

熟悉 thrift 或是使用 proto2 協議的都習慣使用 required optional 來定義字段屬于,擴展字段一般標記為 optional, 必傳字段使用 required 來約束

官方解釋如下 issues2497[1],簡單說就是 required 打破了更新 IDL 時的兼容性

  • 永遠不能安全地向 proto 定義添加 required 字段,也不能安全地刪除現有的 required 字段,因為這兩個操作都會破壞兼容性
  • 在一個復雜的系統中,proto 定義在系統的許多不同組件中廣泛共享,添加/刪除 required 字段可以輕松地降低系統的多個部分
  • 多次看到由此造成的生產問題,并且 Google 內部幾乎禁止任何人添加/刪除 required 字段

上面是谷歌得出的結論,大家可以借鑒一下,但也不能唯 G 家論

小結

IDL 修改還有很多測試用例,感興趣的可以多玩玩,比如結構體間的轉換問題,比如 enum 枚舉類型。上文測試的都是 server 端使用新協義,client 使用舊協義,如果反過來呢?想測試 thrift 的可以看看這篇 thrift missing guide[2]

 

本文能過測試 case 想告訴大家,IDL 只能追加杜絕修改 (產品測試階段隨變改,無所謂)

 

責任編輯:武曉燕 來源: 董澤潤的技術筆記
相關推薦

2022-12-26 00:00:03

非繼承關系JDK

2022-05-17 22:20:41

哨兵Redis機制

2022-05-11 08:22:54

IO負載NFSOS

2012-03-06 20:51:04

iOS

2025-10-10 01:00:00

2022-02-21 07:54:28

單元測試編程開發

2024-01-30 07:55:03

KubernetesAPI服務器

2022-01-19 22:51:57

設計匿名用戶

2015-08-27 16:48:11

FirefoxChrome

2022-03-28 08:24:52

MySQL聚簇索引非聚簇索引

2017-02-10 09:55:53

SwiftObjective-C

2024-09-24 08:18:13

2021-11-29 10:24:56

WasmEnvoy 負載均衡

2023-02-15 08:41:56

多層維表性能寬表

2017-04-17 11:50:13

51CTO 學院

2019-07-02 08:30:25

蘋果 iOS系統

2020-12-29 05:34:00

動態代理

2023-07-05 08:17:38

JDK動態代理接口

2018-12-29 15:41:41

阿里巴巴程序員serialVersi

2024-08-07 08:14:26

點贊
收藏

51CTO技術棧公眾號

成人黄色小视频在线观看| 在线观看精品| 成人亚洲一区二区一| 午夜精品免费视频| 国产精品美女高潮无套| 99re8精品视频在线观看| 亚洲一区欧美一区| 日韩欧美视频一区二区| 国产精品久久久午夜夜伦鲁鲁| 国语对白精品一区二区| 亚洲美女性生活视频| 亚洲制服中文字幕| 樱花草涩涩www在线播放| 国产日韩精品久久久| yy111111少妇影院日韩夜片| 欧美brazzers| 亚洲激情另类| 久久精品国产免费观看| 五月婷婷综合在线观看| 久久天堂久久| 欧洲精品一区二区| 精品人妻少妇一区二区| 日本黄色片在线观看| 99精品欧美一区二区三区综合在线| 国产精品综合网站| www.欧美色| 在线成人黄色| 久久亚洲一区二区三区四区五区高 | 偷拍女澡堂一区二区三区| 国产精品一区二区三区四区在线观看 | 欧美网站免费| 福利一区福利二区微拍刺激| 中文字幕第一页亚洲| 丁香婷婷在线观看| 91免费看片在线观看| 国产精品久久国产精品| 国产成人精品无码高潮| 久久99精品国产麻豆婷婷| 国产精品2018| 久久国产视频播放| 亚洲精选在线| 午夜精品在线视频| 69精品久久久| 影音先锋中文字幕一区二区| 色在人av网站天堂精品| 国产极品国产极品| 一级毛片免费高清中文字幕久久网| 国产一区二区久久精品| 欧美老熟妇乱大交xxxxx| 成人自拍在线| 欧美成人性战久久| 久久久久亚洲av无码麻豆| 色综合一区二区日本韩国亚洲 | 国产一区二区在线视频聊天| 日韩av一区二| 国产精品久久久久一区二区| 日韩熟女一区二区| 三级一区在线视频先锋 | 中文字幕日韩av综合精品| 一级黄色性视频| 最新亚洲精品| 亚洲人成五月天| 天天操天天舔天天射| 日韩免费视频| 日韩综合中文字幕| 朝桐光av在线| 黄色日韩在线| 97视频在线观看免费| 欧美日韩精品区| 久久激情久久| 国产欧美精品在线| 国产免费无遮挡| 国产91精品久久久久久久网曝门| 国产精品免费在线播放| 日韩午夜影院| 国产精品久久久久影院色老大| 亚洲资源在线网| sm国产在线调教视频| 亚洲无线码一区二区三区| 欧美成人高潮一二区在线看| 国偷自产一区二区免费视频| 欧美色窝79yyyycom| а 天堂 在线| 极品尤物一区| 中文字幕在线看视频国产欧美在线看完整 | 一本色道久久综合亚洲精品高清 | 亚洲天天做日日做天天谢日日欢 | 亚洲一区二区在线免费观看| 97影院秋霞午夜在线观看| 亚洲国产成人tv| 国产嫩草在线观看| 超碰在线一区| 国产午夜精品一区理论片飘花| 欧美成人短视频| 韩日成人av| 国产精品久久久久久久9999| 精品国产亚洲AV| 久久噜噜亚洲综合| 日本一道在线观看| 成人免费无遮挡| 日韩午夜中文字幕| 亚洲精品91在线| 激情婷婷久久| 成人黄色免费网站在线观看| 日韩有码第一页| 国产精品家庭影院| 免费黄色福利视频| 奇米一区二区| 一区二区三区视频免费| 日本一二三区视频| 激情综合色综合久久综合| 国产伦精品一区二区三区视频黑人| 久青草国产在线| 亚洲国产日韩精品| 成人不卡免费视频| 国产一区二区三区四区二区| 欧美激情亚洲另类| 91女人18毛片水多国产| 久久久久久久电影| 婷婷五月综合缴情在线视频| 国产激情精品一区二区三区| 亚洲午夜激情免费视频| 日韩av在线播| 国产成a人亚洲精| 中文字幕一区二区三区四区五区人| 在线成人av观看| 精品国产91久久久久久久妲己 | 一本一本久久a久久精品综合麻豆| 久久出品必属精品| 欧美gvvideo网站| 国产精品国产福利国产秒拍| 亚洲人视频在线观看| 一区av在线播放| 亚洲三级在线观看视频| 大色综合视频网站在线播放| 欧美中在线观看| 性感美女视频一二三| 一区二区三区在线视频免费观看| 污视频免费在线观看网站| 国产探花在线精品一区二区| 欧美在线xxx| 五月婷在线视频| 香蕉成人伊视频在线观看| 色诱av手机版| 亚洲午夜91| 国产九色91| av资源在线播放| 亚洲国产美女精品久久久久∴| 波多野结衣亚洲色图| 激情国产一区二区| 黄色www在线观看| 国产亚洲观看| 欧美风情在线观看| 狠狠人妻久久久久久综合麻豆| 一区二区三区产品免费精品久久75| 日韩视频在线观看一区二区三区| 偷偷www综合久久久久久久| 91在线观看免费| 99热国产在线| 亚洲成人aaa| 日本天堂网在线| 国产欧美日韩精品a在线观看| 妺妺窝人体色www在线观看| 不卡中文字幕| 91香蕉亚洲精品| 免费不卡av| 日韩久久精品成人| 日批视频免费观看| 日韩毛片高清在线播放| 少妇性l交大片7724com| 在线观看亚洲| 日韩欧美一区二区视频在线播放| 超薄肉色丝袜脚交一区二区| www.日韩.com| 神马久久久久久久久久| 一本一道波多野结衣一区二区| a资源在线观看| 国产激情视频一区二区在线观看 | 99在线热播精品免费| 热久久精品国产| 99久久综合狠狠综合久久aⅴ| 亚洲综合第一页| 无遮挡爽大片在线观看视频 | 免费精品视频在线| 人妻互换免费中文字幕| 亚洲三级精品| 91视频国产精品| 色资源二区在线视频| 丝袜情趣国产精品| 搡老岳熟女国产熟妇| 欧美色倩网站大全免费| 五月天婷婷网站| 中文字幕成人av| 日本三级日本三级日本三级极| 三级不卡在线观看| 特级西西444| 欧美亚洲国产激情| 国产精品一区二区欧美| 欧美黄页在线免费观看| 91国在线精品国内播放| 美女隐私在线观看| 亚洲免费福利视频| www.五月婷| 欧美特级限制片免费在线观看| 免费在线观看亚洲| 中文字幕不卡的av| 中文字幕免费在线播放| 黄色精品一二区| 哪个网站能看毛片| 伊人成人在线视频| 青青草原国产免费| 欧美精品乱码| 欧美12av| 岛国av一区| 99re在线观看视频| 亚洲人成网站在线在线观看| 国产999视频| 9999热视频在线观看| 久久久成人av| 97视频在线观看网站| 亚洲精品国精品久久99热| www.成人免费视频| 欧美精品丝袜久久久中文字幕| 国产成人综合欧美精品久久| 亚洲一二三四区| 欧美日韩精品在线观看视频| 亚洲国产岛国毛片在线| 免费a级黄色片| av一区二区三区在线| 香蕉在线观看视频| 国产精品一区不卡| 亚洲天堂av一区二区| 久久美女性网| 无码无遮挡又大又爽又黄的视频| 亚洲国产日本| 97久久国产亚洲精品超碰热| 亚洲v在线看| 一区一区视频| 91影院成人| 一区二区视频国产| 天天做天天爱天天爽综合网| 亚洲国产精品一区二区第四页av| 亚洲第一福利专区| 欧美在线激情| 精品一二三区| 在线一区高清| 国产精品成人a在线观看| 亚洲日本理论电影| 99热精品久久| 波多野结衣激情| 一个色综合网| 日韩av高清在线看片| 一本色道久久综合亚洲精品高清| 国产精品裸体瑜伽视频| 亚洲综合另类| 日韩中文字幕免费在线| 免费久久精品视频| www.亚洲自拍| 成人av手机在线观看| 人妻丰满熟妇aⅴ无码| 久久久噜噜噜久久中文字幕色伊伊| www.久久国产| 中文字幕国产精品一区二区| 精品国产视频在线观看| 一级精品视频在线观看宜春院 | 欧美一区二区啪啪| 亚洲成人77777| 日韩精品中文字幕有码专区| 国产三级电影在线| 久久综合五月天| 91在线超碰| 国产精品久久久久久久久久久久久 | 成人在线观看黄色| www国产精品视频| 男男gaygays亚洲| 欧美在线视频观看| 日韩欧美专区| 国产伦精品一区二区三区四区免费| 日韩人体视频| 伊人久久青草| av成人黄色| 日韩高清第一页| 成人精品免费视频| 欧美黄色激情视频| 亚洲精品乱码久久久久久久久| 日韩 欧美 综合| 欧美日韩高清一区二区不卡| 蜜桃av噜噜一区二区三区麻豆| 亚洲欧美国产一本综合首页| 黄网页在线观看| 26uuu久久噜噜噜噜| 在线视频成人| 欧美福利精品| 午夜国产精品视频| 久草福利视频在线| 不卡区在线中文字幕| 免费一级黄色录像| 性做久久久久久免费观看欧美| 人人妻人人爽人人澡人人精品| 日韩亚洲电影在线| 尤物视频在线免费观看| 97碰碰碰免费色视频| 国产免费区一区二区三视频免费 | 在线中文字幕第一页| 国产成人精品在线视频| 6080成人| 在线视频福利一区| 日韩精品电影一区亚洲| 国产av一区二区三区传媒| 国产精品久久久久天堂| 中文字幕第四页| 精品日产卡一卡二卡麻豆| 97视频在线观看网站| 日韩女在线观看| 欧美福利在线播放网址导航| 影音先锋男人的网站| 日韩成人伦理电影在线观看| 手机在线成人av| 亚洲自拍另类综合| 99精品视频在线播放免费| 在线视频国产日韩| 蜜桃视频在线观看免费视频| 91精品国产高清久久久久久91裸体| 成人精品电影| 五月婷婷深爱五月| 久久久久久电影| 亚洲精品男人的天堂| 亚洲国产精品电影| 丁香影院在线| av免费观看久久| 一区二区电影在线观看| 在线一区二区不卡| 国产欧美一区视频| 欧美国产一级片| 亚洲人成毛片在线播放| av日韩电影| 欧美久久久久久| 久久av最新网址| 免费观看av网站| 色综合天天综合网国产成人综合天 | 国产精品毛片大码女人| 中文字幕在线观看视频免费| 亚洲欧美一区二区三区在线| 国产精品av一区二区三区| 欧美激情www| 久久福利影视| 91精品国自产在线| 欧美日韩国产综合一区二区 | 欧美日韩一二三四| 手机在线成人免费视频| 中文字幕久久午夜不卡| 国产精品久久久久久免费免熟| 爱福利视频一区| 亚洲一区二区三区中文字幕在线观看 | 免费福利在线观看| 国产精品欧美一区二区| 99成人在线视频| 国产成人精品综合久久久久99| 一区二区三区中文免费| 婷婷在线免费视频| 日韩av电影手机在线观看| 日本大胆欧美| 久久久久久久久久毛片| 亚洲国产一二三| 青青久在线视频| 国产精品综合网站| 亚洲一级特黄| 黄免费在线观看| 7777精品伊人久久久大香线蕉最新版| a视频在线观看免费| 精品高清视频| 免费成人你懂的| 超碰手机在线观看| 亚洲国产中文字幕在线观看| 超碰aⅴ人人做人人爽欧美| 一区二区不卡在线观看| 国产高清久久久久| 欧美黑人一区二区| 日日骚久久av| 国产日韩三级| 日韩在线不卡一区| 亚洲国产视频直播| 97人人在线| 久久国产精品免费一区| 免费人成在线不卡| 国产污片在线观看| 中文字幕亚洲二区| 粉嫩久久久久久久极品| 在线免费视频a| 一区二区免费在线| 精品成人一区二区三区免费视频| 91在线视频免费| 久久中文精品| 九九视频免费在线观看| 一区二区三区无码高清视频| 亚洲一区二区三区中文字幕在线观看 | 亚洲热线99精品视频| 美女日韩一区| 精品久久久久久久无码 | 免费毛片小视频|