Java性能之优化RPC网络通信
服务框架的核心
- 大型服务框架的核心:RPC通信
- 微服务的核心是远程通信和服务治理
- 远程通信提供了服务之间通信的桥梁,服务治理提供了服务的后勤保障
- 服务的拆分增加了通信的成本,因此远程通信很容易成为系统瓶颈
- 在满足一定的服务治理需求的前提下,对远程通信的性能需求是技术选型的主要影响因素
- 很多微服务框架中的服务通信是基于RPC通信实现的
- 在没有进行组件扩展的前提下,Spring Cloud是基于Feign组件实现RPC通信(基于HTTP+JSON序列化)
- Dubbo是基于SPI扩展了很多RPC通信框架,包括RMI、Dubbo、Hessian等(默认为Dubbo+Hessian序列化)
性能测试
基于Dubbo:2.6.4,单一TCP长连接+Protobuf(响应时间和吞吐量更优),短连接的HTTP+JSON序列化
RPC通信
架构演化
无论是微服务、SOA、还是RPC架构,都是分布式服务架构,都需要实现服务之间的互相通信,通常把这种通信统称为RPC通信
概念
- RPC:Remote Process Call,远程服务调用,通过网络请求远程计算机程序服务的通信技术
- RPC框架封装了底层网络通信和序列化等技术
- 只需要在项目中引入各个服务的接口包,就可以在代码中调用RPC服务(如同调用本地方法一样)
RMI
- RMI:Remote Method Invocation
- RMI是JDK自带的RPC通信框架,已经成熟地应用于EJB和Spring,是纯Java网络分布式应用系统的核心解决方案
- RMI实现了一台虚拟机应用对远程方法的调用可以同对本地方法调用一样,RMI封装好了远程通信的具体细节
实现原理
- RMI远程代理对象是RMI中最核心的组件,除了对象本身所在的虚拟机,其他虚拟机也可以调用此对象的方法
- 这些虚拟机可以分布在不同的主机上,通过远程代理对象,远程应用可以用网络协议和服务进行通信
高并发下的性能瓶颈
- Java默认序列化
- RMI的序列化方式采用的是Java默认序列化,性能不好,而且不支持跨语言
- TCP短连接
- RMI是基于TCP短连接实现的,在高并发情况下,大量请求会带来大量TCP连接的创建和销毁,非常消耗性能
- 阻塞式网络IO
- Socket编程中使用传统的IO模型,在高并发场景下基于短连接实现的网络通信就很容易产生IO阻塞,性能将大打折扣
优化路径
TCP / UDP
- 网络传输协议有TCP和UDP,两个协议都是基于Socket编程
- 基于TCP协议实现的Socket通信是有连接的
- 传输数据要通过三次握手来实现数据传输的可靠性,而传输数据是没有边界的,采用的是字节流模式
- 基于UDP协议实现的Socket通信,客户端不需要建立连接,只需要创建一个套接字发送数据给服务端
- 基于UDP协议实现的Socket通信具有不可靠性
- UDP发送的数据采用的是数据报模式,每个UDP的数据报都有一个长度,该长度与数据一起发送到服务端
- 为了保证数据传输的可靠性,通常情况下会采用TCP协议
- 在局域网且对数据传输的可靠性没有要求的情况下,可以考虑使用UDP协议,UDP协议的效率比TCP协议高
长连接
- 服务之间的通信不同于客户端与服务端之间的通信
- 由于客户端数量众多,基于短连接实现请求,可以避免长时间地占用连接,导致系统资源浪费
- 服务之间的通信,连接的消费端不会像客户端那么多,但消费端向服务端请求的数量却一样多
- 基于长连接实现,可以省去大量建立TCP连接和关闭TCP连接的操作,从而减少系统的性能消耗,节省时间
优化Socket通信
- 传统的Socket通信主要存在IO阻塞,线程模型缺陷以及内存拷贝等问题,Netty4对Socket通信编程做了很多方面的优化
- 实现非阻塞IO:多路复用器Selector实现了非阻塞IO通信
- 高效的Reactor线程模型
- Netty使用了主从Reactor多线程模型
- 主线程:用于客户端的连接请求操作,一旦连接建立成功,将会监听IO事件,监听到事件后会创建一个链路请求
- 链路请求将会注册到负责IO操作的IO工作线程上,由IO工作线程负责后续的IO操作
- Reactor线程模型解决了在高并发的情况下,由于单个NIO线程无法监听海量客户端和满足大量IO操作造成的问题
4.串行设计
- 服务端在接收消息之后,存在着编码、解码、读取和发送等链路操作
- 如果这些操作基于并行实现,无疑会导致严重的锁竞争,进而导致系统的性能下降
- 为了提升性能,Netty采用串行无锁化完成链路操作,提供了Pipeline,实现链路的各个操作在运行期间不会切换线程
5.零拷贝
- 数据从内存发到网络中,存在两次拷贝,先是从用户空间拷贝到内核空间,再从内核空间拷贝到网络IO
- NIO提供的ByteBuffer可以使用Direct Buffer模式
- 直接开辟一个非堆物理内存,不需要进行字节缓冲区的二次拷贝,可以直接将数据写入到内核空间
6.优化TCP参数配置,提高网络吞吐量,Netty可以基于ChannelOption来设置
- TCP_NODELAY:用于控制是否开启Nagle算法
- Nagle算法通过缓存的方式将小的数据包组成一个大的数据包,从而避免大量发送小的数据包,导致网络阻塞
- 在对时延敏感的应用场景,可以选择关闭该算法
- SO_RCVBUF / SO_SNDBUF:Socket接收缓冲区和发送缓冲区的大小
- SO_BACKLOG:指定客户端连接请求缓冲队列的大小
- 服务端处理客户端连接请求是按顺序处理的,同一时间只能处理一个客户端连接
- 当有多个客户端进来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
- SO_KEEPALIVE
- 连接会检查长时间没有发送数据的客户端的连接状态,检测到客户端断开连接后,服务端将回收该连接
- 将该值设置得小一些,可以提高回收连接的效率
定制报文格式
- 设计一套报文,用于描述具体的校验、操作、传输数据等内容
- 为了提高传输效率,可以根据实际情况来设计,尽量实现报体小,满足功能,易解析等特性
字段长度(字节)备注魔数4协议的标识,类似于字节码的魔数,通常为固定数字版本号1序列化算法1Protobuf / Thrift指令1类似于HTTP中的增删改查数据长度4数据N
编解码
- 实现一个通信协议,需要兼容优秀的序列化框架
- 如果只是单纯的数据对象传输,可以选择性能相对较好的Protobuf序列化,有利于提高网络通信的性能
Linux的TCP参数设置
三次握手
四次挥手
配置项
1.fs.file-max = 194448 / ulimit
2.net.ipv4.tcp_keepalive_time
3.net.ipv4.tcp_max_syn_backlog
4.net.ipv4.ip_local_port_range
5.net.ipv4.tcp_max_tw_buckets
6.net.ipv4.tcp_tw_reuse
备注
1.Linux默认单个进程可以打开的文件数量上限为1024,Socket也是文件
2.与Netty的SO_KEEPALIVE配置项的作用一致
3.SYN队列的长度,加大队列长度,可以容纳更多等待连接的网络连接数
4.客户端连接服务器时,需要动态分配源端口号,该配置项表示向外连接的端口范围
5. 当一个连接关闭时,TCP会通过四次挥手来完成一次关闭连接操作,在请求量比较大的情况下,消费端会有大量TIME_WAIT状态的连接,该参数可以限制TIME_WAIT状态的连接数量,如果TIME_WAIT的连接数量超过该值,TIME_WAIT将会立即被清除掉并打印警告信息
6.客户端每次连接服务器时,都会获得一个新的源端口以实现连接的唯一性,在TIME_WAIT状态的连接数量过大的情况下,会增加端口号的占用时间,由于处于TIME_WAIT状态的连接属于关闭连接,所以新创建的连接可以复用该端口号
最后
又到了我们最喜欢的资料分享环节了
快来关注我吧!
关注+转发,加我的交流群772300343获取哦!
我是小架,我们下篇文章再见!
Java性能之优化RPC网络通信的更多相关文章
- Java性能 -- Lock优化
Lock / synchronized Lock锁的基本操作是通过乐观锁实现的,由于Lock锁也会在阻塞时被挂起,依然属于悲观锁 synchronized Lock 实现方式 JVM层实现 Jav ...
- Java 性能优化之 String 篇
原文:http://www.ibm.com/developerworks/cn/java/j-lo-optmizestring/ Java 性能优化之 String 篇 String 方法用于文本分析 ...
- java 性能优化(代码优化)
参考博文: java 性能优化:35 个小细节,让你提升 java 代码的运行效率
- java 性能优化:35 个小细节,让你提升 java 代码的运行效率
前言 代码 优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没 ...
- 读书笔记系列之java性能优化权威指南 一 第一章
主题:java性能优化权威指南 pdf 版本:英文版 Java Performance Tuning 忽略:(0~24页)Performance+Acknowledge 1.Strategies, A ...
- [原创]Java性能优化权威指南读书思维导图
[原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt Binu John 译者: 柳飞 ...
- 如何优化 Java 性能?
对于 Java 性能比较关心的同学大概都知道<Java Performance>这本书,一般而言,很多同学在日常写 Java Code 的时候很少去关心性能问题,但是在我们写 Code 的 ...
- Java性能优化之使用NIO提升性能(Buffer和Channel)
在软件系统中,由于IO的速度要比内存慢,因此,I/O读写在很多场合都会成为系统的瓶颈.提升I/O速度,对提升系统整体性能有着很大的好处. 在Java的标准I/O中,提供了基于流的I/O实现,即Inpu ...
- JAVA性能优化:35个小细节让你提升java代码的运行效率
代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...
随机推荐
- 前端之HTML介绍及使用
一.HTML介绍 1.1 web本质 在pycharm写入一下代码,然后在浏览器地址栏输入地址和端口127.0.0.1:8080,回车,回来运行代码,直接访问客户端发送的内容conn.send(b'& ...
- CentOS 7安装配置MySQL 5.7
概述 前文记录了在Windows系统中安装配置MySQL 5.7(前文连接:https://www.cnblogs.com/Dcl-Snow/p/10513925.html),由于安装部署大数据环境需 ...
- Ubuntu Server中怎样卸载keepalived
场景 在Ubuntu Server中进行安装keepalived ,如果安装过程中出现纰漏,想要重新安装keepalived或者就是想直接卸载keepalived. 我们在安装keepalived时指 ...
- SpringCloud(六):服务网关zuul-API网关(服务降级和过滤)
什么是API网关: 在微服务架构中,通常会有多个服务提供者.设想一个电商系统,可能会有商品.订单.支付.用户等多个类型的服务,而每个类型的服务数量也会随着整个系统体量的增大也会随之增长和变更.作为UI ...
- 关于kubernetes我们还有什么可做的?
kubernetes在容器编排大战中由于应用的可移植性以及支持混合云/多云部署方式上的灵活性.加上开放可扩展的理念,使得周边社区非常活跃.从既有调研结果看,kubernetes已成为容器编排领域的标准 ...
- kafka cmd首个单机例子配置
下载地址:http://kafka.apache.org/downloads http://mirror.bit.edu.cn/apache/kafka/2.3.0/kafka_2.12- ...
- JavaScript学习笔记-----NaN、isNan
NaN / Number.NaN 全局属性 NaN 的值表示不是一个数字(Not-A-Number), NaN 属性的初始值就是 NaN,和 Number.NaN 的值一样. 在现代浏览器中(ES ...
- 大话Git系列之初识版本控制系统(2)
本次接着上次的来介绍版本控制系统,这个讲到的将是Git与Github,说一下什么是Git,什么是GitHub?他们之间的关系是什么? 1.Git 是代码管理的工具 2.GitHub 是基于Git实现的 ...
- Java反射01 : 概念、入门示例、用途及注意事项
1.Java反射定义 本文转载自:https://blog.csdn.net/hanchao5272/article/details/79360452 官方定义如下: Reflection enabl ...
- 关于sql sp_send_dbmail 发送邮件的怪异问题
存储过程,其实就是将sp_send_dbmail采用参数的方式发送邮件,存储过程如下: ALTER PROCEDURE [dbo].[SP_Email_Send] @EmailTo varchar(m ...