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をリリースしました。
導入:この記事では、マーケティング担当者がソーシャル メディアの ROI に関して抱くよくある誤解を...
3G や 4G に不満を言い続ける時代に生きている人たちは、ダイヤルアップ インターネット アクセス...
コンピューティング能力の限界化により、現代ではより多くのビジネスチャンスが生まれています。従来のクラ...
Apache Foundation の取締役会が、分散ファイル オブジェクト ストレージ Ozone...
urpad買収後の新たな動きです。サーバーレンタル事業に着手しました。多角的な展開も必至です。企業は...
インターネットの拡大に伴い、今年のタオバオ11フェスティバルも取引高の記録を更新しました。しかし...
セルフサービス Web サイト構築の仲間に、また一人の初心者が加わりました。友人が Web サイトを...
1. このシリーズの紹介私はずっと、PythonとSEOに関する記事をシリーズで書きたいと思っていま...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています企業や個人...
テンセントは本日、長年の努力と革新を経て、自社で開発した大規模な社内事業をクラウドに完全に移行したこ...
仮想マシン (VM) をパブリック クラウドに移動すると、多くの互換性の問題が発生する可能性がありま...
Google PR 値は、ウェブマスターがフレンドリー リンクを交換するための基準の 1 つであるた...
企業と顧客・潜在顧客との関係やさまざまな双方向戦略を管理するシステムとして、CRM(顧客関係管理)が...
Vultrはどうですか? Vultr Japanはどうですか?何年も経ちましたが、Vultr の日本...
中央アジアのカザフスタン VPS は市場では珍しいようですね。現在、pq.hosting はカザフス...