平滑加权轮询负载均衡
Smooth weighted round-robin balancing

原始链接: https://github.com/nginx/nginx/commit/52327e0627f49dbda1e8db695e63a4b0af4448b1

此补丁重构了Nginx HTTP上游模块中的轮询对等选择逻辑。 之前使用`current_weight`跟踪对等选择,但这存在问题。 更新引入了`effective_weight`来表示实际考虑用于选择的权重,并以服务器的权重进行初始化。 `current_weight`现在用于在选择周期内进行跟踪,并经常重置为零。 `ngx_http_upstream_get_peer`函数已修改为接受`ngx_http_upstream_rr_peer_data_t`而不是`ngx_http_upstream_rr_peers_t`。 选择过程现在遍历对等体,考虑它们的`effective_weight`、`down`状态和失败计数。 选择`current_weight`最高的对等体。 此外,代码现在处理由于失败而不可用的对等体的情况,并相应地调整权重。 释放轮询对等体的逻辑也已更新,以反映权重跟踪的变化,使用`effective_weight`而不是`current_weight`。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 平滑加权轮询负载均衡 (github.com/nginx) 28 分,由 grep_it 1 天前发布 | 隐藏 | 过去 | 收藏 | 3 条评论 exabrial 1 天前 [–] 优势/劣势是什么?我通常使用 leastconn 与 haproxy(原因显而易见,但这比纯 RR 更好),因为我们的一些帖子需要 10 毫秒或 5500 毫秒。 回复 nasretdinov 1 天前 | 父评论 [–] 减少峰值负载,尤其是在服务器权重较高时,例如,我们服务器的权重为 100 和 137,因为两位数的权重无法提供足够的精度来实现不同硬件代之间的均衡负载。 由于这种改变降低了峰值负载,你可以获得更低的 99% 延迟,从而需要更少的机器来达到服务器上的相同 99% 延迟。 exabrial 1 天前 | 根评论 | 父评论 [–] 很好!谢谢你的解释。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文
12121313

static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,

1414

const void *two);

15-

static ngx_uint_t

16-

ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers);

15+

static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(

16+

ngx_http_upstream_rr_peer_data_t *rrp);

17171818

#if (NGX_HTTP_SSL)

1919

@@ -81,7 +81,8 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,

8181

peers->peer[n].fail_timeout = server[i].fail_timeout;

8282

peers->peer[n].down = server[i].down;

8383

peers->peer[n].weight = server[i].down ? 0 : server[i].weight;

84-

peers->peer[n].current_weight = peers->peer[n].weight;

84+

peers->peer[n].effective_weight = peers->peer[n].weight;

85+

peers->peer[n].current_weight = 0;

8586

n++;

8687

}

8788

}

@@ -131,7 +132,8 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,

131132

backup->peer[n].socklen = server[i].addrs[j].socklen;

132133

backup->peer[n].name = server[i].addrs[j].name;

133134

backup->peer[n].weight = server[i].weight;

134-

backup->peer[n].current_weight = server[i].weight;

135+

backup->peer[n].effective_weight = server[i].weight;

136+

backup->peer[n].current_weight = 0;

135137

backup->peer[n].max_fails = server[i].max_fails;

136138

backup->peer[n].fail_timeout = server[i].fail_timeout;

137139

backup->peer[n].down = server[i].down;

@@ -190,7 +192,8 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,

190192

peers->peer[i].socklen = u.addrs[i].socklen;

191193

peers->peer[i].name = u.addrs[i].name;

192194

peers->peer[i].weight = 1;

193-

peers->peer[i].current_weight = 1;

195+

peers->peer[i].effective_weight = 1;

196+

peers->peer[i].current_weight = 0;

194197

peers->peer[i].max_fails = 1;

195198

peers->peer[i].fail_timeout = 10;

196199

}

@@ -306,7 +309,8 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,

306309

peers->peer[0].socklen = ur->socklen;

307310

peers->peer[0].name = ur->host;

308311

peers->peer[0].weight = 1;

309-

peers->peer[0].current_weight = 1;

312+

peers->peer[0].effective_weight = 1;

313+

peers->peer[0].current_weight = 0;

310314

peers->peer[0].max_fails = 1;

311315

peers->peer[0].fail_timeout = 10;

312316

@@ -338,7 +342,8 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,

338342

peers->peer[i].name.len = len;

339343

peers->peer[i].name.data = p;

340344

peers->peer[i].weight = 1;

341-

peers->peer[i].current_weight = 1;

345+

peers->peer[i].effective_weight = 1;

346+

peers->peer[i].current_weight = 0;

342347

peers->peer[i].max_fails = 1;

343348

peers->peer[i].fail_timeout = 10;

344349

}

@@ -378,8 +383,6 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)

378383

{

379384

ngx_http_upstream_rr_peer_data_t *rrp = data;

380385381-

time_t now;

382-

uintptr_t m;

383386

ngx_int_t rc;

384387

ngx_uint_t i, n;

385388

ngx_connection_t *c;

@@ -389,8 +392,6 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)

389392

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,

390393

"get rr peer, try: %ui", pc->tries);

391394392-

now = ngx_time();

393-394395

/* ngx_lock_mutex(rrp->peers->mutex); */

395396396397

if (rrp->peers->last_cached) {

@@ -423,118 +424,15 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)

423424424425

/* there are several peers */

425426426-

if (pc->tries == rrp->peers->number) {

427-428-

/* it's a first try - get a current peer */

429-430-

i = pc->tries;

431-432-

for ( ;; ) {

433-

rrp->current = ngx_http_upstream_get_peer(rrp->peers);

434-435-

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,

436-

"get rr peer, current: %ui %i",

437-

rrp->current,

438-

rrp->peers->peer[rrp->current].current_weight);

439-440-

n = rrp->current / (8 * sizeof(uintptr_t));

441-

m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));

442-443-

if (!(rrp->tried[n] & m)) {

444-

peer = &rrp->peers->peer[rrp->current];

445-446-

if (!peer->down) {

447-448-

if (peer->max_fails == 0

449-

|| peer->fails < peer->max_fails)

450-

{

451-

break;

452-

}

427+

peer = ngx_http_upstream_get_peer(rrp);

453428454-

if (now - peer->checked > peer->fail_timeout) {

455-

peer->checked = now;

456-

break;

457-

}

458-459-

peer->current_weight = 0;

460-461-

} else {

462-

rrp->tried[n] |= m;

463-

}

464-465-

pc->tries--;

466-

}

467-468-

if (pc->tries == 0) {

469-

goto failed;

470-

}

471-472-

if (--i == 0) {

473-

ngx_log_error(NGX_LOG_ALERT, pc->log, 0,

474-

"round robin upstream stuck on %ui tries",

475-

pc->tries);

476-

goto failed;

477-

}

478-

}

479-480-

peer->current_weight--;

481-482-

} else {

483-484-

i = pc->tries;

485-486-

for ( ;; ) {

487-

n = rrp->current / (8 * sizeof(uintptr_t));

488-

m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));

489-490-

if (!(rrp->tried[n] & m)) {

491-492-

peer = &rrp->peers->peer[rrp->current];

493-494-

if (!peer->down) {

495-496-

if (peer->max_fails == 0

497-

|| peer->fails < peer->max_fails)

498-

{

499-

break;

500-

}

501-502-

if (now - peer->checked > peer->fail_timeout) {

503-

peer->checked = now;

504-

break;

505-

}

506-507-

peer->current_weight = 0;

508-509-

} else {

510-

rrp->tried[n] |= m;

511-

}

512-513-

pc->tries--;

514-

}

515-516-

rrp->current++;

517-518-

if (rrp->current >= rrp->peers->number) {

519-

rrp->current = 0;

520-

}

521-522-

if (pc->tries == 0) {

523-

goto failed;

524-

}

525-526-

if (--i == 0) {

527-

ngx_log_error(NGX_LOG_ALERT, pc->log, 0,

528-

"round robin upstream stuck on %ui tries",

529-

pc->tries);

530-

goto failed;

531-

}

532-

}

533-534-

peer->current_weight--;

429+

if (peer == NULL) {

430+

goto failed;

535431

}

536432537-

rrp->tried[n] |= m;

433+

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,

434+

"get rr peer, current: %ui %i",

435+

rrp->current, peer->current_weight);

538436

}

539437540438

pc->sockaddr = peer->sockaddr;

@@ -545,11 +443,6 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)

545443546444

if (pc->tries == 1 && rrp->peers->next) {

547445

pc->tries += rrp->peers->next->number;

548-549-

n = rrp->peers->next->number / (8 * sizeof(uintptr_t)) + 1;

550-

for (i = 0; i < n; i++) {

551-

rrp->tried[i] = 0;

552-

}

553446

}

554447555448

return NGX_OK;

@@ -595,56 +488,71 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)

595488

}

596489597490598-

static ngx_uint_t

599-

ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers)

491+

static ngx_http_upstream_rr_peer_t *

492+

ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)

600493

{

601-

ngx_uint_t i, n, reset = 0;

602-

ngx_http_upstream_rr_peer_t *peer;

494+

time_t now;

495+

uintptr_t m;

496+

ngx_int_t total;

497+

ngx_uint_t i, n;

498+

ngx_http_upstream_rr_peer_t *peer, *best;

603499604-

peer = &peers->peer[0];

500+

now = ngx_time();

605501606-

for ( ;; ) {

502+

best = NULL;

503+

total = 0;

607504608-

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

505+

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

609506610-

if (peer[i].current_weight <= 0) {

611-

continue;

612-

}

507+

n = i / (8 * sizeof(uintptr_t));

508+

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

613509614-

n = i;

615-616-

while (i < peers->number - 1) {

617-618-

i++;

510+

if (rrp->tried[n] & m) {

511+

continue;

512+

}

619513620-

if (peer[i].current_weight <= 0) {

621-

continue;

622-

}

514+

peer = &rrp->peers->peer[i];

623515624-

if (peer[n].current_weight * 1000 / peer[i].current_weight

625-

> peer[n].weight * 1000 / peer[i].weight)

626-

{

627-

return n;

628-

}

516+

if (peer->down) {

517+

continue;

518+

}

629519630-

n = i;

631-

}

520+

if (peer->max_fails

521+

&& peer->fails >= peer->max_fails

522+

&& now - peer->checked <= peer->fail_timeout)

523+

{

524+

continue;

525+

}

632526633-

if (peer[i].current_weight > 0) {

634-

n = i;

635-

}

527+

peer->current_weight += peer->effective_weight;

528+

total += peer->effective_weight;

636529637-

return n;

530+

if (peer->effective_weight < peer->weight) {

531+

peer->effective_weight++;

638532

}

639533640-

if (reset++) {

641-

return 0;

534+

if (best == NULL || peer->current_weight > best->current_weight) {

535+

best = peer;

642536

}

537+

}

643538644-

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

645-

peer[i].current_weight = peer[i].weight;

646-

}

539+

if (best == NULL) {

540+

return NULL;

647541

}

542+543+

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

544+545+

rrp->current = i;

546+547+

n = i / (8 * sizeof(uintptr_t));

548+

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

549+550+

rrp->tried[n] |= m;

551+552+

best->current_weight -= total;

553+

best->checked = now;

554+555+

return best;

648556

}

649557650558

@@ -683,15 +591,15 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,

683591

peer->checked = now;

684592685593

if (peer->max_fails) {

686-

peer->current_weight -= peer->weight / peer->max_fails;

594+

peer->effective_weight -= peer->weight / peer->max_fails;

687595

}

688596689597

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,

690598

"free rr peer failed: %ui %i",

691-

rrp->current, peer->current_weight);

599+

rrp->current, peer->effective_weight);

692600693-

if (peer->current_weight < 0) {

694-

peer->current_weight = 0;

601+

if (peer->effective_weight < 0) {

602+

peer->effective_weight = 0;

695603

}

696604697605

/* ngx_unlock_mutex(rrp->peers->mutex); */

@@ -705,12 +613,6 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,

705613

}

706614

}

707615708-

rrp->current++;

709-710-

if (rrp->current >= rrp->peers->number) {

711-

rrp->current = 0;

712-

}

713-714616

if (pc->tries) {

715617

pc->tries--;

716618

}

联系我们 contact @ memedata.com