基于netty轻量的高性能分布式RPC服务框架forest<上篇>
工作几年,用过不不少RPC框架,也算是读过一些RPC源码。之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子。
顺便也记录一下撸RPC的过程,一来作为总结和回顾,二来算是一种推广。
首先,当然是推广:forest 基于netty轻量的高性能分布式RPC服务框架.
既然是RPC框架,那么首先都弄清楚RPC是什么?
1.如何用通俗的语言解释一下RPC呢?
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC简单的来说就是像调用本地服务一样调用远程服务。
RPC要解决哪些问题呢?
- 首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
- 第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
- 第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
- 第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
- 第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用
2.高性能RPC的设计要点
1) 传输:用什么样的通道将数据发送给对方,BIO、NIO或者AIO,IO模型在很大程度上决定了框架的性能。
2) 协议:采用什么样的通信协议,HTTP或者内部私有协议。协议的选择不同,性能模型也不同。相比于公有协议,内部私有协议的性能通常可以被设计的更优。
3) 线程:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,Reactor线程模型的不同,对性能的影响也非常大。
forest基于netty 4实现(netty 5官方已下架),netty已经帮我们搞定了1)传输,3)线程两点,至于协议也实现了很好的编解码支持。当然netty还有鼎鼎大名的零拷贝,R大在知乎里面说过基于JVM实现socket如果能利用好零拷贝和c++实现的server差别是不大的。
下面我们看看forest的协议设计:
通讯协议包括header和body部分,header部分如下:
基于以上的可以保证基本上forest在性能上有一些可靠的理论保障,只要代码实现的不会太糟,性能应该不成问题。
后面的压测也证实了forest的性能还算可以,在hession2序列化的模式下,win64 8g可以有8w+ tps。
3.forest实现了哪些特性
工作中,我们机会处处离不开RPC。现在要实现一个RPC框架已经不是什么难事了,网上已经有大把的开源项目供我们参考(比如淘宝的dubbo,新浪的motan,百度的protobufRPC等),有很多成熟的第三方开源项目可以依赖,可以说是站在巨人的肩膀上。
一个RPC框架可大可小,比如dubbo,大而全,甚至还可以更大,实现更多的功能;同时也可以很轻量,仅仅做远程调用的功能。至于究竟要把RPC实现成一个什么样子,是一件很私人的事情。
比如我希望的RPC要实现如下功能:
- 支持通过spring配置方式集成,支持注解。
- 支持集成zookeeper等配置服务组件,提供集群环境的服务发现及治理能力。
- 支持动态自定义负载均衡、跨机房流量调整等高级服务调度能力。
- 支持自定义隔离策略,容灾策略
- 通过jersey支持同时暴露restful服务
- 通讯协议层面支持多种序列化方式和压缩方式,
- 基于netty 4.x版本实现
4.快速入门
在pom中添加依赖
<dependency>
<groupId>com.zhizus</groupId>
<artifactId>forest-rpc</artifactId>
<version>0.0.2</version>
</dependency> <dependency>
<groupId>com.zhizus</groupId>
<artifactId>forest-common</artifactId>
<version>0.0.2</version>
</dependency>
1.定义接口
通过注解@ServiceProvider暴露服务,通过@MethodProvider暴露方法默认配置,如:压缩方式,序列化方式,客户端超时时间
@ServiceProvider(serviceName = "sampleService", haStrategyType = HaStrategyType.FAIL_FAST,
loadBalanceType = LoadBalanceType.RANDOM, connectionTimeout = Constants.CONNECTION_TIMEOUT)
public interface SampleService { @MethodProvider(methodName = "say")
String say(String str); @MethodProvider(methodName = "echo", serializeType = SerializeType.Hession2, compressType = CompressType.None)
String echo(String msg);
}
2.实现接口
基于注解@ServiceExport发布服务,基于注解 @MethodExport发布方法,可同时支持jersey发布简单的restful服务
@Path("/sample")
@ServiceExport
public class SampleServiceImpl implements SampleService { /**
* 支持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;
} @Interceptor("metricInterceptor")
@MethodExport
@Override
public String echo(String msg) {
return "echo>>> " + msg;
}
}
3.服务端开发
spring context 配置:
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.zhizus.forest.demo"/>
<bean id="forestServer" class="com.zhizus.forest.support.spring.ForestServerBean"/> </beans>
Server开发
public class SampleServer {
public static void main(String[] args) throws Exception {
new ClassPathXmlApplicationContext(new String[]{"application.xml"});
}
}
4.客户端开发
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);
}
}
}
});
}
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
23:10:13.295 [pool-1-thread-1] INFO MetricInterceptor 34 - methodName:/sampleService/say, current tps:84305, avgTime:0, maxTime:63, minTime:0
Documents
文章太长似乎没太多人愿意看,今天就到此为止。
---------------------------------------------------------------------
补充下篇地址:基于netty轻量的高性能分布式RPC服务框架forest<下篇>
源代码地址:forest
欢迎各路大侠参与。
基于netty轻量的高性能分布式RPC服务框架forest<上篇>的更多相关文章
- 基于netty轻量的高性能分布式RPC服务框架forest<下篇>
基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...
- RSF 分布式 RPC 服务框架的分层设计
RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知 ...
- 基于开源Dubbo分布式RPC服务框架的部署整合
一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目 ...
- 【Rpc】基于开源Dubbo分布式RPC服务框架的部署整合
一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目 ...
- vue-swiper 基于Vue2.0开发 轻量、高性能轮播插件
vue-swiper 基于 Vue2.0 开发,基本满足大部分功能 轻量.高性能轮播插件.目前支持 无缝衔接自动轮播.无限轮播.手势轮播 没有引入第三方库,原生 js 封装,打包之后只有 8.2KB ...
- vue-calendar 基于 vue 2.0 开发的轻量,高性能日历组件
vue-calendar-component 基于 vue 2.0 开发的轻量,高性能日历组件 占用内存小,性能好,样式好看,可扩展性强 原生 js 开发,没引入第三方库 Why Github 上很多 ...
- 基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇
基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇 前提 最近对网络编程方面比较有兴趣,在微服务实践上也用到了相对主流的RPC框架如Spring Cloud Gateway底层也切换 ...
- 基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇
前提 前置文章: Github Page:<基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> Coding Page:<基于Netty和SpringBoot实现 ...
- 基于Netty和SpringBoot实现一个轻量级RPC框架-Client篇
前提 前置文章: <基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> <基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇> 前 ...
随机推荐
- 关于若干php 表单 的重新审视
对于表单验证来说 应该在任何可能的时候对用户输入进行验证(通过客户端脚本).浏览器验证速度更快,并且可以减轻服务器的负载. 如果用户输入需要插入数据库,您应该考虑使用服务器验证.在服务器验证表单的一种 ...
- 聊聊 Apache 开源协议
摘要 用一句话概括 Apache License 就是,你可以用这代码,但是如果开源你必须保留我写的声明:你可以改我的代码,但是如果开源你必须写清楚你改了哪些:你可以加新的协议要求,但不能与我所 公布 ...
- 【bzoj4518】 Sdoi2016—征途
http://www.lydsy.com/JudgeOnline/problem.php?id=4518 (题目链接) 题意 给出n个连续的整数,求将它们分成m段,求最小方差*m^2. Solutio ...
- Python Logging模块的简单使用
前言 日志是非常重要的,最近有接触到这个,所以系统的看一下Python这个模块的用法.本文即为Logging模块的用法简介,主要参考文章为Python官方文档,链接见参考列表. 另外,Python的H ...
- MSSQLServer 纵向表转横向表 横向表转纵向表 行转列 列转行
MSSQLServer 纵向表转横向表 横向表转纵向表 建表语句及插入数据语句: CREATE TABLE Test_y( ) NULL, ) NULL, [Grade] [int] NULL ) ...
- 如何提高账户密码存储的安全性——PasswordSalt的使用
使用 Salt + Hash 将密码加密后再存储进数据库 如果你需要保存密码(比如网站用户的密码),你要考虑如何保护这些密码数据,象下面那样直接将密码写入数据库中是极不安全的,因为任何可以打开数据库的 ...
- Ubuntu14.04安装python3.5
Ubuntu14.04系统会自带python2.7,请不要卸载它,不同版本的Python可以共存. #sudo add-apt-repository ppa:fkrull/deadsnakes #su ...
- CJCMS系列--持久层对MangoDB的支持
持久层添加对MangoDB数据库的支持 using System; using System.Collections.Generic; using System.Linq; using System. ...
- CSS3教程:box-sizing属性的理解
说到 IE 的 bug,一个臭名昭著的例子是它对于“盒模型”的错误解释:在 IE5.x 以及 Quirks 模式的 IE6/7 中,将 border 与 padding 都包含在 width 之内.这 ...
- Python - 类与对象的方法
类与对象的方法