远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。RPC的主要目标是让构建分布式应用更加容易,在提供强大的远程调用能力的同时不损失本地调用的语义的简洁性。
趁实习前的这段业余时间,我实现了一个轻量级的分布式RPC框架,名字叫做 buddha,代码量不大,但是麻雀虽小却五脏俱全。本篇文章将一步步阐明buddha的设计、框架组件的拆解以及需要考虑的因素。
在网络中,所有的数据都将会被转化为字节进行传送,所以在代码层面上,一个RPC框架需要实现特定格式的数据与字节数组之间的相互转化。像Java已经提供了默认的序列化方式,但是如果是在高并发的场景下,使用Java原生的序列化方式可能会遇到性能瓶颈。于是,出现了许多开源的、高效的序列化框架:如Kryo、fastjson和Protobuf等。buddha目前支持Kryo和fastjson两种序列化框架。
由于TCP只关心字节流,并不知晓上层的数据格式。如果客户端应用层一次要发送的数据过大时,TCP会将该数据进行分解传送,因此在服务端需要进行粘包处理(由TCP来保证数据的有序性);如果客户端一次要发送的数据量很小时,TCP并不会马上把数据发送出去,而是将其存储在缓冲区,当达到某个阈值的时候再发送出去,因此在服务端需要进行拆包的工作。
通过以上分析,我们了解了TCP粘包或者拆包的原因,解决这个问题的关键在于向数据包添加边界信息,常用的方法有如下三个。
buddha采用第一种方式来解决TCP拆包、粘包的问题。
BIO往往用于经典的每连接每线程模型,之所以使用多线程,是因为像accept()、read()和write()等函数都是同步阻塞的,这意味着当应用为单线程且进行IO操作时,如果线程阻塞那么该应用必然会进入挂死状态,但是实际上此时CPU是处于空闲状态的。开启多线程,就可以让CPU去为更多的线程服务,提高CPU的利用率。但是在活跃线程数较多的情况下,采用多线程模型回带来如下几个问题。
使用线程池的方式解决前两个问题,但是线程切换带来的开销还是存在。所以在高并发的场景下,传统的BIO是无能为力的。而NIO的重要特点是:读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,可以立即返回,这就允许我们不使用多线程充分利用CPU。如果一个连接不能读写,可以把这个事件记录下来,然后切换到别的就绪的连接进行数据读写。在buddha中,Netty被用来编写结构更加清晰的NIO程序。
在实际应用中,RPC服务的提供者往往需要使用集群来保证服务的稳定性与可靠性。因此需要实现一个服务注册中心,服务提供者将当前可用的服务地址信息注册至注册中心,而客户端在进行远程调用时,先通过服务注册中心获取当前可用的服务列表,然后获取具体的服务提供者的地址信息(该阶段可以进行负载均衡),根据地址信息向服务提供者发起调用。客户端可以缓存可用服务列表,当注册中心的服务列表发生变更时需要通知客户端。同时,当服务提供者变为不可用状态时也需要通知注册中心服务不可用。buddha使用ZooKeeper实现服务注册与发现功能。
buddha是我学习验证RPC过程中诞生的一个轻量级分布式RPC框架,代码放在了 GitHub。
原文来自:tinylcy
声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com
支持全球约2.4万个城市地区天气查询,如:天气实况、逐日天气预报、24小时历史天气等
支持识别各类商场、超市及药店的购物小票,包括店名、单号、总金额、消费时间、明细商品名称、单价、数量、金额等信息,可用于商品售卖信息统计、购物中心用户积分兑换及企业内部报销等场景
涉农贷款地址识别,支持对私和对公两种方式。输入地址的行政区划越完整,识别准确度越高。
根据给定的手机号、姓名、身份证、人像图片核验是否一致
通过企业关键词查询企业涉讼详情,如裁判文书、开庭公告、执行公告、失信公告、案件流程等等。