V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
zhoumengkang
V2EX  ›  PHP

快如闪电的并行化 RPC 框架 —— Yar 的 Java Client。完美继承 Yar 的优点:快如闪电;轻如鸿毛(依旧轻量级);支持并行化调用。

  •  
  •   zhoumengkang · Dec 26, 2015 · 4408 views
    This topic created in 3785 days ago, the information mentioned may be changed or developed.

    标题党强势注入。

    简介

    Yar 是一个轻量级, 高效的 RPC 框架, 它提供了一种简单方法来让 PHP 项目之间可以互相远程调用对方的本地方法. 并且 Yar 也提供了并行调用的能力. 可以支持同时调用多个远程服务的方法.

    Yar 鸟哥博客介绍 http://www.laruence.com/2012/09/15/2779.html

    Yar 鸟哥原始项目 https://github.com/laruence/yar

    Yar Java Client 则实现了跨语言的远程调用。使得 Java 客户端能够调用 Yar PHP 服务器端本地的方法。

    Github: https://github.com/zhoumengkang/yar-java-client

    特性

    1. 执行速度快,依旧保持鸟哥初衷,框架轻,使用简单
    2. 支持并行的 RPC 调用
    3. 方法的使用和参数的和 PHP 版本保持一致

    范例

    PHP 服务器端提供了服务

    两个 rpc api ,模拟的业务场景是点赞赠送金币和发布帖子赠送金币。

    <?php
    
    class RewardScoreService {
        /**
         * $uid 给 $fid 点赞
         * @param $fid  interge
         * @param $uid  interge
         * @return void
         */
        public function support($uid,$fid){
            return "support:uid:$uid:fid:$fid";
        }
    
        /**
         * $uid 发布了帖子 $fid 
         * @param $fid  interge
         * @param $uid  interge
         * @return void
         */
        public function post($uid,$fid){
            return "post:uid:$uid:fid:$fid";
        }
    }
    
    $yar_server = new Yar_server(new RewardScoreService());
    $yar_server->handle();
    

    Java 客户端同步调用这两个服务

    public class YarClientTest extends TestCase {
        /**
         * 定义 rpc 接口
         */
        public interface RewardScoreService{
            String support(int uid,int fid);
            String post(int uid,int fid);
        }
    
        /**
         * rpc api 地址
         */
        static String uri = "http://mengkang.net/demo/yar-server/RewardScoreService.php";
    
        public void testUserService(){
            // 第一种调用方式
            YarClient yarClient  = new YarClient(uri);
            RewardScoreService rewardScoreService = (RewardScoreService) yarClient.useService(RewardScoreService.class);
            for (int i = 0; i < 10; i++) {
                System.out.println(rewardScoreService.support(1, 2));
            }
            // 第二种调用方式
            YarClientOptions yarClientOptions = new YarClientOptions();
            yarClientOptions.setConnect_timeout(2000);
            YarClient yarClient2  = new YarClient(uri,yarClientOptions);
            RewardScoreService rewardScoreService2 = (RewardScoreService) yarClient2.useService(RewardScoreService.class);
            for (int i = 0; i < 10; i++) {
                System.out.println(rewardScoreService2.post(1, 20));
            }
        }
    
    }
    

    考虑到 Java 和 PHP 的数据类型的不同,这里做了一个折中的处理,返回数据类型客户端框架统一以 Object 类型接受,然后使用时再根据接口定义的数据类型进行转换。

    Java 客户端并行调用这两个服务

    这里的方法的命令皆以 Yar 原版为准则。
    YarConcurrentClient.call方法注册,
    YarConcurrentClient.loop并行调用,
    YarConcurrentClient.reset清空任务。
    回调函数需要继承实现YarConcurrentCallback里面定义了两个方法:async是针对并行调用发出之后立即执行的任务,而success则是每个请求之后返回的结果。

    public class YarConcurrentClientTest extends TestCase {
    
        /**
         * rpc api 地址
         */
        static String uri = "http://mengkang.net/demo/yar-server/RewardScoreService.php";
    
        public class callback extends YarConcurrentCallback {
    
            public void async() {
                System.out.println("现在, 所有的请求都发出去了, 还没有任何请求返回");
            }
    
            public Object success() {
                return retValue;
            }
    
        }
    
        public class errorCallback extends YarConcurrentErrorCallback {
            @Override
            void error() {
                System.out.println("出错了");
            }
        }
    
        public void testLoop() throws Exception {
    
            String packagerName = YarConfig.getString("yar.packager");
            YarClientOptions yarClientOptions = new YarClientOptions();
            yarClientOptions.setConnect_timeout(2000);
    
            for (int i = 0; i < 10; i++) {
                // 第一种调用方式
                YarConcurrentClient.call(new YarConcurrentTask(uri, "support", new Object[]{1, 2}, packagerName, new callback()));
                // 第二种调用方式 增加一些额外配置选项
                YarConcurrentClient.call(new YarConcurrentTask(uri, "support", new Object[]{1, 2}, packagerName, new callback(),yarClientOptions));
            }
    
            for (int i = 0; i < 10; i++) {
                // 第三种调用方式 有正确的回调和错误的回调
                YarConcurrentClient.call(new YarConcurrentTask(uri,"post",new Object[]{1,2},packagerName,new callback(),new errorCallback()));
                // 第四种调用方式 在第三种的基础上增加额外的配置选项
                YarConcurrentClient.call(new YarConcurrentTask(uri,"post",new Object[]{1,2},packagerName,new callback(),new errorCallback(),yarClientOptions));
            }
    
            YarConcurrentClient.loop(new callback());
            YarConcurrentClient.reset();
        }
    }
    
    18 replies    2015-12-28 23:34:43 +08:00
    xufang
        1
    xufang  
       Dec 26, 2015   ❤️ 1
    http2 普及之后,这些 RPC 都得跪。。。
    xufang
        2
    xufang  
       Dec 26, 2015   ❤️ 1
    curl 的 http2 的实现还不成熟,所以一时半会 php-curl 还用不起 http2 ,这是个问题。
    java 的 okhttp 库倒是很成熟的,可惜是在客户端。不过服务端有 nginx 挡在前面,也无所谓。
    est
        3
    est  
       Dec 26, 2015
    @xufang http2 跟 rpc 有毛关系。。。。。。。
    xufang
        4
    xufang  
       Dec 26, 2015
    @est 。。。 你琢磨一下,在 v2 一般不喜欢长篇大论
    xufang
        5
    xufang  
       Dec 26, 2015
    reeco
        6
    reeco  
       Dec 26, 2015 via iPhone
    java 的 rpc 好像要成熟很多
    xufang
        7
    xufang  
       Dec 26, 2015
    @reeco 是在服务端组件内部通信比较完善,不过现在互联网那个的趋势是块糙猛,所以客户端倒是 java(安卓),服务端 php 这个比较常见
    phoneli
        8
    phoneli  
       Dec 26, 2015
    thrift 呢?
    ncisoft
        9
    ncisoft  
       Dec 26, 2015 via Android
    实在没看出哪就快如闪电了,,,
    phoneli
        10
    phoneli  
       Dec 26, 2015
    @xufang 这里想问下,和 thrift 对比,性能如何?
    xufang
        11
    xufang  
       Dec 26, 2015
    @phoneli thift 各个语言的绑定的坑比较多。性能的话,如果基于 http2 选用 protobuf 序列化和 h2c 协议的话,没有差别。

    不过 http2 用起来都是简单,外部接口一般就是 jsonrpc over http2 了。内部组件的才会用上面这种方式。
    phoneli
        12
    phoneli  
       Dec 26, 2015
    @xufang
    “各个语言的绑定”,这里是指生成多种语言的 gen-xxx 代码,它们混合互相调用有很多坑?
    xufang
        13
    xufang  
       Dec 26, 2015
    @phoneli 恩。封装太重,出了问题要调试一番才知道问题在哪。而 http2 最大的优势是保持了 http 语义的不便,使用起来傻瓜话,不会出现所谓的“误用”。
    zonghua
        14
    zonghua  
       Dec 26, 2015 via iPhone
    微博用的是这个吗?微博可是越来越慢了。
    zhoumengkang
        15
    zhoumengkang  
    OP
       Dec 26, 2015
    @xufang 说得很对。都得学习!
    zhoumengkang
        16
    zhoumengkang  
    OP
       Dec 26, 2015
    @ncisoft 标题党,把拉进来看看。。不好意思哈。
    mengzhuo
        17
    mengzhuo  
       Dec 27, 2015 via iPhone
    rpc 的性能消耗最大在于序列化
    真要拼速度的话 我想没人能干的过 capno
    zhoumengkang
        18
    zhoumengkang  
    OP
       Dec 28, 2015
    @mengzhuo 好,谢谢,回头看看,好多高人呀!
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1374 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 100ms · UTC 23:55 · PVG 07:55 · LAX 16:55 · JFK 19:55
    ♥ Do have faith in what you're doing.