rndc status の recursive clients
rndc status 打つと以下のような表示が出るが、
number of zones: 14 debug level: 0 xfers running: 0 xfers deferred: 0 soa queries in progress: 0 query logging is ON recursive clients: 194/1900/2000 tcp clients: 0/100 server is up and running
recursive clients: 194/1900/2000
これの真ん中の 1900 ってナニ?
という質問をされました。
気分転換に調べてみたのでメモ。
まずBINDのソースをダウンロードしてきます。
それを展開して以下のファイルを見ます。
bin/named/server.c
n = snprintf((char *)isc_buffer_used(text), isc_buffer_availablelength(text), "version: %s%s%s%s\n" #ifdef ISC_PLATFORM_USETHREADS "CPUs found: %u\n" "worker threads: %u\n" #endif "number of zones: %u\n" "debug level: %d\n" "xfers running: %u\n" "xfers deferred: %u\n" "soa queries in progress: %u\n" "query logging is %s\n" "recursive clients: %d/%d/%d\n" "tcp clients: %d/%d\n" "server is up and running", ns_g_version, ob, alt, cb, #ifdef ISC_PLATFORM_USETHREADS ns_g_cpus_detected, ns_g_cpus, #endif zonecount, ns_g_debuglevel, xferrunning, xferdeferred, soaqueries, server->log_queries ? "ON" : "OFF", server->recursionquota.used, server->recursionquota.soft, server->recursionquota.max, server->tcpquota.used, server->tcpquota.max);
ここに以下のような記述があります。
"recursive clients: %d/%d/%d\n"
実際に recursive clients: 194/1900/2000 と表示される部分ね。
ここの %d に当てはまるのがそれぞれ、
server->recursionquota.used, server->recursionquota.soft, server->recursionquota.max,
のようです。
usedとmaxはいいとして、softが何なのか謎です。
もうちょい調べてみる。
bin/named/server.c をもう一度良く見て、以下の記述を発見
/* * Configure various server options. */ configure_server_quota(maps, "transfers-out", &server->xfroutquota); configure_server_quota(maps, "tcp-clients", &server->tcpquota); configure_server_quota(maps, "recursive-clients", &server->recursionquota); if (server->recursionquota.max > 1000) isc_quota_soft(&server->recursionquota, server->recursionquota.max - 100); else isc_quota_soft(&server->recursionquota, 0);
ここでサーバパラメータを設定している。
MAXが1000より大きな値ならば、Soft Quotaに MAX - 100 の値を設定している。
たとえば
recursive clients: 194/1900/2000
のように 2000 にしたとしたら、 Soft Quotaは 1900 になる。
で、isc_quota_soft は何かというと以下のCファイルに関数が定義されていて、
lib/isc/quota.c
void isc_quota_soft(isc_quota_t *quota, int soft) { LOCK("a->lock); quota->soft = soft; UNLOCK("a->lock); }
isc_quota_soft(&server->recursionquota, server->recursionquota.max - 100);
のように呼び出して MAX - 100 の値を入れているだけのようだ。
設定されたSoft Quota がどのように利用されるかというと、
まず、lib/isc/quota.c の中の以下の関数で現在のクライアント数をカウントしていて、
lib/isc/quota.c
isc_result_t isc_quota_reserve(isc_quota_t *quota) { isc_result_t result; LOCK("a->lock); if (quota->max == 0 || quota->used < quota->max) { if (quota->soft == 0 || quota->used < quota->soft) result = ISC_R_SUCCESS; else result = ISC_R_SOFTQUOTA; quota->used++; } else result = ISC_R_QUOTA; UNLOCK("a->lock); return (result); }
通常は ISC_R_SUCCESS が返るが、Soft Quotaに達したら ISC_R_SOFTQUOTA を返す。
MAXに達したら ISC_R_QUOTA を返す。
その返り値を見て、
bin/named/query.c の
if (client->recursionquota == NULL) { result = isc_quota_attach(&ns_g_server->recursionquota, &client->recursionquota); if (result == ISC_R_SOFTQUOTA) { static isc_stdtime_t last = 0; isc_stdtime_t now; isc_stdtime_get(&now); if (now != last) { last = now; ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "recursive-clients soft limit " "exceeded, aborting oldest query"); } ns_client_killoldestquery(client); result = ISC_R_SUCCESS; } else if (result == ISC_R_QUOTA) { static isc_stdtime_t last = 0; isc_stdtime_t now; isc_stdtime_get(&now); if (now != last) { last = now; ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "no more recursive clients: %s", isc_result_totext(result)); } ns_client_killoldestquery(client); } if (result == ISC_R_SUCCESS && !client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0) { result = ns_client_replace(client); if (result != ISC_R_SUCCESS) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, ISC_LOG_WARNING, "ns_client_replace() failed: %s", isc_result_totext(result)); isc_quota_detach(&client->recursionquota); } } if (result != ISC_R_SUCCESS) return (result); ns_client_recursing(client); }
if (result == ISC_R_SOFTQUOTA) でクライアント数がSoft Quotaに達したら
"recursive-clients soft limit "
"exceeded, aborting oldest query"
のようなログを吐いて、
ns_client_killoldestquery(client); 関数を呼んで
古いクエリを殺し、ISC_R_SUCCESS を返す。
if (result == ISC_R_QUOTA) でクライアント数がHard Quota (MAX)に達したら、
no more recursive clients:
のようなログを吐いて、
ns_client_killoldestquery(client); 関数を呼んで
古いクエリを殺すが ISC_R_SUCCESSは返さない。
このns_client_killoldestquery(client)関数の中身までは追ってない。
ソース読むの苦手だけど、BINDのソースってずいぶん丁寧に書かれていてわかりやすいな……すごい。