1. 程式人生 > >protobuf詳解

protobuf詳解

      protobuf是由google開發的一種資料交換格式。使用protobuf可以很輕鬆的實現訊息的序列化與反序列化。序列化時,根據.proto檔案將資料解析成二進位制流用於傳輸;反序列化時,再根據.proto檔案將二進位制流解析成所需要的資料。它可以作為RabbitMQ的Message資料格式進行傳輸,由於是結構化的資料,這樣就極大地方便了Consumer的資料高效處理。

附上一張RabbitMQ的結構圖,在ClientA、ClientB、Client1、Client2、Client3端分別使用protobuf用於資料的序列化與反序列化。

關於RabbitMQ的詳細介紹,歡迎檢視我的上篇博文

RabbitMQ基礎知識詳解

優點:

1、效能好、效率高

2、程式碼生成機制

比如有個電子商務的系統(假設用C++實現),採用上圖的RabbitMQ架構,其中的ClientA、B需要傳送大量的訂單資訊給Client1、2、3,通訊的方式使用socket。
假設訂單包括如下屬性:
--------------------------------
  時間:time(用整數表示)
  客戶id:userid(用整數表示)
  交易金額:price(用浮點數表示)
  交易的描述:desc(用字串表示)
--------------------------------
  如果使用protobuf實現,首先要寫一個proto檔案(不妨叫Order.proto),在該檔案中新增一個名為"Order"的message結構,用來描述通訊協議中的結構化資料。該檔案的內容大致如下:

--------------------------------

message Order
{
  required int32 time = 1;
  required int32 userid = 2;
  required float price = 3;
  optional string desc = 4;
}

--------------------------------
  然後,使用protobuf內建的編譯器編譯該proto檔案。由於本例子的模組是C++,你可以通過protobuf編譯器的命令列引數,讓它生成C++語言的“訂單包裝類”。(一般來說,一個message結構會生成一個包裝類)
  然後你使用類似下面的程式碼來序列化/解析該訂單包裝類:
--------------------------------

// 傳送方

Order order;
order.set_time(XXXX);
order.set_userid(123);
order.set_price(100.0f);
order.set_desc("a test order");

string sOrder;
order.SerailzeToString(&sOrder);

// 然後呼叫某種socket的通訊庫把序列化之後的字串傳送出去
// ......

--------------------------------

// 接收方

string sOrder;
// 先通過網路通訊庫接收到資料,存放到某字串sOrder
// ......

Order order;
if(order.ParseFromString(sOrder))  // 解析該字串
{
  cout << "userid:" << order.userid() << endl
          << "desc:" << order.desc() << endl;
}
else
{
  cerr << "parse error!" << endl;
}

--------------------------------

      有了這種程式碼生成機制,開發人員就不用吭哧吭哧地編寫那些協議解析的程式碼了。
      萬一將來需求發生變更,要求給訂單再增加一個“狀態”的屬性,那隻需要在Order.proto檔案中增加一行程式碼。對於傳送方(模組A),只要增加一行設定狀態的程式碼;對於接收方(模組B)只要增加一行讀取狀態的程式碼。
  另外,如果通訊雙方使用不同的程式語言來實現,使用這種機制可以有效確保兩邊的模組對於協議的處理是一致的。

3、支援“向後相容”和所謂的“向後相容”

      “向後相容“:當ClientA、B沒有改變,而Client1、2、3給訂單增加了一個“狀態”的屬性時,它能夠正確識別接受到的資料。由於ClientA、B端沒有“狀態”這個屬性,在擴充協議時,可以考慮把“狀態”屬性設定成非必填 的,或者給“狀態”屬性設定一個預設值。
   “向前相容”:當ClientA、B給訂單增加了一個“狀態”的屬性,而Client1、2、3沒有改變時,它能夠正確識別接受到的資料。這時候,新增加的“狀態”屬性會被忽略。
   “向後相容”和“向前相容”有什麼作用呢?

     舉個例子:當你維護一個很龐大的分散式系統時,由於你無法同時升級所有模組,為了保證在升級過程中,整個系統能夠儘可能不受影響,就需要儘量保證通訊協議的“向後相容”或“向前相容”。

4,支援多種程式語言(java,c++,python)

缺點:

1、應用不夠廣

2、二進位制格式導致可讀性差

3、缺乏自描述

本文部分轉載自http://blog.csdn.net/caisini_vc/article/details/5599468