Redisソースのプロファイリング--Notifyに通知
6548 ワード
Redisは2.8以降、データベース内のキーと値に影響を与える操作イベントをサブスクリプション/パブリッシュモードで受信できるようにするキースペース通知機能を追加しました.Redis通知のソースコードはnotifyである.cファイルで実現するには、ソースコードには3つの機能関数しかなく、比較的簡単であるが、その機能を理解するにはserverに協力する必要がある.cとpubsub.cの中のコードの一部.
Notifyの概要Redisサーバでは、パブリケーション機能を購読することで、サーバ内のキースペースイベントを送信できます.キー空間イベントとは、データベース内のキーの増加、変更、削除などの操作であり、そのクラスのイベントを受信したクライアントが現在データベースで実行している操作を通知するために使用されます.通知機能はサーバの生産性に影響を与えるため、Redisは起動時にキースペースイベント通知機能をオンにしないことをデフォルトで設定します.
キー空間イベント通知機能をオンにするか、redisを変更する特定のタイプの通知のみを受け入れるかの2つの方法がある.confの指定パラメータは、次のとおりです.
/*デフォルトは空で、キースペースイベント通知機能をオンにしないことを示します*/notify-keyspace-events""第2の方法は、CONFIGSETコマンドを使用してnotify-keyspace-eventsパラメータを設定することです.コマンド形式は次のとおりです.
/*xxはサブスクリプションのイベントタイプを表し、後で*/CONFIG SET notify-keyspace-events KEについて説明します.
サーバがキー空間イベント通知機能をオンにする場合は、イベントのタイプ、すなわち、どの特定のタイプの通知をオンにするかを指定する必要があります.Redisは、イベントのタイプを識別する一連のマクロ定義を設定します.
#define NOTIFY_KEYSPACE (1<<0)/* K/#define NOTIFY_KEYEVENT (1<<1)/E/#define NOTIFY_GENERIC (1<<2)/g/#define NOTIFY_STRING (1<<3)/$/#define NOTIFY_LIST (1<<4)/l/#define NOTIFY_SET (1<<5)/s/#define NOTIFY_HASH (1<<6)/h/#define NOTIFY_ZSET (1<<7)/z/#define NOTIFY_EXPIRED (1<<8)/x/#define NOTIFY_EVICTED (1<<9)/e/#define NOTIFY_ALL(NOTIFY_GENERIC|NOTIFY_STRING|NOTIFY_LIST|NOTIFY_SET|NOTIFY_HASH|NOTIFY_ZSET|NOTIFY_ZSET|NOTIFY_EXPIRED|NOTIFY_EVICTED)/A*/各マクロ定義が表すイベントタイプは以下の表の通りである.
イベント番号イベントタイプKキースペース通知、すべての通知が_keyspace@__接頭辞Eキーイベント通知、すべての通知は_keyevent@__プレフィックスg DEL、EXPIRE、RENAMEなどのタイプに関係のない汎用コマンド$文字列コマンドの通知lリストコマンドの通知hハッシュコマンドの通知z整列集合コマンドの通知x期限切れイベント:期限切れキーが削除されるたびにe駆逐イベントを送信:maxmemoryポリシーによりキーが削除されるたびにAパラメータg$lshzxeの別名を送信する上記のすべてのコマンドを表すnotify-keyspace-eventsの設定については、入力パラメータには、通知がキー空間であるかキーイベントであるかを識別するために少なくとも1つのKまたはEが必要である.含まない場合は、残りのパラメータにかかわらず、通知は配布されません.例:
~redis-cli/*すべてのイベントを開く/127.0.0.1:6379>CONFIG SET notify-keyspace-events KEA OK/すべてのキースペースを開くコマンドを開く/127.0.0.1:6379>CONFIG SET notify-keyspace-events KA OK/リストを開くコマンドのキーイベント通知*/127.0.0.1:6379>CONFIG SET notify-keyspace-events ElOK
Notifyソース実装
Notifyの機能は3つの関数で実現され,間違いなく3つであり,Redisモジュールの区分が明確な利点を十分に体現し,コードの再利用性が強い.この3つの関数を見てみましょう.
/*Notify設定パラメータを文字列から識別量flag*/int keyspaceEventsStringToFlags(char classes);/Notify設定パラメータを識別量flagsから文字列/sds keyspaceEventsFlagsToString(int flags);通知機能の実現*/void notifyKeyspaceEvent(int type,char*event,robj*key,int dbid);まず最初の関数を見てみましょう.Notify設定パラメータを文字列から識別量flagに変換する機能です.
int keyspaceEventsStringToFlags(char*classes){char*p=classes;int c,flags=0;//各文字while((c=*p+)!='0'){switch© { case ‘A’: flags |= NOTIFY_ALL; break; case ‘g’: flags |= NOTIFY_GENERIC; break; case ‘$’: flags |= NOTIFY_STRING; break; case ‘l’: flags |= NOTIFY_LIST; break; case ‘s’: flags |= NOTIFY_SET; break; case ‘h’: flags |= NOTIFY_HASH; break; case ‘z’: flags |= NOTIFY_ZSET; break; case ‘x’: flags |= NOTIFY_EXPIRED; break; case ‘e’: flags |= NOTIFY_EVICTED; break; case ‘K’: flags |= NOTIFY_KEYSPACE; break; case ‘E’: flags |= NOTIFY_KEYEVENT; break; default: return -1; } } return flags; } 次に、その逆関数を見てみましょう.
sds keyspaceEventsFlagsToString(int flags) { sds res;
}次に,主役が登場し,Redisのサブスクリプションとパブリッシュ機能を利用してキー空間イベント通知を送信する.
void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24];
}通知全体の実装は、pub/sub機能によってイベント通知を送信し、クライアントがキー空間イベントを受信できるようにする.
Notifyインスタンス上記の通知を検証するために予想通りに送信したかどうかは,小さな実験をして検証することができる.まず2つのredis-cliクライアントを開き、各クライアントは次のコマンドを実行します.
/*0番クライアント/127.0.0.1:6379>PSUBScriBE_keyevent Reading messages… (press Ctrl-C to quit) “psubscribe” “__keyevent*” (integer)1/*1番クライアント*/127.0.0.1:6379>CONFIG SET notify-keyspace-events KEA OK 127.0.0.1:6379>set str value OK 0番クライアントがPSUBScriBEコマンドを実行すると、該当パターン列_の購読が開始されます.keyevent*のイベントで、1番クライアントはまずサーバーオープンキー空間イベント通知機能を設定し、SETコマンドを実行し、この時間0番クライアントはこのイベントを受信することができます.以下のようにします.
/*0番クライアント/127.0.0.1:6379>PSUBScriBE_key Reading messages… (press Ctrl-C to quit) “psubscribe” “__key*” (integer)1/*keyspaceキースペース通知*/ “pmessage” “__key*” “keyspace@0:str” 「set」/*keyeventsキーイベント通知*/ “pmessage” “__key*” “keyevent@0:set” "str"Notify小結本編ブログでは、通知機能の実現を簡単に分析した.ソースコード部分は比較的簡単で、データベース内のキーが変更され、サーバが対応するイベントタイプ通知を開いた場合、Redisはキーイベント通知を送信し、pub/sub命令によってクライアントに現在のデータベースでの変更操作を通知する.pub/sub機能は後続のブログで述べられ、その時になったら、以下の通知プロセス全体を後で理解することができます.
Notifyの概要Redisサーバでは、パブリケーション機能を購読することで、サーバ内のキースペースイベントを送信できます.キー空間イベントとは、データベース内のキーの増加、変更、削除などの操作であり、そのクラスのイベントを受信したクライアントが現在データベースで実行している操作を通知するために使用されます.通知機能はサーバの生産性に影響を与えるため、Redisは起動時にキースペースイベント通知機能をオンにしないことをデフォルトで設定します.
キー空間イベント通知機能をオンにするか、redisを変更する特定のタイプの通知のみを受け入れるかの2つの方法がある.confの指定パラメータは、次のとおりです.
/*デフォルトは空で、キースペースイベント通知機能をオンにしないことを示します*/notify-keyspace-events""第2の方法は、CONFIGSETコマンドを使用してnotify-keyspace-eventsパラメータを設定することです.コマンド形式は次のとおりです.
/*xxはサブスクリプションのイベントタイプを表し、後で*/CONFIG SET notify-keyspace-events KEについて説明します.
サーバがキー空間イベント通知機能をオンにする場合は、イベントのタイプ、すなわち、どの特定のタイプの通知をオンにするかを指定する必要があります.Redisは、イベントのタイプを識別する一連のマクロ定義を設定します.
#define NOTIFY_KEYSPACE (1<<0)/* K/#define NOTIFY_KEYEVENT (1<<1)/E/#define NOTIFY_GENERIC (1<<2)/g/#define NOTIFY_STRING (1<<3)/$/#define NOTIFY_LIST (1<<4)/l/#define NOTIFY_SET (1<<5)/s/#define NOTIFY_HASH (1<<6)/h/#define NOTIFY_ZSET (1<<7)/z/#define NOTIFY_EXPIRED (1<<8)/x/#define NOTIFY_EVICTED (1<<9)/e/#define NOTIFY_ALL(NOTIFY_GENERIC|NOTIFY_STRING|NOTIFY_LIST|NOTIFY_SET|NOTIFY_HASH|NOTIFY_ZSET|NOTIFY_ZSET|NOTIFY_EXPIRED|NOTIFY_EVICTED)/A*/各マクロ定義が表すイベントタイプは以下の表の通りである.
イベント番号イベントタイプKキースペース通知、すべての通知が_keyspace@__接頭辞Eキーイベント通知、すべての通知は_keyevent@__プレフィックスg DEL、EXPIRE、RENAMEなどのタイプに関係のない汎用コマンド$文字列コマンドの通知lリストコマンドの通知hハッシュコマンドの通知z整列集合コマンドの通知x期限切れイベント:期限切れキーが削除されるたびにe駆逐イベントを送信:maxmemoryポリシーによりキーが削除されるたびにAパラメータg$lshzxeの別名を送信する上記のすべてのコマンドを表すnotify-keyspace-eventsの設定については、入力パラメータには、通知がキー空間であるかキーイベントであるかを識別するために少なくとも1つのKまたはEが必要である.含まない場合は、残りのパラメータにかかわらず、通知は配布されません.例:
~redis-cli/*すべてのイベントを開く/127.0.0.1:6379>CONFIG SET notify-keyspace-events KEA OK/すべてのキースペースを開くコマンドを開く/127.0.0.1:6379>CONFIG SET notify-keyspace-events KA OK/リストを開くコマンドのキーイベント通知*/127.0.0.1:6379>CONFIG SET notify-keyspace-events ElOK
Notifyソース実装
Notifyの機能は3つの関数で実現され,間違いなく3つであり,Redisモジュールの区分が明確な利点を十分に体現し,コードの再利用性が強い.この3つの関数を見てみましょう.
/*Notify設定パラメータを文字列から識別量flag*/int keyspaceEventsStringToFlags(char classes);/Notify設定パラメータを識別量flagsから文字列/sds keyspaceEventsFlagsToString(int flags);通知機能の実現*/void notifyKeyspaceEvent(int type,char*event,robj*key,int dbid);まず最初の関数を見てみましょう.Notify設定パラメータを文字列から識別量flagに変換する機能です.
int keyspaceEventsStringToFlags(char*classes){char*p=classes;int c,flags=0;//各文字while((c=*p+)!='0'){switch© { case ‘A’: flags |= NOTIFY_ALL; break; case ‘g’: flags |= NOTIFY_GENERIC; break; case ‘$’: flags |= NOTIFY_STRING; break; case ‘l’: flags |= NOTIFY_LIST; break; case ‘s’: flags |= NOTIFY_SET; break; case ‘h’: flags |= NOTIFY_HASH; break; case ‘z’: flags |= NOTIFY_ZSET; break; case ‘x’: flags |= NOTIFY_EXPIRED; break; case ‘e’: flags |= NOTIFY_EVICTED; break; case ‘K’: flags |= NOTIFY_KEYSPACE; break; case ‘E’: flags |= NOTIFY_KEYEVENT; break; default: return -1; } } return flags; } 次に、その逆関数を見てみましょう.
sds keyspaceEventsFlagsToString(int flags) { sds res;
res = sdsempty();
//
if ((flags & NOTIFY_ALL) == NOTIFY_ALL) {
res = sdscatlen(res,"A",1);
} else {
//
if (flags & NOTIFY_GENERIC) res = sdscatlen(res,"g",1);
if (flags & NOTIFY_STRING) res = sdscatlen(res,"$",1);
if (flags & NOTIFY_LIST) res = sdscatlen(res,"l",1);
if (flags & NOTIFY_SET) res = sdscatlen(res,"s",1);
if (flags & NOTIFY_HASH) res = sdscatlen(res,"h",1);
if (flags & NOTIFY_ZSET) res = sdscatlen(res,"z",1);
if (flags & NOTIFY_EXPIRED) res = sdscatlen(res,"x",1);
if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1);
}
// K,E
if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1);
if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1);
return res;
}次に,主役が登場し,Redisのサブスクリプションとパブリッシュ機能を利用してキー空間イベント通知を送信する.
void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid) { sds chan; robj *chanobj, *eventobj; int len = -1; char buf[24];
// ,
if (!(server.notify_keyspace_events & type)) return;
//
eventobj = createStringObject(event,strlen(event));
// , __keyspace@__:
if (server.notify_keyspace_events & NOTIFY_KEYSPACE) {
chan = sdsnewlen("__keyspace@",11);
len = ll2string(buf,sizeof(buf),dbid);
chan = sdscatlen(chan, buf, len);
chan = sdscatlen(chan, "__:", 3);
chan = sdscatsds(chan, key->ptr);
chanobj = createObject(OBJ_STRING, chan);
// pub/sub
pubsubPublishMessage(chanobj, eventobj);
decrRefCount(chanobj);
}
// , __keyevente@__:
if (server.notify_keyspace_events & NOTIFY_KEYEVENT) {
chan = sdsnewlen("__keyevent@",11);
if (len == -1) len = ll2string(buf,sizeof(buf),dbid);
chan = sdscatlen(chan, buf, len);
chan = sdscatlen(chan, "__:", 3);
chan = sdscatsds(chan, eventobj->ptr);
chanobj = createObject(OBJ_STRING, chan);
// pub/sub
pubsubPublishMessage(chanobj, key);
decrRefCount(chanobj);
}
decrRefCount(eventobj);
}通知全体の実装は、pub/sub機能によってイベント通知を送信し、クライアントがキー空間イベントを受信できるようにする.
Notifyインスタンス上記の通知を検証するために予想通りに送信したかどうかは,小さな実験をして検証することができる.まず2つのredis-cliクライアントを開き、各クライアントは次のコマンドを実行します.
/*0番クライアント/127.0.0.1:6379>PSUBScriBE_keyevent Reading messages… (press Ctrl-C to quit)
/*0番クライアント/127.0.0.1:6379>PSUBScriBE_key Reading messages… (press Ctrl-C to quit)