シングルスレッドモードのRedisの理解

0.5の概要

Redisのバージョンに基づいて4.0以下である、完全ではない後のRedisにシングルスレッド、BIO-ねじの増加、シングルスレッドモードは、本稿では、作業のメインスレッドを記述する。

この記事を通して、あなたは次のことを学びます。

  1. シングルスレッドサーバモデルを採用するためのRedisの理由
  2. シングルスレッド処理ファイルとイベント時間イベントは、Redisの
  3. Redisの実行とスケジュールイベント

1.Redisシングルスレッドモード

  • ステータスシングルスレッド

Redisのは、主なポイントは、シングルスレッドクライアントの相互作用は、コマンドの要求と応答を完了することであることを基本的にここではBIOのスレッドによって実行され、削除タスクの不活性シンプルなシングルスレッドサービスモデルは、そのような永続的なブラシプレートなどの一部の補助作業、ではありませんワーカースレッド。

  • 理由は、シングルスレッド化

デザインに関してはAntirezは兄がシングルスレッドとして知られていなかったと思う方法を、唯一のシングルスレッドモデルを選んだ理由を決定するために、いくつかの角度から分析することができます。

  • CPUがボトルネックではありません

マルチスレッドモデルは、他のスレッドにCPUを使用する権利を放棄するIOをブロックしながら、スレッドが中断されるように、マルチコアCPUを活用し、完全にCPUの使用率を向上させるために、主ですが、CPUではないのでシーンは、Redisの中で明らかにされていませんRedisのボトルネックは、すべての操作がRedisのメモリに基づいており、ハンドルのイベントが速いので、CPU使用率の需要を向上させるためにスイッチスレッドにマルチスレッドを使用すると、強力ではありません。

  • メモリがボトルネックになって

Redisのは、単球の単一のインスタンスは非常に良いされているが、メモリが唯一の16ギガバイト、そのマルチスレッドのRedisの場合はRedisのメモリのボトルネックがでてくるものを、64コアのマシンを想定しているでしょうか?

  • バリュー型錯体

Redisのは、単にまた、一般的に使用されるハッシュされている人気の理由のRedis、大きな値でZSET、一覧およびその他の構造であるキー値のNoSQLを入力しないで、CURD操作が非常に複雑になる、データ構造の富を持っています

同じ操作キーロック中にマルチスレッドモードを同期する必要がある場合は、そのためには、デッドロックが発生することがあります。

今度は、要求されます:ハッシュキーは、それが解決することができます処理するために、同じスレッドに割り当てられますか、実際にそうであるので、Redisの中でロードバランシングとマルチスレッド処理のハッシュキープロセスを増やす必要があるでしょう、

; Redisの実装は、確かに問題はありませんが、Antirezがそうしなかったかのように、偉大な神は確かに、そう案の定を行う理由は、マルチスレッドモードので、我々はRedisののクラスタを見たとなっています

  • クラスタの拡張機能

マシンが現在多核であるが、メモリは、128ギガバイト/ 64ギガバイトは、比較的一般的であるが、60%のパフォーマンスの50%ほど良好としてメモリRedisの安定性の使用(少なくともI Redisのクラスタリングが70%以上を使用して、一般的である場合周波数のフェールオーバークラスタが高くなります)、

したがって、データはRedisのメインメモリとして、複数のマシンを使用する必要がある場合、大きい場合のRedisにより延長されているようなシングルスレッドモードRedisのクラスタリング処理以降にデータベース・システムを、クラスター化構築。

  • ソフトウェア工学の視点

すべての開発と保守でシングルスレッドのRedisはかなりの優位性を持たせるために簡単にたくさんよりマルチスレッド開発と保守をシングルスレッド、また、サービスの安定性を向上させることができ、治療ロックなしの面では、

  • Redisのクラスシステム:

最初の実用的かつ工学的に付着したデザイン、Redisの理論的には多くの優れたデザインモードがあるが、必ずしも自分自身を適用されませんが、ソフトウェアの設計プロセスは、トレードオフのプロセスです。

業界はまた、Redisのにすべての機能をアナログ上位層プロトコル変換をカプセル化するSSDストレージエンジンとロックスに基づいて、インフラストラクチャ360ピカ基開発されたシステム、などのNoSQL Redisのクラスの多くを有しており、研究の関心を使用することができます。

 

2.シングルスレッドのファイルイベントとタイムイベント

仕事のシングルスレッドプロセスへのサービスもたくさんあるなどのRedis、Redisのは、イベント駆動型サーバーで、イベントの主な種類は次のとおりです。

  1. イベントのファイルタイプ
  2. タイムイベントの種類

その中でも、時間イベントは、シングルスレッドモデルのロジックを理解する鍵です。

  • タイムイベント

Redisの時間イベントは、2つのカテゴリに分類されます。

  1. 時限イベント:タスクが待機時間指定したサイズのを待った後に実行され、完全な実行は、もはや一度だけトリガーされ実行していません。
  2. サイクルイベント:タスクが所定の時間間隔で実行され、実行が完了した後、次のパフォーマンスのための待ち時間、周期的にトリガ。
  3. 定期的な時間イベント

ほとんどはRedisのサイクルイベント、サイクルイベントは、HAの安定性を確保するために自分自身を検出し、調整するために主に定期的にサーバの動作にあり、この作業は主にServerCron機能を実行され、コンテンツサイクルイベントは、次のとおりです。

  1. Deleteキーデータベース
  2. AOFトリガーRDBと持続性
  3. マスター・スレーブ同期
  4. キープアライブクラスタ
  5. 死んクライアントリンククリーンアップ閉じます
  6. メモリ、このような更新サーバーなどの重要な統計情報の数

支援任務を扱うメインイベントが、サービス全体の安定した動作が、重要な役割を果たしているが、目に見える景気循環のRedis。

  • イベントの順序なしリストの時間

イベントは3つの部分に分割され、それぞれの時間をRedisの:

  1. 昇順にグローバルに一意のイベントID
  2. ミリ秒の精度のタイムスタンプトリガレベル
  3. イベントハンドライベントコールバック関数

タイムイベントTime_Event構造:

Redisの時間イベントは、リンクされたリストに保存され、されていると、保存されたIDに基づいている、頭の中で新たなイベント古いイベントの終わりではなく、順番に格納されていないが、実行されようとしています

各GETリストから、実行する最近の出来事をRedisのように、それは実行後の50msの最初の要素であるが、第三は、30ミリ秒後に実行することがありますO(N)トラバーサルことの必要性

もちろんパフォーマンスは、最高確かに最良の場合の最小スタックMinStack同様の考え方ではありませんが、Antirez首長は無秩序リンクリストを選択しました。

Redisの障害、選択したシーンリストは時間がO(N)の性能損失は最小限のトラバーサルでもある場合でも、毎回多くのRedisのイベント番号ではありませんので、また適切である転位挿入リストの必要がない新しいイベント。

無秩序のRedis示すように、イベントリストの保存時間:

イベントのシングルスレッドのスケジューリングと実行3.

Redisのサービス、それは物事が複雑になるだろう、タイムイベントとファイルイベントが含まれているため、ファイルサーバーたときにイベントを処理すべきかを決定するために、イベントの処理時間を、また、時間の長さが正確処理時間を知るために、イベントのため、実装そして、スケジューリングが焦点となっています。

Redisのサーバーがします順番にイベントのファイルイベントと時間との契約は、アトミックに実行され、注文し、両方のイベントが同期している処理するために、イベントを終了しないサーバが実行されている、イベントが先取りされることはありません。

スケジューリングプロセスは非常に興味深いです、一緒に見てみましょう:

  • イベント実行スケジューリングルール

ファイルイベント処理が完了した場合、ファイルイベントは、ランダムである、ファイルがまだ到着し、サーバーが待機していきます他のイベントではありません、

ファイルの継続的な実施の場合には、時間が徐々に早いタイムイベントに達する設定時間で、最終的には、到着時間を掴むだろう、

这时服务器就可以开始处理到达的时间事件了。由于时间事件在文件事件之后执行,并且事件之间不会出现抢占,

所以时间事件的实际处理时间一般会比设定的时间稍晚一些。

  • 事件执行调度的代码实现

Redis源码ae.c中对事件调度和执行的详细过程在aeProcessEvents中实现的,具体的代码如下:

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
  int processed = 0, numevents;
  if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS))
    return 0;

  if (eventLoop->maxfd != -1 ||
    ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
    int j;
    aeTimeEvent *shortest = NULL;
    struct timeval tv, *tvp;

    if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
      shortest = aeSearchNearestTimer(eventLoop);
    if (shortest) {
      long now_sec, now_ms;
      aeGetTime(&now_sec, &now_ms);
      tvp = &tv;
      long long ms =
        (shortest->when_sec - now_sec)*1000 +
        shortest->when_ms - now_ms;

      if (ms > 0) {
        tvp->tv_sec = ms/1000;
        tvp->tv_usec = (ms % 1000)*1000;
      } else {
        tvp->tv_sec = 0;
        tvp->tv_usec = 0;
      }
    } else {
      if (flags & AE_DONT_WAIT) {
        tv.tv_sec = tv.tv_usec = 0;
        tvp = &tv;
      } else {
        tvp = NULL; /* wait forever */
      }
    }
    numevents = aeApiPoll(eventLoop, tvp);
    if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP)
      eventLoop->aftersleep(eventLoop);

    for (j = 0; j < numevents; j++) {
      aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
      int mask = eventLoop->fired[j].mask;
      int fd = eventLoop->fired[j].fd;
      int fired = 0;
      int invert = fe->mask & AE_BARRIER;
      if (!invert && fe->mask & mask & AE_READABLE) {
        fe->rfileProc(eventLoop,fd,fe->clientData,mask);
        fired++;
      }
      if (fe->mask & mask & AE_WRITABLE) {
        if (!fired || fe->wfileProc != fe->rfileProc) {
          fe->wfileProc(eventLoop,fd,fe->clientData,mask);
          fired++;
        }
      }
      if (invert && fe->mask & mask & AE_READABLE) {
        if (!fired || fe->wfileProc != fe->rfileProc) {
          fe->rfileProc(eventLoop,fd,fe->clientData,mask);
          fired++;
        }
      }
      processed++;
    }
  }
  /* Check time events */
  if (flags & AE_TIME_EVENTS)
    processed += processTimeEvents(eventLoop);
  return processed;
}
  • 事件执行和调度的伪码

上面的源码可能读起来并不直观,在《Redis设计与实现》书中给出了伪代码实现:

def aeProcessEvents()
  #获取当前最近的待执行的时间事件
  time_event = aeGetNearestTimer()
  #计算最近执行事件与当前时间的差值
  remain_gap_time = time_event.when - uinx_time_now()
  #判断时间事件是否已经到期 则重置 马上执行
  if remain_gap_time < 0:
    remain_gap_time = 0
  #阻塞等待文件事件 具体的阻塞等待时间由remain_gap_time决定
  #如果remain_gap_time为0 那么不阻塞立刻返回
  aeApiPoll(remain_gap_time)
  #处理所有文件事件
  ProcessAllFileEvent()
  #处理所有时间事件
  ProcessAllTimeEvent()

可以看到Redis服务器是边阻塞边执行的,具体的阻塞事件由最近待执行时间事件的等待时间决定的,在阻塞该最小等待时间返回之后,开始处理事件任务,

并且先执行文件事件、再执行时间事件,所有即使时间事件要即刻执行,也需要等待文件事件完成之后再执行时间事件,所以比预期的稍晚。

  • 事件调度和执行流程

 

 

4.参考资料

    • 深入了解Redis之事件原理和实现
    • 《Redis设计与实现》黄健宏

おすすめ

転載: www.cnblogs.com/backnullptr/p/12010391.html