【1】JMicro简介

一,为什么写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做的后台管理,服务编排。。。。,到现下图功能基本上都有实现,并且正常可用,后期肯定会不断优化。
在这里插入图片描述

实现以上功能的全部第三方依赖如下:

其中

javapoet是编译时做代码生成用的,在最终运行包中并不需要

guava前期实现限流试验性用到,最后限速并不理想,实际上已经排除
在这里插入图片描述
Curator后期打算去除,只保留Zookeeper.

三,目前最满意的一个特性:异步RPC

大家都知道,NodeJS单线程,但其性能却很强劲,因为异步;Redis性能也很强劲,因为异步;无数的库或服务都强调通过异步提高性能。

在对JMIcro做压力测试过程中,我深深地体会到一个同步的代价(性能底还不说,高并发时还会死锁)而异步的必要性。在JMicro中,异步体现在很多模块中。其中主要以下几个:

消息服务,一个针对JMicro量身定制的异步消息中间件,服务可以通过其实现消息发布/消息订阅; 还可以做异步RPC,比如发布一个RPC服务方法,使其自动订阅特定主题的消息,消息中间件能识别此种类型的服务方法,并将匹配的消息发送给此服务的服务方法。
以1作为基础,可以在客户端及服务端做异步RPC,比如在客户端直接将消息发送到消息中间件,让消息中间件转发给目标服务;也可以在服务端收到消息后(比如API网关,同步转异步,削峰限流),将消息发送到消息服务器,让消息服务器转发给目标方法。
代码级别的异步RPC调用,让Java代码像Scala,NodeJS等语言一样做异步编程,以下对此做详细的Demo
下面片段代码摘自

https://github.com/mynewworldyyl/jmicro/blob/master/example/example.comsumer/src/main/java/cn/jmicro/example/comsumer/ServiceComsumer.java

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 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个被调用服务输出如下
在这里插入图片描述
以上样例对应的服务接口及实现类分别为:

https://github.com/mynewworldyyl/jmicro/blob/master/example/example.api/src/main/java/cn/jmicro/example/api/rpc/ISimpleRpc.java

@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);
}

https://github.com/mynewworldyyl/jmicro/blob/master/example/example.provider/src/main/java/cn/jmicro/example/rpc/impl/SimpleRpcImpl.java

服务实现类代码有点多,在此只贴我们调用的方法,别的请查看源代码

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;
}

客户端测试类

https://github.com/mynewworldyyl/jmicro/blob/master/example/example.comsumer/src/main/java/cn/jmicro/example/comsumer/ServiceComsumer.java
完整类图
在这里插入图片描述
简化类图
在这里插入图片描述

五,实现原理

建议适当修改上面代码然后编译运行测试,比如修改服务端返回值,修改客户端调用参数,服务端返回改为同步,或再调用别的服务(可以同步调用,也可异步调用)。

启动多个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的细节做更多介绍,以实战为主,微服务概念为铺。

附一个后台管理的前端链路日志查询页面.
下面链接可以打开,但是因为没登陆,所以只有查看部份功能的权限,要登陆的同学可以私信。华为云送的服务器,性能很差,并且只有30天使用期!

http://47.112.161.111/

在这里插入图片描述
大家有任何问题欢迎评论。

如果你对这个项目感兴趣,也欢迎参与开发,共同完善。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值