轻量级RPC设计与实现第二版
在上一个版本中利用netty实现了简单的一对一的RPC,需要手动设置服务地址,限制性较大。
在本文中,利用zookeeper作为服务注册中心,在服务端启动时将本地的服务信息注册到zookeeper中,当客户端发起远程服务调用时,先从zookeeper中获取该服务的地址,然后根据获得的这个地址来利用netty进行网络传送。
在服务端和注册中心之间需要建立监听,当服务信息发生变化或网络连接等问题时需要对注册中心的服务信息进行修改。在本文中创建了服务注册监控中心,利用心跳机制来判断与服务端是否有较稳定的连接,当出现网络不稳定时,则从注册中心中删除属于该服务端的服务信息。在本项目中设定在5分钟内3次以上没有发送心跳包为不稳定状态。
关于心跳机制,之前有一篇文章介绍过:Dubbo心跳机制
zookeeper注册中心
zookeeper是hadoop中的一个重要组件,其主要是作为分布式协调服务
zookeeper采用节点树的数据模型,类似linux文件系统。
每个节点称做一个ZNode,每个ZNode都可以通过路径唯一标识,同时每个节点还可以存储少量数据。
本项目借鉴dubbo的注册中心模型来设计本文的注册中心。
总体上设计了四级节点,在一个节点是一个持久节点/register,表示是记录注册服务的区域。二级节点是服务接口名,三级节点是远程服务ip地址,该节点是临时节点,节点存储的数据是具体的实现类名。

在客户端会根据服务接口名在注册中心进行查找,得到远程服务ip地址,并根据节点中存储的具体实现类名进行反射。
首先进行zookeeper初始化,利用了CuratorFramework有关类
private static void init() {
RetryPolicy retryPolicy = new RetryNTimes(ZKConsts.RETRYTIME, ZKConsts.SLEEP_MS_BEWTEENR_RETRY);
client = CuratorFrameworkFactory.builder().connectString(ZKConsts.ZK_SERVER_PATH)
.sessionTimeoutMs(ZKConsts.SESSION_TIMEOUT_MS).retryPolicy(retryPolicy)
.namespace(ZKConsts.WORK_SPACE).build();
client.start();
}
服务的注册代码
public static void register(URL url) {
try {
String interfaceName = url.getInterfaceName();
String implClassName = url.getImplClassName();
Stat stat = client.checkExists().forPath(getPath(interfaceName, url.toString()));
if (stat != null) {
System.out.println("该节点已存在!");
client.delete().forPath(getPath(interfaceName, url.toString()));
}
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
//权限控制,任何连接的客户端都可以操作该属性znode
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(getPath(interfaceName, url.toString()), implClassName.getBytes());
System.out.println(getPath(interfaceName, url.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
根据服务接口名来获取远程服务连接地址
public static URL random(String interfaceName) {
try {
System.out.println("开始查找服务节点:" + getPath(interfaceName));
List<String> urlList = client.getChildren().forPath("/" + interfaceName);
System.out.println("结果:" + urlList);
String serviceUrl = urlList.get(0);
String[] urls = serviceUrl.split(":");
String implClassName = get(interfaceName, serviceUrl);
return new URL(urls[0], Integer.valueOf(urls[1]), interfaceName, implClassName);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
return null;
}
注册中心与服务端进行连接时需要判断是否维持了稳定的连接,如果服务端出现宕机等情况时需要从注册中心中删除这些服务。
以前的一些处理机制,有session机制和wacher机制。
session机制
每个zookeeper注册中心与服务端进行连接时会创建一个session,在设置的sessionTimeout内,服务端会与注册中心进行心跳包的定时发送,从而感知每个客户端是否宕机,如果创建某个临时Znode节点对应的session销毁时,相应的临时节点也会被注册中心删除。
watcher机制
针对每个节点的操作,都有要给监督者进行watcher,当监控的某个节点发生了变化,则会触发watcher事件。注册中心的watcher是一次性的,触发后会被销毁。父节点,子节点增删改都能够触发watcher。触发销毁后,下次需要监听时还需要再注册一次。
本文心跳机制
服务端定时向注册中心发送本机地址,看作心跳数据包,而注册中心监控则维持一个channelId和具体地址的map,并且通过IdleHandler监听空闲事件,到达一定的空闲次数则认为不活跃,当不活跃时,zookeeper删除对应的url节点。该版本实现了上面的内容,后续的步骤在以后的版本实现。
如果10s内没有触发读,就会执行userEventTriggered方法。如果5分钟中出现两次不活跃次数,就认定该连接不稳定,注册中心会移除属于该服务端的服务。你也可以根据实际情况设定不稳定标准。
service.scheduleAtFixedRate(() -> {
if (future.channel().isActive()) {
int time = new Random().nextInt(5);
log.info("本次定时任务获取的随机数:{}", time);
if (time > 3) {
log.info("发送本地地址到注册中心:{}", url);
future.channel().writeAndFlush(url);
}
}
}, 60, 60, TimeUnit.SECONDS);
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent state = (IdleStateEvent)evt;
if (state.state().equals(IdleState.READER_IDLE)) {
log.info("读空闲");
} else if (state.state().equals(IdleState.WRITER_IDLE)) {
log.info("写空闲");
}
//在一定时间内读写空闲才会关闭链接
else if (state.state().equals(IdleState.ALL_IDLE)) {
if (++inActiveCount == 1) {
start = System.currentTimeMillis();
}
int minute = (int)((System.currentTimeMillis() - start) / (60 * 1000)) + 1;
log.info("第{}次读写都空闲,计时分钟数{}", inActiveCount, minute);
if (inActiveCount > 2 && minute < 5) {
log.info("移除不活跃ip");
removeAndClose(ctx);
} else {
if (minute >= 5) {
log.info("新周期开始");
start = 0;
inActiveCount = 0;
}
}
}
}
}
具体实现代码:RPC第二版
轻量级RPC设计与实现第二版的更多相关文章
- 轻量级RPC设计与实现第三版
在前两个版本中,每次发起请求一次就新建一个netty的channel连接,如果在高并发情况下就会造成资源的浪费,这时实现异步请求就十分重要,当有多个请求线程时,需要设计一个线程池来进行管理.除此之外, ...
- 轻量级RPC设计与实现第五版(最终版)
在最近一段时间里,通过搜集有关资料加上自己的理解,设计了一款轻量级RPC,起了一个名字lightWeightRPC.它拥有一个RPC常见的基本功能.主要功能和特点如下: 利用Spring实现依赖注入与 ...
- 轻量级RPC设计与实现第四版
在本版本中引入了SPI机制,关于Java的SPI机制与Dubbo的SPI机制在以前的文章中介绍过. 传送门:Dubbo的SPI机制与JDK机制的不同及原理分析 因为设计的RPC框架是基于Spring的 ...
- 轻量级RPC设计与实现第一版
什么是RPC RPC (Remote Procedure Call Protocol), 远程过程调用,通俗的解释就是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应 ...
- 《FPGA设计技巧与案例开发详解-第二版》全套资料包
本人参与写的一本书(TimeQuest一章由我所写),希望大家多多支持: 全书配套资料上传各大网盘资料中附送大量源码,你值得拥有--<FPGA设计技巧与案例开发详解-第二版>全套资料包-V ...
- 微博轻量级RPC框架Motan
Motan 是微博技术团队研发的基于 Java 的轻量级 RPC 框架,已在微博内部大规模应用多年,每天稳定支撑微博上亿次的内部调用.Motan 基于微博的高并发和高负载场景优化,成为一套简单.易用. ...
- python核心编程第二版笔记
python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d 提供调试输出1.2 –O 生成优化的字节码(生成 ...
- 微博轻量级RPC框架Motan正式开源:支撑千亿调用
支撑微博千亿调用的轻量级 RPC 框架 Motan 正式开源了,项目地址为https://github.com/weibocom/motan. 微博轻量级RPC框架Motan正式开源 Motan 是微 ...
- 浅谈Hybrid技术的设计与实现第二弹
前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...
随机推荐
- centos7中搭建ftp服务
博客搬家: centos7中搭建ftp服务 最近想和同学共享一些文件资源,于是在实验室服务器上搭建个ftp服务,本博客记录一下配置的流程.过程基本是参照别人的方法来做的,博客也是在别人博客基础上修改的 ...
- 基于 HTML5 WebGL 的智慧楼宇可视化系统
前言 可视化的智慧楼宇在 21 世纪是有急迫需求的,中国被世界称为"基建狂魔",全球高层建筑数量位居首位,所以对于楼宇的监控是必不可少.智慧楼宇可视化系统更多突出的是管理方面的功能 ...
- centos6.5下oracle11g下OGG单向复制
命名规范: local==> l remote==> r extract==> x data pump==> p ------------------------------- ...
- 大话IDL编程之函数功能调用(envi_doit、ENVIRaster、ENVITask)
2020年2月1日.好长时间没更新博客,还真有点不习惯.受新型冠性病毒的影响,平时街上熙熙攘攘的人流了无踪影,2020的春节竟然来的如此冷清.为响应“呆在家里就是做贡献的号召”,在家一宅就是十多天.闲 ...
- PHP在程序处理过程中动态输出内容
在安装discuz或其他一些开源产品的时候,在安装数据库时页面上的安装信息都是动态输出出来的,主要通过php两个函数来实现的, flush();ob_flush(); 代码如下 <html xm ...
- centos7 安装 iRedmail 后 给nginx添加虚拟主机
iRedmail安装参考官方文档和 https://ywnz.com/linuxyffq/4563.html 准备工作 更新操作系统 yum update -y 安装必要组件 yum install ...
- Kubernetes 部署 Nginx Ingress Controller 之 nginxinc/kubernetes-ingress
更新:这里用的是 nginxinc/kubernetes-ingress ,还有个 kubernetes/ingress-nginx ,它们的区别见 Differences Between nginx ...
- helm 错误the server has asked for the client to provide credentials
一.造成错误的原因 不小心把helm的RBAC权限文件删除了.虽然重新apply了RBAC配置,但是已经无法使用helm install了. 二.解决方法 把运行的tiller的pod干掉,让他自动重 ...
- CodeForces 327B 水题。
I - 9 Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit Statu ...
- 关于Java/Kotlin下载图片,图片打开不能显示问题探究
图片下载其实是个很简单的功能,通过IO流从在线地址获取流,之后将流输出到文件即可完成下载功能,但是,最近我发现某个网站中的图片下载成功,但是打开却是无法打开,这让我迷惑,百度上根本就没有人说清楚 今天 ...