在 PHP 使用 Protobuf Buffers 有性能问题

栏目: 服务器 · 发布时间: 6年前

Protocol Buffers 是一种应用广泛的数据交换格式,内部服务间通信时常常用它做为数据传输格式,主要是因为较之 Json 它具有更好的性能(体现在空间占用更少、编解码更快)、数据结构定义更规范。 然而在 PHP 中使用 Protocol Buffers 却是一场灾难。

Protocol Buffers 初始化是很慢的

通过 protoc 编译出来的骨架代码本质上只是将 proto 文件编译成方便解析的中间文件格式,建立 PHP 层对应的类型系统,绝大部分的工作放到了运行时。

参考 php performance problem · Issue #4227 · protocolbuffers/protobuf

使用 XHProf 分析实际的请求,发现 40% 的时间(133 毫秒)花在了初始化上

使用的是 Protocol Buffers 的 PHP 实现,耗时的调用栈如下

 PaymentEvent::__construct 
 – GPBMetadata\Xllivensq::initOnce 
 -— Google\Protobuf\Internal\DescriptorPool::internalAddGeneratedFile 

C 扩展性能是 PHP 实现的 10 倍以上,主要是因为使用 C 扩展后底层对 Protocol Buffers 字节流的编、解码更快了。

Protocol Buffers 的 C 扩展不稳定

线上系统使用中发现内存和 CPU 占用过高。

Protocol Buffers 性能问题对 PHP 应用的影响是巨大的

其它语言(如:Go、C++)程序是常驻内存运行的,初始化 Protocol Buffers 的开销只付出一次,所以往往意识不到这个问题。

PHP 采用 FastCGI 模型,每次请求都要承担 Protocol Buffers 的开销,很快就会发现采用 Protocol Buffers 后接口响应时间变长,系统的吞吐率下降。

PHP 实现与 C 扩展的性能对比

  • Protocol Buffers C 扩展的安装

    sudo pecl install protobuf-3.7.0
  • Protocol Buffers C 扩展的启用与禁用

    php.ini 加入以下配置项启用 C 扩展

    extension=protobuf.so

    注释掉上面的配置项禁用 C 扩展。

  • 创建性能测试 PHP 项目

    进入项目目录

    创建 composer.json 文件,内容如下

    {
        "require": {
            "google/protobuf": "3.7.0"
        }
    }

    创建 index.php 文件,内容如下

    <?php
    $startTime = microtime(true);
    
    require __DIR__ . '/vendor/autoload.php';
    require __DIR__ . '/generated/GPBMetadata/Addressbook.php';
    require __DIR__ . '/generated/Tutorial/AddressBook.php';
    require __DIR__ . '/generated/Tutorial/Person.php';
    require __DIR__ . '/generated/Tutorial/Person/PhoneType.php';
    require __DIR__ . '/generated/Tutorial/Person/PhoneNumber.php';
    
    $addressBook = new Tutorial\AddressBook();
    
    $person = new Tutorial\Person();
    $person->setId(1);
    $person->setName("user1");
    $person->setEmail("[email protected]");
    $phone = new Tutorial\Person\PhoneNumber();
    $phone->setType(Tutorial\Person\PhoneType::HOME);
    $phone->setNumber("1000001");
    $person->getPhones()[] = $phone;
    $addressBook->getPeople()[] = $person;
    
    $person = new Tutorial\Person();
    $person->setId(2);
    $person->setName("user2");
    $person->setEmail("[email protected]");
    $phone = new Tutorial\Person\PhoneNumber();
    $phone->setType(Tutorial\Person\PhoneType::HOME);
    $phone->setNumber("2000002");
    $person->getPhones()[] = $phone;
    $addressBook->getPeople()[] = $person;
    
    $person = new Tutorial\Person();
    $person->setId(3);
    $person->setName("user3");
    $person->setEmail("[email protected]");
    $phone = new Tutorial\Person\PhoneNumber();
    $phone->setType(Tutorial\Person\PhoneType::HOME);
    $phone->setNumber("3000003");
    $person->getPhones()[] = $phone;
    $addressBook->getPeople()[] = $person;
    
    $data = $addressBook->serializeToString();
    
    $endTime = microtime(true);
    $runTime = ($endTime-$startTime)*1000 . ' ms';
    
    $class = new ReflectionClass('Google\Protobuf\Internal\DescriptorPool');
    if ($class->getFileName()) {
        echo "protobuf-php $runTime\n";
    } else {
        echo "protobuf-c   $runTime\n";
    }

    创建 Makefile 内容如下

    all: install generate benchmark
    
    install: vendor
    
    vendor: composer.json
        composer install
    
    generate: generated/GPBMetadata
    
    generated/GPBMetadata: addressbook.proto
        -mkdir generated
        protoc --php_out=generated addressbook.proto
    
    benchmark:
        php index.php | tee -a ./benchmark.log
    
    addressbook.proto:
        wget https://raw.githubusercontent.com/protocolbuffers/protobuf/master/examples/addressbook.proto -O ${CURDIR}/addressbook.proto
    
    clean:
        -rm -rf ${CURDIR}/vendor ${CURDIR}/generated
  • 运行性能测试

    make

    交替启用禁用 C 扩展的运行结果

    protobuf-c   2.335 ms
    protobuf-php 29.14 ms
    protobuf-c   2.443 ms
    protobuf-php 27.962 ms
    protobuf-c   2.238 ms
    protobuf-php 14.957 ms
    protobuf-c   2.221 ms
    protobuf-php 29.814 ms
    protobuf-c   2.295 ms
    protobuf-php 29.304 ms
    protobuf-c   2.435 ms
    protobuf-php 37.493 ms

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning PHP, MySQL, and JavaScript

Learning PHP, MySQL, and JavaScript

Robin Nixon / O'Reilly Media / 2009-7-21 / USD 39.99

Learn how to create responsive, data-driven websites with PHP, MySQL, and JavaScript - whether or not you know how to program. This simple, streamlined guide explains how the powerful combination of P......一起来看看 《Learning PHP, MySQL, and JavaScript》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具