【JMICRO】 微服务简介及异步RPC体验
一,为什么写JMicro
印象中初次接触微服务大概是2011年,那会做Eclpise插件开发,网上查看好多关于OSGI的技术文章,发现Spring新出了一个叫Spring-boot的框架,那会没太上心,只是了解了点皮毛,工作又太忙,之后就没下文了。
直到大概2015年的某天,碰到一个小项目,没什么难度,都用老套路去玩,没什么意思,得玩点新东西才行,也不枉一翻付出,于是选择用GO语言实现,选择GO主要是想体验一下GO,看是不是真如传说中的那样无敌。经过一翻折腾,最终确定GOGIN+GOMICRO实现。是的,从那会开始,通过学心和使用GOMICRO,从此迷上微服务。后来因为工作需要,再没什么机会在项目中接触GO。
后面也曾试图去用Dubbo和Spring-Cloud做项目,但也止于浅尝则止,没能深入。一方面项目时间太紧,折腾不起。另一方面,也是最重要的,项目组成员根本不愿意去学新东西,在很多成员心中,微服务,Spring-Cloud太深奥,玩不起,没时间,至于Dubbo,写个服务,做个RPC也是从百度复制下来的,跑起来就完事了,没人关心个中的原理,经常碰到问题就抓狂!
从那时候起,就一直琢磨着能不能用Java写一个像GoMicro一样简单的微服务框架,这个框架要确保足够简单,入门和使用成本要底,就像写HelloWord一样,但微服务的基本功能要全。因此项目依赖不能多,打出来的运行包也要小,能不用的第三方包坚决不用,最好使用JDK库就行!
二.从RPC开始
微服务的基础是RPC,而反过来单单有RPC却不能叫微服务,微服务是在RPC基础上,实现一系列的基础性功能支持后才能叫微服务。没有超时,限流,熔断这些基础支持,服务“微”了之后,随时都可能挂机,这就是为什么微服务之前存在很多RPC框架,但却没人说那是微服务。
坚持从JDK库入手,使用原生NIO SOCKET做了个简单的RPC,并且兼容了HTTP方式,完后做压力测试发现性能太差,然后退一步吧,选择Mina做底层通信重新再折腾一遍,结果还是不尽如人间,性能还可以,就是自觉得太繁琐臃肿,还是不满意,最终又改为Netty才完成RPC基本功能开发。很多时候,路就是一步一个脚印走出来的,如果前面碰到大山大河,实在跨不过去,回头绕个湾也是必须的,否则一步没跨过去就OVER了。最优的不是选择最好的,而是选择合适的。
接着做IOC,超时,熔断,限速,配置管理,服务注理,监控服务,负载均衡,服务路由,API网关,HTTP,WEB Socket,全局ID,链路追踪,消息服务,异步RPC,基于VUE做的后台管理,服务编排。。。。,到现下图功能基本上都有实现,并且正常可用,后期肯定会不断优化。
图中最底层是JMicro依赖服务,没做任何修改,Redis用于做高速一至性ID生成及消息缓存,Zookeeper做配置管理及服务注册中心,应用可以通过JMicro IOC容器直接获得Redis和Zookeeper实例组件并使用,非常方便;Netty做RPC底层数据通信,同时支持HTTP及Websocket,应此支持Web端直接访问微服务;Mongodb是一个可选依赖,用于存储RPC监控日志和事件信息;Vue+IView实现后台管理的前端页面。
智能控制:目前没有实现,之所以列出来,是因为一直把他当作JMicro的核心功能,目的是通过监控获取到的系统数据训练一个人工智能大脑,让其自动完成JMicro系统的日常维护。
IOC容器:之所以没用现成的Spring等容器实现,就如一开始所说的,他们太复杂,不够轻量(即使他们一直坚持认为他们是轻量级容器),对于JMicro来说,他们还是大重了,也不利于JMicro对微服务的量身定制。JMIcro IOC使用非常简单,在99%情况,通过Component注解组件,通过Inject注解字段就够了,就这么简单。
编码解码:如果说RPC是微服务的基础,那么编码解码则是微服务的基石,基石不牢,服务的大厦随时都可能倒塌。我将JMicro实现的编码解码实命名为前缀类型编码解码器,首先对类对进行编码,然后将类的编码信息和要传输的数据一起序列化到二进制数据中,解码时则将编码转为类信息,然后反序列化二进制数据为类对象,当然,编码考虑了高频使用的类并确保其编码最短,从而达到序列化的数据冗余最底。测试效果还是相当不错的,对比ProtoBuffer性能不相上下,某此情况差此,但某些情况比ProtoBuffer还好,甩JDK原生序列化及Kryo序列化几条街。
别的功能待以后再细说。

实现以上功能的全部第三方依赖如下:
其中
javapoet是编译时做代码生成用的,在最终运行包中并不需要
guava前期实现限流试验性用到,最后限速并不理想,实际上已经排除

Curator后期打算去除,只保留Zookeeper.
三,目前最满意的一个特性:异步RPC
大家都知道,NodeJS单线程,但其性能却很强劲,因为异步;Redis性能也很强劲,因为异步;无数的库或服务都强调通过异步提高性能。
在对JMIcro做压力测试过程中,我深深地体会到一个同步的代价(性能底还不说,高并发时还会死锁)而异步的必要性。在JMicro中,异步体现在很多模块中。其中主要以下几个:
- 消息服务,一个针对JMicro量身定制的异步消息中间件,服务可以通过其实现消息发布/消息订阅; 还可以做异步RPC,比如发布一个RPC服务方法,使其自动订阅特定主题的消息,消息中间件能识别此种类型的服务方法,并将匹配的消息发送给此服务的服务方法。
- 以1作为基础,可以在客户端及服务端做异步RPC,比如在客户端过直接将消息发送到消息中间件,让消息中间件转发给目标服务;也可以在服务端收到消息后(比如API网关,同步转异步,绡峰限流),将消息发送到消息服务器,让消息服务器转发给目标方法。
- 代码级别的异步RPC调用,让Java代码像Scala,NodeJS等语言一样做异步编程,以下对此做详细的Demo
下面片段代码摘自
ISimpleRpcAsyncClient src = (ISimpleRpcAsyncClient)of.get(ISimpleRpc.class);
//最外层异步RPC调用
src.helloAsync("Hello JMicro").then((rst, fail)->{
//第一次异步返回结果
System.out.println(rst);
//做一次同步调用
String r = src.hello("Hello two");
//同步返回结果
System.out.println(r);
//再做一次异步调用
src.helloAsync("Hello two").then((rst1, fail1)->{
//异步返回结果
System.out.println(rst);
});
});
我觉得这种异步RPC风格是最有杀伤力的,这使得我们的远程RPC调用不再阻塞线程,包括工作线程和网络IO线程,只要我们的线程占用CPU,他都是在做有用的工作!
四,体验JMiro异步RPC
前面吹了这么多,不来点实际可见的操作,肯定不能让人信服,现在手把手教你体验一把JMicro是不是真的做了远程RPC调用,是不是真的是异步调用。
1. 环境准备
首先确保本机安装了Java,Maven,Zookeeper监听在2181端口,Redis工作在6379端口,保持默认,所有配置都省了。
2. 下载JMicro代码
到https://github.com/mynewworldyyl/jmicro下载代码到特定目录,下面以${basedir}指代此目录
3. 打开一个命令行窗口,cd进入到${basedir}\codegenerator目录,执行
mvn clean install -Dmaven.test.skip=true
4. 上面命令执行成功后,cd进入到${basedir}目录,执行mvn clean install -Dmaven.test.skip=true
5. 确保3和4成功后,cd进入到${basedir}\example目录, 执行mvn clean install-Dmaven.test.skip=true
6. 通过3,4,5步确保相关依赖包都已经安装在Maven本地仓库中,打包可执行的服务Jar包,cd进入到${basedir}\example\example.provider目录, 执行mvn mvn clean install -Pbuild-main -Dmaven.test.skip=true
7. 运行服务端
java -jar target/jmicro-example.provider-0.0.1-SNAPSHOT-jar-with-dependencies.jar -javaagent: ${basedir}\target\jmicro-agent-0.0.1-SNAPSHOT.jar
看到以下输出说明服务启动成功

8. 打包可执行的测试客户端Jar包,cd进入到${basedir}\example\example.comsumer目录, 执行mvn clean install -Pbuild-main -Dmaven.test.skip=true
9. 运行客户端
java -jar target/jmicro-example.comsumer-0.0.1-SNAPSHOT-jar-with-dependencies.jar -javaagent: ${basedir}\target\jmicro-agent-0.0.1-SNAPSHOT.jar
以下是客户端两次异步调用,一次同步调用返回的结果

对应服务器的3个被调用的输出

以上样例对应的服务接口及实现类分别为:
@Service //指定此接口是一个远程接口,对外提供RPC服务
@AsyncClientProxy //编译时注解,Javac编译器调用特定注解处理器生成客户端访问代码
public interface ISimpleRpc {
//我们测试用的方法
String hello(String name);
//IPromise<String> helloAsync(String name);
//POJO对象为参数的RPC方法
String hi(Person p);
//测试RPC链路
String linkRpc(String msg);
}
服务实现类代码有点多,在此只贴我们调用的方法,别的请查看源代码
public String hello(String name) {
if(SF.isLoggable(MC.LOG_DEBUG)) {
//向监控服务发送一条日志事件,请放心,调用此方法只是把日志存于本地并立即返回,不影响正常的性能
SF.eventLog(MC.MT_PLATFORM_LOG,MC.LOG_DEBUG,SimpleRpcImpl.class, name);
}
System.out.println("Server hello: " +name);
//返回一条信息给客户端
return "Server say hello to: "+name;
}
客户端测试类
完整类图

简化类图

五,实现原理
建议适当修改上面代码然后编译运行测试,比如修改服务端返回值,修改客户端调用参数,服务端返回改为同步,或再调用别的服务(可以同步调用,也可异步调用)。
启动多个example.provider实例(理论上,你可以启动无数个服务实例,那怕都在同一台机器上)多次运行客户端调用看看调用了那个服务实例(服务路由及负载均衡)
如果你对微服务有兴趣,并且有足够的耐心,你应该能从中获得乐趣。
如果认真查看了原代码,应该看到以下几个关键的注解,而使用JMIcro,基本上使用这几个注解就够了:

1. Service:如果注解在接口上,意思是告诉JMicro容器,这个一个服务接实口,客户端使用接口类为参数get实例时,请返回服务代理实例;如果注解在实现类上,告诉JMicro容器,这是一个RPC服务,请将服务信息发布到服务注册中心,让客户端知道我的存在。
2. AsyncClientProxy:注解服务接口,告诉编译器在编译全部源代码前,请调用注解处理器生成服务客户端代理接口及实现类,供客户端直接使用,让客户端觉得自己就好像获得了服务实现类的直接引用一样,完全不知道是跨JVM的远程调用。

3. Component:JMIcro容器组件,JMicro容器启动时实例化,供容器中的其他组件使用,是的,服务本身也是一个组件,只不过其实现了服务接口,并向注册中心注册自己才变成了远程服务,同时其本身也是一个组件,可以被同一个容器中的其他组件依赖并被自动注入。
4. Reference:注解在组件的字段上,告诉JMicro容器,我需要一个远程服务代理实例,请将这个实例值赋给我注解的字段。

5. SMethod注解在方法上,告诉JMicro容器,我是一个服务方法,并指定服务参数,比如超时时间,熔断策略,是否可监控,日志级别等。
6. 每个服务都由三个值唯一确定,分别是服务接口全称(serviceName),名称空间(namespace),版本(version),并使用在Service及Reference注解上。
后面有时间会对JMicro的细节做更多介绍,以实战为主,微服务概念为铺。
附一个后台管理的前端链路日志查询页面

大家有任何问题欢迎评论。
如果你对这个项目感兴趣,也欢迎参与开发,共同完善。
后面资金允许后,买个服务器在公网上部署一套,让大家体验!
【JMICRO】 微服务简介及异步RPC体验的更多相关文章
- 【13】JMicro微服务-ID生成与Redis
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 往下看前,建议完成前面1到12小节 1. 微服务中ID地位 如果说前面小节的功能点是微服务的大脑,那么全局唯一ID则是微服务 ...
- 【12】JMicro微服务-Zookeeper
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 往下看前,建议完成前面1到11小节 1. CuratorFramework支持 JMicro目前基于Zookeeper实现统 ...
- 【11】JMicro微服务-配置管理
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 往下看前,建议完成前面1到10小节 JMicro目前仅支持基于Zookeeper做配置管理,全部配置信息可以在ZK做增删改查 ...
- 【2】JMicro微服务-Hello World
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 1. 首先完成 JMicro微服务-RPC体验 的1到5步. 按默认方式启动ZK及Redis: JDK需要Java8及以上. ...
- 微服务架构介绍和RPC框架对比
微服务架构介绍和RPC框架对比 1.微服务架构 1.1 特征 自动化部署,端点智能化,语言和数据的去中心化控制. 1.2架构 一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中 ...
- 微服务治理平台的RPC方案实现
导读:本文主要探讨了rpc框架在微服务化中所处的位置,需要解决的问题.同时介绍了用友云微服务治理平台的rpc解决方案,为什么选择该方案.该方案提供的好处是什么.同时也会介绍用友RPC框架的基本结构以及 ...
- 远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo、SpringClound对比
远程服务调用RPC框架介绍,微服务架构介绍和RPC框架对比,dubbo.SpringClound对比 远程服务调用RPC框架介绍,RPC简单的来说就是像调用本地服务一样调用远程服务. 分布式RPC需要 ...
- 【10】JMicro微服务-API网关
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 往下看前,建议完成前面1到9小节 1. Api网关基本特性: Api网关作为对外网提供服务的基本入口,地位类似于NGINX, ...
- 【8】JMicro微服务-JMicro ZKUI
ZKUI是一个开源项目,是一个查看,修改ZK数据非常方便的工具.JMicro基于ZK做服务治理,配置管理,因此使用ZKUI会提供非常大的方便. Github地址:https://github.com/ ...
随机推荐
- Python--函数&过程
函数式编程与过程式编程打的区分:过程是没有返回值的函数,过程在python3中也有返回值,为None 函数的作用:代码复用.保持代码的一致性.使代码更容易扩展 过程的定义与调用: 1 def func ...
- 君荣一卡通软件mysql转sqlserver 教程
Mysql数据库转sql数据库方法 注意:新建的SQL数据库一得先登录一次后再做迁移!!!!特别注意 如果客户以前安装的是mysql数据库,现在希望把mysql数据库转换的sql数据库,方法如下: 1 ...
- 数据库连接池 Druid和C3p0
datasource.properties数据源 #数据源 datasource.peoperties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc: ...
- Spring:扫描组件
<context:component-scan>:扫描组件,对设置的包下面的类进行扫描,会讲加上注解的类作为Spring的组件进行加载 组件:指Spring中管理的bean 作为Spr ...
- springboot使用自定义异常
sprinboot使用自定义注解 创建自定义异常类,继承RuntimeException public class MyException extends RuntimeException { p ...
- 让LED程序在片外SDRAM中运行
让LED程序在片外SDRAM中运行 一.引子 在前一篇文章中,我们已经成功点亮过LED了,为什么还要再重复一次呢? 我们已经知道,Mini2440开发板有两种启动模式:从NorFlash启动和从Nan ...
- @bzoj - 2658@ [Zjoi2012]小蓝的好友(mrx)
目录 @description@ @solution@ @accepted code@ @details@ @description@ 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事 ...
- ArchLinux的安装
ArichLinux安装教程 Arch Linux 于 2002 年发布,由 Aaron Grifin 领头,是当下最热门的 Linux 发行版之一.从设计上说,Arch Linux 试图给用户提供简 ...
- linux安装syncthing
https://blog.csdn.net/weixin_30527551/article/details/98882344 https://syncthing.net/downloads/ http ...
- PageHelper支持GreenPlum
greenplum是pivotal在postgresql的基础上修改的一个数据库,语法和postgresql通用.使用PageHelper做分页插件的时候,发现目前没有针对greenplum做支持,但 ...