Redis起動プロセス
9344 ワード
redisの起動プロセスについて話します.
まず起動関数を見つけなければならない.Cプログラムは
コード全体で最も重要な構造体は
例:
serverフィールド
意味
runid
ノード識別占有40 B
port
起動ポートのデフォルトは6379です
tcp_backlog
デフォルト511 B
aof_fsync
デフォルトaofは1秒あたりディスクをブラシしますが、aofはデフォルトで閉じます.
aof_filename
デフォルトaofファイル名はappendonlyです.aof
rdb_filename
デフォルトrdbファイル名はdump.rdb
cluster_node_timeout
デフォルト15 s、デフォルトclusterモードオフ
backlogに関する設定が含まれます.
浮動小数点データの精度設定.
全部で3種類あり、以下の通りです.
初期化redisコマンドテーブルは
注意:redis.confプロファイルではrename-commandを使用してCommandの名前を変更できます(通常はセキュリティ上の考慮のためにいくつかのコマンドを無効にします).したがって、コマンドテーブルには
また、頻繁にクエリーされるコマンドも個別に提出され、以下の変数にそれぞれ配置されます.
デフォルトは10 msです.
このモードをオンにするには、次のようにします.
コマンドラインパラメータ
このモードをオンにすると、対応する初期を行い、オンにしないでスキップします.
主に、プロファイルの絶対パス
プロファイルの読み込みには専用の関数があります
プロファイルをロードすると、以前のserverのデフォルト構成の一部が上書きされます.実際には、redis-serverが起動すると、いくつかの構成は
信号処理をredisで復習します.
主にプログラム終了の善後作業である.
前提はシステムのrsyslogを使用したことです.
この関数は、頻繁に使用される文字列を保存し、リリースを申請するときのCPU時間、メモリの破片などを減らすことを目的としています.
例えば
さらに、ここでは、0〜999の大きな共有デジタルオブジェクトも初期化される.したがってvalueを設定するときにこれらの数字を使用すると、メモリの使用を減らすことができます.
この関数は、プロファイルで構成されている最大client数に基づいて、開くことができる最大ファイル数を増やします.
ここでio多重化はepollを用いると仮定し,これも最も多く用いられる.
データベース・オブジェクトは
登録タイミング時間は、コールバック関数
では、なぜこの周波数なのでしょうか.redisではイベント処理について以前のブログで書いたことがありますが、Redisのイベントを参考にして、ここでも簡単に振り返ることができます.
タイムイベント処理関数
ユーザ要求を受信し(ユーザ接続はここから入る)、読み取り可能なイベントを傍受し、コールバック関数
cluster modeがオンの場合、対応する初期化が行われます.
この関数は実用的で、psが良好なフォーマットのプロセス名を見るのに便利です.一緒に復習しましょう.
sentinelモードで起動しない場合は、
aofがオンの場合はaofファイルをロードし、そうでない場合はrdbファイルをロードします.
loadAppendOnlyFile
この関数はaofファイルを記述するために使用され、主な流れは偽クライアントを作成し、aofファイルからコマンドを解析し、serverにもう一度実行させることです.
以上の関数がaofファイル解析プロセスです.
redisプロトコルデータを添付し、関数の分析を容易にします.
注意:aofファイルのロード中にaofが一時的に閉じられます.
rdbLoad
この関数はrdbファイルをロードするために使用されます.aofロードとは異なり、rdbファイルを解析してメモリに直接入れます.
フローチャートを描いて、以上のフローをよく体現することができます.
まず起動関数を見つけなければならない.Cプログラムは
main
関数から始まることを知っているので、「夢」が始まる場所server.c
->main
を見つけた.ここでは主に起動過程の主な部分を話しているので、一つ一つは触れません.概ねプロセスの開始
initServerConfig関数
コード全体で最も重要な構造体は
struct redisServer server
であり、グローバル変数として現れる.この関数は主にそのメンバーに付与操作を行い、これらのメンバーは基本的にredisを通過することができる.confファイルで構成します.ほとんどのメンバーに初期値を付与
例:
serverフィールド
意味
runid
ノード識別占有40 B
port
起動ポートのデフォルトは6379です
tcp_backlog
デフォルト511 B
aof_fsync
デフォルトaofは1秒あたりディスクをブラシしますが、aofはデフォルトで閉じます.
aof_filename
デフォルトaofファイル名はappendonlyです.aof
rdb_filename
デフォルトrdbファイル名はdump.rdb
cluster_node_timeout
デフォルト15 s、デフォルトclusterモードオフ
デフォルトrdbトリガ条件
appendServerSaveParams(60 * 60,1); /* save after 1 hour and 1 change */
appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
Replication related
backlogに関する設定が含まれます.
Double constants initialization
浮動小数点データの精度設定.
client output buffer limit
全部で3種類あり、以下の通りです.
clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {
{0, 0, 0}, /* normal */
{1024*1024*256, 1024*1024*64, 60}, /* slave */
{1024*1024*32, 1024*1024*8, 60} /* pubsub */
};
redisコマンドテーブル
初期化redisコマンドテーブルは
server.commands
に配置され、これは主にpopulateCommandTable
関数で完了する.注意:redis.confプロファイルではrename-commandを使用してCommandの名前を変更できます(通常はセキュリティ上の考慮のためにいくつかのコマンドを無効にします).したがって、コマンドテーブルには
server.commands
とserver.orig_commands
の2つが保存されます.また、頻繁にクエリーされるコマンドも個別に提出され、以下の変数にそれぞれ配置されます.
struct redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand,
*rpopCommand, *sremCommand, *execCommand;
Slow log
デフォルトは10 msです.
sentinelモード
このモードをオンにするには、次のようにします.
int checkForSentinelMode(int argc, char **argv) {
int j;
if (strstr(argv[0],"redis-sentinel") != NULL) return 1;
for (j = 1; j < argc; j++)
if (!strcmp(argv[j],"--sentinel")) return 1;
return 0;
}
コマンドラインパラメータ
--sentinel
を使用するか、バイナリファイルredis-sentinel
を直接使用します.このモードをオンにすると、対応する初期を行い、オンにしないでスキップします.
if (server.sentinel_mode) {
initSentinelConfig(); // sentinel 26379
initSentinel(); // sentinel
}
コマンドラインパラメータ解析とプロファイルの読み込み
主に、プロファイルの絶対パス
server.configfile = getAbsolutePath(configfile)
が取得される.プロファイルの読み込みには専用の関数があります
void loadServerConfig(char *filename, char *options){}
プロファイルをロードすると、以前のserverのデフォルト構成の一部が上書きされます.実際には、redis-serverが起動すると、いくつかの構成は
config get
コマンドで表示することも、config set
コマンドで変更することもでき、修正後のconfig rewrite
ブラシディスクを表示することもできます.initServer関数
initServerConfig
関数とは異なり、redis-server実行中のメンバーを主に初期化します.しんごうしょり
信号処理をredisで復習します.
// SIGHUP SIGPIPE
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
void setupSignalHandlers(void) {
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sigShutdownHandler;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
return;
}
主にプログラム終了の善後作業である.
システムログ
if (server.syslog_enabled) {
openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,
server.syslog_facility);
}
前提はシステムのrsyslogを使用したことです.
createSharedObjects関数
この関数は、頻繁に使用される文字列を保存し、リリースを申請するときのCPU時間、メモリの破片などを減らすことを目的としています.
例えば
shared.ok = createObject(OBJ_STRING,sdsnew("+OK\r
"))
です.さらに、ここでは、0〜999の大きな共有デジタルオブジェクトも初期化される.したがってvalueを設定するときにこれらの数字を使用すると、メモリの使用を減らすことができます.
#define OBJ_SHARED_INTEGERS 10000
for (j = 0; j < OBJ_SHARED_INTEGERS; j++) { // 10000
shared.integers[j] = createObject(OBJ_STRING,(void*)(long)j);
shared.integers[j]->encoding = OBJ_ENCODING_INT;
}
struct sharedObjectsStruct shared
もグローバル変数です.adjustOpenFilesLimit関数
この関数は、プロファイルで構成されている最大client数に基づいて、開くことができる最大ファイル数を増やします.
eventLoopの作成
server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR)
ここでio多重化はepollを用いると仮定し,これも最も多く用いられる.
データベース・オブジェクトの初期化
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
データベース・オブジェクトは
struct redisDb
で、16個あります.ポートのリスニング
if (server.port != 0 &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
exit(1);
server.port
を傍受し、返されたfdをserver.ipfd
に格納し、エラーが発生したら返す.システムcronタイマの作成
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
serverPanic("Can't create the serverCron time event.");
exit(1);
}
登録タイミング時間は、コールバック関数
serverCron
をバインドします.この関数では、実行サイクルが1000/server.hz
msであることがわかります.したがって、1秒当たりserver.hz
が実行されます(この値はユーザーが設定できます).では、なぜこの周波数なのでしょうか.redisではイベント処理について以前のブログで書いたことがありますが、Redisのイベントを参考にして、ここでも簡単に振り返ることができます.
タイムイベント処理関数
ae.c
->processTimeEvents
では、タイムイベントのコールバック戻り値に基づいて、このときの1サイクルイベントが1回のイベントであるか、すなわち、{
int retval;
id = te->id;
retval = te->timeProc(eventLoop, id, te->clientData);
processed++;
if (retval != AE_NOMORE) {
aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
} else {
te->id = AE_DELETED_EVENT_ID;
}
}
ユーザーリクエストのリスニング/受信
for (j = 0; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, //
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
ユーザ要求を受信し(ユーザ接続はここから入る)、読み取り可能なイベントを傍受し、コールバック関数
acceptTcpHandler
を登録する.初期化
cluster modeがオンの場合、対応する初期化が行われます.
if (server.cluster_enabled) clusterInit();
その他の環境初期化
replicationScriptCacheInit();
scriptingInit(1);
slowlogInit();
latencyMonitorInit();
bioInit();
プロセス名の設定
この関数は実用的で、psが良好なフォーマットのプロセス名を見るのに便利です.一緒に復習しましょう.
void redisSetProcTitle(char *title) {
#ifdef USE_SETPROCTITLE
char *server_mode = "";
if (server.cluster_enabled) server_mode = " [cluster]";
else if (server.sentinel_mode) server_mode = " [sentinel]";
setproctitle("%s %s:%d%s",
title,
server.bindaddr_count ? server.bindaddr[0] : "*",
server.port,
server_mode);
#else
UNUSED(title);
#endif
}
永続化データのロード
sentinelモードで起動しない場合は、
loadDataFromDisk
の処理関数で永続化されたデータがロードされます.aofがオンの場合はaofファイルをロードし、そうでない場合はrdbファイルをロードします.
loadAppendOnlyFile
この関数はaofファイルを記述するために使用され、主な流れは偽クライアントを作成し、aofファイルからコマンドを解析し、serverにもう一度実行させることです.
if (buf[0] != '*') goto fmterr; //
if (buf[1] == '\0') goto readerr; //
argc = atoi(buf+1);
if (argc < 1) goto fmterr;
argv = zmalloc(sizeof(robj*)*argc); // argc robj
fakeClient->argc = argc;
fakeClient->argv = argv;
for (j = 0; j < argc; j++) {
if (fgets(buf,sizeof(buf),fp) == NULL) { // 128B
fakeClient->argc = j; /* Free up to j-1. */
freeFakeClientArgv(fakeClient);
goto readerr;
}
if (buf[0] != '$') goto fmterr;
len = strtol(buf+1,NULL,10); //
argsds = sdsnewlen(NULL,len);
if (len && fread(argsds,len,1,fp) == 0) {
sdsfree(argsds);
fakeClient->argc = j; /* Free up to j-1. */
freeFakeClientArgv(fakeClient);
goto readerr;
}
argv[j] = createObject(OBJ_STRING,argsds);
if (fread(buf,2,1,fp) == 0) { // \r
fakeClient->argc = j+1; /* Free up to j. */
freeFakeClientArgv(fakeClient);
goto readerr; /* discard CRLF */
}
}
cmd = lookupCommand(argv[0]->ptr);
if (!cmd) {
serverLog(LL_WARNING,"Unknown command '%s' reading the append only file", (char*)argv[0]->ptr);
exit(1);
}
// fakeClient
cmd->proc(fakeClient);
以上の関数がaofファイル解析プロセスです.
redisプロトコルデータを添付し、関数の分析を容易にします.
*3
$3
SET
$2
xx
$2
yy
*3
注意:aofファイルのロード中にaofが一時的に閉じられます.
rdbLoad
この関数はrdbファイルをロードするために使用されます.aofロードとは異なり、rdbファイルを解析してメモリに直接入れます.
イベントループ初期化
// beforeSleep()
aeSetBeforeSleepProc(server.el,beforeSleep);
//
aeMain(server.el);
// ,
aeDeleteEventLoop(server.el);
小結
フローチャートを描いて、以上のフローをよく体現することができます.