基于netty轻量的高性能分布式RPC服务框架forest<下篇>

基于netty轻量的高性能分布式RPC服务框架forest<上篇>

文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南。

基本介绍

Forest是一套基于java开发的RPC框架,除了常规的点对点调用外,Motan还提供服务治理功能,包括服务节点的自动发现、摘除、高可用和负载均衡等。

架构概述

Forest中分为服务提供方(RPC Server),服务调用方(RPC Client)和服务注册中心(Registry)三个角色。

Server提供服务,向Registry注册自身服务,并向注册中心定期发送心跳汇报状态; Client使用服务,需要向注册中心订阅RPC服务,Client根据Registry返回的服务列表,与具体的Sever建立连接,并进行RPC调用。 当Server发生变更时,Registry会同步变更,Client感知后会对本地的服务列表作相应调整。 三者的交互关系如下图:

模块概述

forest代码层面包含三个module

forest-common:一些基础的功用的功能

forest-rpc:和rpc相关的核心功能实现,

forest-demo:一些forest示例的推荐示例

forest从设计的分层包含以下基层,分层设计图如下:

配置概述

Forest体功能了灵活的功能,可以基于注解来配置,也可以通过spring xml来覆盖这些配置,当然你可以可以代码里面自己构造。

配置优先级如下:注解默认配置<spring xml配置(或者代码构造)

基于注解配置

1.interface api的配置

a. inteface api类上可以通过@ServiceProvider注解来提供服务,@ServiceProvider用于接口类上,可以配置参数如下:

public @interface ServiceProvider {
    String serviceName() default "";//服务名称,隔离级别是以一个服务为粒度
    HaStrategyType haStrategyType() default HaStrategyType.FAIL_FAST;
    LoadBalanceType loadBalanceType() default LoadBalanceType.RANDOM;
    String hashKey() default "";// 仅当使用hash策略时候使用
    int connectionTimeout() default Constants.CONNECTION_TIMEOUT;
}

  

接口层提供给调用方,调用方的client可以继承interface上的@ServiceProvider配置作为默认配置。

b. interface method可以通过@MethodProvider注解来提供具体的业务服务,参数配置如下:

public @interface MethodProvider {
    String methodName() default "";
    SerializeType serializeType() default SerializeType.Kyro;
    CompressType compressType() default CompressType.None;
    int timeout() default Constants.DEFAULT_TIMEOUT; // 客户端超时时间
}

  

你可以针对不同的业务方法指定不同的序列化方式或者 压缩方式。

2.server端interface impl的配置

a. servcieImpl可以通过@ServiceExport注解来发布服务,interface impl只有加上了@ServiceExport才会发布服务。 如果不指定port,则使用默认的port,如需和其他业务隔离,建议使用不同的port来发布。

public @interface ServiceExport {
    int port() default Constants.DEF_PORT;
}

  

当然你也可以加上@Path来暴露restful的path,Forest支持基于jersey的restful服务。

b. servcieImpl可以通过@MethodExport注解来发布方法

serviceImpl的方法上面同时可以支持其他的注解,类似如下:

 /**
     * 支持jersey,可以通过配置打开,同时启动http服务
     *
     * @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配置

对于客户端,是没有办法控制提供方提供接口层的注解配置,如果客户端想自定义配置,可以选择基于spring xml的配置来覆盖服务提供方推荐的默认配置。

示例如下:

  <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" class="com.zhizus.forest.support.spring.ForestProxyFactoryBean">
        <property name="serviceInterface" value="com.zhizus.forest.demo.api.SampleService"/>
        <!--methodConfMap如果不配置,则使用接口方法注解上面的配置-->
        <property name="methodConfigMap">
            <map>
                <entry key="echo" value-ref="methodConfig"/>
                <entry key="say" value-ref="methodConfig"/>
            </map>
        </property>
    </bean>

  

有的时候觉得xml配置很麻烦,但是又不想使用服务提供方注解上面的默认配置,那么我们可以可以使用代码自己实例化, 示例如下:

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());

  

常用功能介绍

压缩方式&序列化方式

Forest在协议层面支持多种压缩方式&多种序列化方式,也就是说,你可以指定某一个请求的压缩方式和序列化的方式。压缩方式和序列化方式的粒度都是每个请求的。

  • 目前支持的压缩方式:1.gzip 2.snappy
  • 目前支持的序列化方式:1.hession2, 2.fastjson, 3.kyro

负载均衡

RANDOM, ROBBIN, HASH

容错

 FAIL_FAST,
 FAIL_OVER,

客户端的隔离

Forest支持定制策略,(在一个时间段出现一定次数的错误,则自动将服务隔离开来,一段时间后恢复)

内置连接池

Forest采用common-pool2连接池来管理连接,每个客户端的proxy对应一个或者多个pool,不需要额外的创建连接池来提供吞吐。

第三方服务的支持

Forest基于hystrix使用示例

hystrix是一个非常优秀的服务容错组件,这里也非常推荐能使用hystrix对forest提供的服务做一层包装来加强服务的容错降级能力。

服务端支持连接器&限流

Forest可以自定义拦截器,同时也可以自定义限流。只需要在发布的方法上面加上对应的注解。

@Component
public 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;
    }
}

  

xml 配置如下:

 <context:component-scan base-package="com.zhizus.forest.demo.client"/>

    <!--添加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 static-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" value="com.zhizus.forest.demo.api.SampleService"/>
        <!--注册本地-->
        <property name="discovery" ref="zkRegistry"/>
        <!--methodConfMap如果不配置,则使用接口方法注解上面的配置-->
        <property name="methodConfigMap">
            <map>
                <entry key="echo" value-ref="methodConfig"/>
                <entry key="say" value-ref="methodConfig"/>
            </map>
        </property>
    </bean>

  

对jersey的支持

有时候,我们需要同时暴露http服务供第三方服务调用或者测试。针对这些情况,Forest支持基于jersey的restful服务。

http服务打开的开关:server.properties

http.server.start=true

  

其他的参数配置,详见:com.zhizus.forest.common.config.ServerConfig 之后,我们可以无阻碍的使用基于jersey的restful服务了。

性能测试

对Forest进行了简单的压测,发现在hession2的序列化方式下,win64 8g内存可以达到8w+的tps。 其他的情况也均在3w+的tps。

当然Forest应该还有一些性能优化空间,到目前为止,还没有对其进行一些性能优化。

client代码:

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

  

服务端加上系统自带的metric拦截器:

 @Interceptor("metricInterceptor")
    @MethodExport
    @Override
    public String echo(String msg) {
        return "echo>>> " + msg;
    }

  

console日志:

23:10:10.295 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:83342, avgTime:0, maxTime:63, minTime:0
23:10:11.298 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:86271, avgTime:0, maxTime:63, minTime:0
23:10:12.295 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:86063, avgTime:0, maxTime:63, minTime:0

源代码地址:forest

欢迎各路大侠参与。

时间: 2024-07-30 13:49:29

基于netty轻量的高性能分布式RPC服务框架forest<下篇>的相关文章

RSF 分布式 RPC 服务框架的分层设计

RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知.使用RSF可以点对点调用,也可以分布式调用.部署方式上:可以搭配注册中心,也可以独立使用. 渊源 RSF 的核心思想参考了淘宝HSF.Dubbo 等优秀框架.功能上大体相似,但是实现逻辑完全不同.因此没有什么历史包袱.总的来说对比淘宝HSF少了历史包袱,相比Dubbo更加轻量化.而且还支持了虚拟机

基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

【Rpc】基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

下载-深入浅出Netty源码剖析、Netty实战高性能分布式RPC、NIO+Netty5各种RPC架构实战演练三部曲视频教程

下载-深入浅出Netty源码剖析.Netty实战高性能分布式RPC.NIO+Netty5各种RPC架构实战演练三部曲视频教程 第一部分:入浅出Netty源码剖析 第二部分:Netty实战高性能分布式RPC 第三部分:NIO+Netty5各种RPC架构实战演练

Netty实战高性能分布式RPC

Netty实战高性能分布式RPC 课程观看地址:http://www.xuetuwuyou.com/course/171 课程出自学途无忧网:http://www.xuetuwuyou.com 一.课程用到的软件 netty4.1.6.Final Spring Tool Suite 3.8.2.RELEASE Maven3.1 Spring4 Zookeeper3.4.6 JDK1.8.0_111 二.课程目标 1.快速学习netty的使用 2.自己学会构建高性能服务器 3.熟练使用多线程之间交

基于Netty和SpringBoot实现一个轻量级RPC框架-Client篇

前提 前置文章: <基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> <基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇> 前一篇文章相对简略地介绍了RPC服务端的编写,而这篇博文最要介绍服务端(Client)的实现.RPC调用一般是面向契约编程的,而Client的核心功能就是:把契约接口方法的调用抽象为使用Netty向RPC服务端通过私有协议发送一个请求.这里最底层的实现依赖于动态代理,因此动态代理是动态实现接口的最简单方式(如果

分布式 RPC 系统框架 Dubbo入门介绍

Dubbo 概述 Dubbo 产生的背景 随着互联网项目用户量的急剧增长,访问并发量的陡然增加,一个应用中所有的功能都集中于一个项目中,已经完全不能满足需要了,系统性能急需提升.提升性能的最直接的方式是构建集群,构建具有负载均衡功能的集群.但仅仅依靠增加具有相同业务功能的主机来提高系统的性能,能力是有限的.需要将应用的功能进行分解,分解为多个子工程,每个子工程仅完成某一特定功能,例如,登录子工程.订单业务子工程.支付业务子工程.红包业务子工程等.即,将原来项目中的业务模块,变为了独立工程.在这种

Thrift 个人实战--Thrift RPC服务框架日志的优化

前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还是有一定距离, 本系列将对Thrift作代码解读和框架扩充, 使得它更加贴近生产环境. 本文讲述RPC服务框架中, 日志的重要性, 以及logid的引入. 日志不仅包含丰富的数据(就看是否会挖掘), 而且还是线上服务问题追踪和排查错误最好的方式. 日志级别 采用大家喜闻乐见的log4j作为该RPC服

RPC服务框架探索之Thrift

前言架构服务化后,需要实现一套方便调用各服务的框架,现在开源如日中天,优先会寻找开源实现,如果没有合适自家公司业务的,才会考虑从零开发,尤其是一切以KPI为准绳的公司,谁会跟钱过不去?N个月之前,公司大神就开始调研了,最后选中了Thrift这个RPC服务框架.使用不熟悉的技术,我会感到很恐惧,它就相当于一个黑盒,我对它一无所知,它是如何运转的?出了问题该如何解决?带着一丝不安,查阅了相关技术文档. RPC很早之前听说过soap,restful api,rpc之类的服务协议,一直都没有机会深入实践