如何使用Netty开发实现高性能的RPC服务器

合集下载

netty 实现原理

netty 实现原理

netty 实现原理Netty 是一种基于Java NIO(Non-blocking I/O)的网络编程框架,用于开发高性能的、可扩展的网络服务器和客户端应用程序。

Netty 的实现原理主要包括以下几个方面:1. Reactor 模式:Netty 使用 Reactor 模式来处理并发请求。

Reactor 模式由三部分组成:Selector、Acceptor 和 Handler。

Selector 负责监听客户端的连接请求,当有新的连接到达时,Selector 将连接注册到对应的 Handler 中,然后由 Handler 进行处理。

2. NIO Channel 和 Buffer:Netty 使用 NIO 的 Channel 和Buffer 来实现非阻塞的网络通信。

Channel 是对原生 Java NIO 中的SocketChannel 的封装,Channel 可以通过 Selector 来进行事件监听和处理。

Buffer 是对 Java NIO 中的 ByteBuffer 的封装,用于读写网络数据。

3. 线程模型:Netty 采用了多线程模型来处理并发请求。

Netty 将读写事件的处理分离到不同的线程池中,读事件由专门的线程池处理,写事件则由 I/O 线程池处理。

这样能够充分利用多核 CPU 的优势,提高并发处理能力。

4. 异步编程模型:Netty 使用异步的方式处理网络请求。

当有网络事件发生时,Netty 会立即返回,并将相应的处理逻辑提交到线程池中进行处理。

这样可以避免线程的阻塞,提高系统的吞吐量。

5. 编解码器:Netty 提供了一系列的编解码器,用于将 Java 对象转换为网络数据包,并在收到数据包时将其转换为 Java 对象。

这样可以简化编程工作,并提高网络传输的效率。

总的来说,Netty 的实现原理是基于 Reactor 模式、NIO Channel 和 Buffer、多线程模型以及异步编程模型来实现高性能、可扩展的网络编程框架。

netty 用法

netty 用法

netty 用法
Netty 是一个基于 Java 的网络应用框架,用于快速、简单地开
发高性能、高可靠性的网络服务器和客户端应用程序。

下面是Netty 的一些主要用法:
1. 异步网络编程:Netty 提供了高度可扩展的异步事件驱动模型,允许并发地处理数千个连接。

通过使用 Netty 的异步编程
模型,可以轻松地编写高效的服务器和客户端应用程序。

2. 高性能的传输:Netty 提供了一组用于传输的抽象,如NIO、Epoll(Linux 2.6+ 版本)、OIO(旧 I/O)等,并通过使用非
阻塞 I/O 操作实现了高性能的数据传输。

3. TCP/UDP 支持:Netty 提供了对 TCP 和 UDP 的支持,开发
者可以轻松地构建各种类型的服务器和客户端应用程序,如HTTP、FTP、DNS、WebSocket 等。

4. 处理器链:Netty 使用处理器链(Pipeline)的概念来处理和
转换网络数据。

每个处理器(Handler)都有其特定的功能,
通过将多个处理器链接在一起,可以构建复杂的网络协议处理逻辑。

5. 简单的线程模型:Netty 提供了简单而灵活的线程模型,可
以根据应用程序的需要配置不同类型的线程池,例如单线程、多线程、线程池等,以实现最佳的性能和资源利用。

6. 即时重连和故障转移:Netty 提供了自动的即时重连和故障
转移机制,使得在网络故障时能够快速地重连,并选择备用服务器进行通信,提高了应用程序的可靠性。

总之,Netty 是一个功能丰富、易用且高性能的网络应用框架,可以满足开发者构建各种类型的服务器和客户端应用程序的需求。

netty应用案例

netty应用案例

netty应用案例Netty是一个高性能的网络通信框架,被广泛应用于各种领域。

下面我将从多个角度给出一些Netty的应用案例。

1. 服务器开发,Netty在服务器开发中得到了广泛应用。

它提供了高性能的网络通信能力,可以处理大量的并发连接。

很多大型互联网公司的服务器后端都使用了Netty,例如游戏服务器、即时通讯服务器、实时数据推送服务器等。

2. 分布式系统,Netty可以作为分布式系统中的通信框架,用于不同节点之间的数据传输和通信。

例如,分布式缓存系统、分布式数据库系统等都可以使用Netty来实现节点之间的通信。

3. 实时数据处理,Netty的高性能和低延迟特性使其在实时数据处理领域得到了广泛应用。

例如,金融领域的实时行情系统、实时交易系统等都可以使用Netty来处理高并发的实时数据。

4. IoT(物联网)应用,Netty可以用于构建物联网平台,用于设备之间的通信和数据传输。

例如,智能家居系统、智能工厂系统等都可以使用Netty来实现设备之间的通信。

5. 高性能代理服务器,Netty可以作为代理服务器的核心框架,用于实现高性能的代理功能。

例如,反向代理服务器、负载均衡服务器等都可以使用Netty来实现。

6. 即时通讯应用,Netty的高性能和可靠性使其成为构建即时通讯应用的理想选择。

例如,聊天应用、视频通话应用等都可以使用Netty来实现实时通信功能。

总结来说,Netty在各种领域中都有广泛的应用。

它的高性能、可靠性和灵活性使其成为构建高性能网络应用的首选框架。

无论是服务器开发、分布式系统、实时数据处理,还是物联网应用、代理服务器、即时通讯应用,Netty都能提供强大的支持。

netty应用案例

netty应用案例

netty应用案例Netty是一个用于快速开发可扩展的网络应用程序的Java框架。

它的设计目标是提供一个高性能、高速度和可靠的网络服务器和客户端框架。

Netty是一个事件驱动的网络编程框架,通过轻量级的、非阻塞的异步网络通信,提供了快速的数据传输和处理。

下面将介绍几个Netty的应用案例。

1.聊天服务器一个常见的使用Netty的案例是构建一个实时聊天服务器。

Netty可以通过NIO的非阻塞方式处理大量的并发连接,使得用户可以实时地发送和接收消息。

使用Netty可以轻松地实现高性能的聊天服务器,支持多种协议和编解码方式。

2.实时数据流处理Netty可以用于构建实时数据流处理应用程序,比如实时数据分析、实时监控等。

Netty提供了高性能的异步网络通信能力,可以快速地传输大量的数据流,并同时支持高并发连接。

这使得Netty成为处理实时数据流的理想框架。

3.代理服务器Netty可以作为代理服务器的核心框架,用于实现HTTP、HTTPS、SOCKS等多种类型的代理服务器。

Netty提供了高性能的异步网络通信,可以有效地处理代理请求,并将其转发到目标服务器。

同时,Netty支持自定义的编解码器,可以对请求进行解析和编码。

4.游戏服务器Netty在构建游戏服务器方面也有广泛的应用。

Netty的非阻塞和事件驱动的设计使得它能够支持高并发连接和实时的消息传输,非常适合用于构建多人在线游戏服务器。

此外,Netty还提供了一些常用的功能,如心跳检测、断线重连等,方便开发者构建稳定可靠的游戏服务器。

5.分布式系统通信Netty可以作为分布式系统中节点之间通信的框架。

在一个分布式系统中,节点之间需要快速地发送和接收消息,以实现数据同步和协调工作。

Netty提供了高性能的网络通信能力,并支持各种通信协议和编解码方式,使得节点之间的通信变得简单和高效。

在以上应用示例中,Netty都发挥了它异步非阻塞的优势,通过事件驱动的方式处理并发连接,提供了高性能的网络通信能力。

rpc服务搭建方法

rpc服务搭建方法

rpc服务搭建方法
搭建RPC服务通常涉及以下几个步骤,包括选择合适的RPC框架、定义接口、实现服务端和客户端等。

接下来我将从多个角度分别介绍这些步骤。

首先,选择合适的RPC框架非常重要。

市面上有很多成熟的RPC框架可供选择,比如Dubbo、gRPC、Thrift等。

选择框架时需要考虑技术栈的兼容性、性能、易用性等因素,并根据项目需求进行权衡。

其次,定义接口是搭建RPC服务的关键一步。

在RPC服务中,接口定义语言(IDL)起着非常重要的作用,它能够定义服务接口、数据结构等。

常用的IDL包括Protobuf、Thrift IDL等。

在定义接口时,需要考虑接口的清晰性、易用性以及版本兼容性等因素。

然后,实现服务端是搭建RPC服务的核心步骤之一。

服务端负责接收客户端的请求并进行处理,然后将结果返回给客户端。

在实现服务端时,需要考虑并发处理、容错机制、性能优化等方面的问题,保证服务的稳定性和可靠性。

最后,实现客户端也是搭建RPC服务的重要一环。

客户端负责
向服务端发起请求,并处理服务端返回的结果。

在实现客户端时,
需要考虑连接管理、负载均衡、超时处理等问题,以保证客户端能
够稳定地与服务端进行通信。

总的来说,搭建RPC服务需要综合考虑框架选择、接口定义、
服务端实现和客户端实现等多个方面,确保整个RPC系统能够稳定、高效地运行。

希望这些信息能够帮助到你。

如何构建高可用的分布式RPC服务系统

如何构建高可用的分布式RPC服务系统

如何构建高可用的分布式RPC服务系统构建高可用的分布式RPC服务系统随着业务的不断扩展,单个服务已经无法满足需求,因此很多公司会采用分布式架构来进行横向扩展,提高系统的性能和可扩展性。

RPC(Remote Procedure Call),即远程过程调用,是分布式架构中很重要的一环。

如何构建高可用的分布式RPC服务系统,是一个需要思考和解决的问题。

一、RPC概念和基本原理RPC是一种远程服务调用的协议,允许客户端和服务端的程序在不同的计算机上运行,通过网络连接来通信和传递数据。

RPC的基本原理是将服务端的方法封装成远程调用接口,在客户端调用远程接口时,通过网络传输数据到服务端,服务端接收到请求后执行对应的方法,并将结果返回给客户端。

RPC协议有很多种实现方式,例如dubbo、gRPC、thrift等。

二、分布式RPC服务系统的需求和挑战分布式RPC服务系统的要求是高可用、高性能、可扩展、易于维护,同时也需要满足安全、容错、可监控等方面的需求。

实现一个高可用的分布式RPC服务系统,需要解决以下挑战:1、负载均衡在分布式架构中,服务会部署在多个节点上,客户端需要选择一个可用的节点来调用服务。

因此需要实现负载均衡机制,将请求均匀地分配到各个节点上,避免某个节点的负载过高导致性能下降或服务崩溃。

负载均衡的实现方式有很多,例如轮询、随机、权重等。

2、故障恢复由于分布式架构中的节点数量较多,节点之间的网络交互也比较复杂。

因此节点的故障是不可避免的,需要实现故障恢复机制,当某个节点出现故障时,能够自动切换到其他可用节点继续提供服务。

故障恢复的实现方式有很多,例如心跳检测、状态同步、备份等。

3、服务治理分布式RPC服务系统中的服务很多,需要对服务进行统一的管理和监控,包括服务的部署、升级、调试等。

因此需要实现服务治理机制,能够对服务进行统一的配置、路由、限流等操作,以保证服务的稳定性和可靠性。

服务治理的实现方式有很多,例如注册中心、分布式配置中心、限流熔断等。

netty 实现原理

netty 实现原理

Netty是一个高性能、异步事件驱动的网络应用框架,基于Java NIO实现。

它的实现原理主要包括以下几个方面:
1. 异步事件驱动:Netty采用异步事件驱动模型,能够处理并发连接和快速响应事件。

当有网络事件发生
时,Netty会将其封装为一个事件对象,然后通过事件队列将其传递给处理器进行处理。

处理器根据事件的类型和业务逻辑进行相应的处理。

2. IO多路复用:Netty使用Java NIO实现IO多路复用技术,可以同时处理多个网络连接。

通过使用
Selector机制,Netty可以在一个单线程中管理多个Channel,从而实现非阻塞IO操作。

这大大提高了程序的并发性能和吞吐量。

3. 高效编解码器:Netty内置了多种编解码器,如ByteToMessageDecoder和
MessageToByteEncoder等,这些编解码器能够高效地将字节流转换为消息对象或者将消息对象转换为字节流。

用户可以根据自己的需求选择合适的编解码器来处理网络数据。

4. 线程模型:Netty采用了高效的线程模型,可以支持单线程、多线程和主从多线程等多种模型。

这些线
程模型能够在不同场景下发挥不同的优势,从而满足不同的需求。

5. 容错机制:Netty内部实现了多种容错机制,如快速失败和优雅失败等。

当发生异常时,Netty能够快
速地捕获异常并进行处理,保证程序的稳定性和可靠性。

综上所述,Netty通过异步事件驱动、IO多路复用、高效编解码器、线程模型和容错机制等技术实现高性能的网络应用框架。

这些技术使得Netty在处理高并发、低延迟的网络请求方面具有出色的性能和可靠性。

netty channelpool 用法

netty channelpool 用法

一、概述Netty是一个基于NIO的网络应用框架,它可以快速地开发可维护的高性能协议服务器和客户端。

Channel是Netty的核心组件,它代表了一个网络连接,通过Channel可以进行读写操作。

在实际的应用中,为了提高性能和减少资源消耗,通常会使用Channelpool来管理Channel的复用。

二、Channelpool的作用Channelpool主要用于管理和复用Channel,可以通过Channelpool 来提高应用的性能和降低资源消耗。

当需要与多个远程服务进行通信时,如果为每个通信创建新的Channel,对资源的消耗会很大。

而通过Channelpool可以在需要通信时从池中获取可用的Channel,使用完毕后再归还给池,这样可以减少频繁创建和关闭Channel带来的性能开销。

三、Channelpool的用法1.初始化Channelpool当需要使用Channelpool时,需要首先初始化Channelpool。

可以通过ChannelPoolMap接口中的newPool方法来创建Channelpool,例如:```javaChannelPoolMap<InetSocketAddress, SimpleChannelPool> poolMap = new AbstractChannelPoolMap<InetSocketAddress,SimpleChannelPool>() {Overrideprotected SimpleChannelPool newPool(InetSocketAddress key) {Bootstrap bootstrap = new Bootstrap();bootstrap.group(new NioEventLoopGroup());bootstrap.channel(NioSocketChannel.class);return newFixedChannelPool(bootstrap.remoteAddress(key), new MyChannelPoolHandler(), 10);}};```在上述代码中,首先创建了一个ChannelPoolMap对象poolMap,然后通过newPool方法初始化了Channelpool。

netty应用案例

netty应用案例

netty应用案例一、Netty简介etty是一款高性能、异步事件驱动的网络应用框架,主要用于Java 领域。

它提供了完善的网络编程解决方案,使得开发者能够轻松实现高性能、高可靠性的网络应用。

Netty 底层使用Java NIO 实现,并提供了丰富的API 和工具,使得开发者能够快速构建网络应用。

二、Netty应用场景1.网络协议开发:Netty 提供了对多种网络协议的支持,如TCP、UDP、HTTP、WebSocket 等,开发者可以基于Netty 快速实现自定义的网络协议。

2.网络应用框架:许多开源的Java 网络应用框架,如Spring WebFlux、Vert.x 等,都采用了Netty 作为底层通信引擎。

3.分布式系统:Netty 的高性能和异步事件驱动特性使其在分布式系统中具有广泛的应用,如消息队列、RPC 等场景。

4.嵌入式系统:由于Netty 的小巧和高性能,它在嵌入式系统和物联网领域也有广泛的应用。

三、Netty案例介绍flixOSS:Netflix 开源了一套基于Netty 的分布式系统框架,包括聊天室、实时消息队列、RPC 等组件,这套框架在Netflix 内部得到了广泛应用,也为其他企业提供了很好的参考。

2.Apache HttpClient:Apache HttpClient 是Java 世界里著名的HTTP 客户端库,采用了Netty 作为底层通信框架。

它提供了丰富的功能,如连接池管理、代理支持、重试策略等,为开发者提供了便捷的HTTP 请求发送功能。

3.Vert.x:Vert.x 是一个基于Netty 的轻量级、事件驱动的Java 应用框架。

它支持多种编程模型,如流式处理、命令行、Web 应用等,并在微服务、并发编程等领域具有广泛的应用。

四、Netty优势与不足1.优势:- 高性能:Netty 采用了Java NIO 实现,具有较高的吞吐量和低延迟特性。

- 异步事件驱动:Netty 采用异步事件驱动架构,使得开发者能够轻松处理高并发场景。

高并发下_netty同步响应方案__概述

高并发下_netty同步响应方案__概述

高并发下netty同步响应方案概述1. 引言1.1 概述在当前互联网时代,高并发已经成为了许多网络应用程序所面临的共同挑战。

在这种情况下,如何实现高效的网络通信成为了一个重要的问题。

本文将针对这一问题,介绍并分析一种适用于高并发场景下的netty同步响应方案。

1.2 文章结构本文共分为五个部分,具体如下:第一部分为引言部分,主要介绍文章概述、文章结构以及研究目的;第二部分是关于高并发下netty同步响应方案的说明,包括高并发背景、netty介绍以及同步响应方案概述;第三部分着重介绍实现高并发的关键技术,其中包括线程池调优、IO多路复用技术以及数据压缩与解压缩技术;第四部分详细描述netty同步响应方案的实现步骤和流程,包括架构设计理念、请求接收与处理流程以及响应返回与处理流程;最后一节为结论与展望部分,主要对实践效果进行分析,并提出可能存在的问题和改进空间。

1.3 目的本文旨在探讨解决高并发场景下netty同步响应问题的方案,并分析其实践效果以及可能存在的问题和改进空间。

通过本文的研究,希望能够为开发者提供一个可行且高效的网络通信方案,在处理大量并发请求时能够保证系统性能和稳定性。

2. 高并发下netty同步响应方案:2.1 高并发背景:随着互联网的快速发展,大量用户同时访问网站或使用应用程序已成为常态。

在高并发情况下,传统的服务器架构可能无法有效地处理大量请求,并且容易导致响应延迟增加、系统崩溃等问题。

因此,需要一个高效且可靠的解决方案来满足高并发环境下的需求。

2.2 netty介绍:Netty是一种基于Java NIO的异步事件驱动网络编程框架,专门设计用于开发高性能、高可靠性的网络应用程序。

它提供了一套易于使用且灵活的API,使开发者能够快速构建各种类型的网络应用。

Netty具有较低的资源消耗和较高的吞吐量,在处理大规模并发连接时表现出色。

2.3 同步响应方案概述:在高并发场景中,客户端请求与服务器之间存在一对多关系,即一个客户端发送多个请求到服务器,并期望同步地接收到每个请求对应的响应。

基于Netty框架的高性能RPC通信系统的设计与实现

基于Netty框架的高性能RPC通信系统的设计与实现

基于Netty框架的高性能RPC通信系统的设计与实现张艳军;王剑;叶晓平;李培远【期刊名称】《工业控制计算机》【年(卷),期】2016(029)005【摘要】This paper designs and implements a RPC communication system,which is a kind of important means to build distributed service system.The system based on C/S architecture,and the framework of the system adopts the producer-consumer model.For a good performance,the design of the system from buffer,thread intercommunication,containers of meth-ods,thread implementation,etc,and the network module is based on Netty.%远程过程调用(RPC)是构建分布式服务系统的重要技术[1],设计并实现了一种RPC通信系统。

该系统基于C/S架构,系统框架采用“生产者-消费者”模型。

为实现系统的良好性能,在接收/发送缓冲区、线程通信、装载方法的容器、线程实现等方面做了良好的设计。

网络模块是基于异步的、事件驱动的Netty框架实现,同时,对序列化方式、定时器也进行了优化。

【总页数】3页(P11-12,15)【作者】张艳军;王剑;叶晓平;李培远【作者单位】杭州电子科技大学,浙江杭州 310018;杭州电子科技大学,浙江杭州 310018;丽水学院,浙江丽水 323000;丽水学院,浙江丽水 323000【正文语种】中文【相关文献】1.一种高性能异步RPC框架的设计与实现 [J], 于天;黄昶2.基于Netty的RPC通信系统的编解码技术研究 [J], 韩星;刘姣;周淑君3.基于Netty的高性能消息中间件设计与实现 [J], 王宁;张娜;于泽川;苏逸凡;包晓安4.基于Netty的高性能消息中间件设计与实现 [J], 王宁;张娜;于泽川;苏逸凡;包晓安5.基于Netty的信息发布通信框架设计与实现 [J], 朱广福因版权原因,仅展示原文概要,查看原文内容请购买。

Netty与RPC

Netty与RPC

Netty与RPC⼀、Netty原理 Netty是⼀个⾼性能、异步事件驱动的NIO框架,基于Java NIO提供的API实现。

它提供了对TCP、UDP和⽂件传输的⽀持,作为⼀个异步NIO框架,Netty的所有IO操作都是异步⾮阻塞的,通过Future-Listener机制,⽤户可以⽅便的主动获取或通过通知机制获得IO操作结果。

⼆、Netty的⾼性能 在IO编程过程中,当需要同时处理多个客户端接⼊请求时,可以利⽤多线程或IO多路复⽤技术进⾏处理。

IO多路复⽤技术通过多个IO阻塞复⽤到同⼀个select的阻塞上,从⽽使得系统在单线程的情况下可以同时处理多个客户端请求。

与传统的多线程/多进程模型相⽐,IO多路复⽤的最⼤优势是系统开销⼩,系统不需要创建新的额外进程或线程,也不需要维护这些进程和线程的运⾏,降低了系统的维护⼯作量,节省了系统资源。

与socket类和serversocket类相对应,NIO也提供了socketchannel和serversocketchannel两种不同的套接字通道实现。

1.多路复⽤通讯⽅式 Netty架构按照Reactor模式设计和实现,它的服务端通信序列图如下: 客户端通信序列图如下: Netty的IO线程NIOEventLoop由于聚合了多路复⽤器Selector,可以同时并发处理成败上千个客户端Channel,由于读写操作都是⾮阻塞的,这就可以充分提升IO线程的运⾏效率,避免由于频繁IO阻塞导致的线程挂起。

2.异步通讯NIO 由于Netty采⽤了异步通信模式,⼀个IO线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO⼀连接⼀线程模型,架构的性能、弹性伸缩能⼒和可靠性都得到了极⼤的提升。

3.零拷贝(direct buffers 使⽤堆外直接内存) 1)Netty的接受和发送ByteBuffer采⽤direct buffers,使⽤堆外直接内存进⾏socket读写,不需要进⾏字节缓冲区的⼆次拷贝。

基于Springboot+Netty实现rpc的方法

基于Springboot+Netty实现rpc的方法

基于Springboot+Netty实现rpc的⽅法附demo 今天翻看了⼀下Netty相关的知识点,正好练练⼿,简单捣⿎了这个demo;这⾥简单梳理⼀下;前提知识点:Springboot、 Netty、动态代理(反射)、反射项⽬整体结构如下:1.在⽗项⽬中引⼊相关依赖;<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.2.RELEASE</version></dependency><dependency><groupId>ty</groupId><artifactId>netty-all</artifactId><version>4.1.48.Final</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>2.0.0-alpha1</version></dependency>2.服务提供模块整体结构如下:这⾥重点关注⼀下 RequestModel 和 ResponseModel 两个消息体类,@Data@AllArgsConstructorpublic class RequestModel {private String requestId;private String serviceName;private String methodName;private Class[] paramTypes;private Object[] paramValues;}@Data@AllArgsConstructorpublic class ResponseModel {private String responseId;private String serviceName;private String methodName;private String code;private String data;}⽤于服务端和客户端的数据传输;再者就是关注 ServerChannelInboundHandler 中的 channelRead0() 报⽂解码处理; @Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {StringBuilder sb = null;RequestModel result = null;try {// 报⽂解析处理sb = new StringBuilder();result = JSON.parseObject(msg, RequestModel.class);requestId = result.getRequestId();String serviceName = result.getServiceName();String methodName = result.getMethodName();Class[] paramType = result.getParamTypes();Object[] paramValue = result.getParamValues();System.out.println(serviceName + " " + methodName);String substring = serviceName.substring(stIndexOf(".") + 1);String s = substring.substring(0, 1).toLowerCase() + substring.substring(1);Object serviceObject = applicationContext.getBean(s);Method method = Class.forName(serviceName).getMethod(methodName, paramType);Object returnValue = method.invoke(serviceObject, paramValue);ResponseModel responseModel = new ResponseModel(requestId,serviceName,methodName,"200",JSON.toJSONString(returnValue)); sb.append(JSON.toJSONString(responseModel));sb.append("\n");System.out.println(sb.toString());ctx.writeAndFlush(sb);} catch (Exception e) {ResponseModel responseModel = new ResponseModel(requestId,"","","500",e.getMessage());String errorCode = JSON.toJSONString(responseModel)+"\n";log.error(errorCode);ctx.writeAndFlush(errorCode);log.error("报⽂解析失败: " + e.getMessage());}}客户端的模块代码如下;这⾥重点关注的是 ClientHandler 类中 channelRead0() ⽅法的处理@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("收到服务端消息: " + msg);ResponseModel responseModel = JSON.parseObject(msg,ResponseModel.class);String responseId = responseModel.getResponseId();Promise promise = LocalPromise.promiseMap.remove(responseId);if(promise != null){String code = responseModel.getCode();if(code.equals("200")){promise.setSuccess(responseModel.getData());}else{promise.setFailure(new RuntimeException(responseModel.getData()));}}}和 AppStart 类中获取获取服务的处理;private <T> T getProxyService(Class<T> serviceClass) {Object service = Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Channel channel = NettyClient.getChannel(host, port);RequestModel requestModel = new RequestModel("100001", method.getDeclaringClass().getName(), method.getName(), method.getParameterTypes(), args); channel.writeAndFlush(JSON.toJSONString(requestModel) + "\n");Promise promise = new DefaultPromise(channel.eventLoop());LocalPromise.promiseMap.put(requestModel.getRequestId(), promise);System.out.println(LocalPromise.promiseMap+">>>>>>>>>>>>");promise.await();if (promise.isSuccess()) {Class<?> returnType = method.getReturnType();return JSON.toJavaObject(JSON.parseObject(promise.getNow()+""),returnType);} else {System.out.println(promise.cause());return promise.cause();}}});return (T) service;}测试结果:总结:这个demo相对⽐较简单,但对于理解rpc 远程调⽤有⼀定帮助,最后分享⼀下这个代码地址:到此这篇关于基于Springboot+Netty实现rpc功能的⽂章就介绍到这了,更多相关Springboot Nett实现rpc内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。

基于Netty打造RPC服务器设计经验谈

基于Netty打造RPC服务器设计经验谈

基于Netty打造RPC服务器设计经验谈 ⾃从在园⼦⾥,发表了两篇如何基于Netty构建RPC服务器的⽂章:、之后,收到了很多同⾏、园友们热情的反馈和若⼲个优化建议,于是利⽤闲暇时间,打算对原来NettyRPC中不合理的模块进⾏重构,并且增强了⼀些特性,主要的优化点如下:1. 在原来编码解码器:JDK原⽣的对象序列化⽅式、kryo、hessian,新增了:protostuff。

2. 优化了NettyRPC服务端的线程池模型,⽀持LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue,并扩展了多个线程池任务处理策略。

3. RPC服务启动、注册、卸载⽀持,通过Spring中⾃定义的nettyrpc标签进⾏统⼀管理。

在最早的NettyRPC消息编解码插件中,我使⽤的是:JDK原⽣的对象序列化(ObjectOutputStream/ObjectInputStream)、Kryo、Hessian这三种⽅式,后续有园友向我提议,可以引⼊Protostuff序列化⽅式。

经过查阅⽹络的相关资料,Protostuff基于Google protobuf,但是提供了更多的功能和更简易的⽤法。

原⽣的protobuff是需要数据结构的预编译过程,需要编写.proto格式的配置⽂件,再通过protobuf提供的⼯具翻译成⽬标语⾔代码,⽽Protostuff则省略了这个预编译的过程。

以下是Java主流序列化框架的性能测试结果(图⽚来⾃⽹络): 可以发现,Protostuff序列化确实是⼀种很⾼效的序列化框架,相⽐起其他主流的序列化、反序列化框架,其序列化性能可见⼀斑。

如果⽤它来进⾏RPC消息的编码、解码⼯作,再合适不过了。

现在贴出具体的Protostuff序列化编解码器的实现代码。

⾸先是定义Schema,这个是因为Protostuff-Runtime实现了⽆需预编译对java bean进⾏protobuf序列化/反序列化的能⼒。

netty服务器解析参数

netty服务器解析参数

netty服务器解析参数摘要:1.引言ty 服务器简介3.解析Netty 服务器参数3.1 端口号3.2 线程模型3.3 缓冲区大小3.4 连接参数3.5 安全参数4.参数配置实例5.总结正文:etty 是一个高性能的NIO 框架,用于构建异步、事件驱动的网络应用程序。

在Netty 中,服务器参数的配置对服务器的性能和稳定性有着至关重要的影响。

本文将详细解析Netty 服务器的各种参数,以帮助大家更好地理解和使用Netty。

1.引言etty 是一个基于Java 的高性能、异步事件驱动的网络应用框架,广泛应用于网络编程、游戏服务器、RPC 框架等领域。

在使用Netty 搭建服务器时,我们需要根据实际需求配置一系列参数,以满足性能和稳定性的要求。

ty 服务器简介etty 服务器是一个基于NIO(非阻塞IO)的TCP 服务器,它通过事件驱动的方式处理网络连接和数据收发。

在使用Netty 搭建服务器时,我们需要配置一系列参数,如端口号、线程模型、缓冲区大小等,以满足不同场景的需求。

3.解析Netty 服务器参数3.1 端口号端口号是Netty 服务器的一个重要参数,用于标识服务器的通信端口。

通常情况下,我们无需手动设置端口号,因为Netty 会自动分配一个可用的端口号。

当然,在特定场景下,如需要与其他服务器或应用程序共享端口时,我们可以手动设置端口号。

3.2 线程模型etty 支持多种线程模型,如单线程、多线程、主从线程等。

线程模型决定了服务器如何处理并发连接和任务分发。

根据实际需求选择合适的线程模型可以有效提高服务器的性能和稳定性。

3.3 缓冲区大小缓冲区大小是Netty 服务器的一个重要参数,它决定了数据在发送和接收过程中的缓存空间。

合理设置缓冲区大小可以减少不必要的内存分配和数据拷贝,从而提高服务器性能。

3.4 连接参数连接参数包括连接超时时间、读超时时间和写超时时间等。

这些参数决定了服务器在建立连接、读取数据和发送数据时的超时行为。

netty mqtt 实现原理 -回复

netty mqtt 实现原理 -回复

netty mqtt 实现原理-回复Netty是基于Java的异步网络应用框架,提供了一系列易于使用的API 来快速地开发高性能和可扩展性的网络应用程序。

而MQTT(Message Queuing Telemetry Transport)是一种轻量级、灵活和可靠的发布-订阅消息传输协议。

Netty MQTT实现原理就是在Netty框架的基础上实现MQTT协议的消息传输,使得开发者可以快速地构建可靠的高性能MQTT服务器和客户端应用。

Netty MQTT实现的主要步骤如下:1. 建立连接:Netty MQTT通过建立TCP连接来与MQTT服务器进行通信。

在建立连接之前,客户端需要首先配置MQTT连接参数,包括MQTT服务器的地址和端口号。

客户端使用Netty的ChannelInitializer来配置ChannelPipeline,在连接建立时初始化处理器。

2. 握手:握手是MQTT连接的第一步。

Netty MQTT客户端发送MQTT Connect报文给服务器,并等待服务器回复。

服务器根据报文中的内容来判断客户端是否有权限连接,如果验证通过,服务器返回MQTT ConnAck报文,表示连接成功。

3. 订阅与发布:Netty MQTT客户端可以通过发送MQTT Subscribe报文来订阅主题。

服务器将收到的订阅信息记录在订阅列表中,并在有消息发布时进行通知。

当客户端收到订阅的消息时,会通过Netty的ChannelPipeline将消息传递给相关处理器。

4. 取消订阅与退订:Netty MQTT客户端可以发送MQTT Unsubscribe报文来取消订阅特定主题。

服务器将从订阅列表中删除相应的数据,并停止向该主题发送消息。

5. 断开连接:当客户端需要断开与MQTT服务器的连接时,可以发送MQTT Disconnect报文。

服务器在接收到断开请求后会清除与该客户端的相关信息,并关闭连接。

Netty MQTT的实现原理体现在上述步骤的具体细节中。

Netty+Spring+ZooKeeper搭建轻量级RPC框架

Netty+Spring+ZooKeeper搭建轻量级RPC框架

Netty+Spring+ZooKeeper搭建轻量级RPC框架本⽂参考本篇⽂章主要参考⾃OSCHINA上的⼀篇"轻量级分布式RPC 框架",因为原⽂对代码的注释和讲解较少,所以我打算对这篇⽂章的部分关键代码做出⼀些详细的解释在本篇⽂章中不详细列出原⽂章的代码,根据试验,原⽂的代码是可以跑通的,只不过原⽂写⾃2014年,它给出的pom⽂件稍微有点旧,我们只需要更新原⽂的框架版本即可,原⽂链接如下另外再推荐⼀篇⽂章,作者在OSCHINA⽂章的基础上增加了部分功能,并且也改进了部分代码代码中涉及到CGLib代理,Java动态代理,以及Protostuff的使⽤,本篇⽂章不作详解,在之后的⽂章中单独作解环境idea 2020 + Spring 5.2.4.RELEASE + Netty 4.1.42.FINAL + ZooKeeper 3.4.10(CentOS 7)任务分⼯注意我们需要先启动服务器进程,服务器的任务如下:与ZooKeeper节点建⽴连接将服务器的地址注册到ZooKeeper中,注册的路径为 /registry/data****加载所有具备@RpcService注解的Bean,保存@RpcService注解的value值(value值保存Bean实现的服务接⼝名)以及这个Bean,作为"服务注册表"以供查询打开Netty的Socket监听端⼝,准备和客户端进⾏连接连接到客户端并接收到客户端发送的消息时,解码消息,按消息中的某个字段值查询服务注册表,然后根据消息的其它字段值和注册表内容决定执⾏哪⼀项服务,最后将服务执⾏结果编码后发送回客户端之后启动客户端进程,客户端的任务如下:从ZooKeeper获得服务端的地址,地址保存在ZooKeeper的 /registry 节点下,地址可能有多个,根据具体情况选取与服务端建⽴连接,发送编码后的消息,请求某项服务接下来举例说明和这些任务相关的代码,以便对这些任务有更好的认识下⾯⼤部分代码中的变量名,⽅法名,类名,接⼝名等都和OSCHINA⽂章中相同两个基本的POJORpcRequest的各个字段的含义如下public class RpcRequest {/*** 全局唯⼀UUID*/private String requestId;/*** 远程服务接⼝名* (原⽂中为className,或许interfaceName更好理解)*/private String className;/*** 远程服务⽅法名*/private String methodName;/*** ⽅法的参数类型*/private Class<?>[] parameterTypes;/*** 要赋给⽅法的实参*/private Object[] parameters;……}RpcResponse的各个字段的含义如下public class RpcResponse {/*** 全局唯⼀UUID*/private String requestId;/*** 错误信息,若error不为空,则result为空*/private Throwable error;/*** 请求响应结果,若result不为空,则error为空*/private Object result;……}与ZooKeeper节点建⽴连接不管是服务端注册地址还是客户端获取地址,我们都需要先连接ZooKeeper获取client,下⾯是connectServer()⽅法的代码⽚段zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMOUT, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {/** 连接成功*/if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {/** 若计数值为零,释放所有等待的线程*/latch.countDown();}}});/** 线程等待*/latch.await();我们向ZooKeeper构造⽅法的第⼀个参数connectionString传递了registryAddress,它可以仅包含⼀个ZooKeeper的地址,如:127.0.0.1:2181,也可以按逗号分隔填写多个地址,有多个地址时可以保证容错性,允许其中⼏个地址⽆法成功建⽴连接To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.The instantiated ZooKeeper client object will pick an arbitrary server from the connectString and attempt to connect to it. If establishment of the connection fails, another server in the connect string will be tried (the order is non-deterministic, as we random shuffle the list), until a connection is established. The client will continue attempts until the session is explicitly closed.第⼆个参数表⽰连接超时时间因为和客户端的连接是异步的,所以需要向第三个参数传递⼀个Watch对象监听状态变化,当监听到连接成功的状态事件时,CountDownLartch对象的值减1这种机制也类似于Netty的ChannelFuture和userEventTriggered()Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - potentially (usually) before the session is fully established. The watcher argument specifies the watcher that will be notified of any changes in state. This notification can come at any point before or after the constructor call has returned.我们注意到这⾥有⼀个奇怪的减1操作,因为CountDownLatch的awaite()⽅法能够保证在计数值为零时才会停⽌线程等待,并且countDown()操作可以发⽣在其它线程内,这就能够应对ZooKeeper构造⽅法异步所导致的,还未与服务器成功建⽴连接⽽继续执⾏后续代码的危险A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.注册服务端地址我们需要创建⼀个临时的znode存放服务端地址值private void creatNode(ZooKeeper zk, String data) {try {byte[] bytes = data.getBytes();String path = zk.create(Constant.ZK_DATA_PATH, bytes,ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);LOGGER.debug("create zookeeper node({} => {})", path, data);} catch (InterruptedException | KeeperException e) {LOGGER.error(e.getMessage(), e);}}create()⽅法对应了ZooKeeper命令⾏的create命令,在程序中,它的参数分别代表存放服务器地址的znode路径,服务器地址值的byte数组形式,开放所有权限,创建znode的策略为——当服务端和ZooKeeper断连时,删除创建的znode,下⼀次创建znode时的name递增The znode will be deleted upon the client's disconnect, and its name will be appended with a monotonically increasing number.这⾥要求⽗节点必须已经创建,原⽂的路径为 /registry/data,那么必须已有 /registry路径下⾯的代码调⽤了connectServer()和createNode(),实现了与ZooKeeper的连接和服务器地址的存放public void register(String data) {if (data != null) {ZooKeeper zk = connectServer();if (zk != null) {creatNode(zk, data);}}}最后在启动服务端的afterPropertiesSet()⽅法内调⽤register()ChannelFuture future = serverBootstrap.bind(host, port).sync();if (serviceRegistry != null) {/** 在 ZooKeeper 注册 server 地址*/serviceRegistry.register(serverAddress);}serverAddress值从properties⽂件中读取服务端加载"服务注册表"从Spring容器获取所有被@RpcService注解的Bean,再获取@RpcService注解的value值,这个value值就是Bean实现的服务接⼝名,handlerMap即为"服务注册表"@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {/** 获取被 @RpcService 注解的类*/Map<String, Object> serviceMap = applicationContext.getBeansWithAnnotation(RpcService.class);if (MapUtils.isNotEmpty(serviceMap)) {for (Object serviceBean : serviceMap.values()) {/** 获取 Annotation 的值*/String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName();/** 存放注册的服务*/handlerMap.put(interfaceName, serviceBean);}}}到这⾥我们注意到"服务注册表"的加载在setApplicationContext()重载⽅法中,⽽上⾯服务端地址的注册却在afterPropertiesSet()⽅法中,这有什么讲究吗?setApplicationContext()⽅法的调⽤在afterPropertiesSet()⽅法之前,可以保证afterPropertiesSet()⽅法的channelHandler查询"服务注册表"时,"服务注册表"已经建⽴Set the ApplicationContext that this object runs in. Normally this call will be used to initialize the object.Invoked after population of normal bean properties but before an init callback such asorg.springframework.beans.factory.InitializingBean.afterPropertiesSet() or a custom init-method.服务端处理客户端消息服务端包括三个ChannelHandler,接收客户端消息和发送客户端消息会经过它们pipeline.addLast(new RpcDecoder(RpcRequest.class)).addLast(new RpcEncoder(RpcResponse.class)).addLast(new RpcHandler(handlerMap));⼀个⾃定义的解码器,⼀个⾃定义的编码器,以及⼀个处理请求消息的RpcHandler此处WebSocket数据帧的解码是基于长度的协议,不过没有应⽤LengthFieldBasedFrameDecoder,采⽤⾃定义实现的解码器关键的处理过程在RpcHandler中,通过CGLib代理获取了服务执⾏后的结果存放到RpcResponse的result字段中private Object handleRpcRequest(RpcRequest request)throws Throwable {/** 远程接⼝名*/String className = request.getClassName();/** 查询"服务注册表"*/Object serviceBean = handlerMap.get(className);Class<?> serviceClass = serviceBean.getClass();String methodName = request.getMethodName();Class<?>[] parameterTypes = request.getParameterTypes();Object[] parameters = request.getParameters();/** 使⽤ CGLib 提供的反射 API* 返回实现类、⽅法名、形参类型和实参指定下的处理结果*/FastClass serviceFastClass = FastClass.create(serviceClass);FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);return serviceFastMethod.invoke(serviceBean, parameters);}handlerMap.get()⽅法的调⽤,便是查询"服务注册表"获取Bean的过程最后在channelRead0()⽅法中,将RpcResponse冲刷到客户端即可客户端获取服务端地址⾸先获取 /registry 下所有的 znode,在我们的程序中,若只启动⼀个服务端,则只有⼀个 znode然后获取所有 znode 的值存放到指定的List中private void watchNode(final ZooKeeper zk) {try {/** 获取 /registry 下的 znode*/List<String> nodeList = zk.getChildren(Constant.ZK_REGISTRY_PATH, new Watcher() {@Overridepublic void process(WatchedEvent event) {/** znode 发⽣变化时重新调⽤ watchNode() 为 nodeList 赋值*/if (event.getType() == Event.EventType.NodeChildrenChanged) {watchNode(zk);}}});List<String> dataList = new ArrayList<>();for (String node : nodeList) {/** 获取 /registry 下每⼀个 znode 注册的 server 地址*/byte[] bytes = zk.getData(Constant.ZK_REGISTRY_PATH + '/' + node, false, null);dataList.add(new String(bytes));}LOGGER.debug("node data: {}", dataList);this.serverList = dataList;} catch (KeeperException | InterruptedException e) {LOGGER.error(e.getMessage(), e);}}getData()⽅法对应了ZooKeeper命令⾏中的get命令,第⼀个参数给定存放服务端地址值的路径,第⼆个参数watcher监听指定路径的znode的data是否被修改或被删除,因为前⾯已经有getChildren()⽅法监听是否有新的znode被创建,或已存在的znode被删除,所以此处设置为false,没有做值修改的严格检查当然我们也可以不设置为false,监听Event.EventType.NodeDataChanged事件是否发⽣,若发⽣,则重新执⾏watchNode()⽅法Return the data and the stat of the node of the given path.If the watch is true and the call is successful (no exception is thrown), a watch will be left on the node with the given path. The watch will be triggered by a successful operation that sets data on the node, or deletes the node.A KeeperException with error code KeeperException.NoNode will be thrown if no node with the given path exists.客户端发送请求OSCHINA原⽂中使⽤Object的wait()⽅法和notifyAll()⽅法来使线程等待和唤醒,但是这实际上存在假死等待的情况,这⾥借⽤另⼀篇⽂章的话:这⾥每次使⽤代理远程调⽤服务,从Zookeeper上获取可⽤的服务地址,通过RpcClient send⼀个Request,等待该Request的Response返回。

netty的工作流程

netty的工作流程

netty的工作流程Netty是一种基于Java NIO的网络应用框架,用于快速开发可扩展的网络服务器和客户端程序。

它提供了一种高级的抽象层,使得网络编程变得简单和易于维护。

本文将介绍Netty的工作流程,帮助读者更好地理解和使用Netty。

一、概述Netty的工作流程可以分为以下几个步骤:初始化、启动、接收请求、处理请求和发送响应。

下面将详细介绍每个步骤的具体操作。

二、初始化在Netty中,初始化是指创建和配置服务器或客户端的基本参数。

包括创建EventLoopGroup、设置Channel类型、配置ChannelPipeline等。

EventLoopGroup是Netty的核心组件,用于处理I/O操作,可以理解为一个线程池。

Channel是网络通信的基本单元,通过Channel可以进行数据的读写操作。

ChannelPipeline是ChannelHandler的容器,用于处理事件和执行业务逻辑。

三、启动启动是指绑定和监听网络端口,准备接收客户端的请求。

在Netty 中,通过ServerBootstrap启动服务器,通过Bootstrap启动客户端。

ServerBootstrap和Bootstrap是Netty提供的启动类,分别用于启动服务器和客户端。

通过调用bind方法绑定端口,并调用sync方法等待服务器启动完成。

四、接收请求一旦服务器启动,就可以开始接收客户端的请求了。

当有新的连接请求到达时,Netty会创建一个新的Channel,并将其注册到EventLoopGroup中。

然后,Netty会触发ChannelActive事件,表示连接已建立。

同时,Netty会将Channel的Pipeline中的ChannelHandler按照顺序执行,处理请求。

五、处理请求在Netty中,请求的处理是通过ChannelHandler来完成的。

ChannelHandler是Netty的另一个核心组件,用于处理事件和执行业务逻辑。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

如何使用Netty开发实现高性能的RPC服务器RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议。

说的再直白一点,就是客户端在不必知道调用细节的前提之下,调用远程计算机上运行的某个对象,使用起来就像调用本地的对象一样。

目前典型的RPC实现框架有:Thrift(facebook开源)、Dubbo(alibaba开源)等等。

RPC框架针对网络协议、网络I/O模型的封装是透明的,对于调用的客户端而言,它就认为自己在调用本地的一个对象。

至于传输层上,运用的是TCP协议、UDP协议、亦或是HTTP协议,一概不关心。

从网络I/O模型上来看,是基于select、poll、epoll方式、还是IOCP (I/O Completion Port)方式承载实现的,对于调用者而言也不用关心。

目前,主流的RPC框架都支持跨语言调用,即有所谓的IDL(接口定义语言),其实,这个并不是RPC所必须要求的。

如果你的RPC框架没有跨语言的要求,IDL就可以不用包括了。

最后,值得一提的是,衡量一个RPC框架性能的好坏与否,RPC的网络I/O模型的选择,至关重要。

在此基础上,设计出来的RPC服务器,可以考虑支持阻塞式同步IO、非阻塞式同步IO、当然还有所谓的多路复用IO模型、异步IO模型。

支持不同的网络IO模型,在高并发的状态下,处理性能上会有很大的差别。

还有一个衡量的标准,就是选择的传输协议。

是基于TCP协议、还是HTTP协议、还是UDP协议?对性能也有一定的影响。

但是从我目前了解的情况来看,大多数RPC开源实现框架都是基于TCP、或者HTTP的,目测没有采用UDP 协议做为主要的传输协议的。

明白了RPC的使用原理和性能要求。

现在,我们能不能撇开那些RPC开源框架,自己动手开发一个高性能的RPC服务器呢?我想,还是可以的。

现在本人就使用Java,基于Netty,开发实现一个高性能的RPC服务器。

如何实现、基于什么原理?并发处理性能如何?请继续接着看下文。

我们有的时候,为了提高单个节点的通信吞吐量,提高通信性能。

如果是基于Java后端的,一般首选的是NIO框架(No-block IO)。

但是问题也来了,Java的NIO掌握起来要相当的技术功底,和足够的技术积累,使用起来才能得心应手。

一般的开发人员,如果要使用NIO开发一个后端的TCP/HTTP服务器,附带考虑TCP粘包、网络通信异常、消息链接处理等等网络通信细节,开发门槛太高,所以比较明智的选择是,采用业界主流的NIO框架进行服务器后端开发。

主流的NIO框架主要有Netty、Mina。

它们主要都是基于TCP通信,非阻塞的IO、灵活的IO线程池而设计的,应对高并发请求也是绰绰有余。

随着Netty、Mina 这样优秀的NIO框架,设计上日趋完善,Java后端高性能服务器开发,在技术上提供了有力的支持保障,从而打破了C++在服务器后端,一统天下的局面。

因为在此之前,Java的NIO 一直受人诟病,让人敬而远之!既然,这个RPC服务器是基于Netty的,那就在说说Netty吧。

实际上Netty是对JAVA NIO 框架的再次封装,它的开源网址是http://netty.io/,本文中使用的Netty版本是:4.0版本,可以通过/netty/downloads/netty-4.0.37.Final.tar.bz2,进行下载使用。

那也许你会问,如何使用Netty进行RPC服务器的开发呢?实际不难,下面我就简单的说明一下技术原理:1、定义RPC请求消息、应答消息结构,里面要包括RPC的接口定义模块、包括远程调用的类名、方法名称、参数结构、参数值等信息。

2、服务端初始化的时候通过容器加载RPC接口定义和RPC接口实现类对象的映射关系,然后等待客户端发起调用请求。

3、客户端发起的RPC消息里面包含,远程调用的类名、方法名称、参数结构、参数值等信息,通过网络,以字节流的方式送给RPC服务端,RPC服务端接收到字节流的请求之后,去对应的容器里面,查找客户端接口映射的具体实现对象。

4、RPC服务端找到实现对象的参数信息,通过反射机制创建该对象的实例,并返回调用处理结果,最后封装成RPC应答消息通知到客户端。

5、客户端通过网络,收到字节流形式的RPC应答消息,进行拆包、解析之后,显示远程调用结果。

上面说的是很简单,但是实现的时候,我们还要考虑如下的问题:1、RPC服务器的传输层是基于TCP协议的,出现粘包咋办?这样客户端的请求,服务端不是会解析失败?好在Netty里面已经提供了解决TCP粘包问题的解码器:LengthFieldBasedFrameDecoder,可以靠它轻松搞定TCP粘包问题。

2、Netty服务端的线程模型是单线程、多线程(一个线程负责客户端连接,连接成功之后,丢给后端IO的线程池处理)、还是主从模式(客户端连接、后端IO处理都是基于线程池的实现)。

当然在这里,我出于性能考虑,使用了Netty主从线程池模型。

3、Netty的IO处理线程池,如果遇到非常耗时的业务,出现阻塞了咋办?这样不是很容易把后端的NIO线程给挂死、阻塞?本文的处理方式是,对于复杂的后端业务,分派到专门的业务线程池里面,进行异步回调处理。

4、RPC消息的传输是通过字节流在NIO的通道(Channel)之间传输,那具体如何实现呢?本文,是通过基于Java原生对象序列化机制的编码、解码器(ObjectEncoder、ObjectDecoder)进行实现的。

当然出于性能考虑,这个可能不是最优的方案。

更优的方案是把消息的编码、解码器,搞成可以配置实现的。

具体比如可以通过:protobuf、JBoss Marshalling方式进行解码和编码,以提高网络消息的传输效率。

5、RPC服务器要考虑多线程、高并发的使用场景,所以线程安全是必须的。

此外尽量不要使用synchronized进行加锁,改用轻量级的ReentrantLock方式进行代码块的条件加锁。

比如本文中的RPC消息处理回调,就有这方面的使用。

6、RPC服务端的服务接口对象和服务接口实现对象要能轻易的配置,轻松进行加载、卸载。

在这里,本文是通过Spring容器进行统一的对象管理。

客户端并发发起RPC调用请求,然后RPC服务端使用Netty连接器,分派出N个NIO连接线程,这个时候Netty连接器的任务结束。

然后NIO连接线程是统一放到Netty NIO 处理线程池进行管理,这个线程池里面会对具体的RPC请求连接进行消息编码、消息解码、消息处理等等一系列操作。

最后进行消息处理(Handler)的时候,处于性能考虑,这里的设计是,直接把复杂的消息处理过程,丢给专门的RPC业务处理线程池集中处理,然后Handler对应的NIO线程就立即返回、不会阻塞。

这个时候RPC调用结束,客户端会异步等待服务端消息的处理结果,本文是通过消息回调机制实现(MessageCallBack)。

其中ty.rpc.core包是NettyRPC的核心实现。

ty.rpc.model包里面,则封装了RPC消息请求、应答报文结构,以及RPC服务接口与实现绑定关系的容器定义。

ty.rpc.config里面定义了NettyRPC的服务端文件配置属性。

下面先来看下ty.rpc.model包中定义的内容。

复制代码/*** @filename:MessageRequest.java** Newland Co. Ltd. All rights reserved.** @Description:rpc服务请求结构* @author tangjie* @version 1.0**/package ty.rpc.model;import java.io.Serializable;import ng.builder.ToStringBuilder;import ng.builder.ToStringStyle;public class MessageRequest implements Serializable {private String messageId;private String className;private String methodName;private Class<?>[] typeParameters;private Object[] parametersVal;public String getMessageId() {return messageId;}public void setMessageId(String messageId) {this.messageId = messageId;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Class<?>[] getTypeParameters() {return typeParameters;}public void setTypeParameters(Class<?>[] typeParameters) {this.typeParameters = typeParameters;}public Object[] getParameters() {return parametersVal;}public void setParameters(Object[] parametersVal) {this.parametersVal = parametersVal;}public String toString() {return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("messageId", messageId).append("className", className).append("methodName", methodName).toString();}}复制代码RPC应答消息结构复制代码/*** @filename:MessageResponse.java** Newland Co. Ltd. All rights reserved.** @Description:rpc服务应答结构* @author tangjie* @version 1.0**/package ty.rpc.model;import java.io.Serializable;import ng.builder.ToStringBuilder; import ng.builder.ToStringStyle;public class MessageResponse implements Serializable {private String messageId;private String error;private Object resultDesc;public String getMessageId() {return messageId;}public void setMessageId(String messageId) {this.messageId = messageId;}public String getError() {return error;}public void setError(String error) {this.error = error;}public Object getResult() {return resultDesc;}public void setResult(Object resultDesc) {this.resultDesc = resultDesc;}public String toString() {return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("messageId", messageId).append("error", error).toString();}}复制代码RPC服务接口定义、服务接口实现绑定关系容器定义,提供给spring作为容器使用。

相关文档
最新文档