Netty-based lightweight high-performance distributed RPC service framework forest <Part 2>, nettyforest
Netty-based lightweight high-performance distributed RPC service framework forest <Part 1>
The article has briefly introduced the Quick Start of forest. This article aims to introduce the forest user guide.
Basic Introduction
Forest is a java-based RPC framework. In addition to conventional point-to-point calls, Motan also provides service governance functions, including automatic discovery, removal, high availability, and load balancing of service nodes.
Architecture Overview
Forest consists of three roles: Service Provider (RPC Server), service caller (RPC Client), and service Registry.
The Server provides services, registers its own services to the Registry, and periodically sends heartbeat reports to the Registry. When using the service, the Client needs to subscribe to the RPC service from the Registry. Based on the list of services returned by the Registry, the Client, establish a connection with a specific server and call RPC. When the Server changes, the Registry changes synchronously, and the local service list is adjusted after the Client perceives it. The interaction between the three elements is as follows:
Module Overview
The forest Code layer contains three modules.
Forest-common: basic functions
Forest-rpc: core functions related to rpc are implemented,
Forest-demo: recommended examples of some forest examples
Forest consists of the following layers:
Configuration Overview
The Forest body provides flexible functions, which can be configured based on Annotations or overwrite these configurations through spring xml. Of course, you can construct them in the code.
Configuration priority: annotation default configuration <spring xml configuration (or code Construction)
Annotation-based configuration 1. interface api Configuration
A.inteface api
Class@ServiceProvider
Annotation to provide services,@ServiceProvider
For interface classes, you can configure the following parameters:
Public @ interface ServiceProvider {String serviceName () default ""; // The service name. The isolation level is a service granularity. HaStrategyType haStrategyType () default HaStrategyType. FAIL_FAST; LoadBalanceType loadBalanceType () default LoadBalanceType. RANDOM; String hashKey () default ""; // use int connectionTimeout () default Constants only when the hash policy is used. CONNECTION_TIMEOUT ;}
The interface layer is provided to the caller. The caller's client can inherit@ServiceProvider
Configuration as the default configuration.
B. The interface method can provide specific service through the @ MethodProvider annotation. The parameter configuration is as follows:
Public @ interface MethodProvider {String methodName () default ""; SerializeType serializeType () default SerializeType. kyro; CompressType compressType () default CompressType. none; int timeout () default Constants. DEFAULT_TIMEOUT; // client timeout}
You can specify different serialization methods or compression methods for different business methods.
2. server interface impl Configuration
A. servcieImpl can be passed through@ServiceExport
Annotations are used to publish services. interface impl must be added.@ServiceExport
To publish the service. If no port is specified, the default port is used. To isolate the port from other services, we recommend that you use different ports for release.
public @interface ServiceExport { int port() default Constants.DEF_PORT;}
You can also add@Path
To expose restful paths. Forest supports jersey-based restful services.
B. servcieImpl can be passed through@MethodExport
Annotation to publish Method
The serviceImpl method supports other annotations at the same time, similar to the following:
/*** Jersey is supported. You can enable the http service through configuration. ** @ param str * @ return */@ Path ("/hello/{str }") @ GET @ Produces ("text/plain") @ MethodExport @ Rate (2) @ Override public String say (@ PathParam ("str") String str) {return "say" + str ;}
Spring xml-Based Configuration
There is no way for the client to control the provision of annotation configuration at the interface layer by the provider. If the client wants to customize the configuration, you can choose spring xml-based configuration to overwrite the default configuration recommended by the service provider.
Example:
<Bean id = "methodConfig" class = "com. zhizus. forest. common. config. methodConfig "> <property name =" compressType "> <util: constant static-field =" com. zhizus. forest. common. compressType. none "/> </property> <property name =" serializeType "> <util: constant static-field =" com. zhizus. forest. common. serializeType. fastjson "/> </property> <property name =" timeout "value =" 5000 "/> </bean> <bean id =" sampleServiceProxy "linoleic Ss = "com. zhizus. forest. support. spring. forestProxyFactoryBean "> <property name =" serviceInterface "value =" com. zhizus. forest. demo. api. sampleService "/> <! -- MethodConfMap if not configured, use the interface method to annotate the preceding configuration --> <property name = "methodConfigMap"> <map> <entry key = "echo" value-ref = "methodConfig"/> <entry key = "say" value-ref = "methodConfig"/> </map> </property> </bean>
Sometimes we feel that the xml configuration is very troublesome, but we do not want to use the default configuration mentioned in the service provider annotation. We can use the code to instantiate it ourselves, as shown in the following example:
SampleService sampleService = Forest.from(SampleService.class, ServiceProviderConfig.Builder.newBuilder() .withMethodConfig("say", MethodConfig.Builder.newBuilder() .withCompressType(CompressType.None) .withSerializeType(SerializeType.Fastjson) .build()) .withMethodConfig("echo", MethodConfig.Builder.newBuilder() .withCompressType(CompressType.None) .withSerializeType(SerializeType.Hession2) .build()) .build());
Common functions: compression and serialization
Forest supports multiple compression methods and serialization methods at the protocol level. That is to say, you can specify the compression and serialization methods of a request. The compression and serialization methods have the granularity of each request.
- Supported compression methods: 1.gzip 2. snappy
- Supported serialization methods: 1. hession2, 2. fastjson, 3. kyro
Server Load balancer
RANDOM, ROBBIN, HASH
Fault Tolerance
FAIL_FAST, FAIL_OVER,
Client isolation
Forest supports custom policies. (If a certain number of errors occur in a period of time, the service is automatically isolated and restored after a period of time)
Built-in connection pool
Forest uses a common-pool2 connection pool to manage connections. Each client's proxy corresponds to one or more pools and no additional connection pool is required to provide throughput.
Example of hystrix-based Forest supported by third-party services
Hystrix is an excellent service fault-tolerant component. We recommend that you use hystrix to pack the services provided by forest to enhance the service fault-tolerant and degraded capabilities.
Server support connector & throttling
Forest can be used to customize the interceptor or throttling. You only need to add the corresponding annotation on the release method.
@Componentpublic class SampleServiceCommand { @Resource(name = "sampleServiceProxy") SampleService remoteServiceRef; @HystrixCommand(groupKey = "ExampleGroup", commandKey = "HelloWorld", threadPoolKey = "HelloWorldPool", fallbackMethod = "sayFallback") public String say(String str) { String say = remoteServiceRef.say(str); System.out.println("say:" + say); str.toString(); return say; } public String sayFallback(String str) { return "sayFallBack:" + str; }}
The xml configuration is as follows:
<Context: component-scan base-package = "com. zhizus. forest. demo. client"/> <! -- Add hystrix aop --> <aop: aspectj-autoproxy/> <bean id = "hystrixAspect" class = "com. netflix. hystrix. contrib. javanica. aop. aspectj. hystrixCommandAspect "> </bean> <bean id =" methodConfig "class =" com. zhizus. forest. common. config. methodConfig "> <property name =" compressType "> <util: constant static-field =" com. zhizus. forest. common. compressType. none "/> </property> <property name =" serializeType "> <util: constant sta Tic-field = "com. zhizus. forest. common. serializeType. fastjson "/> </property> <property name =" timeout "value =" 5000 "/> </bean> <bean id =" zkRegistry "class =" com. zhizus. forest. common. registry. impl. zkServiceDiscovery "> <property name =" connStr "value =" localhost: 2181 "/> </bean> <bean id =" sampleServiceProxy "class =" com. zhizus. forest. support. spring. forestProxyFactoryBean "> <property name =" serviceInterface "va Lue = "com. zhizus. forest. demo. api. SampleService"/> <! -- Register a local database --> <property name = "discovery" ref = "zkRegistry"/> <! -- MethodConfMap if not configured, use the interface method to annotate the preceding configuration --> <property name = "methodConfigMap"> <map> <entry key = "echo" value-ref = "methodConfig"/> <entry key = "say" value-ref = "methodConfig"/> </map> </property> </bean>
Jersey support
Sometimes, we need to expose http Services for third-party service calls or tests at the same time. In these cases, Forest supports jersey-based restful services.
Http service: server. properties
http.server.start=true
For other parameter configurations, see com. zhizus. forest. common. config. ServerConfig. We can use the jersey-based restful service without hindrance.
Performance Testing
A simple stress test was conducted on Forest, and it was found that in the serialization mode of hession2, The win64 8 GB memory can reach + tps. In other cases, the tps is also 3 w +.
Of course, Forest should have some performance optimization space. So far, it has not been optimized.
Client code:
public static void benchmarkTest() throws Exception { final SampleService sampleService = Forest.from(SampleService.class); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 20; i++) { executorService.submit(new Runnable() { @Override public void run() { for (int i = 0; i < 1000000000; i++) { String say = sampleService.echo("hello"); if (i % 10000 == 0) { System.out.println(say); } } } }); } }
The server is added with the metric interceptor that comes with the system:
@Interceptor("metricInterceptor") @MethodExport @Override public String echo(String msg) { return "echo>>> " + msg; }
Console log:
23:10:10.295 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:83342, avgTime:0, maxTime:63, minTime:023:10:11.298 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:86271, avgTime:0, maxTime:63, minTime:023:10:12.295 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:86063, avgTime:0, maxTime:63, minTime:0
Source Code address: forest
All heroes are welcome.