Nginx 내 장 된 부하 균형 전략 - 가중 폴 링 (Weighted Round Robin)

Nginx 에서 역방향 프 록 시 를 설정 할 때 역방향 프 록 시 에서 모든 백 엔 드 서버 가 차지 하 는 비중 을 지정 하여 부하 균형 을 이 루 는 역할 을 할 수 있 습 니 다. 역방향 프 록 시 예 를 보십시오.
upstream backend {  
        server a weight=5;  
        server b weight=3;  
        server c weight=1;  
    }

예 를 들 어 세 대의 백 스테이지 서버 를 설 치 했 는데 차지 하 는 비중 은 각각 5, 3, 1 이다.그렇다면 요청 을 받 았 을 때 비율 에 따라 백 스테이지 서버 세 대 를 배정 하 는 방법 은 무엇 일 까?생각 할 수 있 는 가장 간단 한 방법 은 바로 현재 가중치 가 0 보다 크 면 이 서버 에 보 내 고 가중치 가 1 을 줄 이 는 것 이다. 그러나 이런 방법 으로 나 누 어 주 는 요청 결 과 는 [a, a, a, a, b, b, b, c] 이다. 목표 의 비례 에 달 했 지만 한 동안 요청 은 모두 a 로 보 냈 고 다른 한 부분 은 b 로 보 냈 다. 이것 은 좋 은 처리 방식 이 아니다.기계 마다 바 쁘 고 한가 한 셈 이지 평균 적 으로 요 구 를 받 지 못 했다.
그러면 nginx 에 서 는 어떻게 부하 균형 을 잡 고 모든 기계 가 받 는 요청 빈 도 를 더욱 고 르 게 합 니까?정 답 은 weighted round robin (WRR) 이라는 알고리즘 입 니 다. 알고리즘 의 데이터 해석 과 증명 에 대해 시간 이 있 으 면 따로 토론 할 수 있 습 니 다. 먼저 Nignx 가 어떻게 이 알고리즘 을 실현 하 는 지 직접 보 세 요. 
nginx 에서 몇 대의 서버 에서 유효한 서버 를 선택 하 는 과정 을 ngx 라 고 합 니 다.http_upstream_get_peer 의 함수 중에서 먼저 전체적인 함 수 를 직접 보 세 요.
/*                          */
static ngx_http_upstream_rr_peer_t *
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
{
    time_t                        now;
    uintptr_t                     m;
    ngx_int_t                     total;
    ngx_uint_t                    i, n;
    ngx_http_upstream_rr_peer_t  *peer, *best;

    now = ngx_time();

    best = NULL;
    total = 0;

    /*           */
    for (i = 0; i < rrp->peers->number; i++) {

        /*                  n */
        n = i / (8 * sizeof(uintptr_t));
        m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

        /*                 ,       ,  continue            */
        if (rrp->tried[n] & m) {
            continue;
        }

        /*                 ,      ,        */
        peer = &rrp->peers->peer[i];

        /*            down    ,   1          ,  continue            */
        if (peer->down) {
            continue;
        }

        /*
         *          down      0,                         max_fails;
         *           fail_timeout,            ,continue           ;
         */
        if (peer->max_fails
            && peer->fails >= peer->max_fails
            && now - peer->checked <= peer->fail_timeout)
        {
            continue;
        }

        /*              ,       */

        /*
         *           current_weight = 0,effective_weight = weight;
         *   ,             current_weight          effective_weight;
         *              effective_weight;
         */
        peer->current_weight += peer->effective_weight;
        total += peer->effective_weight;

        /*      ,   effective_weight    */
        if (peer->effective_weight < peer->weight) {
            peer->effective_weight++;
        }

        /*             current_weight      best       ,            */
        if (best == NULL || peer->current_weight > best->current_weight) {
            best = peer;
        }
    }

    if (best == NULL) {
        return NULL;
    }

    /*                      i */
    i = best - &rrp->peers->peer[0];

    /*             ngx_http_upstream_rr_peer_data_t     current     ,               */
    rrp->current = i;

    /*                   */
    n = i / (8 * sizeof(uintptr_t));
    m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));

    /*                    */
    rrp->tried[n] |= m;

    /*               */
    best->current_weight -= total;

    if (now - best->checked > best->fail_timeout) {
        best->checked = now;
    }

    /*             */
    return best;
}

함수 에서 nginx 는 현재 서버 가 선택 되 었 는 지, 유효 하 는 지 등 다른 검사 와 같은 동작 도 많이 했 습 니 다.단순히 선택 알고리즘 에 만 관심 을 가지 면 다른 과정 을 삭제 하고 남 을 수 있 습 니 다.
/*                          */
static ngx_http_upstream_rr_peer_t *
ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
{
    ....
    best = NULL;
    total = 0;

    /*           */
    for (i = 0; i < rrp->peers->number; i++) {

        ........

        /*              ,       */

        /*
         *           current_weight = 0,effective_weight = weight;
         *   ,             current_weight          effective_weight;
         *              effective_weight;
         */
        peer->current_weight += peer->effective_weight;
        total += peer->effective_weight;

        /*      ,   effective_weight    */
        if (peer->effective_weight < peer->weight) {
            peer->effective_weight++;
        }

        /*             current_weight      best       ,            */
        if (best == NULL || peer->current_weight > best->current_weight) {
            best = peer;
        }
    }

    if (best == NULL) {
        return NULL;
    }

    ........

    /*               */
    best->current_weight -= total;

    if (now - best->checked > best->fail_timeout) {
        best->checked = now;
    }

    /*             */
    return best;
}

모든 백 엔 드 peer 에는 세 개의 가중치 변수 가 있 습 니 다.
(1) weight
설정 파일 에서 지정 한 이 백 엔 드 의 가중치 입 니 다. 이 값 은 고정 적 으로 변 하지 않 습 니 다.
(2) effective_weight
백 엔 드 의 유효 가중치, 초기 값 은 weight 입 니 다.
왜 effective 가 나 와 요?weight? 그냥 weight 가 아 닌 데?현재 서버 에 오류 가 발생 하면 effective 를 줄 일 수 있 기 때 문 입 니 다.weight, 이 기계 가 선 택 될 확률 을 낮 춥 니 다.물론 서버 가 정상 이 라면, effective_weight 는 항상 weight 와 같 습 니 다.
오류 가 발생 한 서버 가 다시 정상 으로 돌아 오 면 선택 하 는 과정 에서 effective 가 점점 증가 합 니 다.weight, 결국 weight 로 회 복 됩 니 다.
(3) current_weight
백 엔 드 의 현재 가중치 는 처음에는 0 이 고 선택 할 때마다 조정 되 며 백 엔 드 마다 currentweight 그것 의 effective 증가weight,
동시에 모든 백 엔 드 를 누적 하 는 effectiveweight, totalk 로 저장.
이 백 엔 드 의 currentweight 가 가장 큽 니 다. 이 백 엔 드 를 선택 하고 currentweight 에서 total 을 빼다.
이 백 엔 드 가 선택 되 지 않 았 다 면 currentweight 줄 일 필요 없어 요.
 
세 개의 weight 필드 의 의 미 를 파악 한 후 가중 폴 링 알고리즘 은 다음 과 같이 설명 할 수 있 습 니 다.
1. 모든 요청 에 대해 클 러 스 터 의 모든 사용 가능 한 백 엔 드 를 옮 겨 다 니 며 모든 백 엔 드 peer 를 실행 합 니 다.
    peer->current_weight += peer->effecitve_weight。
    동시에 모든 peer 의 effective 를 누적 합 니 다.weight, totalk 로 저장.
2. 클 러 스 터 에서 current 선택weight 가 가장 큰 peer 는 이번 선 택 된 백 엔 드 입 니 다.
3. 이번 선 택 된 백 엔 드 에 대해 실행: per - > currentweight -= total。
위의 소스 코드 를 직접 대조 하여 이해 할 수 있다. 
 
처음 설정 을 예 로 들다
upstream backend {
    server a weight=5;
    server b weight=3;
    server c weight=1;
}
처음 엔 currentweight = { 0, 0, 0 }, effective_weight = { 5, 3, 1 }。서버 가 중간 에 고장 이 나 지 않 는 다 고 가정 하면 토 탈 은 모든 effectiveweight 의 총화, 즉 9.
번호
current_weight 선택 전
게다가 effective무게 후
선택 하 다.
토 탈 빼 고.
1
 { 0, 0, 0 }
 { 5, 3, 1 }
a
 { -4, 3, 1 }
2
{ -4, 3, 1 }
{1, 6, 2 }
b
{ 1, -3, 2 }
3
{ 1, -3, 2 }
{6, 0, 3 }
a
{ -3, 0, 3 }
4
{ -3, 0, 3 }
{ 2, 3, 4 }
c
{ 2, 3, -5 }
5
{ 2, 3, -5 }
{ 7, 6, -4 }
a
{ -2, 6, -4 }
6
{ -2, 6, -4 }
{ 3, 9, -3 }
b
{ 3, 0, -3 }
7
{ 3, 0, -3 }
{ 8, 3, -2 }
a
{ -1, 3, -2 }
8
{ -1, 3, -2 }
{ 4, 6, -1 }
b
{ 4, -3, -1 }
9
{ 4, -3, -1 }
{ 9, 0, 0 }
a
 { 0, 0, 0 }
9 개의 요청 은 윤회 이 고 완전한 서열 은 [a, b, a, c, a, b, a, b, a, b, a] 이 며 상대 적 으로 평균 적 인 과정 으로 알고리즘 의 유효성 을 검증 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기