本文我们主要是想测试和研究几点:

  • 基于Netty写的最简单的转发HTTP请求的程序,四层和七层性能的差异
  • 三种代理线程模型性能的差异,下文会详细解释三种线程模型
  • 池和非池化ByteBuffer性能的差异

本文测试使用的代码在:
https://github.com/JosephZhu1983/proxytest

在代码里我们实现了两套代理程序:

测试使用的机器配置是(阿里云ECS):

一共三台机器:

  • server 服务器安装了nginx,作为后端
  • client 服务器安装了wrk,作为压测客户端
  • proxy 服务器安装了我们的测试代码(代理)

Nginx后端

nginx 配置的就是默认的测试页(删了点内容,减少内网带宽):

直接对着nginx压测下来的qps是26.6万:

有关四层和七层

四层的代理,我们仅仅是使用Netty来转发ByteBuf。
七层的代理,会有更多额外的开销,主要是Http请求的编码解码以及Http请求的聚合,服务端:

客户端:

这里我们可以想到,四层代理因为少了Http数据的编解码过程,性能肯定比七层好很多,好多少我们可以看看测试结果。

有关线程模型

我们知道作为一个代理,我们需要开启服务端从上游来获取请求,然后再作为客户端把请求转发到下游,从下游获取到响应后,返回给上游。我们的服务端和客户端都需要Worker线程来处理IO请求,有三种做法;

  • A:客户端Bootstrap和服务端ServerBootstrap独立的线程池NioEventLoopGroup,简称IndividualGroup
  • B:客户端和服务端共享一套线程池,简称ReuseServerGroup
  • C:客户端直接复用服务端线程EventLoop,简称ReuseServerThread

以七层代理的代码为例:

接下去的测试我们会来测试这三种线程模型,这里想当然的猜测是方案A的性能是最好的,因为独立了线程池不相互影响,我们接下去看看结果

四层代理 + ReuseServerThread线程模型

Layer4ProxyServer Started with config: ServerConfig(type=Layer4ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerThread, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

四层代理 + IndividualGroup线程模型

Layer4ProxyServer Started with config: ServerConfig(type=Layer4ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=IndividualGroup, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

四层代理 + ReuseServerGroup线程模型

Layer4ProxyServer Started with config: ServerConfig(type=Layer4ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerGroup, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

看到这里其实已经有结果了,ReuseServerThread性能是最好的,其次是ReuseServerGroup,最差是IndividualGroup,和我们猜的不一致。

四层系统监控图

从网络带宽上可以看到,先测试的ReuseServerThread跑到了最大的带宽(后面三个高峰分别代表了三次测试):

从CPU监控上可以看到,性能最好的ReuseServerThread使用了最少的CPU资源(后面三个高峰分别代表了三次测试):

七层代理 + ReuseServerThread线程模型

Layer7ProxyServer Started with config: ServerConfig(type=Layer7ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerThread, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

七层代理 + IndividualGroup线程模型

Layer7ProxyServer Started with config: ServerConfig(type=Layer7ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=IndividualGroup, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

七层代理 + ReuseServerGroup线程模型

Layer7ProxyServer Started with config: ServerConfig(type=Layer7ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerGroup, receiveBuffer=10240, sendBuffer=10240, allocatorType=Unpooled, maxContentLength=2000)

结论一样,ReuseServerThread性能是最好的,其次是ReuseServerGroup,最差是IndividualGroup。我觉得是这么一个道理:

  • 复用IO线程的话,上下文切换会比较少,性能是最好的,后来我也通过pidstat观察验证了这个结论,但是当时忘记截图
  • 复用线程池,客户端有机会能复用到服务端线程,避免部分上下文切换,性能中等
  • 独立线程池,大量上下文切换(观察下来是复用IO线程的4x),性能最差

七层系统监控图

下面分别是网络带宽和CPU监控图:


可以看到明显七层代理消耗更多的资源,但是带宽相比四层少了一些(QPS少了很多)。
出流量比入流量多一点,应该是代码里多加的请求头导致:

试试HttpObjectAggregator设置较大maxContentLength

Layer7ProxyServer Started with config: ServerConfig(type=Layer7ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerThread, receiveBuffer=10240, sendBuffer=10240, allocatorType=Pooled, maxContentLength=100000000)

试试PooledByteBufAllocator

Layer7ProxyServer Started with config: ServerConfig(type=Layer7ProxyServer, serverIp=172.26.5.213, serverPort=8888, backendIp=172.26.5.214, backendPort=80, backendThreadModel=ReuseServerThread, receiveBuffer=10240, sendBuffer=10240, allocatorType=Pooled, maxContentLength=2000)

可以看到Netty 4.1中已经把默认的分配器设置为了PooledByteBufAllocator

总结

这里总结了一个表格,性能损失比例都以第一行直接压Nginx为参照:

结论是:

  • Nginx很牛,其实机器配置不算太好,在配置比较好的物理机服务器上跑的化,Nginx单机百万没问题
  • Netty很牛,毕竟是Java的服务端,四层转发仅损失3% QPS
  • 不管是七层还是四层,复用线程的方式明显性能最好,占用CPU最少
  • 因为上下文切换的原因,使用Netty开发网络代理应该复用IO线程
  • 七层的消耗比四层大很多,即使是Netty也避免不了,这是HTTP协议的问题
  • PooledByteBufAllocator性能比UnpooledByteBufAllocator有一定提升(接近3%)
  • HttpObjectAggregator如果设置较大的最大内容长度,会略微影响点性能

基于Netty的四层和七层代理性能方面的一些压力测试的更多相关文章

  1. Nginx的四层和七层代理

    理论部分: 所谓四层负载均衡,也就是主要通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器,它一般走的是tcp,udp协议    所谓七层负载均衡,也称为“内 ...

  2. linux负载均衡总结性说明(四层负载/七层负载)

    在常规运维工作中,经常会运用到负载均衡服务.负载均衡分为四层负载和七层负载,那么这两者之间有什么不同?废话不多说,详解如下: 一,什么是负载均衡1)负载均衡(Load Balance)建立在现有网络结 ...

  3. 老斜两宗事-七层代理模式还是IP层VPN

    1.七层代理模式还是IP层VPN 非常多人会问,我究竟是使用代理模式呢,还是使用VPN模式,假设我想数据在中间不安全的链路上实现加密保护的话.这个问题有一个背景.那就是,你想保护你的数据,能够使用VP ...

  4. 四层和七层负载均衡的特点及常用负载均衡Nginx、Haproxy、LVS对比

    一.四层与七层负载均衡在原理上的区别 图示: 四层负载均衡与七层负载均衡在工作原理上的简单区别如下图: 概述: 1.四层负载均衡工作在OSI模型中的四层,即传输层.四层负载均衡只能根据报文中目标地址和 ...

  5. Web负载均衡学习笔记之四层和七层负载均衡的区别

    0x00 简介 简单理解四层和七层负载均衡: ① 所谓四层就是基于IP+端口的负载均衡:七层就是基于URL等应用层信息的负载均衡:同理,还有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡. ...

  6. 四层and七层负载均衡

    四层负载/七层负载 在常规运维工作中,经常会运用到负载均衡服务.负载均衡分为四层负载和七层负载,那么这两者之间有什么不同? 废话不多说,详解如下: 1.    什么是负载均衡 1)负载均衡(Load ...

  7. kubernetes系列(十) - 通过Ingress实现七层代理

    1. Ingress入门 1.1 Ingress简介 1.2 原理和组成部分 1.3 资料信息 2. Ingress部署的几种方式 2.1 前言 2.1 Deployment+LoadBalancer ...

  8. 搭建Nginx七层反向代理

    基于https://www.cnblogs.com/Dfengshuo/p/11911406.html这个基础上,在来补充下七层代理的配置方式.简单理解下四层和七层协议负载的区别吧,四层是网络层,负载 ...

  9. 四层LB和七层LB

    总结: 基于MAC地址玩的是二层(虚拟MAC地址接收请求,然后再分配到真实的MAC地址),      基于IP地址玩的是三层(虚拟IP地址接收请求,然后再分配到真实的IP地址),      基于IP地 ...

随机推荐

  1. 权限控制方案之——基于URL拦截

    概述: 在系统开发过程中需要考虑的一个重要的问题就是权限问题,权限问题也是安全问题的一个范畴,我们要求在用户登录系统之后,要控制用户可以访问的系统资源,使得用户只可以访问到系统事先分配好的资源:这里的 ...

  2. Android studio中的6大布局

    1.相对布局代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns: ...

  3. WPF-WPF BitmapEffect (按钮凹凸效果)

    原文:WPF-WPF BitmapEffect (按钮凹凸效果) BitmapEffect位图效果是简单的像素处理操作.它可以呈现下面几种特殊效果.              BevelBitmapE ...

  4. 如何诊断rac环境sysdate 返回的时间错误

    最近处理了若干rac环境访问sysdate错误的时间返回.而这个问题通常是一个数据库链接是由现在Listener创建的情况下.并且.大部分情况下都是和时区设置相关的.在这篇文章中我们会针对怎样诊断这样 ...

  5. Matlab随笔之三维图形绘制

    1.三维曲线 用到了plot3函数.plot3(x,y,z)用来绘制3维曲线图,而不能绘制曲面图!就是把所有的(x,y,z)点连接在一起. t=linspace(,*pi,); x=sin(t); y ...

  6. Angular常用指令

    安装Node 先去Node官网下载并安装Node.js Install the Angular CLI(安装Angular CLI) npm install -g @angular/cli Creat ...

  7. OA 框架

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  8. WPF支持OneWay,TwoWay,OneTime,Default和OneWayToSource

    原文:WPF支持OneWay,TwoWay,OneTime,Default和OneWayToSource 无论是目标属性还是源属性,只要发生了更改,TwoWay 就会更新目标属性或源属性. OneWa ...

  9. LINUX 蓝牙耳机的配置方法

    由于经常使用SKYPE聊天打电话,一直觉得被拴在电脑前面不是很自由,终于在一个周末,一激动买了一个蓝牙耳机.经过几天的努力在Linux/Debian上用了起来,现在就把这个配置过程和大家分享. 第一 ...

  10. 【Git】生成Patch和使用Patch

    1.生成Patch(俗称快照) 先来看看repo manifest 的用法 <1>cd /工作目录/项目目录/.repo/manifests <2>repo manifest ...