本論文では、主にポイントをテストして勉強したいです:
- 最も単純な差異ベースの転送手順、ネッティーが書いたHTTPリクエストの4と7のパフォーマンス
- モデルのパフォーマンスをスレッド3つのエージェント間の違いは、以下のスレッドモデルの3種類を説明します
- 違いは、プールとプールされていないパフォーマンスのByteBuffer
:この記事で使用したコードのテスト
https://github.com/JosephZhu1983/proxytestを
コードでは、エージェントの2セットを実装しました:
テスト(アリ雲ECS)を使用して、マシンの構成:
3台のマシンの合計:
- サーバーサーバーは、バックエンドとして、nginxのインストール
- クライアントサーバはWRK、クライアント圧力測定を持っています
- 我々のテストコード(プロキシ)に設置されたプロキシサーバー
nginxのバックエンド
nginxのは、テストページのデフォルトの設定(ポイントがネットワーク帯域幅を減らし、コンテンツを削除した)である:
直接QPS2660万をダウン測定nginxの圧力の前に:
約4と7
四剤には、我々は唯一のByteBufを転送するネッティーを使用しています。
七剤には、より多くのオーバーヘッド、主にコーデックHTTPリクエストと集約、サーバーのHTTPリクエストがあるでしょう。
クライアント:
少ないデータ符号化と復号化処理のHttpが、パフォーマンスは確かに我々はテストの結果を見ることができますどのくらい良く7、よりはるかに優れているので、ここでは4回の薬、と考えることができます。
スレッドモデルについて
私たちは、下流から上流に戻っへの応答を取得するために、我々は、上流側からサービス取得要求を開く必要があり、プロキシとして知っているし、クライアントとして下流に要求を転送します。当社のサービスおよびクライアントが要求を処理するためにワーカーIOスレッドを必要とする、3つのアプローチがあります。
- :クライアントとサーバーのServerBootstrap別のスレッド・プールNioEventLoopGroupブートストラップ、IndividualGroupを呼び
- B:クライアントとサーバー共有スレッドプールは、ReuseServerGroupと呼ばれます
- C:多重サーバーとの直接スレッドのイベントループクライアント、ReuseServerThreadを呼び
一例として、7つのプロキシコードを持ちます:
接下去的测试我们会来测试这三种线程模型,这里想当然的猜测是方案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の単一百万で、実際には、マシンの構成は非常に良いではない、牛です
- ネッティーは、結局のところ、Javaサーバー側で、牛である4フォワード損失わずか3%QPS
- 4階建てのかどうか、7、多重スレッド化アプローチは、明らかに最高のパフォーマンスは、最小限のCPUを取ります
- そのため、コンテキスト切り替えの、ネッティーエージェントを使用して、ネットワークの開発者は、IOスレッドを再利用する必要があります
- 七つの消費量は4よりもはるかに大きい、でもネッティーが、これはHTTPプロトコルの問題であり、避けることはできません
- PooledByteBufAllocator UnpooledByteBufAllocatorより一定の性能を向上させる(約3%)
- あなたは、より大きな最大コンテンツ長を設定した場合は、少しパフォーマンスポイントに影響を与えHttpObjectAggregator
この分析を行うために、この記事を書く理由があるため、当社の自己開発のゲートウェイの最適化とhttps://github.com/spring-avengers/teslaのストレステストの最近のパフォーマンスで実行されます。
私はそれがまた、再利用可能である、私はZuulコードの下に見えた、いくつかの他のオープンソースプロジェクトは、複数の接続のネッティーエージェントをベースにしていない、著者はこれを実現しないことがありました。