Redis、hiredis、libev、およびマルチスレッド。 パート2

最初の部分の続きでは、それが実際にどのように機能するかをお伝えしたい思います。 テストとデバッグに多くの時間が費やされました。次に、実施された研究の結果に関する詳細な推奨事項を提示したいと思います。



注意! 私がそれを必要とする理由を理解するためではなく、それがどのように機能するかを理解するために研究が行われました!







それで、最初の部分で何をしたのですか:C ++コードに単純に含まれていた純粋なCコードは、データベースにデータを入力することはほとんどなく、楽しくコンパイルされ、結果が得られました。 しかし、私たちはまだリアルタイムにアプローチしたいので、ストレステストを行います...



Hiredis + Libev:蹴ってください。



最初につまずいたのは、クライアントが10〜15秒でサーバーから脱落することです。これは、当然、非同期モードのサーバーがデータを期待しているのに、そうではない場合は当然です。 この誤解を取り除くには、サーバーへの「PING」コマンドの送信を一定の頻度で、たとえばサーバーへの前回の要求が完了した後100マイクロ秒(100マイクロ秒)に1回送信を固定する必要があります。 これはサーバーの動作に影響を与えず、アプリケーションはデータが利用できないときに接続を維持します。



Hiredis + Libev:清らかであるが、狂信的ではない。



pingを台無しにした後、驚いたことに皮質への放射性降下物を観察し始めました。そして、hiredisマニュアルがメモリをクリーニングすることを推奨している場所で、引用文があります。 コマンドのコールバックがNULLでない場合、応答をクリーンアップする責任があります。 ただし、応答はNULLではなく、同じfreeReplyObject関数の安定したドロップです。 まあ、何をすべきか、ハイレディスのソースに登った、そして...メモリは2回掃除されることが判明しました! そもそもping専用のメモリクリアをクリーンアップしましたが、後でコールバック関数でメモリをクリアする必要がないことがわかりました。 また、他のスレッドからのリクエストの受信に関連する関数(async-watcherに関連する関数)でまだクリーニングする必要はありません。渡されたポインターはev_io_stop関数でクリーニングされます。キューからリクエストを削除します。 同時に、もちろん、Taras Bulbaとして、いわゆる「プライベートデータ」に対処する必要があります。「私はあなたを出産しました-私はあなたを殺します。」 ちなみに、pingの場合、プライベートデータをNULLとして指定できます。何も落ちず、メモリリークはありません。



Hiredis + Libev + Multithread:私はdrれています!



驚いたことに、一方で。 単一のスレッドからデータベースに10kプッシュリクエストを10秒間サイフォンしようとすると(数字は毎秒120kリクエストの宣言されたRedisパフォーマンスではまったく何もありません)、DBMSから接続が落ちるという問題に再び遭遇しました。 再び腸内に入り、トレースを行い、...「マルチスレッドはデフォルトではサポートされていません。スレッドセーフな実装を行うための単一値アルゴリズムがないため」というフレーズを認識し始めました。 何が起こっているの? 次のようになります:他のストリームからのリクエストのバッファーへの書き込みアクセスを制限するセマフォは不十分です。これは、同じバッファー(およびhiredisに存在し、無限のリソースを消費する可能性がある)が成長する一方で、データが明らかに記録の進行中は、イベントループにバッファへの読み取りアクセス権がありません。 最初に、リクエスト間のタイムアウトを設定して問題を解決し、セマフォをアダプタの腸にlibevに移動し、セマフォが新しいリクエストを追加するのを待機し、DBMSに送信した後にセマフォを解放しました。 ただし、リクエスト間で1μsのタイムアウトが必要な問題をまだ完全に理解できていません。 おそらく次のパート(ある場合)で、すでにレシピについて説明します。 これに基づいて:



Hiredis + Libev +マルチスレッド:1つのスレッドから最大を絞り出します。



その結果、サービスでの予備データ処理により、単一ストリームでRedisへのプッシュリクエストを1秒あたり約600件達成することができました(どのくらい時間がかかったかはカウントしませんでした)。 一般に、今のところこれで開始できますが、スレッド数の増加と、バッファへのリクエストの追加のより正確な同期についてさらに掘り下げます。



Hiredis:組み立てる前に慎重にファイルしてください。



あなたが好きなことを言ってください。hiredisは若いライブラリです。私のコードをデバッグする過程で、私はその腸に何度も登りました。 私を幸せにしなかったのは、次のような構造がしばしばあるという事実です。

<some_struct> *p = (some_struct*)malloc(sizeof(*p)); //    , .
      
      







 //    char[] - -   , ,   (err),       : ... = ... sizeof(err) ...; // ,           ...
      
      







一般に、私は自分でパッチを適用し、開発者にそれを書き留め、すぐに応答しませんでしたが、彼らはそれを修正すると思います。



ご清聴ありがとうございました。 批判とコメントを楽しみにしています。



All Articles