1. Nettyとは何ですか?それは何ができるのでしょうか? Netty は、高性能ネットワーク アプリケーションの作成に特化した成熟した IO フレームワークです。 基盤となる Java IO API を直接使用する場合と比較して、Netty に基づく複雑なネットワーク アプリケーションを構築するためにネットワークの専門家である必要はありません。 業界におけるネットワーク通信に関連する一般的なミドルウェアのほとんどは、Netty に基づいてネットワーク層を実装しています。 2. 分散サービスフレームワークを設計する 1 アーキテクチャ 2 リモートコールプロセス サーバー(サービスプロバイダー)を起動し、登録センターにサービスを公開します。 3 リモートコールクライアント図 重要な概念: RPC トリプレット <ID、リクエスト、レスポンス>。 PS: netty4.x のスレッド モデルの場合、グローバル Map の代わりに IO Thread(worker) —> Map<InvokeId, Future> を使用すると、スレッドの競合をより適切に回避できます。 4. リモートコールサーバーの図 5 リモートコールトランスポート層図 6 トランスポート層プロトコルスタックの設計 プロトコル ヘッダー 合意 1) メタデータ: <グループ、プロバイダー名、バージョン> 2) メソッド名 3)parameterTypes[]は本当に必要ですか? (a) 問題は何ですか? デシリアライズ時に ClassLoader.loadClass() でロック競合が発生する可能性があります。 Java メソッドの静的ディスパッチ ルールについては、JLS <Java 言語仕様> $15.12.2.5 最も具体的なメソッドの選択の章を参照してください。 (d) その他: traceId、appName… 3. いくつかの機能と優れた実践とパフォーマンスの圧縮 1 クライアントプロキシオブジェクトを作成する 1) プロキシは何をするのですか? クラスタフォールトトレランス -> 負荷分散 -> ネットワーク jdk プロキシ/javassist/cglib/asm/bytebuddy リモート呼び出しを回避するために、toString、equals、hashCode などのメソッドをインターセプトする必要があることに注意してください。 2 エレガントな同期/非同期呼び出し 上にスクロールして「リモートコールクライアントダイアグラム」を見てください。 3 ユニキャスト/マルチキャスト メッセージディスパッチャ 4 一般化された呼び出し 5 シリアル化/デシリアル化 プロトコル ヘッダーはシリアライザー タイプをマークし、複数のタイプをサポートします。 6. スケーラビリティ Java SPI: java.util.ServiceLoader 7 サービスレベルスレッドプール分離 電話を切りたいなら、まずあなたが切った方がいいですよ。私を落ち込ませないでください。 責任連鎖パターンの 8 つのインターセプター ここから始めるには拡張が多すぎます。 9 指標 10 リンクトラッキング オープントレーシング 11 登録センター 12 フロー制御(アプリケーションレベル/サービスレベル) サードパーティのフロー制御ミドルウェアに簡単に接続できるように拡張できる必要があります。 13 プロバイダーのスレッド プールがいっぱいになった場合はどうすればよいですか? 14 ソフトロードバランシング 1) 重み付きランダム(バイナリ検索、トラバーサルなし) 2) 加重ラウンドロビントレーニング(最大公約数) 3) 最小負荷 4) 一貫性のあるハッシュ(ステートフルサービスシナリオ) 5) その他 注: 予熱ロジックが必要です。 15 クラスタのフォールトトレランス 1) 失敗を早くする 2) フェイルオーバー 非同期呼び出しをどのように処理しますか? 悪い より良い 3) フェイルセーフ 4) フェイルバック 5) フォーク 6) その他 16 パフォーマンスを絞り出す方法(信頼するのではなく、テストする) 1) ASMは、サーバー側のリフレクション呼び出しを置き換えるためにFastMethodAccessorを記述します。 2) シリアル化/デシリアル化 IO スレッドを占有しないように、ビジネス スレッドでシリアル化/デシリアル化します。 シリアル化/デシリアル化には、ごくわずかな数の IO スレッド タイム スライスが消費されます。 kryo/protobuf/protostuff/hessian/fastjson/… など。 従来のシリアル化/デシリアル化 + 書き込み/読み取りネットワーク プロセス: Java オブジェクト --> byte[] --> オフヒープ メモリ / オフヒープ メモリ --> byte[] --> Java オブジェクト。 4) 同期ブロッキング呼び出しのクライアントがボトルネックになる可能性が高い、クライアント コルーチン: Java レベルでは選択肢があまり多くなく、どれもまだ完璧ではありません。 5) Netty ネイティブトランスポートと PooledByteBufAllocator: GC による変動を軽減します。 なぜNettyなのか? 1 BIO 対 NIO 2 JavaネイティブNIO APIの導入から廃止まで 高い複雑性 API は複雑で理解しにくいため、使い始めるのが困難です。 デバッグは難しく、再現するのが非常に難しい奇妙なバグに遭遇することもあります。デバッグ中に泣くことはよくあることです。 NIOコード実装のいくつかの欠点 1) Selector.selectedKeys() は大量のゴミを生成します Netty は sun.nio.ch.SelectorImpl の実装を変更し、selectedKeys を格納するために HashSet の代わりに double 配列を使用しました。 HashSet (イテレータ、ラッパー オブジェクトなど) と比較すると、生成されるガベージが少なくなります (GC に役立ちます)。 直接バッファを割り当てるために、Netty の pooledBytebuf には、ロック競合を効果的に削減できる事前 TLAB (スレッドローカル割り当てバッファ) があります。 EPollSelectorImpl#fdToKey は、接続されているすべての fd (記述子) と SelectionKey (HashMap) のマッピングを維持します。 Netty Native Transport は Epoll ET をサポートしています。 DirectByteBuffer.cleaner は、直接メモリを解放する役割を果たす仮想参照です。 DirectByteBuffer は単なるシェルです。この殻が新世代の年齢制限を生き延びて、最終的に旧世代に昇格するとしたら悲しいことです... ネッティの素顔 1 Nettyにおけるいくつかの重要な概念とその関係 イベントループ セレクター。 ボス: mainReactor の役割、ワーカー: subReactor の役割 Boss と Worker は EventLoop のコード ロジックを共有します。 Boss は受け入れイベントを処理し、Worker は読み取り、書き込み、およびその他のイベントを処理します。 2 Netty4 スレッドモデル 3 チャンネルパイプライン 4 プーリングと再利用 プールバイトバッファアロケータ jemalloc 論文 (3.x) に基づく リサイクラー スレッドローカル + スタック。 5 ネッティネイティブトランスポート Nio と比較すると、作成されるオブジェクトが少なくなり、GC の圧力も少なくなります。 Linux プラットフォーム向けに最適化されており、次のような特定の機能があります。 SO_REUSEPORT - ポートの再利用 (複数のソケットが同じ IP+ポートをリッスンできるようにし、RPS/RFS と連携してパフォーマンスをさらに向上させます): RPS/RFS は、ソフトウェア レベルでマルチキュー ネットワーク カードをシミュレートし、ネットワーク カードのパケットの送受信の中断が 1 つの CPU コアに集中してパフォーマンスに影響するのを回避するための負荷分散機能を提供するものと漠然と理解できます。 6 多重化の概要 選択/投票 実装メカニズム自体には制限があります (ポーリングを使用して準備完了イベントを検出し、時間の計算量は O(n) で、肥大化した fd_set を毎回ユーザー空間とカーネル空間の間でコピーする必要があります)。同時接続数が増えるほど、パフォーマンスは低下します。 コールバック メソッドは、準備完了イベントを検出するために使用されます。時間計算量はO(1)です。各 epoll_wait 呼び出しは、準備完了のファイル記述子のみを返します。 7 エポルについてもう少し深く理解する LT 対 ET コンセプト: LT:レベルトリガー バッファが空でない場合、fd のイベント内の対応する読み取り可能ステータスは 1 に設定され、それ以外の場合は 0 に設定されます。 バッファに書き込み可能なスペースがある場合、fd のイベント内の対応する書き込み可能ステータスは 1 に設定され、それ以外の場合は 0 に設定されます。 3つのepollメソッドの紹介 1) メインコード: linux-2.6.11.12/fs/eventpoll.c 2) int epoll_create(int サイズ) rb-tree (赤黒木) と ready-list (準備完了リンクリスト) を作成します。 容量要件が不確実で大きくなる可能性がある場合、効率とメモリ使用量のバランスをとる赤黒木 O(logN) が最適な選択肢です。 epitem を rb-tree に配置し、カーネル割り込みハンドラに ep_poll_callback を登録します。コールバックがトリガーされると、エピテムを準備リストに追加します。 準備リスト —> イベント[]。 epoll データ構造 epoll_wait ワークフローの概要 比較コード: linux-2.6.11.12/fs/eventpoll.c: 1) epoll_waitはep_pollを呼び出す rdlist (ready-list) が空 (準備完了ファイルなし) の場合、現在のスレッドは中断され、rdlist が空でなくなるまでスレッドは起動されません。 2) ファイル記述子fdのイベントステータスが変化する バッファが読み取り不可から読み取り可能へ、または書き込み不可から書き込み可能へ変更され、対応する fd 上のコールバック関数 ep_poll_callback がトリガーされます。 3) ep_poll_callbackがトリガーされる 対応する fd を rdlist の epitem に追加して、rdlist が空にならないようにし、スレッドを起動して、epoll_wait が実行を継続できるようにします。 4) ep_events_transfer関数を実行する rdlist 内の epitem を txlist にコピーし、rdlist をクリアします。 5) ep_send_events関数を実行する txlist 内の各 epitem をスキャンし、関連付けられている fd に対応する poll メソッドを呼び出して、新しいイベントを取得します。 Netty の 8 つのベスト プラクティス 1) ビジネススレッドプールの必要性 ビジネス ロジック、特にブロック時間が長いロジックは、Netty の IO スレッドを占有せず、ビジネス スレッド プールにディスパッチする必要があります。 2) バッファウォーターマークの書き込み デフォルトの高低ウォーターマーク設定(32K〜64K)に注意し、シーンに応じて適切に調整します(使用方法を考えることができます)。 3) MessageSizeEstimator を書き換えて、実際の最高値と最低値を反映させる デフォルトの実装ではオブジェクトのサイズを計算できません。メッセージ サイズは書き込み中に outboundHandler が渡される前に計算され、この時点ではオブジェクトは Bytebuf にエンコードされていないため、サイズ計算は間違いなく不正確です (小さすぎます)。 4) EventLoop#ioRatio の設定に注意してください (デフォルト 50) これは、EventLoop が IO タスクと非 IO タスクを実行する時間比率を制御します。 5) アイドル リンク検出をスケジュールするのは誰ですか? Netty4.x は、デフォルトで、O(log N) の複雑度を持つバイナリ ヒープによって実装された優先キューである eventLoop の delayQueue を使用して、IO スレッド スケジューリングを使用します。各ワーカーは独自のリンク監視を処理するため、コンテキストの切り替えが削減されますが、ネットワーク IO 操作とアイドルは相互に影響を及ぼします。 6) ctx.writeAndFlush または channel.writeAndFlush を使用しますか? ctx.write は次の送信ハンドラーに直接送られます。本来の意図に反してアイドル リンク検出をバイパスしないように注意してください。 7) rangeCheck() を避けるために ByteBuf.readByte() をループする代わりに Bytebuf.forEachByte() を使用する 8) 不要なメモリコピーを避けるためにCompositeByteBufを使用する 欠点は、インデックス計算時間の複雑さが高いことです。独自のシナリオに応じて測定してください。 9) int を読み取りたい場合は、Bytebuf.readBytes(buf, 0, 4) ではなく、Bytebuf.readInt() を使用してください。 これにより、メモリのコピーを回避できます (long、short などでも同様)。 10) JDKのDirectByteBufを置き換えるためにUnpooledUnsafeNoCleanerDirectByteBufを設定し、Nettyフレームワークが参照カウントに基づいてオフヒープメモリを解放できるようにします。 io.netty.maxDirectMemory: < 0: クリーナーを使用せず、Netty は JDK によって設定された最大直接メモリ サイズを直接継承します (JDK の直接メモリ サイズは独立しているため、合計直接メモリ サイズは JDK 構成の 2 倍になります)。 11) 最適な接続数 1 つの接続にボトルネックがあると、CPU を効果的に活用できません。接続が多すぎると役に立たなくなります。ベストプラクティスは、独自のシナリオに従ってテストすることです。 12) PooledBytebufを使用する場合は、-Dio.netty.leakDetection.levelパラメータの使用に注意してください。 4 つのレベル: DISABLED、SIMPLE、ADVANCED、PARANOID。 13) Channel.attr() でオブジェクトをチャンネルにアタッチします ジッパー方式で実装されたスレッドセーフなハッシュテーブルもセグメントロックされており(リンクリストの先頭のみがロックされます)、ハッシュの競合がある場合にのみロックの競合が発生します(ConcurrentHashMapV8 バージョンと同様)。 Netty ソースコードから学ぶ 9 つのコーディングのヒント 1) AtomicIntegerFieldUpdater --> 大規模オブジェクト シナリオでの AtomicInteger Java では、オブジェクト ヘッダーは 12 バイトです (圧縮ポインターが有効な場合)。 Java オブジェクトは 8 バイトに揃えられているため、オブジェクトの最小サイズは 16 バイトです。 AtomicInteger のサイズは 16 バイト、AtomicLong のサイズは 24 バイトです。 2) FastThreadLocal、JDK実装よりも高速 線形検出用のハッシュ テーブル -> インデックスのアトミック自動増分を備えたネイキッド配列ストレージ。 3)IntObjectHashMap/LongObjectHashMap… 整数—> int 4) リサイクル可能な配列リスト 上記の Recycler に基づいて、新しい ArrayList が頻繁に作成されるシナリオが考えられます。 5) JCTツール 一部の SPSC/MPSC/SPMC/MPMC ロックフリー同時実行キューと NonblockingHashMap は JDK では利用できません (ConcurrentHashMapV6/V8 と比較できます) |
<<: アリババは、NvidiaやGoogleと比較してコンピューティング電力消費を80%削減する1兆パラメータのAIモデルM6をリリースしました。
250MB のハード ドライブ、月間トラフィック 10G、Web サイト 1 つ、MySQL 5 つ...
現在、クラウド コンピューティングの導入は、ホスト型データ センター インフラストラクチャと同様の傾...
タオバオがアリペイ機能を開始した後、オンラインショッピングの古いモデルが覆され、消費者のショッピング...
インターネットの健全な発展を促進するため、大手検索エンジンはネットワークリソースの再編成を行ってきま...
今日、QQにはネットユーザーからの質問が殺到したが、それらはすべて、自身のウェブサイト上の大規模なK...
量子コンピュータは、複雑な問題を分類するのに特に適しています。しかし、この技術の登場により、人々がま...
導入WebAssembly は、Microsoft のクラウド ネイティブ コンピューティング チー...
私はしばらくウェブサイトの制作に携わっており、そこから多くのことを学びました。新しく立ち上げたウェブ...
ご存知のとおり、休暇旅行への熱意は非常に高まっており、需要の増加により安定性の確保にも大きなプレッシ...
ウェブサイト上のデッドリンクは、ウェブサイトの開発に大きな影響を与えます。検索エンジンのスパイダーが...
数日前、YYのSutu Online Salon第11回に参加する栄誉に恵まれました。Wang To...
月収10万元の起業の夢を実現するミニプログラム起業支援プランロゴデザインのウェブサイトには多くのユー...
Fastdomain は 2005 年に設立され、ドメイン名と仮想ホスティング サービスを提供してい...
ウェブマスターの道を歩み続けるなら、遅かれ早かれ、ウェブサイト関連の他の職業に転向する必要があります...
馬華クラウドは「ダブル12」休暇に向けて特別プロモーションを開始しました:(1)香港CN2クラウドサ...