Poundの振り分けアルゴリズム

Sessionディレクティブでバックエンドの振り分けルールを指定しないときのアルゴリズムが気になったので調べてみる。

svc.c 516行目あたり

/*
 * Find the right back-end for a request
 */
BACKEND *
get_backend(SERVICE *const svc, const struct in_addr *from_host, const char *request, char **const headers)
{
    BACKEND     *res;
    char        key[KEY_SIZE + 1];
    int         ret_val;
    void        *vp;

    if(svc->tot_pri <= 0)
        /* it might be NULL, but that is OK */
        return svc->emergency;

    if(ret_val = pthread_mutex_lock(&svc->mut))
        logmsg(LOG_WARNING, "get_backend() lock: %s", strerror(ret_val));
    switch(svc->sess_type) {
    case SESS_NONE:
        /* choose one back-end randomly */
        res = rand_backend(svc->backends, random() % svc->tot_pri);
        break;
    case SESS_IP:
        addr2str(key, KEY_SIZE, from_host);
        if((vp = t_find(svc->sessions, key)) == NULL) {
            /* no session yet - create one */
            res = rand_backend(svc->backends, random() % svc->tot_pri);
            svc->sessions = t_add(svc->sessions, key, &res, sizeof(res));
        } else
            memcpy(&res, vp, sizeof(res));
        break;
    case SESS_PARM:
        if(get_REQUEST(key, svc, request)) {
            if((vp = t_find(svc->sessions, key)) == NULL) {
                /* no session yet - create one */
                res = rand_backend(svc->backends, random() % svc->tot_pri);
                svc->sessions = t_add(svc->sessions, key, &res, sizeof(res));
            } else
                memcpy(&res, vp, sizeof(res));
        } else {
            res = rand_backend(svc->backends, random() % svc->tot_pri);
        }
        break;
    default:
        /* this works for SESS_BASIC, SESS_HEADER and SESS_COOKIE */
        if(get_HEADERS(key, svc, headers)) {
            if((vp = t_find(svc->sessions, key)) == NULL) {
                /* no session yet - create one */
                res = rand_backend(svc->backends, random() % svc->tot_pri);
                svc->sessions = t_add(svc->sessions, key, &res, sizeof(res));
            } else
                memcpy(&res, vp, sizeof(res));
        } else {
            res = rand_backend(svc->backends, random() % svc->tot_pri);
        }
        break;
    }
    if(ret_val = pthread_mutex_unlock(&svc->mut))
        logmsg(LOG_WARNING, "get_backend() unlock: %s", strerror(ret_val));

    return res;
}

バックエンドの振り分けはget_backend()関数で処理しているらしい。
Sessionディレクティブを指定しない場合の振り分けは「case SESS_NONE」かな。

    case SESS_NONE:
        /* choose one back-end randomly */
        res = rand_backend(svc->backends, random() % svc->tot_pri);
        break;

「svc->tot_pri」はバックエンドのPriorityの合計。Priorityの合計の範囲内のランダムな値をrand_backend()関数に渡している。。。と。

svc.c 498行目あたり

/*
 * Pick a random back-end from a candidate list
 */
static BACKEND *
rand_backend(BACKEND *be, int pri)
{
    while(be) {
        if(!be->alive || be->disabled) {
            be = be->next;
            continue;
        }
        if((pri -= be->priority) < 0)
            break;
        be = be->next;
    }
    return be;
}

バックエンドのリンクリストをぐるぐる回してトータルのPriorityからバックエンドのPriorityを引いていく。トータルのPriorityがマイナスになったときのバックエンドを返す。。。と。
Priorityが高ければ、マイナスになる確率が高いから優先度が高いってことになるのかな?

ちなみに、バックエンドのPriorityのデフォルト値は5。

    res->priority = 5;

この方法だと、振り分けに偏りがでそう。