Motan RPC Framework
repository·master·Indexed 26 days ago
https://github.com/weibocom/motanA high-performance, cross-language RPC framework for distributed services supporting Java, Golang, PHP, and Lua (Openresty). Motan features synchronous and asynchronous communication patterns, service discovery integration via Consul or Zookeeper, weighted load-balancing, and cross-IDC scheduling. It supports module extension through the Service Provider Interface (SPI) and provides specialized protocol support such as YAR for PHP.
What's inside Motan
- Motan is a cross-language remote procedure call (RPC) framework designed for high-performance distributed services. It supports cluster management, service discovery (via Consul or Zookeeper), and advanced scheduling like weighted load-balancing and cross-IDC scheduling. It is optimized for high-load production environments and supports both synchronous and asynchronous communication patterns across multiple languages including Java, Golang, PHP, and Lua (Openresty).
Understand Motan Architecture and Roles
masterMotan is a Java-based RPC framework providing service governance like automatic discovery, removal, high availability, and load balancing. The architecture consists of three primary roles:
- Server (RPC Server): Provides services, registers itself with the Registry, and sends periodic heartbeats.
- Client (RPC Client): Consumes services by subscribing to the Registry, obtaining a server list, and establishing connections for RPC calls.
- Registry (Service Registry): Manages service information and synchronizes changes to Clients when Servers change.
Key functional modules (extensible via SPI):
register: Handles interaction with the Registry (registration, subscription, heartbeats).protocol: Manages RPC service descriptions, configuration, and filters (statistics, concurrency limits).serialize: Converts objects to byte streams (defaults tohessian2).transport: Handles remote communication (defaults to Netty NIO TCP long connections).cluster: A logical wrapper for a group of Servers used by the Client to apply HA and Load Balancing strategies.
Key Features of Motan
masterMotan provides several advanced capabilities for distributed service management:
- Spring Integration: Supports integration via Spring configuration, allowing you to provide distributed calling capabilities without writing additional code.
- Service Discovery & Governance: Supports integration with configuration services like Consul and Zookeeper to provide service discovery and governance in cluster environments.
- Advanced Service Scheduling: Supports dynamic custom load balancing and cross-datacenter traffic adjustment.
- High Availability: Optimized for high-concurrency and high-load scenarios to ensure stability in production.
Use ZooKeeper as a service registry in a cluster
masterTo enable service discovery in a cluster using ZooKeeper:
- Install ZooKeeper: Download and set up ZooKeeper on your environment.
- Add Dependency: Add
motan-registry-zookeeperto your project'spom.xml. - Configure Registry: Define the registry in your XML configuration using
<motan:registry regProtocol="zk" name="[NAME]" address="[ADDRESS]"/>.- For a single node:
address="127.0.0.1:2181" - For multi-nodes:
address="127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183"
- For a single node:
- Update Service/Referer:
- For the server: Add
registry="[NAME]"to the<motan:service>tag. - For the client: Add
registry="[NAME]"to the<motan:referer>tag.
- For the server: Add
- Enable Heartbeat: You must explicitly enable the heartbeat switcher in your server code:
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true)
<!-- 1. Dependency --> <dependency> <groupId>com.weibo</groupId> <artifactId>motan-registry-zookeeper</artifactId> <version>RELEASE</version> </dependency> <!-- 2. Registry Definition (Multi-node) --> <motan:registry regProtocol="zk" name="my_zookeeper" address="127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183"/> <!-- 3. Server Configuration --> <motan:service interface="quickstart.FooService" ref="serviceImpl" registry="my_zookeeper" export="8002" /> <!-- 4. Client Configuration --> <motan:referer id="remoteService" interface="quickstart.FooService" registry="my_zookeeper"/> <!-- 5. Enable Heartbeat in Java --> MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true)Use OpenTracing with Motan
masterMotan supports OpenTracing via its filter SPI extension mechanism. To enable tracing:
- Add the
filter-opentracingdependency. - If your third-party tracing tool (e.g., Zipkin) provides an
io.opentracing.TracerSPI extension, simply include its JAR. - If no SPI extension is provided, implement a custom
TracerFactory(implementing theTracerFactoryinterface) that returns the desiredTracerimplementation viagetTracer(). Set this custom factory as theOpenTracingContexttracer factory.
<!-- Dependency --> <dependency> <groupId>com.weibo</groupId> <artifactId>filter-opentracing</artifactId> <version>RELEASE</version> </dependency>- Add the
Configure Consul as a Motan Registry
masterTo use Consul for service discovery in a cluster environment:
- Add Dependency: Add
motan-registry-consulto both server and client. - Define Registry: In both server and client XML configs, define the registry using
<motan:registry regProtocol="consul" name="[NAME]" address="[ADDRESS]"/>. - Enable Discovery: Update
<motan:service>and<motan:referer>to use theregistryattribute instead ofdirectUrl. - Enable Heartbeat: You MUST explicitly enable the registry heartbeat in your server code to register with Consul:
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true)
<!-- 1. Dependency --> <dependency> <groupId>com.weibo</groupId> <artifactId>motan-registry-consul</artifactId> <version>RELEASE</version> </dependency> <!-- 2. Registry Definition --> <motan:registry regProtocol="consul" name="my_consul" address="127.0.0.1:8500"/> <!-- 3. Service/Referer Configuration --> <motan:referer id="remoteService" interface="quickstart.FooService" registry="my_consul"/> <motan:service interface="quickstart.FooService" ref="serviceImpl" registry="my_consul" export="8002" /> <!-- 4. Server Code to enable registration --> MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true);- Add Dependency: Add
Configure Motan using Annotations (Server-side)
masterYou can configure Motan using Spring beans instead of XML. For the server-side:
- Define an
AnnotationBeanto specify the package name for scanning. - Define
ProtocolConfigBean,RegistryConfigBean, andBasicServiceConfigBeanas Spring beans. These correspond to theprotocol,registry, andbasicServiceXML tags. - Annotate your service implementation class with
@MotanService. The parameters match theserviceXML tag. - Start the service using Spring Boot.
// 1. AnnotationBean @Bean public AnnotationBean motanAnnotationBean() { AnnotationBean bean = new AnnotationBean(); bean.setPackage("com.weibo.motan.demo.server"); return bean; } // 2. Config Beans @Bean(name = "demoMotan") public ProtocolConfigBean protocolConfig1() { ProtocolConfigBean config = new ProtocolConfigBean(); config.setDefault(true); config.setName("motan"); config.setMaxContentLength(1048576); return config; } @Bean(name = "registryConfig1") public RegistryConfigBean registryConfig() { RegistryConfigBean config = new RegistryConfigBean(); config.setRegProtocol("local"); return config; } @Bean public BasicServiceConfigBean baseServiceConfig() { BasicServiceConfigBean config = new BasicServiceConfigBean(); config.setExport("demoMotan:8002"); config.setGroup("testgroup"); config.setAccessLog(false); config.setShareChannel(true); config.setModule("motan-demo-rpc"); config.setApplication("myMotanDemo"); config.setRegistry("registryConfig1"); return config; } // 3. Service Implementation @MotanService(export = "demoMotan:8002") public class MotanDemoServiceImpl implements MotanDemoService { public String hello(String name) { return "Hello " + name + "!"; } } // 4. Spring Boot Startup @EnableAutoConfiguration @SpringBootApplication public class SpringBootRpcServerDemo { public static void main(String[] args) { System.setProperty("server.port", "8081"); SpringApplication.run(SpringBootRpcServerDemo.class, args); MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true); } }- Define an
Setup Motan for Asynchronous RPC Calls
masterAsynchronous calls allow non-blocking service invocation.
- Annotate Interface: Add
@MotanAsyncto your service interface. - Code Generation: Motan automatically generates an async version of your interface (e.g.,
FooServicebecomesFooServiceAsync) intarget/generated-sources/annotations/. Ensure this path is added to your project's source path via Maven. - Client Configuration: In
motan_client.xml, change theinterfaceattribute of the<motan:referer>to use the generated async class (e.g.,quickstart.FooServiceAsync). - Usage: Use methods like
helloAsync(name)which return aResponseFuture. You can usegetValue()for synchronous retrieval, or attach aFutureListenerfor callback-based handling.
<!-- 1. Interface with Annotation --> @MotanAsync public interface FooService { public String hello(String name); } <!-- 2. Client Config --> <motan:referer id="remoteService" interface="quickstart.FooServiceAsync" directUrl="localhost:8002"/> <!-- 3. Async Usage --> FooServiceAsync service = (FooServiceAsync) ctx.getBean("remoteService"); ResponseFuture future = service.helloAsync("motan async "); System.out.println(future.getValue()); // With Listener service.helloAsync("test").addListener(new FutureListener() { @Override public void operationComplete(Future future) throws Exception { System.out.println(future.isSuccess() ? "success: " + future.getValue() : "fail: " + future.getException().getMessage()); } });- Annotate Interface: Add
Install and Run the Motan Management Backend
masterThe management backend allows RPC service querying, traffic switching, and command settings. It requires ZooKeeper as the registry.
1. Configuration Modify
application.propertiesto set the registry type (zookeeperorconsul) and address. Default credentials:- Admin:
admin/admin - Guest:
guest/guest
To enable historical operation queries, import the
motan-manager.sqlschema and updateMotanManagerAppto importspring-mybatis.xml:@ImportResource(locations = {"classpath:spring-mybatis.xml", "classpath:spring-security.xml"})2. Build and Start Run the following commands in the
motan/motan-manager/directory:mvn package java -jar target/motan-manager.jar- Admin:
Use the Restful protocol
masterMotan supports the Restful protocol, allowing services to be called via standard HTTP. This is useful for cross-language integration.
Features
- Supports standalone RPC processes or deployment in Servlet containers (e.g., Tomcat).
- Supports full service governance, attachment mechanisms, and filter mechanisms.
- Programming model follows JAX-RS.
Implementation Steps
- Add the
motan-protocol-restfuldependency. - Define your service interface using JAX-RS annotations (
@Path,@GET,@POST,@Produces, etc.). - Implement the interface.
- Configure the server and client using XML.
Deployment Modes
- Standalone RPC Process (Recommended): Use
endpointFactory="netty"in the protocol configuration. This is more efficient for Java clients. - Servlet Container (e.g., Tomcat): Use
endpointFactory="servlet". Requires configuring aRestfulServletContainerListenerand aHttpServletDispatcherinweb.xml. Note that you must handle thecontextpathcorrectly in URLs.
<!-- Dependency --> <dependency> <groupId>com.weibo</groupId> <artifactId>motan-protocol-restful</artifactId> <version>RELEASE</version> </dependency> <!-- Interface Example --> @Path("/rest") public interface RestfulService { @GET @Produces(MediaType.APPLICATION_JSON) List<User> getUsers(@QueryParam("uid") int uid); } <!-- Standalone Server XML Configuration --> <motan:protocol id="demoRest" name="restful" endpointFactory="netty"/> <motan:basicService export="demoRest:8004" group="motan-demo-rpc" module="motan-demo-rpc" application="myMotanDemo" registry="registry" id="serviceBasicConfig"/> <motan:service interface="com.weibo.motan.demo.service.RestfulService" ref="motanDemoServiceImpl" basicService="serviceBasicConfig"/> <!-- Servlet Container web.xml Configuration --> <listener> <listener-class>com.weibo.api.motan.protocol.restful.support.servlet.RestfulServletContainerListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class> <init-param> <param-name>resteasy.servlet.mapping.prefix</param-name> <param-value>/servlet</param-value> </init-param> </servlet>Implement Synchronous RPC calls
masterTo implement synchronous calls, follow these steps:
- Define an interface: Create a standard Java interface for both the provider and consumer.
- Implement the service: Write the implementation class.
- Configure the Server: Use a Spring XML configuration to export the service using the
<motan:service>tag. Specify theinterface, the implementationref, and theexportport. - Configure the Client: Use a Spring XML configuration to reference the remote service using the
<motan:referer>tag. Specify theinterfaceand thedirectUrl(e.g.,localhost:8002). - Run: Start the Spring ApplicationContext for the server, then the client to invoke the method.
<!-- Server Configuration (motan_server.xml) --> <motan:service interface="quickstart.FooService" ref="serviceImpl" export="8002" /> <!-- Client Configuration (motan_client.xml) --> <motan:referer id="remoteService" interface="quickstart.FooService" directUrl="localhost:8002"/> <!-- Client Usage --> ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:motan_client.xml"); FooService service = (FooService) ctx.getBean("remoteService"); System.out.println(service.hello("motan"));Update Motan Wiki
masterSince GitHub Wiki does not support Pull Requests, documentation is maintained within the repository in thedocs/wikidirectory. To update the wiki, submit a Pull Request targeting the files in thedocs/wikifolder.