Motan原理、使用、JavaAPI简化、为什么使用Motan
前言,本文包括,rpc解释与为什么使用rpc、rpc性能对比、Motan依赖问题、Motan源码梳理、Motan功能、特点、使用。
主要中心:为什么使用Motan?
一、什么是RPC
官方解释:RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络IO从其他节点程序上请求服务,而不需要了解底层网络技术的协议。RPC协议通过传输协议,如TCP或UDP,为通信程序之间携带信息数据。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
我眼中的RPC:本地接口使用代理通过网络IO在远程节点进行加强的调用过程。
二、为什么使用RPC
- 传输更快。相较于直接通过http协议远程调用,RPC框架的自定义协议使请求报文体积更小,且相较http传输更高效的二进制传输。
- 负载均衡。通过注册中心的RPC携带软负载均衡功能。而http请求需要Nginx、Lvs等配置实现。
- 服务治理。负载均衡、容错策略、连接控制、服务自动发现等。
三、Motan与Dubbo等其他RPC性能对比
- 吞吐率。结果:Motan>Dubbo
2、并发下的平均响应。Motan>Dubbo
3、请求最长响应时间。Motan>Dubbo
总结:Thrift、Grpc虽然支持JavaServer且性能较优,但实现语言不是Java语言,这为故障排查梳理带来了难度,且对应的序列化方式中都需要按照其自己的代码结构定义传输的数据结构,这种方式虽然带来了跨语言优势但是降低了易用性。
而Java语言实现的Motan、Dubbo框架。从图中可以发现,单从远程调用这一个方面讲,Motan略优于Dubbo.
四、Motan依赖、根据调用图简单介绍原理
1)Motan依赖m:otan 注册中心 consul时依赖motan-registry-consul-->
<!--motan 核心依赖 -->
<dependency><groupId>com.weibo</groupId><artifactId>motan-core</artifactId><version>1.1.6</version>
</dependency>
<!--motan 注册中心 consul时依赖motan-registry-consul-->
<dependency><groupId>com.weibo</groupId><artifactId>motan-registry-zookeeper</artifactId><version>1.1.6</version>
</dependency>
<!--motan Spring支持依赖 -->
<dependency><groupId>com.weibo</groupId><artifactId>motan-springsupport</artifactId><version>1.1.6</version>
</dependency>
<!--motan Netty依赖 还有一个模块为motan-transport-netty -->
<dependency><groupId>com.weibo</groupId><artifactId>motan-transport-netty4</artifactId><version>1.1.6</version>
</dependency>
Vertx3.5.4 依赖的Netty版本为4.1.19.Final
Motan1.1.6中 motan-transport-Netty4模块依赖的版本为4.1.16.Final
motan-transport-Netty模块依赖的版本为3.2.5.Final
motan-transport-Netty与motan-transport-Netty4两个模块同时依赖会产生异常。motan-transport-Netty4是升级版,故依赖此模块,与Vertx3.4.5以上的版本使用时execlusion掉netty-all包。例:
<dependency><groupId>com.weibo</groupId><artifactId>motan-transport-netty4</artifactId><version>1.1.6</version><exclusions><exclusion><groupId>io.netty</groupId><artifactId>netty-all</artifactId></exclusion></exclusions>
</dependency>
2)、调用图如下
- Server流程:
ServiceConfig的doExport方法将我们的服务参数,如分组、协议、序列化方式、注册中心等等进行组装成为将要在注册中心存储的URL。若设置了多个注册中心则都会在此时与上面的URL进行处理拼接。在过程中拿到SimpleConfigHandler前在ExtensionLoader处可以进行SPI扩展。SimpleConfigHandler的export方法具体进行在注册中心中注册。注册到注册中心的url如下:
motan2://10.0.4.248:8002/com.cloudwise.service.TestService?maxContentLength=1048576&module=usergroup&nodeType=service&version=1.0&accessLog=false&codec=motan2&protocol=motan2&application=dodp&shareChannel=true&refreshTimestamp=1565619237617&id=protocolConfig2&export=protocolConfig2:8002&group=usergroup-mac&
注意:Protocol、ConfigHandler、RegistryFactory都是ExtensionLoader的getExtension()得到,故若想自定义扩展协议、注册中心、url配置处理应从此处着手。而ProtocolFilterDecorator则装饰了Protocol,留下了可以自定义配置Filter的扩展点。
Provider:具体实现的执行细节。存在Method+Params反射拿到结果再放入response中这样的逻辑。
Exportor:Protocol的export方法返回,构造方法中通过EndpointFactory的createServer方法开启NettyServer。发现Yar协议则为Netty4HttpServer,可知Yar协议本质上还是Netty实现的Http协议。
上图中的transport部分则是私有协议内部的协议编解码和序列化编解码。
- Client流程
RefererConfig的initRef()方法将我们的服务参数,如分组、协议、序列化方式、注册中心等等进行组装成为要访问的url,SimpleConfigHandler的buildClusterSupport获得ClusterSupport,用来注册自己(Client)及根据url从注册中心订阅。
SimpleConfigHandler的refer方法获得ProxyFactory.
默认为CommonProxyFactory其中实例化RefererCommonHandler
此类为远程执行的具体逻辑,其中存在refer时多协议的开关降级,具体的call方法的具体执行由ClusterSpi中的HaStrategy的call方法执行,HaStrategy为容错策略目前由快速失败和失效切换两个实现,
HaStrategy的构造参数需要loadBalance即指定的负载策略,根据策略选择出当前服务的refer。HaStrategy的call方法的具体执行又由不同协议(Protocol)的doCall方法执行如Motan2协议的refer实现为MotanV2Protocol,以此类为例,doCall最终由NettyClient向NettyServer发起了调用。
五、Motan功能与特点
- 跨语言支持。
- Motan2协议+Simple序列化。支持Java、PHP、Go等语言
- Yar协议。支持Java、PHP
- Rest协议:基于Netty框架实现的Http协议,支持Restful风格。
4)可以多种协议同时发布。既同一个接口多种发布方式。
2、服务治理
1)负载均衡
目前支持的负载策略有:
ActiveWeight(缺省):低并发度优先: referer 的某时刻的 call 数越小优先级越高。
Random:随机选择。
RoundRobin:轮询选择
ConfigurableWeight:权重可配置的负载策略。
Consistent:一致性 Hash,相同参数的请求总是发到同一提供者
LocalFirst:本地优先+ ActiveWeight。
2)容错策略
Failover :失效切换。失效自动切换,重试其他服务器。
Failfast :快速失败。一次调用,失效立即报错。
- 服务发现
Motan支持Zookeeper、Consul等注册中心,做到服务注册、服务订阅等。由于Client在调用时是拿到注册中心的对应服务提供节点的IP等信息,再按照设置的负载均衡算法来选择一个节点进行调用。从这个角度实现了服务自动发现。
3、简单易用
1)代码层次简单
Motan
dubbo、
2、Api易用。
这里主要指集成Spring后的Motan注解开发。简单配置即可使用。
1)配置类
Slf4j
@Configuration
public class MotanConfig {@Bean(name="protocolConfig")public ProtocolConfigBean protocolConfig1() {ProtocolConfigBean config = new ProtocolConfigBean();config.setDefault(true);config.setName("motan");config.setMaxContentLength(1048576);return config;}@Bean(name = "protocolConfig2")public ProtocolConfigBean protocolConfig2() {ProtocolConfigBean config = new ProtocolConfigBean();//config.setId("demoMotan2");config.setName("motan2");config.setMaxContentLength(1048576);return config;}@Bean(name="registryConfig")public RegistryConfigBean registryConfig() {RegistryConfigBean config = new RegistryConfigBean();config.setRegProtocol("zookeeper");config.setAddress("127.0.0.1:2181");//config.setRegProtocol("local");return config;}@Beanpublic BasicServiceConfigBean baseServiceConfig() {BasicServiceConfigBean config = new BasicServiceConfigBean();config.setExport("protocolConfig2:10086");config.setGroup("usergroup-mac");config.setAccessLog(false);config.setShareChannel(true);config.setModule("usergroup");config.setApplication("dodp");config.setRegistry("registryConfig");return config;}
2)注解开发
server:
@MotanService(export = "protocolConfig2:10086")
public class ServerServiceImpl implements ServerService {client:
@Component
public class ReferServerService {@MotanRefererServerService service;Client还要有注册中心、协议等配置。因与server相似,不再展示
五、脱离Spring使用。
1)Server
public class MotanApiExportDemo {public static void main(String[] args) {// 配置注册中心直连调用RegistryConfig registry = new RegistryConfig();//use local registry//registry.setRegProtocol("local");// use ZooKeeper registryregistry.setRegProtocol("zookeeper");registry.setAddress("127.0.0.1:2181");// 配置RPC协议ProtocolConfig protocol = new ProtocolConfig();protocol.setId("restful");protocol.setName("restful");protocol.setEndpointFactory("netty");//protocol.setSerialization("protobuf");BasicServiceInterfaceConfig basic = new BasicServiceInterfaceConfig();basic.setVersion("1.0");basic.setGroup("usergroup-mac");basic.setApplication("dodp");basic.setModule("usergroup");ServiceConfig<ServerService> motanDemoService = new ServiceConfig<ServerService>();motanDemoService.setBasicService(basic);motanDemoService.setRegistry(registry);motanDemoService.setProtocol(protocol);// 设置接口及实现类motanDemoService.setInterface(ServerService.class);motanDemoService.setRef(new ServerServiceImpl());// 配置服务的group以及版本号//motanDemoService.setGroup("motan2-demo-rpc");//motanDemoService.setVersion("1.0");// registry.setCheck("false"); //是否检查是否注册成功//motanDemoService.setRegistry(registry);motanDemoService.setExport("motan2:8002");// 服务的发布及注册的核心 这里是重点 接下来,深入分析motanDemoService.export();MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true);System.out.println("server start...");}
2)Client
public class MotanApiClient {public static void main(String[] args) {RefererConfig<ServerService> motanDemoServiceReferer = new RefererConfig<ServerService>();// 设置接口motanDemoServiceReferer.setInterface(ServerService.class);// 配置服务的group以及版本号motanDemoServiceReferer.setGroup("usergroup-mac");motanDemoServiceReferer.setVersion("1.0");motanDemoServiceReferer.setRequestTimeout(1000);// 配置注册中心直连调用RegistryConfig registry = new RegistryConfig();//use direct registryregistry.setRegProtocol("zookeeper");registry.setAddress("127.0.0.1:2181");// use ZooKeeper registry//registry.setRegProtocol("zookeeper");//registry.setAddress("127.0.0.1:2181");motanDemoServiceReferer.setRegistry(registry);// 配置RPC协议ProtocolConfig protocol = new ProtocolConfig();protocol.setId("motan2");protocol.setName("motan2");// protocol.setSerialization("protobuf");motanDemoServiceReferer.setProtocol(protocol);// motanDemoServiceReferer.setDirectUrl("localhost:8002"); // 注册中心直连调用需添加此配置// 使用服务ServerService service = motanDemoServiceReferer.getRef();RequestHead head = new RequestHead("groupName", "version", "serviceName", "transferFile", "requestTime");Map<String, Object> body = new HashMap<String, Object>() {{put("attr", new HashMap() {{put("ll", 11);}});}};File file = new File("id", "filePath", "isCompress", "isScrete","isConsume", "attrpath");Message mess = new Message(head, body, new ArrayList<UserModel>() {{this.add(new UserModel(1, "back"));this.add(new UserModel(2, "test"));}}, file);String s = JSONObject.toJSONString(mess);System.out.println(s);RespMessage resp = service.testMessageTrans(mess);System.out.println(JSONObject.toJSONString(resp));System.exit(0);}
最后,对于不使用Spring的Motan JavaAPI的注解简化思路。
1)实现简单IOC用于启动初始化Motan配置信息,如注册中心、协议等。
2)注解扫描,完成service 的export前的设置,公共设置从上面的简单ioc中拿,特色的就要通过注解的值来拿。
3)referer和service思路一样,但考虑到依赖注入的问题,比如使用了Gui ce来做依赖注入,则bean的实例化不能反射拿,应该从Guice中获取,然后设置,但这也意味着被依赖的类要为单例。
进行初步封装后,使用展示:
1、配置类。
package com.cloudwise.config;import com.cloudwise.annotation.Bean;
import com.cloudwise.annotation.Config;
import com.cloudwise.constant.MotanConstant;
import com.weibo.api.motan.config.ProtocolConfig;
import com.weibo.api.motan.config.RegistryConfig;
import com.weibo.api.motan.config.springsupport.BasicServiceConfigBean;/*** @program RpcTest* @description: motan server config* @author: back* @create: 2019/08/05 11:42*/@Config
public class MotanConfig {@Bean("protocolConfig")public ProtocolConfig protocolConfig1() {ProtocolConfig config = new ProtocolConfig();config.setDefault(true);config.setName("motan");config.setMaxContentLength(1048576);return config;}@Bean("protocolConfig2")public ProtocolConfig protocolConfig2() {ProtocolConfig config = new ProtocolConfig();config.setId("protocolConfig2");config.setName("motan2");config.setMaxContentLength(1048576);return config;}@Bean(MotanConstant.REGISTRY_NAME)public RegistryConfig registryConfig() {RegistryConfig config = new RegistryConfig();config.setRegProtocol("zookeeper");config.setAddress("127.0.0.1:2181");//config.setRegProtocol("local");return config;}@Bean(MotanConstant.BASIC_SERVICE_NAME)public BasicServiceConfigBean baseServiceConfig() {BasicServiceConfigBean config = new BasicServiceConfigBean();config.setGroup(MotanConstant.CLIENT_GROUP_NAME);config.setAccessLog(false);config.setShareChannel(true);config.setVersion("1.0");config.setModule("usergroup");config.setApplication("dodp");config.setRegistry(MotanConstant.REGISTRY_NAME);return config;}
}
2、server
@MotanService(interfaceClass = TestService.class,protocols="protocolConfig2",export="protocolConfig2:8002")
public class TestServiceImpl implements TestService{server start:public class Latch {public static void main(String[] args) {MotanServiceAutoConfig.start("com.cloudwise.service");MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER
,true);log.info("Motan Server start !");
3、Client
@Slf4j
@Singleton
@Service("myServiceImpl")
public class MyServiceImpl implements MyService{@MotanReferTestService testService;Client start:@Slf4j
public class ClientLatch {public static void main(String[] args) {Injector injector = Guice.createInjector(new MotanModule());MotanReferAutoConfig.start("com.cloudwise.service",injector);MyService instance = injector.getInstance(MyServiceImpl.class);instance.print();}
Motan原理、使用、JavaAPI简化、为什么使用Motan相关推荐
- 编译原理—小型(简化)高级语言分析器前端(Java)
实现一个一遍扫描的编译前端,将简化高级语言的部分语法成分(含赋值语句.分支语句.循环语句等)翻译成四元式(或三地址代码),还要求有合理的语法出错报错和错误恢复功能. 测试样例 beginwhile a ...
- motan rpc java demo_轻量级RPC框架-motan
四步完成NodeJS安装,配置和测试 四步完成NodeJS安装,配置和测试 NodeJS 官网地址: http://nodejs.org/ 第一步:在官网点击 ' INSTALL ',下载相应的版本( ...
- 从(新浪)motan看RPC框架设计
kris的文章开始 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决 从零开发一款RPC框架,说难也难说简单也简单.难的是你的设计将如何面对实际中的复杂应用场景:简单的是其思想可以仅仅浓缩 ...
- 微博开源框架Motan初体验
前两天,我在开源中国的微信公众号看到新浪微博的轻量Rpc框架--Motan开源了.上网查了下,才得知这个Motan来头不小,支撑着新浪微博的千亿调用,曾经在2014年的春晚中有着千亿次的调用,对抗了春 ...
- 从motan看RPC框架设计
kris的文章开始 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决 从零开发一款RPC框架,说难也难说简单也简单.难的是你的设计将如何面对实际中的复杂应用场景:简单的是其思想可以仅仅浓缩 ...
- motan用户开发指南
目录 基本介绍 架构概述 模块概述 配置概述 使用Motan 工程依赖 处理调用异常 配置说明 协议与连接(motan:protocol) 介绍 Motan协议 本地调用 注册中心与服务发现(mota ...
- 支撑微博千亿调用的轻量级RPC框架:Motan
随着微博容器化部署以及混合云平台的高速发展,RPC 在微服务化的进程中越来越重要,对 RPC 的需求也产生了一些变化.今天主要介绍一下微博 RPC 框架 Motan,以及为了更好的适应混合云部署所做的 ...
- Motan的SPI机制实现分析
Motan使用SPI机制来实现模块间的访问,基于接口和name来获取实现类,降低了模块间的耦合. 首先来看一下使用方式: 有两个注解 @Documented@Retention(RetentionPo ...
- motan yar php,motan学习笔记 六 opentracing Brave+zipkin实现-Go语言中文社区
前面我们学习了,opentracing的接口定义 本文来学习motan用filter 来拦截请求,并用brace来实现,上报数据到zipkin zipkin是什么 本文主要讲brace 如何实现ope ...
最新文章
- 450g吐司烘烤温度_美晨烘焙丨会吐蛋黄的黄金吐司
- 【转】python编码大坑详解2
- 漏洞高危 中危 低危的划分标准
- C++ Primer 5th笔记(8)chapter8 类:IO库-文件流
- frameset用法
- .NET core3.0 使用Jwt保护api
- 超文本引用href的几种用法
- 互联网晚报 | 9月3日 星期五 | vivo正式公布自研芯片V1;天猫公布今年双11节奏;网易云音乐去除歌曲“独家”标志...
- vmware-安装vmware tools教程190915
- pycharm的项目文件中包括什么_婚庆策划是什么?婚庆策划都包括哪些项目
- [原创软件]手机截屏及格式转换工具
- matlab切割肿瘤算法,ML之RF:基于Matlab利用RF算法实现根据乳腺肿瘤特征向量高精度(better)预测肿瘤的是恶性还是良性...
- 1059 Prime Factors (25 分)质因子 易错题
- 作业成本分析法如何计算?作业成本怎么分析计算
- 几种常用的PID控制算法
- is not eligible for getting processed by all BeanPostProcessors 导致找不到路径报404
- 真实评测 rtx3080ti对比rx6800xt选哪个好
- c语言数学作业及答案,2004年9月全国计算机等级考试二级C语言笔试试题及答案...
- 解析Excel获取单元格数据
- STM32F4xx FPU和DSP库的使用