随着分布式架构运用的越来越多,RPC框架成为了我们不得不掌握的知识,这里一步一步来手写一个简单的RPC框架,以博文作为记录及自我监督。
首先是技术选型,这边我选用的是当前比较流行的Netty+Zookeeper来实现,通过zookeeper的特性来实现服务注册与发现,通信则使用netty框架。
这里贴出github代码地址,想直接看代码的可以直接下载运行:https://github.com/whiteBX/wrpc
这里先来讲服务注册发现原理: 利用zookeeper的创建临时节点和watcher机制,可以做到在一个服务下注册多个服务器地址,并且在节点发生变动时通过watcher动态更新服务器列表,来达到在新增/修改/删除时自动注册发现/删除/更新服务器连接信息.这里说一点,zookeeper的增删改操作会交由leader去处理,所以这里不用担心并发问题.
zookeeper相关代码如下:
public class ZKClient {
/**
* 获取zookeeper连接
*
* @param connectString
* @param sessionTimeout
* @return
*/
public ZooKeeper newConnection(String connectString, int sessionTimeout) {
ZooKeeper zooKeeper = null;
try {
final CountDownLatch countDownLatch = new CountDownLatch(1);
zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
if (Event.KeeperState.SyncConnected.equals(watchedEvent.getState())) {
countDownLatch.countDown();
}
}
});
countDownLatch.await();
} catch (IOException e) {
System.out.println("获取zookeeper连接失败:连接不上zookeeper" + e.getMessage());
} catch (InterruptedException e) {
System.out.println("获取zookeeper连接失败:本地线程原因" + e.getMessage());
}
System.out.println("zookeeper连接成功");
return zooKeeper;
}
/**
* 创建临时节点
*
* @param zk
* @param appCode
* @param data
*/
public void createEphemeralNode(ZooKeeper zk, String appCode, byte[] data) {
try {
initAppPath(zk, appCode);
String path = zk.create(MessageFormat.format("{0}/{1}/", CommonConstant.ZK_REGISTORY_ROOT_PATH, appCode), data,
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("临时节点创建成功:" + path);
} catch (Exception e) {
System.out.println("创建临时节点失败:" + e.getMessage());
}
}
/**
* 初始化appPath
*
* @param zk
* @param appCode
*/
private void initAppPath(ZooKeeper zk, String appCode) {
initRootPath(zk);
try {
if (zk.exists(MessageFormat.format("{0}/{1}", CommonConstant.ZK_REGISTORY_ROOT_PATH, appCode), false) == null) {
zk.create(MessageFormat.format("{0}/{1}", CommonConstant.ZK_REGISTORY_ROOT_PATH, appCode), null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
} catch (Exception e) {
System.out.println("zookeeper创建跟节点失败" + e);
}
}
/**
* 初始化根节点
*
* @param zk
*/
private void initRootPath(ZooKeeper zk) {
try {
if (zk.exists(CommonConstant.ZK_REGISTORY_ROOT_PATH, false) == null) {
zk.create(CommonConstant.ZK_REGISTORY_ROOT_PATH, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
} catch (Exception e) {
System.out.println("zookeeper创建跟节点失败" + e);
}
}
}
接下来看provider相关类,提供服务:
/**
* <p>
* 1.创建ne