Press "Enter" to skip to content

Yar-2.1 新功能介绍

Yar(Yet Another RPC framework)是一个轻量级支持并行调用的PHP RPC框架,是我还在微博的时候为了优化微博的性能而开发的一个工具,Yar的并行调用在微博被大量应用以降低用户请求耗时。

最近还是因为疫情,我把Yaf,Yaconf都优化了一轮,今天也完成了Yar的优化(事实上,Yar之前写的就还不错,没啥可优化的,哈哈),也新增了俩个能力。我来简单介绍下:

链接持久化

也就是YAR_OPT_PERSISTENT, 这个配置之前一直有,只不过之前是设计为跨请求的持久化,这次做了优化,变成了基于PHP请求生命期的链接保持。

也就是说,当你对一个Yar_Client设置了YAR_OPT_PERSISTEN为true的话,在一次RPC调用结束后,Yar不会销毁这个链接,从而加速后续的针对同样这个Client的RPC调用,我们来看个例子:

<?php
function bench($client) {
    $start = microtime(true);
    $client->header("connection");
    echo microtime(true) - $start, "s\n";
}
$client = new Yar_Client("http://remote_host/index.php");

$client->setOpt(YAR_OPT_PERSISTENT, 1);
bench($client);
bench($client);
bench($client);

输出:

0.090613842010498s
0.045492887496948s
0.045512914657593s

可见,第二次调用的时候,耗时降低了一半,这是因为节省了TCP链接建立的耗时。

最后,链接会在PHP请求结束以后,整体释放,也就是PHP请求生命期的存活,不会垮请求,也不用担心内存泄漏。

不过很遗憾,这个并不能用于加速并行调用:

function callback($retval, $callinfo) {
    global $start;
    if ($callinfo) {
        echo "Num ", $callinfo["sequence"] , " costs: ", microtime(true) - $start, "s\n";
    }
}

Yar_Concurrent_Client::call("http://remote_host/index.php", "header", array("connection"), NULL,  NULL, array(YAR_OPT_PERSISTENT=>1));
$start = microtime(true);
Yar_Concurrent_Client::loop("callback", function($error) { var_dump($error); });
$start = microtime(true);
Yar_Concurrent_Client::loop("callback", function($error) { var_dump($error); });

我们会发现俩次调用没有加速的效果:

Num 1 costs: 0.091023921966553s
Num 1 costs: 0.090677976608276s

这跟Yar底层使用的libcurl有关系,从libcurl的官方文档关于curl_multi_add_handle:

When an easy interface is added to a multi handle, it will use a shared connection cache owned by the multi handle. Removing and adding new easy handles will not affect the pool of connections or the ability to do connection re-use.

也就是说,只要我把一个我们打开的libcurl cp通过curl_multi_add_handle加入到并行队列,这个cp就会使用libcurl multi自己管理的共享连接池,不会受Yar自己管理的persistent与否影响了。而这个共享是指在整个一次libcurl multi的请求过程中的共享,但事实上因为我们一次会发出所有请求,不会存在一个请求完成下一个请求开始的情况,那么也就不会存在复用了。

不过,我后来观察到在某些版本之上的libcurl,比如我测试的7.58.0下,可以看到加速的效果(这个是本机测试,所以看起来速度快很多):

Num 1 costs: 0.0017080307006836s
Num 1 costs: 0.0010600090026855s

后续有时间需要慢慢研究下,从libcurl哪个版本开始的变化。

自定义DNS

这个是来自HuangeChaodian网友的PR,基本上是有的时候,我们需要自定义某个Host的DNS解析结果,比如在测试的时候,把一个Hostname指向本地。

诚然,我们可以使用编辑hosts来达到这个效果, 但如果能在代码中切换,还是会方便不少,看例子:

<?php
$client = new Yar_Client("http://remote_host/index.php");

$client->setOpt(YAR_OPT_RESOLVE, "remote_host:80:127.0.0.1");

这样,Yar就会把remote_host解析为127.0.0.1了, 可以方便我们做一些本地调试。

性能优化

我现在发现,我写的代码随着时间的变化性能提升还是很明显的, 因为Yar写的比较晚, 相对来说可优化的点不多, 于是就简单点做了一些小修补,就不提了,:)

最后,2.1.0 已经发布Yar-2.1.0.

Enjoy!

22 Comments

  1. YY
    YY May 24, 2023

    大佬,这个框架无法执行后续方法吗?
    比如:
    class A{
    function __constract(){
    $server = new \Yar_Server($this);
    $server->handle();
    }
    function a(){
    echo ‘aa’;
    }
    function __destruct(){
    echo ‘该方法不被执行’;
    }
    }

    $a = new A();
    $a->a();

    这里的注销函数不执行吗?

  2. truthbet
    truthbet March 15, 2023

    truthbet Online service providers That answers all needs Excellent 24 hours a day.

  3. dna
    dna March 15, 2023

    so much great information on here, : D.
    dna24bet

  4. phpseven
    phpseven August 16, 2021

    YAR 能否支持TCP直接传递数据。。。

  5. yue zhuo
    yue zhuo April 10, 2021

    老是识别不了我的方法,驼峰命名,蛇形命名都试过,10次要出现4,5次
    这里:spprintf(msg, 0, “%s”, “need specifical request method”);

    • laruence
      laruence April 13, 2021

      可以总结一个重现方法,包括你使用的php的版本,操作系统等信息,贴在github上提个issue

  6. yue zhuo
    yue zhuo April 10, 2021

    请求10次有4-5次报这个错误 need specifical request method ,应该怎么办?

  7. Shane
    Shane December 29, 2020

    支持鸟哥,个人微服务使用了鸟哥的yar rpc框架,但是最近升级php8.0后发现yar框架编译失败了,希望鸟哥帮忙抽空升级下兼容下php8.0. github上也提了一个issue。😃

  8. tomato
    tomato August 5, 2020

    正在使用中,赞赞赞

  9. jre zhang
    jre zhang May 8, 2020

    鸟哥,用了yar很久了, 但是目前就一直有一个困扰的问题像请求解决方法。

    使用yar请求远程服务器,如果响应http code是 200 则正常,如果是其他 比如301,302, 307 之类的,就不能正常跳转,直接抛出异常了。

    • laruence
      laruence May 8, 2020

      那肯定不能跳转啊, 这个是RPC啊, 你自我克服下。

  10. phper-he
    phper-he April 1, 2020

    升级到2.1.2版本 ,报错:curl exec failed ‘Timeout was reached’ 对libcurl版本有要求吗

    • laruence
      laruence April 1, 2020

      你适当增大yar.timeout看看,单位是毫秒, 默认5000

    • heyhey
      heyhey August 8, 2020

      我也遇到了这个问题。。

  11. phper
    phper March 31, 2020

    支持鸟哥

  12. DusNoob
    DusNoob March 20, 2020

    现在项目中就有在用

  13. spark
    spark March 19, 2020

    占鸟哥的坑

Comments are closed.