CMDB系统一直使用json 格式作为API接口进行数据的收集和渲染。当数据量比较大时,使用http协议对json数据传输时,传输比较耗时。无意间发现google有一款开源软件protocol buffer,通过测试发现的确性能比json提高不少。

 

  1. protobuf

           Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。           

          Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

     

  2. protobuf 优点

    > 跨平台、跨语言

    > 向下兼容性好,易于扩展

    > 自动生成解析代码

    > 序列化后占用空间小

    > 特别方便用于RPC和消息存储的场合


  3. RPC通讯模型和ZeroRpc

       RPC通讯模型:

       一种通过网络从远程计算机程序服务,而不需要了解底层网络技术的协议。

       RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。

        wKioL1ODS3-BqTNBAADqwNKnOPo495.jpg

        ZeroRPC:

            ZeroRPC 是基于zeromq、gevent和msgpack 开发的分布式RPC框架zerorpc-python。这个框架简单、易用。


  4. protobuf 安装和配置

I. 下载源码包
     wget http://protobuf.googlecode.com/files/protobuf-2.3.0.zip  
     
II.安装软件包
     unzip protobuf-2.3.0.zip
     cd protobuf-2.3.0
     ./configure
     make
     make install  
     
III. 编写hostinfo.proto 描述文件
     package hostinfo;
     message HostInfo {
         required string factername = 1;
         optional string hostname = 2;
         optional string serverhardtype = 3;
         optional string servertag = 4;
         optional string servertype = 5;
         optional string gatewayIP = 6;
         optional string serverproduct = 7;
         optional Ram rams = 8;
         repeated cpuinfo cpus = 9;
         
         message cpuinfo {
             optional string cpuCoreNum = 1;
             optional string cpuBit = 2;
             optional string cpuClockSpeed = 3;
             optional string cpupynum = 4;
             optional string cpuName = 5;
             optional string band = 6;
             optional string model = 7;
         }
         
         message Ram {
             repeated memory mem = 1;
         }
         
         message memory {
             optional string Serial_Number = 1;
             optional string Manufacturer = 2;
             optional string Speed = 3;
             optional string Size = 4;
         }
     }
     
VI. 用protoc生成访问代码
  protoc hostinfo.proto --python_out=./         
     
生成访问代码如下(hostinfo_pb2.py):

# Generated by the protocol buffer compiler.  DO NOT EDIT!
from google.protobuf import descriptor
from google.protobuf import message
from google.protobuf import reflection
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)

DESCRIPTOR = descriptor.FileDescriptor(
  name='hostinfo.proto',
  package='info',
  serialized_pb='\n\x0ehostinfo.proto\x12\x04info\"\xd3\x03\n\x08HostInfo\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12\x16\n\x0eserverhardtype\x18\x03 \x01(\t\x12\x11\n\tservertag\x18\x04 \x01(\t\x12\x12\n\nservertype\x18\x05 \x01(\t\x12\x11\n\tgatewayIP\x18\x06 \x01(\t\x12\x15\n\rserverproduct\x18\x07 \x01(\t\x12 \n\x04rams\x18\x08 \x01(\x0b\x32\x12.info.HostInfo.Ram\x12$\n\x04\x63pus\x18\x01 \x03(\x0b\x32\x16.info.HostInfo.cpuinfo\x1a\x84\x01\n\x07\x63puinfo\x12\x12\n\ncpuCoreNum\x18\x01 \x01(\t\x12\x0e\n\x06\x63puBit\x18\x02 \x01(\t\x12\x15\n\rcpuClockSpeed\x18\x03 \x01(\t\x12\x10\n\x08\x63pupynum\x18\x04 \x01(\t\x12\x0f\n\x07\x63puName\x18\x05 \x01(\t\x12\x0c\n\x04\x62\x61nd\x18\x06 \x01(\t\x12\r\n\x05model\x18\x07 \x01(\t\x1a)\n\x03Ram\x12\"\n\x03mem\x18\x01 \x03(\x0b\x32\x15.info.HostInfo.memory\x1aR\n\x06memory\x12\x15\n\rSerial_Number\x18\x01 \x01(\t\x12\x14\n\x0cManufacturer\x18\x02 \x01(\t\x12\r\n\x05Speed\x18\x03 \x01(\t\x12\x0c\n\x04Size\x18\x04 \x01(\t')

_HOSTINFO_CPUINFO = descriptor.Descriptor(
  name='cpuinfo',
  full_name='info.HostInfo.cpuinfo',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    descriptor.FieldDescriptor(
      name='cpuCoreNum', full_name='info.HostInfo.cpuinfo.cpuCoreNum', index=0,
      number=1, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='cpuBit', full_name='info.HostInfo.cpuinfo.cpuBit', index=1,
      number=2, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='cpuClockSpeed', full_name='info.HostInfo.cpuinfo.cpuClockSpeed', index=2,
      number=3, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='cpupynum', full_name='info.HostInfo.cpuinfo.cpupynum', index=3,
      number=4, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='cpuName', full_name='info.HostInfo.cpuinfo.cpuName', index=4,
      number=5, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='band', full_name='info.HostInfo.cpuinfo.band', index=5,
      number=6, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='model', full_name='info.HostInfo.cpuinfo.model', index=6,
      number=7, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  extension_ranges=[],
  serialized_start=233,
  serialized_end=365,
)

_HOSTINFO_RAM = descriptor.Descriptor(
  name='Ram',
  full_name='info.HostInfo.Ram',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    descriptor.FieldDescriptor(
      name='mem', full_name='info.HostInfo.Ram.mem', index=0,
      number=1, type=11, cpp_type=10, label=3,
      has_default_value=False, default_value=[],
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  extension_ranges=[],
  serialized_start=367,
  serialized_end=408,
)

_HOSTINFO_MEMORY = descriptor.Descriptor(
  name='memory',
  full_name='info.HostInfo.memory',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    descriptor.FieldDescriptor(
      name='Serial_Number', full_name='info.HostInfo.memory.Serial_Number', index=0,
      number=1, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='Manufacturer', full_name='info.HostInfo.memory.Manufacturer', index=1,
      number=2, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='Speed', full_name='info.HostInfo.memory.Speed', index=2,
      number=3, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='Size', full_name='info.HostInfo.memory.Size', index=3,
      number=4, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  extension_ranges=[],
  serialized_start=410,
  serialized_end=492,
)

_HOSTINFO = descriptor.Descriptor(
  name='HostInfo',
  full_name='info.HostInfo',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    descriptor.FieldDescriptor(
      name='hostname', full_name='info.HostInfo.hostname', index=0,
      number=2, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='serverhardtype', full_name='info.HostInfo.serverhardtype', index=1,
      number=3, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='servertag', full_name='info.HostInfo.servertag', index=2,
      number=4, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='servertype', full_name='info.HostInfo.servertype', index=3,
      number=5, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='gatewayIP', full_name='info.HostInfo.gatewayIP', index=4,
      number=6, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='serverproduct', full_name='info.HostInfo.serverproduct', index=5,
      number=7, type=9, cpp_type=9, label=1,
      has_default_value=False, default_value=unicode("", "utf-8"),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='rams', full_name='info.HostInfo.rams', index=6,
      number=8, type=11, cpp_type=10, label=1,
      has_default_value=False, default_value=None,
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
    descriptor.FieldDescriptor(
      name='cpus', full_name='info.HostInfo.cpus', index=7,
      number=1, type=11, cpp_type=10, label=3,
      has_default_value=False, default_value=[],
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None),
  ],
  extensions=[
  ],
  nested_types=[_HOSTINFO_CPUINFO, _HOSTINFO_RAM, _HOSTINFO_MEMORY, ],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  extension_ranges=[],
  serialized_start=25,
  serialized_end=492,
)

_HOSTINFO_CPUINFO.containing_type = _HOSTINFO;
_HOSTINFO_RAM.fields_by_name['mem'].message_type = _HOSTINFO_MEMORY
_HOSTINFO_RAM.containing_type = _HOSTINFO;
_HOSTINFO_MEMORY.containing_type = _HOSTINFO;
_HOSTINFO.fields_by_name['rams'].message_type = _HOSTINFO_RAM
_HOSTINFO.fields_by_name['cpus'].message_type = _HOSTINFO_CPUINFO
DESCRIPTOR.message_types_by_name['HostInfo'] = _HOSTINFO

class HostInfo(message.Message):
  __metaclass__ = reflection.GeneratedProtocolMessageType
  
  class cpuinfo(message.Message):
    __metaclass__ = reflection.GeneratedProtocolMessageType
    DESCRIPTOR = _HOSTINFO_CPUINFO
    
    # @@protoc_insertion_point(class_scope:info.HostInfo.cpuinfo)
  
  class Ram(message.Message):
    __metaclass__ = reflection.GeneratedProtocolMessageType
    DESCRIPTOR = _HOSTINFO_RAM
    
    # @@protoc_insertion_point(class_scope:info.HostInfo.Ram)
  
  class memory(message.Message):
    __metaclass__ = reflection.GeneratedProtocolMessageType
    DESCRIPTOR = _HOSTINFO_MEMORY
    
    # @@protoc_insertion_point(class_scope:info.HostInfo.memory)
  DESCRIPTOR = _HOSTINFO
  
  # @@protoc_insertion_point(class_scope:info.HostInfo)

  # @@protoc_insertion_point(module_scope)

V.编写应用代码(RPC client端)

#!/usr/bin/env python

import hostinfo_pb2
import zerorpc
import sys

hostinfo = hostinfo_pb2.HostInfo()

def ServerInfo(hostinfo):
    '''这些信息可以通过脚本进行收集'''
    hostinfo.hostname = 'cdn.oss.david.com'
    hostinfo.serverhardtype = 'IBM System x3550 M2 -[7946I1M]-'
    hostinfo.servertag = '99G0665'
    hostinfo.servertype = 'physical'
    hostinfo.gatewayIP = '113.207.61.1'
    hostinfo.serverproduct = 'IBM'

    cpu = hostinfo.cpus.add()
    cpu.cpuCoreNum = '1'
    cpu.cpuBit = '64'
    cpu.cpuClockSpeed = '2.00GHz'
    cpu.cpupynum = '1'
    cpu.cpuName = 'Intel Xeon'
    cpu.band = 'Intel'
    cpu.model = 'E5504'

    memory = hostinfo.rams.mem.add()
    memory.Serial_Number = '5F787C83'
    memory.Manufacturer = 'Samsung'
    memory.Speed = '800 MHz'
    memory.Size = '4096 MB'

if __name__ == "__main__":
    ServerInfo(hostinfo)
    c = zerorpc.Client()
    c.connect("tcp://127.0.0.1:4242")            #连接RPC 服务端
    print c.info(hostinfo.SerializeToString())    #向服务端发送数据

   
VI. protobuf 基础
    字段约束:
       required:必须赋值字段,禁止为空
       optional:可选字段,可以为空
       repeated:集合,可以填充零到多个对象


5.Zero RPC安装和配置  

I.Zero RPC 安装
  yum -y install zeromq
  yum install gcc gcc-c++ libuuid-devel python-uuid uuid
  wget  http://download.zeromq.org/zeromq-2.1.9.tar.gz   
  ./configure
  make
  make install

II. 安装gevent
   pip install gevent
  
III. 安装zerorpc
   pip install zerorpc

VI. 编写ZeroRPC Server

PRC 服务端:
#!/usr/bin/env python

import zerorpc
import hostinfo_pb2    

class HostRpc(object):
    def info(self, name):
        data = hostinfo_pb2.HostInfo()
        data.ParseFromString(name)
        print data.hostname
        print data.serverhardtype
        print data.servertag
        print data.gatewayIP
        print data.serverproduct
        return 'success'


s = zerorpc.Server(HostRpc())
s.bind("tcp://0.0.0.0:4242")
s.run()

启动RPC Server:

wKiom1ODUw6z4OCcAAA2LjQUQ9k406.jpg

查看RPC 状态:

wKiom1ODU17SziMWAAByH_Hz7OI764.jpg


客户端向服务端传输数据:

客户端:

wKioL1ODVJLAQlGUAAOHQqwAG_o143.jpg

服务端:

wKiom1ODVEvTVBezAAQdhClJt3o866.jpg

    通过以上服务端的输出信息可以看出,客户端可以成功将信息发送至服务端。这只是为测试效果,可以将传输过来的数据通过Mysqldb写入到数据库。