刚接触数据库就有一直思考一个问题:要是数据量巨大对于数据的存储以及解读有没有什么神器可以助我一臂之力。长大后知道了,原来google家有一开源神器叫protobuf。刚知道的时候俺还是属于懵逼状态。这是啥?有什么好处?要怎么安装?要怎么用?,这篇文章主要就回答这几个问题。
基于自己也是查过很多的资料,大多资料都是copy来copy去,无可奈何,只好自己动手总结一下。
protobuf是什么,怎么来的?
简单的说就是干和xml一样的事,把某种数据结构的信息,以某种格式保存起来。主要用于数据存储、传输协议格式等场合。
专业的解答:
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
有同学就问了,那不是已经有xml了还造轮子搞个protobuf干啥?。
根本原因还是:xml性能不好啊。
1.时间维度:xml格式化(序列化)的开销倒还好;但是XML解析(反序列化)的开销就呵呵了。
2.空间维度:XML格式为了有较好的可读性,引入了一些冗余的文本信息,所以空间开销也不是太好。
这对于大牛众多的google不能忍啊。必须搞一个不管是性能还是都优于xml的。
protobuf有什么好处?
1.对于数据结构的序列化反序列化等性能均优于xml
2.代码生成机制,使用起来十分方便(后续会提到)
3.明星项目有使用:据了解 google、新浪、美拍等均有使用protobuf,所以搬到项目使用肯定不会错。
protobuf如何安装?
安装protobuf
protobuf
wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
可以看到就是如下的安装过程:
su root
wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz
tar zxvf protobuf-2.6.1.tar.gz
cd protobuf-2.6.1/
./configure --prefix=/usr/local/protobuf
make && make install
export PATH=/usr/local/protobuf/bin:$PATH
protoc --version
接下来安装php的protobuf扩展:
sudo vim /etc/php/7.2/mods-available/protobuf.ini添加extension=protobuf.so
重启php
可以看到一件安装成功!
接着进入安装依赖:
建立cbstest.proto文件:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
optional double money = 4;
}
执行php ./protoc-gen-php.php cbstest.proto命令:
可以看到目录下面生成Person.php文件
<?php
/**
* Auto generated from cbstest.proto at 2021-03-05 04:02:43
*/
namespace {
/**
* Person message
*/
class Person extends \ProtobufMessage
{
/* Field index constants */
const NAME = 1;
const ID = 2;
const EMAIL = 3;
const MONEY = 4;
/* @var array Field descriptors */
protected static $fields = array(
self::NAME => array(
'name' => 'name',
'required' => true,
'type' => \ProtobufMessage::PB_TYPE_STRING,
),
self::ID => array(
'name' => 'id',
'required' => true,
'type' => \ProtobufMessage::PB_TYPE_INT,
),
self::EMAIL => array(
'name' => 'email',
'required' => false,
'type' => \ProtobufMessage::PB_TYPE_STRING,
),
self::MONEY => array(
'name' => 'money',
'required' => false,
'type' => \ProtobufMessage::PB_TYPE_DOUBLE,
),
);
/**
* Constructs new message container and clears its internal state
*/
public function __construct()
{
$this->reset();
}
/**
* Clears message values and sets default ones
*
* @return null
*/
public function reset()
{
$this->values[self::NAME] = null;
$this->values[self::ID] = null;
$this->values[self::EMAIL] = null;
$this->values[self::MONEY] = null;
}
/**
* Returns field descriptors
*
* @return array
*/
public function fields()
{
return self::$fields;
}
/**
* Sets value of 'name' property
*
* @param string $value Property value
*
* @return null
*/
public function setName($value)
{
return $this->set(self::NAME, $value);
}
/**
* Returns value of 'name' property
*
* @return string
*/
public function getName()
{
$value = $this->get(self::NAME);
return $value === null ? (string)$value : $value;
}
/**
* Returns true if 'name' property is set, false otherwise
*
* @return boolean
*/
public function hasName()
{
return $this->get(self::NAME) !== null;
}
/**
* Sets value of 'id' property
*
* @param integer $value Property value
*
* @return null
*/
public function setId($value)
{
return $this->set(self::ID, $value);
}
/**
* Returns value of 'id' property
*
* @return integer
*/
public function getId()
{
$value = $this->get(self::ID);
return $value === null ? (integer)$value : $value;
}
/**
* Returns true if 'id' property is set, false otherwise
*
* @return boolean
*/
public function hasId()
{
return $this->get(self::ID) !== null;
}
/**
* Sets value of 'email' property
*
* @param string $value Property value
*
* @return null
*/
public function setEmail($value)
{
return $this->set(self::EMAIL, $value);
}
/**
* Returns value of 'email' property
*
* @return string
*/
public function getEmail()
{
$value = $this->get(self::EMAIL);
return $value === null ? (string)$value : $value;
}
/**
* Returns true if 'email' property is set, false otherwise
*
* @return boolean
*/
public function hasEmail()
{
return $this->get(self::EMAIL) !== null;
}
/**
* Sets value of 'money' property
*
* @param double $value Property value
*
* @return null
*/
public function setMoney($value)
{
return $this->set(self::MONEY, $value);
}
/**
* Returns value of 'money' property
*
* @return double
*/
public function getMoney()
{
$value = $this->get(self::MONEY);
return $value === null ? (double)$value : $value;
}
/**
* Returns true if 'money' property is set, false otherwise
*
* @return boolean
*/
public function hasMoney()
{
return $this->get(self::MONEY) !== null;
}
}
}
接着我们写个测试文件:test.php:
保存后,我们运行一下:
可以看到序列化之后,获取的每个值了。这样可以方便在rpc中使用!
顺便安装一下grpc
sudo pecl install grpc
一直编译,等到结束,会看到:
这个时候把grpc.so添加到php.ini中,重启php
可以看到扩展生成了!
后面我们在讲grpc的使用
gmp数学函数,在使用的时候许要 安装gmp扩展:
sudo apt-get install php7.2-gmp
安装完重新启动
后面使用grpc做区块链时会使用到gmp数学函数