大厨小鲜基于 Netty 自己动手实现 RPC 框架 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
codehole
V2EX    程序员

大厨小鲜基于 Netty 自己动手实现 RPC 框架

  •  
  •   codehole
    pyloque 2018-04-16 11:10:28 +08:00 2797 次点击
    这是一个创建于 2803 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天我们要来做一道小菜,这道菜就是 RPC 通讯框架。它使用 netty 作为原料,fastjson 序列化工具作为调料,来实现一个极简的多线程 RPC 服务框架。

    我们暂且命名该 RPC 框架为 rpckids。

    食用指南

    在告诉读者完整的制作菜谱之前,我们先来试试这个小菜怎么个吃法,好不好吃,是不是吃起来很方便。如果读者觉得很难吃,那后面的菜谱就没有多大意义了,何必花心思去学习制作一门谁也不爱吃的大烂菜呢?

    例子中我会使用 rpckids 提供的远程 RPC 服务,用于计算斐波那契数和指数,客户端通过 rpckids 提供的 RPC 客户端向远程服务传送参数,并接受返回结果,然后呈现出来。你可以使用 rpckids 定制任意的业务 rpc 服务。

    斐波那契数输入输出比较简单,一个 Integer,一个 Long。 指数输入有两个值,输出除了计算结果外还包含计算耗时,以纳秒计算。之所以包含耗时,只是为了呈现一个完整的自定义的输入和输出类。

    指数服务自定义输入输出类

    // 指数 RPC 的输入 public class ExpRequest { private int base; private int exp; // constructor & getter & setter } // 指数 RPC 的输出 public class ExpResponse { private long value; private long costInNanos; // constructor & getter & setter } 

    斐波那契和指数计算处理

    public class FibRequestHandler implements IMessageHandler<Integer> { private List<Long> fibs = new ArrayList<>(); { fibs.add(1L); // fib(0) = 1 fibs.add(1L); // fib(1) = 1 } @Override public void handle(ChannelHandlerContext ctx, String requestId, Integer n) { for (int i = fibs.size(); i < n + 1; i++) { long value = fibs.get(i - 2) + fibs.get(i - 1); fibs.add(value); } // 输出响应 ctx.writeAndFlush(new MessageOutput(requestId, "fib_res", fibs.get(n))); } } public class ExpRequestHandler implements IMessageHandler<ExpRequest> { @Override public void handle(ChannelHandlerContext ctx, String requestId, ExpRequest message) { int base = message.getBase(); int exp = message.getExp(); long start = System.nanoTime(); long res = 1; for (int i = 0; i < exp; i++) { res *= base; } long cost = System.nanoTime() - start; // 输出响应 ctx.writeAndFlush(new MessageOutput(requestId, "exp_res", new ExpResponse(res, cost))); } } 

    构建 RPC 服务器

    RPC 服务类要监听指定 IP 端口,设定 io 线程数和业务计算线程数,然后注册斐波那契服务输入类和指数服务输入类,还有相应的计算处理器。

    public class DemoServer { public static void main(String[] args) { RPCServer server = new RPCServer("localhost", 8888, 2, 16); server.service("fib", Integer.class, new FibRequestHandler()) .service("exp", ExpRequest.class, new ExpRequestHandler()); server.start(); } } 

    构建 RPC 客户端

    RPC 客户端要链接远程 IP 端口,并注册服务输出类(RPC 响应类),然后分别调用 20 次斐波那契服务和指数服务,输出结果

    public class DemoClient { private RPCClient client; public DemoClient(RPCClient client) { this.client = client; // 注册服务返回类型 this.client.rpc("fib_res", Long.class).rpc("exp_res", ExpResponse.class); } public long fib(int n) { return (Long) client.send("fib", n); } public ExpResponse exp(int base, int exp) { return (ExpResponse) client.send("exp", new ExpRequest(base, exp)); } public static void main(String[] args) { RPCClient client = new RPCClient("localhost", 8888); DemoClient demo = new DemoClient(client); for (int i = 0; i < 20; i++) { System.out.printf("fib(%d) = %d\n", i, demo.fib(i)); } for (int i = 0; i < 20; i++) { ExpResponse res = demo.exp(2, i); System.out.printf("exp2(%d) = %d cost=%dns\n", i, res.getValue(), res.getCostInNanos()); } } } 

    运行

    先运行服务器,服务器输出如下,从日志中可以看到客户端链接过来了,然后发送了一系列消息,最后关闭链接走了。

    server started @ localhost:8888 connection comes read a message read a message ... connection leaves 

    再运行客户端,可以看到一些列的计算结果都成功完成了输出。

    fib(0) = 1 fib(1) = 1 fib(2) = 2 fib(3) = 3 fib(4) = 5 ... exp2(0) = 1 cost=559ns exp2(1) = 2 cost=495ns exp2(2) = 4 cost=524ns exp2(3) = 8 cost=640ns exp2(4) = 16 cost=711ns ... 

    牢骚

    本以为是小菜一碟,但是编写完整的代码和文章却将近花费了一天的时间,深感写码要比做菜耗时太多了。因为只是为了教学目的,所以在实现细节上还有好多没有仔细去雕琢的地方。如果是要做一个开源项目,力求非常完美的话。至少还要考虑一下几点。

    1. 客户端连接池
    2. 多服务进程负载均衡
    3. 日志输出
    4. 参数校验,异常处理
    5. 客户端流量攻击
    6. 服务器压力极限

    如果要参考 grpc 的话,还得实现流式响应处理。如果还要为了节省网络流量的话,又需要在协议上下功夫。这一大堆的问题还是抛给读者自己思考去吧。

    关注公众号「码洞」,发送「 RPC 」即可获取以上完整菜谱的 GitHub 开源代码链接

    codehole
        1
    codehole  
    OP
       2018-04-16 11:12:04 +08:00
    怕文章太长,看起来难受,后面的菜谱详情略去了,愿意细读的去掘金看看吧

    [大厨小鲜基于 Netty 自己动手实现 RPC 框架]( https://juejin.im/post/5ad2a99ff265da238d51264d)
    关于     帮助文档     自助推广系统     博客   API     FAQ     Solana     5159 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 08:50 PVG 16:50 LAX 00:50 JFK 03:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86