200行代码实现RPC框架
之前因为项目需要,基于zookeeper和thrift协议实现了一个简单易用的RPC框架,核心代码不超过200行。
zookeeper主要作用是服务发现,thrift协议作为通信传输协议, 基于commons pool2构建连接池。
大家感兴趣的话可以参考,具体代码如下:
/**
* @author zhangkai
* 抽象的thrift client,内置socket连接池以及线程池,提供同步阻塞式调用和超时调用
* 具体thrift client需要继承该类并实现其中的抽象方法并按照需要重写相关方法
*/
public abstract class AbstractThriftClient {
private final static int MAX_FRAME_SIZE = 1024 * 1024 * 1024;
private final static int MIN_FRAME_SIZE = 1024; protected ThreadPoolExecutor executor;
protected AbstractThriftClient client = this;
protected ClientConfig clientConfig;
protected CuratorFramework zkClient;
protected List<TConnectionPool> shardInfos = Lists.newArrayList(); /**
* AbstractThriftClient的构造函数
* 初始化线程池、连接池以及服务发现机制
*/
protected AbstractThriftClient(ClientConfig clientConfig) {
int processors = Runtime.getRuntime().availableProcessors();
this.executor = new ThreadPoolExecutor(processors * 5, processors * 10, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(processors * 100),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
this.clientConfig = clientConfig;
this.zkClient = CuratorFrameworkFactory.builder()
.connectString(clientConfig.getZkAddrs())
.retryPolicy(new ExponentialBackoffRetry(500, 4)).build();
this.zkClient.start();
buildConnPool();
} /**
* 唯一需要上层实现的抽象类
* 该方法接收封装好的RPCRequest
* 调用真实的RPC请求
* 将RPC服务返回的结果打包成RPCResponse
* 上层的具体thrift client实例需要实现该方法
*/
protected abstract RPCResponse doService(RPCRequest rpcRequest, TProtocol protocol) throws Exception; /**
* 从连接池中选择连接的方法,
* 上层可以重写该方法,实现自己的hash规则
*/
protected int hashRule(RPCRequest request){
Random rand = new Random();
return rand.nextInt(shardInfos.size());
} /**
* processRequest方法处理流程:
* 1、从连接池中获取连接
* 2、创建相应的Transport协议结构
* 3、调用doService方法获取RPC的返回结果
* @param rpcRequest
* @return
*/
protected RPCResponse processRequest(RPCRequest rpcRequest){
String serviceName = rpcRequest.getServiceName();
RPCResponse response = new RPCResponse();
if(serviceName == null){
LogUtils.warn("serviceName can not be null");
response.setCode(RPCResponse.FAILED);
return response;
}
TConnectionPool connPool = getConnPool(rpcRequest);
if(connPool == null){
response.setCode(RPCResponse.FAILED);
return response;
}
TSocket socket = connPool.getSocket();
try {
TTransport transport = new TFastFramedTransport(socket, MIN_FRAME_SIZE, MAX_FRAME_SIZE);
if (!transport.isOpen()) {
transport.open();
}
TProtocol protocol = new TBinaryProtocol(transport);
return this.doService(rpcRequest, protocol);
} catch (Exception e) {
LogUtils.error("", e);
connPool.removeSocket(socket);
response.setCode(RPCResponse.FAILED);
return response;
} finally {
if (socket.isOpen()) {
connPool.returnSocket(socket);
}
}
} protected RPCResponse sendRequest(RPCRequest request){
if(clientConfig.getRequestTimeout() <= 0){
return this.processRequest(request);
}else{
return this.processRequestTimeout(request, clientConfig.getRequestTimeout());
}
} private TConnectionPool getConnPool(RPCRequest request){
if(shardInfos.size() <= 0){
LogUtils.warn("no valid node available");
return null;
}
int index = hashRule(request);
return shardInfos.get(index % shardInfos.size());
} private RPCResponse processRequestTimeout(RPCRequest request, int timeout){
RPCRequestTask rpcRequestTask = new RPCRequestTask(request);
Future<RPCResponse> future = executor.submit(rpcRequestTask); try {
RPCResponse response = future.get(clientConfig.getRequestTimeout(), TimeUnit.MILLISECONDS);
return response;
} catch (InterruptedException e) {
LogUtils.warn("[ExecutorService]The current thread was interrupted while waiting: ", e);
RPCResponse response = new RPCResponse();
response.setCode(RPCResponse.FAILED);
return response;
} catch (ExecutionException e) {
LogUtils.warn("[ExecutorService]The computation threw an exception: ", e);
RPCResponse response = new RPCResponse();
response.setCode(RPCResponse.FAILED);
return response;
} catch (TimeoutException e) {
LogUtils.warn("[ExecutorService]The wait " + this.clientConfig.getRequestTimeout() + " timed out: ", e);
RPCResponse response = new RPCResponse();
response.setCode(RPCResponse.FAILED);
return response;
} catch(Exception e){
LogUtils.warn("[ExecutorService] failed", e);
RPCResponse response = new RPCResponse();
response.setCode(RPCResponse.FAILED);
return response;
}
} private class RPCRequestTask implements Callable<RPCResponse> {
private RPCRequest rpcRequest; public RPCRequestTask(RPCRequest request) {
this.rpcRequest = request;
} @Override
public RPCResponse call() {
return client.processRequest(rpcRequest);
}
}; private void buildConnPool(){
try{
List<String> nodes = zkClient
.getChildren()
.usingWatcher(new Watcher(){
@Override
public void process(WatchedEvent event) {
if(event.getType() == EventType.NodeChildrenChanged){
buildConnPool();
}
}})
.forPath(clientConfig.getZkNamespace());
List<TConnectionPool> currShardInfos = Lists.newArrayList();
for(String node : nodes){
String path = clientConfig.getZkNamespace() + "/" + node;
byte[] dataArray = zkClient.getData().forPath(path);
String dataStr = new String(dataArray);
RegistryInfo info = JsonUtils.fromJson(dataStr, RegistryInfo.class);
TServerInfo server = new TServerInfo(info.getIp(), info.getPort());
currShardInfos.add(new TConnectionPool(server));
}
this.shardInfos = currShardInfos;
}catch(Exception e){
LogUtils.error("build conn pool failed", e);
}
}
}
完整的代码和demo可以参考:https://github.com/zhangkai253/simpleRPC
200行代码实现RPC框架的更多相关文章
- 200行代码,7个对象——让你了解ASP.NET Core框架的本质
原文:200行代码,7个对象--让你了解ASP.NET Core框架的本质 2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘&g ...
- 200 行代码实现基于 Paxos 的 KV 存储
前言 写完[paxos 的直观解释]之后,网友都说疗效甚好,但是也会对这篇教程中一些环节提出疑问(有疑问说明真的看懂了 ),例如怎么把只能确定一个值的 paxos 应用到实际场景中. 既然 Talk ...
- 不到 200 行代码,教你如何用 Keras 搭建生成对抗网络(GAN)【转】
本文转载自:https://www.leiphone.com/news/201703/Y5vnDSV9uIJIQzQm.html 生成对抗网络(Generative Adversarial Netwo ...
- 200行代码实现Mini ASP.NET Core
前言 在学习ASP.NET Core源码过程中,偶然看见蒋金楠老师的ASP.NET Core框架揭秘,不到200行代码实现了ASP.NET Core Mini框架,针对框架本质进行了讲解,受益匪浅,本 ...
- 200行代码实现简版react🔥
200行代码实现简版react
- SpringBoot,用200行代码完成一个一二级分布式缓存
缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂.早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快. 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存 ...
- 200行代码,7个对象——让你了解ASP.NET Core框架的本质
2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘>的分享.在此次分享中,我按照ASP.NET Core自身的运行原理和设计 ...
- 200行代码,7个对象——让你了解ASP.NET Core框架的本质[3.x版]
2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘>的分享.在此次分享中,我按照ASP.NET Core自身的运行原理和设计 ...
- JavaScript开发区块链只需200行代码
用JavaScript开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...
随机推荐
- 关于InfiniBand几个基本知识点解释
文章出处: https://blog.csdn.net/BtB5e6Nsu1g511Eg5XEg/article/details/83629279 公众号 https://blog.csdn.net/ ...
- Vue.js 相关知识(路由)
1. 简介 路由,工作原理与路由器相似(路由器将网线总线的IP分发到每一台设备上),Vue中的路由根据用户在网页中的点击,将其引导到对应的页面. 2. 使用步骤 安装vue-router或者直接引入v ...
- 第十八次ScrumMeeting博客
第十八次ScrumMeeting博客 本次会议于12月8日(五)22时整在3公寓725房间召开,持续20分钟. 与会人员:刘畅.辛德泰.张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容和 ...
- node 随便升级到最新版本的遭遇
将node 升级到最新版本后,创建一个RN新项目,执行:react-native init AwesomeProject 遇到: error An unexpected error occurred ...
- PAT甲题题解-1046. Shortest Distance (20)-做了一个假的最短路,水
一开始以为是最短路,结果是给你一个环,让你求环上两点之间的距离...那还做毛线 然而还是得做毛线 #include <iostream> #include <cstdio> # ...
- 猎豹CEO傅盛:95%的人碌碌无为,只是不懂这一点!
我一直在思索,怎么才能让一家公司更快地成长?一个人怎么才能从一群人的竞争当中脱颖而出? 1. 人的四种认知状态 最近我看了一幅图,我在其上加了一个数字注脚. 这是一个人认知的四种状态——“不知道自 ...
- Final发布 视频展示
1.视频链接 视频地址:http://v.youku.com/v_show/id_XMzk1OTYyNjE0NA==.html?spm=a2hzp.8244740.0.0 杨老师粉丝群——弹球学成语项 ...
- 《Linux内核分析》 第五节 扒开系统调用的三层皮(下)
<Linux内核分析> 第五节 扒开系统调用的三层皮(下) 20135307 一.给MenusOS增加time和time-asm命令 给MenuOS增加time和time-asm命令需要 ...
- 04-java学习-选择结构
if if else 多重if switch
- Adobe X沙箱
一.Adobe X沙箱简介 Adobe Reader X自从引入沙箱以来,对其攻击的难度就提高了很多.Reader X的沙箱是基于Google的Chrome沙箱,Chrome是开源的,Reader X ...