V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhoumengkang
V2EX  ›  PHP

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

  •  
  •   zhoumengkang · 2015-12-26 12:19:06 +08:00 · 3779 次点击
    这是一个创建于 3281 天前的主题,其中的信息可能已经有所发展或是发生改变。

    标题党强势注入。

    简介

    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 条回复    2015-12-28 23:34:43 +08:00
    xufang
        1
    xufang  
       2015-12-26 12:37:13 +08:00   ❤️ 1
    http2 普及之后,这些 RPC 都得跪。。。
    xufang
        2
    xufang  
       2015-12-26 12:39:11 +08:00   ❤️ 1
    curl 的 http2 的实现还不成熟,所以一时半会 php-curl 还用不起 http2 ,这是个问题。
    java 的 okhttp 库倒是很成熟的,可惜是在客户端。不过服务端有 nginx 挡在前面,也无所谓。
    est
        3
    est  
       2015-12-26 12:40:44 +08:00
    @xufang http2 跟 rpc 有毛关系。。。。。。。
    xufang
        4
    xufang  
       2015-12-26 12:42:16 +08:00
    @est 。。。 你琢磨一下,在 v2 一般不喜欢长篇大论
    xufang
        5
    xufang  
       2015-12-26 12:43:18 +08:00
    reeco
        6
    reeco  
       2015-12-26 12:43:57 +08:00 via iPhone
    java 的 rpc 好像要成熟很多
    xufang
        7
    xufang  
       2015-12-26 12:46:25 +08:00
    @reeco 是在服务端组件内部通信比较完善,不过现在互联网那个的趋势是块糙猛,所以客户端倒是 java(安卓),服务端 php 这个比较常见
    phoneli
        8
    phoneli  
       2015-12-26 12:56:43 +08:00
    thrift 呢?
    ncisoft
        9
    ncisoft  
       2015-12-26 13:00:21 +08:00 via Android
    实在没看出哪就快如闪电了,,,
    phoneli
        10
    phoneli  
       2015-12-26 13:01:59 +08:00
    @xufang 这里想问下,和 thrift 对比,性能如何?
    xufang
        11
    xufang  
       2015-12-26 13:04:51 +08:00
    @phoneli thift 各个语言的绑定的坑比较多。性能的话,如果基于 http2 选用 protobuf 序列化和 h2c 协议的话,没有差别。

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