远程过程调用(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
本服务搭载真人检测和人脸比对等生物识别技术,配合权威数据源验证,可快速校验自然人的真实身份。支持PC和移动端H5网页接入。
输入车牌号码或车架号,判定是否属于营运车辆。
根据身份证号码/统一社会信用代码查询名下车辆数量。
根据身份证号码/社会统一信用代码/车架号/车牌号,查询车辆是否有理赔情况。
根据身份证号码/社会统一信用代码/车牌号/车架号,查询车辆的过户次数信息。