Nettyの一般的な面接の質問

概要:

  • Nettyとは何ですか?
  • Nettyを使用する理由
  • Nettyアプリケーションのシナリオを理解していますか?
  • Nettyのコアコンポーネントは何ですか?それぞれの役割は何ですか?
  • EventloopGroupは理解していますか?EventLoopとの関係は何ですか?
  • BootstrapとServerBootstrapを知っていますか?
  • NioEventLoopGroupのデフォルトコンストラクターはいくつのスレッドを開始しますか?
  • Nettyスレッドモデルを理解していますか?
  • Nettyサーバーとクライアントの起動プロセスを理解していますか?
  • Nettyの長い接続とハートビートメカニズムを理解していますか?
  • Nettyのゼロコピーを理解していますか?

Nettyとは何ですか?

  1. Nettyは、NIOに基づくクライアントサーバーフレームワークであり、ネットワークアプリケーションを迅速かつ簡単に開発するために使用できます。
  2. TCPやUDPソケットサーバーなどのネットワークプログラミングを大幅に簡素化および最適化し、パフォーマンスとセキュリティは多くの面でさらに優れています。
  3. FTP、SMTP、HTTP、さまざまなバイナリおよびテキストベースの従来のプロトコルなどの複数のプロトコルをサポートします。

公式の要約は次のとおりです。Nettyは、保守性とパフォーマンスを損なうことなく、開発の容易さ、パフォーマンス、安定性、柔軟性を実現する方法を見つけることに成功しました。
上記に加えて、一般的に使用されているDubbo、RocketMQ、Elasticsearch、gRPCなどの多くのオープンソースプロジェクトはすべてNettyを使用しています。

Nettyを使用する理由

Nettyには次のような利点があり、JDKに付属のNIO関連のAPIを直接使用するよりも使いやすいためです。

  • Unified APIは、ブロッキングと非ブロッキングの複数の送信タイプをサポートします。
  • シンプルでパワフルなスレッディングモデル。
  • 組み込みコーデックは、TCPのスティッキング/アンパックの問題を解決します。
  • さまざまなプロトコルスタックが付属しています。
  • 真のコネクションレス型パケットソケットのサポート。
  • JavaコアAPIを直接使用する場合と比較して、スループットが高く、レイテンシが低く、リソース消費が少なく、メモリのコピーが少なくなります。
  • 完全なSSL / TLSとStartTLSのサポートにより、セキュリティは良好です。
  • アクティブなコミュニティ
  • 成熟していて安定しており、大規模なプロジェクトで使用およびテストされており、DubboやRocketMQなどの多くのオープンソースプロジェクトでよく使用されています。

Nettyアプリケーションのシナリオを理解していますか?

理論的には、NIOができることは、Netty以上で実行できます。Nettyは主にネットワーク通信に使用されます。

  1. RPCフレームワークのネットワーク通信ツールとして:分散システムでは、多くの場合、異なるサービスノードが相互に呼び出す必要があります。現時点では、RPCフレームワークが必要です。異なるサービスノード間の通信はどのように行われますか?Nettyを使用してそれを行うことができます。たとえば、別のノードのメソッドを呼び出す場合、少なくとも、呼び出しているクラスのメソッドと関連するパラメーターを相手に知らせる必要があります。
  2. 独自のHTTPサーバーを実装する:Nettyを使用して、簡単なHTTPサーバーを自分で実装できます。これは誰もが知っているはずです。HTTPサーバーと言えば、Javaバックエンド開発として、私たちは一般的にTomcatをより多く使用します。基本的なHTTPサーバーは、POSTリクエスト、GETリクエストなどの一般的なHTTPメソッドリクエストを処理できます。
  3. インスタントメッセージングシステムの実装:Nettyを使用すると、WeChatと同様にチャットできるインスタントメッセージングシステムを実装できます。この分野には多くのオープンソースプロジェクトがあります。Githubにアクセスして自分で見つけることができます。
  4. メッセージプッシュシステムの実現:Nettyに基づく多くのメッセージプッシュシステムが市場に出回っています。

Nettyのコアコンポーネントは何ですか?それぞれの役割は何ですか?

1.
チャネルチャネルインターフェイスは、ネットワーク操作用のNettyの抽象クラスであり、bind()、connect()、read()、write()などの基本的なI / O操作が含まれます。

より一般的に使用されるチャネルインターフェイス実装クラスは、NioServerSocketChannel(サーバー)とNioSocketChannel(クライアント)です。これらの2つのチャネルは、BIOプログラミングモデルのServerSocketとSocketの2つの概念に対応できます。Nettyのチャネルインターフェイスによって提供されるAPIは、Socketクラスを直接使用する複雑さを大幅に軽減します。

2. EventLoop
EventLoop(イベントループ)インターフェイスは、Nettyの最もコアな概念であると言えます。「EventLoopは、接続のライフサイクルで発生するイベントを処理するために使用されるNettyのコア抽象化を定義します。率直に言って、EventLoopの主な役割は、実際にはネットワークイベントを監視し、イベントハンドラーを呼び出して関連するI /を処理することです。 O操作。

ChannelとEventLoop間の直接接続は何ですか?
チャネルは、Nettyネットワーク操作(読み取りおよび書き込み操作)の抽象クラスです。EventLoopは、I / O操作を処理するためにそれに登録されたチャネルを処理する責任があり、2つは協力してI / O操作に参加します。

3. ChannelFuture
Nettyは非同期で非ブロッキングであり、すべてのI / O操作は非同期です。

したがって、操作の成功をすぐに取得することはできませんが、ChannelFutureインターフェイスのaddListener()メソッドを介してChannelFutureListenerを登録できます。操作が成功または失敗すると、リスナーは自動的に結果を返します。また、ChannelFutureのchannel()メソッドを使用して、関連付けられたチャネルを取得できます。さらに、ChannelFutureインターフェイスのsync()メソッドを使用して非同期操作を同期させることもできます。

4. ChannelHandlerとChannelPipeline
次のコードは、Nettyを使用したことのある人にはなじみのないものであってはなりません。メッセージを処理するために、シリアル化コーデックとカスタムChannelHandlerを指定しました。

b.group(eventLoopGroup) .handler(new ChannelInitializer<SocketChannel>() {
    
     
@Override protected void initChannel(SocketChannel ch) {
    
     
	ch.pipeline().addLast(new NettyKryoDecoder(kryoSerializer, RpcResponse.class)); 
	ch.pipeline().addLast(new NettyKryoEncoder(kryoSerializer, RpcRequest.class)); 
	ch.pipeline().addLast(new KryoClientHandler()); 
	} 
});

ChannelHandlerは、メッセージの具体的なプロセッサです。彼は、読み取りおよび書き込み操作、クライアント接続、およびその他の処理を担当しています。ChannelPipelineは、コンテナーを提供し、チェーンに沿ってインバウンドおよびアウトバウンドのイベントストリームを伝播するためのAPIを定義するChannelHandlerのチェーンです。チャネルが作成されると、専用のChannelPipelineに自動的に割り当てられます。データまたはイベントは複数のハンドラーによって処理される可能性があるため、addLast()メソッドを使用してChannelPipelineに1つ以上のChannelHandlerを追加できます。ChannelHandlerが処理されると、データは次のChannelHandlerに渡されます。

EventloopGroupは理解していますか?EventLoopとの関係は何ですか?

ここに画像の説明を挿入

EventLoopGroupには複数のEventLoopsが含まれています(各EventLoopには通常、内部にスレッドが含まれています)。前述のように、EventLoopの主な機能は、実際にはネットワークイベントの監視と、関連するI / O操作を処理するためのイベントハンドラーの呼び出しを担当します。

また、EventLoopによって処理されるI / Oイベントは、専用のスレッドで処理されます。つまり、スレッドとEventLoopは1:1の関係に属しているため、スレッドの安全性が確保されます。

上の図は、サーバーが使用するEventLoopGroupの一般的なブロック図であり、Boss EventloopGroupは接続の受信に使用され、Worker EventloopGroupは特定の処理(メッセージの読み取りと書き込みおよびその他の論理処理)に使用されます。

上の図からわかるように、クライアントがconnectメソッドを介してサーバーに接続すると、bossGroupはクライアント接続要求を処理します。クライアントの処理が完了すると、接続は処理のためにworkerGroupに送信され、workerGroupはIO関連の操作の処理を担当します。

BootstrapとServerBootstrapを知っていますか?

Bootstrapは、クライアントの起動ブートクラス/補助クラスです。具体的な使用方法は次のとおりです。

EventLoopGroup group = new NioEventLoopGroup(); try {//クライアントブート/補助クラスを作成します:Bootstrap Bootstrap b = new Bootstrap(); //スレッドモデルを指定しますb.group(group)。…//接続を確立しようとしますChannelFuture f = b.connect(host、port).sync(); f.channel()。closeFuture()。sync();} final {//関連するスレッドグループリソースを正常に閉じるgroup.shutdownGracefully();}

ServerBootstrapクライアントのブートブートクラス/補助クラス。具体的な使用方法は次のとおりです。

// 1.bossGroupは接続の受信に使用され、workerGroupは特定の処理に使用されますEventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try {// 2。サーバーブート/補助クラスの作成:ServerBootstrap ServerBootstrap b = new ServerBootstrap(); //3。ブートクラス用に2つのスレッドグループを構成し、スレッドモデルを決定しますb.group(bossGroup、workerGroup)。…// 6。ポートChannelFuturef = b.bind(port)をバインドします。 sync(); //接続が閉じるのを待つf.channel()。closeFuture()。sync();}最終的に{// 7。関連するスレッドグループリソースを正常に閉じますbossGroup.shutdownGracefully(); workerGroup.shutdownGracefully( );}}

上記の例から、次のことがわかります。

  1. ブートストラップは通常、connet()メソッドを使用して、NettyTCPプロトコル通信のクライアントとしてリモートホストおよびポートに接続します。さらに、Bootstrapは、UDPプロトコル通信の一端としてbind()メソッドを介してローカルポートをバインドすることもできます。
  2. ServerBootstrapは通常、bind()メソッドを使用してローカルポートにバインドし、クライアントが接続するのを待ちます。
  3. Bootstrapは1つのスレッドグループ(EventLoopGroup)を構成するだけでよく、ServerBootstrapは2つのスレッドグループ(EventLoopGroup)を構成する必要があります。1つは接続の受信用で、もう1つは特定の処理用です。

NioEventLoopGroupのデフォルトコンストラクターはいくつのスレッドを開始しますか?

// 1.bossGroupは接続の受信に使用され、workerGroupは特定の処理に使用されますEventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup();

NioEventLoopGroupのデフォルトコンストラクターによって作成されるスレッドの数を確認するために、そのソースコードを見てみましょう。

/ ***引数なしのコンストラクタ。* nThreads:0 / public NioEventLoopGroup(){//次のコンストラクタメソッドthis(0);} / * *エグゼキュータ:null / public NioEventLoopGroup(int nThreads){//次のコンストラクタメソッドthis(nThreads、 (Executor)null);} //コンストラクターの一部が途中で省略されています/ * * RejectedExecutionHandler():RejectedExecutionHandlers.reject()* / public NioEventLoopGroup(int nThreads、Executor executor、final SelectorProviderselectorProvider、final SelectStrategyFactory selectStrategyFactory){ //親の呼び出しを開始しますクラスsuper(nThreads、executor、selectorProvider、selectStrategyFactory、RejectedExecutionHandlers.reject());}のコンストラクター

一番下まで行くと、次のように、MultithreadEventLoopGroupクラスのスレッド数を指定するための関連コードが見つかります。

// 1から、システムプロパティであるCPUコアの数は、3つの値のうち最大のものを取ります// DEFAULT_EVENT_LOOP_THREADSの値は、CPUコアの数として取得できます2 private static final int DEFAULT_EVENT_LOOP_THREADS = Math。 max(1、SystemPropertyUtil.getInt( "Io.netty.eventLoopThreads"、NettyRuntime.availableProcessors()* 2)); //呼び出される親クラスコンストラクター、NioEventLoopGroupのデフォルトコンストラクターには、スレッド数の秘密があります/ /指定されたスレッド数nThreadsが0の場合デフォルトのスレッド数を使用する場合DEFAULT_EVENT_LOOP_THREADSprotected MultithreadEventLoopGroup(int nThreads、ThreadFactory threadFactory、Object ... args){super(nThreads == 0?DEFAULT_EVENT_LOOP_THREADS:nThreads、threadFactory、args); }

要約すると、NioEventLoopGroupのデフォルトコンストラクターによって実際に開始されるスレッドの数は、CPUコアの数* 2であることがわかります。

さらに、さらに深く進んでコンストラクターを見ると、各NioEventLoopGroupオブジェクトがNioEventLoopsのグループを割り当て、そのサイズがnThreadsであり、スレッドプールを構成し、NIOEventLoopがスレッドに対応していることがわかります。これは私たちに対応します上記のEventloopGroupとEventLoopの関係はこの部分に対応します。

Nettyスレッドモデルを理解していますか?

ほとんどのネットワークフレームワークは、Reactorパターンに基づいて設計および開発されています。

「Reactorモードはイベント駆動型に基づいており、多重化を使用してイベントを対応するハンドラーに配布して処理します。これは、大規模なIOシナリオの処理に非常に適しています。

Nettyは、特定のスレッドモデルを実装するために主にNioEventLoopGroupスレッドプールに依存しています。
サーバーを実装するときは、通常、次の2つのスレッドグループを初期化します。

  1. bossGroup:接続を受信します。
  2. workerGroup:対応するハンドラーによって処理される特定の処理を担当します。

1.シングルスレッドモデル:
1つのスレッドで、すべての受け入れ、読み取り、デコード、処理、エンコード、および送信イベントを実行および処理する必要があります。高負荷、高同時実行性、および高パフォーマンス要件のあるシナリオには適用できません。

対応するNettyコードは次のとおりです

「NioEventLoopGroupクラスのパラメーターなしコンストラクターを使用して、スレッド数のデフォルト値をCPUコア数* 2に設定します。

//1.eventGroupは、クライアント接続を処理するために使用されるだけでなく、特定の処理も担当します。EventLoopGroup eventGroup = new NioEventLoopGroup(1); // 2.サーバーブート/補助クラスを作成します:ServerBootstrap ServerBootstrap b = new ServerBootstrap(); boobtstrap.group(eventGroup、eventGroup)// .. ..

2.マルチスレッドモデル
アクセプタースレッドはクライアント接続の監視のみを担当し、NIOスレッドプールは特定の処理(イベントの受け入れ、読み取り、デコード、処理、エンコード、送信)を担当します。ほとんどのアプリケーションシナリオに適合します。同時接続数が少ない場合は問題ありませんが、同時接続数が多い場合は問題が発生し、パフォーマンスのボトルネックになる可能性があります。

対応するNettyコードは次のとおりです。

// 1.bossGroupは接続の受信に使用され、workerGroupは特定の処理に使用されますEventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try {// 2。サーバーブート/補助クラスの作成:ServerBootstrap ServerBootstrap b = new ServerBootstrap(); //3。ブートクラス用に2つのスレッドグループを構成し、スレッドモデルを決定しますb.group(bossGroup、workerGroup)// .. ..
ここに画像の説明を挿入

3.マスタースレーブマルチスレッドモデル
メインスレッドのNIOスレッドプールからアクセプタースレッドとしてスレッドを選択し、リスニングポートをバインドし、クライアント接続を受信します。他のスレッドは、後続のアクセス認証やその他のタスクを担当します。接続が確立された後、サブNIOスレッドプールはI / Oの読み取りと書き込みの特定の処理を担当します。マルチスレッドモデルがニーズを満たせない場合は、マスタースレーブマルチスレッドモデルの使用を検討できます。

// 1.bossGroupは接続の受信に使用され、workerGroupは特定の処理に使用されますEventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try {// 2。サーバーブート/補助クラスを作成します:ServerBootstrap ServerBootstrap b = new ServerBootstrap(); //3。ブートクラス用に2つのスレッドグループを構成し、スレッドモデルを決定しますb.group(bossGroup、workerGroup)// .. ..
ここに画像の説明を挿入

Nettyサーバーとクライアントの起動プロセスを理解していますか?

サーバ

shutdownGracefully(); }

サーバーの作成プロセスを簡単に分析します
。1。最初に、2つのNioEventLoopGroupオブジェクトインスタンス(bossGroupとworkerGroup)を作成します。

  • bossGroup:クライアントのTCP接続要求を処理するために使用されます。
  • workerGroup:各接続の特定の読み取りおよび書き込みデータの処理ロジックを担当し、対応するハンドラーによって処理されるI / O読み取りおよび書き込み操作を実際に担当します。

例:会社のボスをbossGroupとして扱い、従業員をworkerGroupとして扱います。bossGroupが外部でジョブを取得した後、処理のためにworkerGroupにスローされます。通常は、bossGroupのスレッド数を1(同時接続数が少ない場合)とし、workGroupのスレッド数をCPUコア数※2とします。また、ソースコードによると、NioEventLoopGroupクラスのパラメーターなしコンストラクターを使用してスレッド数のデフォルト値を設定すると、CPUコア数* 2になります。

2.次に、サーバーブート/補助クラスServerBootstrapを作成しました。このクラスは、サーバーの起動をガイドします。

3. .group()メソッドを使用してブートクラスServerBootstrapの2つのスレッドグループを構成し、スレッドモデルを決定します。
次のコードを使用して、前述のマルチスレッドモデルを実際に構成します。

EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup();

4.ブートクラスServerBootstrapのIOモデルは、channel()メソッドを介してNIOとして指定されます

  • NioServerSocketChannel:サーバーのIOモデルをNIOとして指定します。これは、BIOプログラミングモデルのServerSocketに対応します。
  • NioSocketChannel:クライアントのIOモデルをNIOとして指定します。これは、BIOプログラミングモデルのソケットに対応します。5。.childHandler()を使用してブートクラスのChannelInitializerを作成し、サーバーメッセージHelloServerHandlerオブジェクト6のサービス処理ロジックを作成します。 。ServerBootstrapクラスbind()メソッドを呼び出して、ポートをバインドします

クライアント

// 1.NioEventLoopGroupオブジェクトインスタンスを作成しますEventLoopGroupgroup = new NioEventLoopGroup(); try {// 2。クライアントブート/補助クラスを作成します:Bootstrap Bootstrap b = new Bootstrap(); // 3。スレッドグループを指定しますb。group (group)// 4. IOモデルを指定します。channel(NioSocketChannel.class).handler(new ChannelInitializer(){@ Override public void initChannel(SocketChannel ch)throws Exception {ChannelPipeline p = ch.pipeline(); // 5 。ここで、メッセージのビジネス処理ロジックをカスタマイズできます。p.addLast(new HelloClientHandler(message));}}); // 6。接続の確立を試みますChannelFuturef = b.connect(host、port).sync( ); // 7.接続が閉じるのを待ちます(チャネルが閉じるまでブロックします)f.channel()。closeFuture()。sync();}最後に{group.shutdownGracefully();}

クライアントの作成プロセスの分析を続行します

  1. NioEventLoopGroupオブジェクトインスタンスを作成します
  2. クライアントスタートアップを作成するためのブートストラップクラスはBootstrapです
  3. .group()メソッドを使用してブートクラスBootstrapのスレッドグループを構成します
  4. BootstrapのIOモデルは、channel()メソッドを介してNIOとして指定されます
  5. .childHandler()を使用してブートストラップクラスのChannelInitializerを作成し、クライアントメッセージHelloClientHandlerオブジェクトのビジネス処理ロジックを作成します。
  6. Bootstrapクラスのconnect()メソッドを呼び出して接続します。このメソッドでは、次の2つのパラメーターを指定する必要があります。
    • inetHost:IPアドレス
    • inetPort:ポート番号
    • public ChannelFuture connect(String inetHost、int inetPort){return this.connect(InetSocketAddress.createUnresolved(inetHost、inetPort)); } public ChannelFuture connect(SocketAddress remoteAddress){ObjectUtil.checkNotNull(remoteAddress、“ remoteAddress”); this.validate(); this.doResolveAndConnect(remoteAddress、this.config.localAddress());を返します。}

connectメソッドは、Futureタイプのオブジェクトを返します。パブリックインターフェイスChannelFutureはFuture {…}を拡張します。つまり、このパーティは非同期であり、addListenerメソッドを介して接続が成功したかどうかを監視し、接続情報を出力できます。特定のメソッドは非常に単純で、コードに次の変更を加える必要があります。ChannelFuturef = b.connect(host、port).addListener(future-> {if(future.isSuccess()){System.out.println ( "接続に成功しました!");} else {System.err.println( "接続に失敗しました!");}})。sync(); TCPのスティッキング/アンパックとは何ですか?解決策はありますか?

TCPのスティッキング/アンパックとは何ですか?

TCPの固定/解凍とは、TCPに基づいてデータを送信する場合、複数の文字列を「固定」する場合、または1つの文字列を「分解」する場合です。たとえば、「こんにちは、あなたはとてもハンサムです!ブラザー!」と繰り返し送信しますが、クライアントは次のようなものを受け取る可能性があります。
ここに画像の説明を挿入

1.Nettyの組み込みデコーダーを使用する

  • LineBasedFrameDecoder:送信者がデータパケットを送信するとき、各データパケットは改行文字で区切られます。LineBasedFrameDecoderの動作原理は、ByteBufの読み取り可能なバイトを順番にトラバースし、改行文字があるかどうかを判断して、対応するインターセプトを実行することです。
  • DelimiterBasedFrameDecoder:Delimiterデコーダーはカスタマイズできます。LineBasedFrameDecoderは実際には特別なDelimiterBasedFrameDecoderデコーダーです。
  • FixedLengthFrameDecoder:固定長デコーダー。指定された長さに応じてメッセージを解凍できます。
  • LengthFieldBasedFrameDecoder

2.カスタムシリアル化コーデック
Javaには、シリアル化を実現するためのSerializableインターフェイスの実装が付属していますが、そのパフォーマンス、セキュリティ、およびその他の理由により、通常の状況では使用されません。通常の状況では、Protostuff、Hessian2、jsonシーケンスメソッドをさらに使用します。非常に優れたシリアル化パフォーマンスを備えたシリアル化メソッドもいくつかあります。

  • 特にJava言語の場合:Kryo、FSTなど。
  • クロスランゲージ:Protostuff(protobufに基づいて開発)、ProtoBuf、Thrift、Avro、MsgPackなど。

Nettyの長い接続とハートビートメカニズムを理解していますか?

TCPの長い接続と短い接続を理解していますか?
TCPが読み取りと書き込みを行う前に、サーバーとクライアントの間で事前に接続を確立する必要があることはわかっています。接続を確立するプロセスには、私たちがよく言う3方向のハンドシェイクが必要であり、接続を解放/閉じるには4つの手の波が必要です。このプロセスはネットワークリソースを消費し、時間遅延があります。

いわゆるショート接続とは、サーバー側がクライアント側との接続を確立した後、読み取りと書き込みが完了した後に接続を閉じることを意味します。次回メッセージを相互に送信する場合は、接続が必要です。短い接続は少し明白です。つまり、管理と実装は比較的単純であり、欠点も明らかです。読み取りと書き込みごとに接続を確立すると、必然的に大量のネットワークリソースが消費されます。また、接続の確立にも時間がかかります。

長い接続とは、クライアントがサーバーへの接続を確立した後、クライアントとサーバーが読み取りと書き込みを完了した場合でも、それらの間の接続はアクティブに閉じられず、後続の読み取りと書き込み操作は引き続きこの接続を使用することを意味します。接続が長いと、TCPの確立と終了の操作を節約し、ネットワークリソースへの依存を減らし、時間を節約できます。リソースを頻繁に要求するお客様には、長い接続が非常に適しています。

なぜハートビートメカニズムが必要なのですか?Nettyの中央ホップメカニズムを理解していますか?

TCPが長い接続を維持している過程で、ネットワーク切断などのネットワーク異常が発生する場合があります。異常が発生した場合、クライアントとサーバーの相互作用がないと、相手が切断されていることを検出できません。 。この問題を解決するには、ハートビートメカニズムを導入する必要があります。ハートビートメカニズムの動作原理は次のとおりです。クライアントとサーバーの間に一定期間データの相互作用がない場合、つまりアイドル状態の場合、クライアントまたはサーバーは特別なデータパケットを他方に送信します。メッセージが送信された後、送信者に応答するために特別なデータメッセージもすぐに送信されます。これはPING-PONGインタラクションです。したがって、一方の端がハートビートメッセージを受信すると、もう一方の側がまだオンラインであることがわかり、TCP接続の有効性が保証されます。実際、TCPには独自の長い接続オプションがあり、ハートビートパケットメカニズムもあります。は、TCPのオプション:SO_KEEPALIVEです。ただし、TCPプロトコルレベルでの長い接続の柔軟性は十分ではありません。したがって、一般に、アプリケーション層プロトコルにカスタムハートビートメカニズムを実装します。つまり、Nettyレベルでコーディングします。ハートビートメカニズムがNettyを介して実装されている場合、コアクラスはIdleStateHandlerです。

Nettyのゼロコピーを理解していますか?

「ゼロコピー(英語:ゼロコピー。ゼロコピーとも呼ばれる)テクノロジとは、コンピュータが操作を実行するときに、CPUが最初に特定のメモリから別の特定の領域にデータをコピーする必要がないことを意味します。このテクノロジは通常使用されます。ネットワーク経由でファイルを転送する時間の節約CPUサイクルとメモリ帯域幅。

OSレベルでのゼロコピーとは、通常、ユーザースペースとカーネルスペースの間でデータを前後にコピーしないようにすることを指します。Nettyレベルでは、ゼロコピーは主にデータ操作の最適化に反映されます。

Nettyのゼロコピーは、次の側面に反映されます。

  1. Nettyが提供するCompositeByteBufクラスを使用すると、複数のByteBufを論理ByteBufにマージして、各ByteBuf間のコピーを回避できます。
  2. ByteBufはスライス操作をサポートしているため、ByteBufを同じストレージ領域を共有する複数のByteBufに分解して、メモリのコピーを回避できます。
  3. ファイル転送は、FileRegionによってラップされたFileChannel.tranferToを介して実現されます。これにより、ファイルバッファー内のデータをターゲットチャネルに直接送信できるため、従来の循環書き込み方式によって引き起こされるメモリコピーの問題を回避できます。

おすすめ

転載: blog.csdn.net/CSDN877425287/article/details/114505079