Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

nginx也可以做web站点,不过更多情况下,nginx都是作为负载均衡服务器来使用的。负载均衡简单的分流类似如下图:

nginx的upstream模块,主要完成网络数据的接收、处理和转发,是做负载均衡的关键。下面介绍几种常见的负载分配算法。

 

Nginx的几种常见负载分配算法

轮询(round-robin 默认)

     默认情况下,Nginx 会为你提供轮询作为负载均衡策略。即每台服务器的权重是一样的。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

轮询调度算法(Round-Robin Scheduling)
轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。
算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。
轮询调度算法流程
假设有一组服务器N台,S = {S1, S2, …, Sn},一个指示变量i表示上一次选择的服务器ID。变量i被初始化为N-1。其算法如下:

j = i;
do
{
j = (j + 1) mod n;
i = j;
return Si;
} while (j != i);
return NULL;

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

参考:http://www.iteye.com/topic/1113595

权重 weight

      指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况,默认每个服务器的weight权重是1,如果后端服务器down掉,能自动剔除。

      当一个客户请求到达后,RR策略是从upstream的所有server中选择一个当前权重(current_weight)最大的server作为最初的server.

 

权重配置例子:

http {
upstream myproject {
server 127.0.0.18000 weight=3;
server 127.0.0.18001;
server 127.0.0.18002;
server 127.0.0.18003;
} server {
listen 80;
server_name www.domain.com;
location / {
proxy_pass http//myproject;
}
}
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

这样的权重算法逻辑:http://blog.sina.com.cn/s/blog_7303a1dc01014i0j.html

最早的算法代码逻辑如下:

 

算法如下:

//按照weight来返回一个peer的下标
//找到当前比率最大的那项,返回这项的下标
static ngx_uint_t
ngx_http_upstream_get_peer( ngx_http_upstream_rr_peers_t *peers )
{
ngx_uint_t i, n;
ngx_http_upstream_rr_peer_t *peer;
peer = &peers->peer[0];
for ( ; ; ){
for ( i = 0; i < peers->number; i++ ) {
if ( peer[i].current_weight <= 0 ){
continue;
}
n = i;
while ( i < peers->number - 1 ) {
i++; // 和下一个比较是否大,如果比下一个小,则返回下一个
if ( peer[i].current_weight <= 0 ){
continue;
}
if ( peer[n].current_weight * 1000 / peer[i].current_weight
> peer[n].weight * 1000 / peer[i].weight ){
return n;
}
n = i;
}
//找到最后了,还没有比第i项比率大的,则说明这项就是,返回这项
if ( peer[i].current_weight > 0 ) {
n = i;
}
return n;
}
//走到这里的时候,说明都是0了,重新初始化为满额,接着循环找,总是能找到一个
for ( i = 0; i < peers->number; i++ ){
peer[i].current_weight = peer[i].weight;
}
}
}

http://blog.xcai.net/fav/nginx-load-balance-analyze

http://stblog.baidu-tech.com/?p=2027

算法伪代码(2012.5.14后修正的算法):

foreach peer in peers {
peer->current_weight += peer->effective_weight;
total += peer->effective_weight; if (best == NULL || peer->current_weight > best->current_weight) {
best = peer;
}
}
best->current_weight -= total;

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

一个具体计算的例子:

selected server current_weight before selected current_weight after selected
a { 5, 1, 2 } { -3, 1, 2 }
c { 2, 2, 4 } { 2, 2, -4 }
a { 7, 3, -2 } { -1, 3, -2 }
a { 4, 4, 0 } { -4, 4, 0 }
b { 1, 5, 2 } { 1, -3, 2 }
a { 6, -2, 4 } { -2, -2, 4 }
b { 3, -1, 6 } { 3, -1, -2 }
a { 8, 0, 0 } { 0, 0, 0 }

http://book.51cto.com/art/201202/314691.htm

 

ip_hash

      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 

在ip_hash策略中,它选择最初的server的方法是根据请求客户端的IP计算出一个哈希值,再根据哈希值选择后台的服务器。

由IP计算哈希值的算法如下, 其中公式中hash初始值为89,iphp->addr[i]表示客户端的IP, 通过三次哈希计算得出一个IP的哈希值:

for (i = 0; i < 3; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

在选择下一个server时,ip_hash的选择策略是这样的:它在上一次哈希值的基础上,再次哈希,就会得到一个全新的哈希值,再根据哈希值选择另外一个后台的服务器。

哈希算法仍然是:

for (i = 0; i < 3; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

在这种ip_hash策略,如果一个后台服务器不能提供提服务(连接超时或读超时),该服务器的失败次数就会加一,当一个服务器的失败次数达到max_fails所设置的值,就会在fail_timeout所设置的时间段内不能对外提供服务,这点和RR是一致的。

如果当前server不能提供服务,就会根据当前的哈希值再哈希出一个新哈希值,选择另一个服务器继续尝试,尝试的最大次是upstream中server的个数,如果server的个数超过20,也就是要最大尝试次数在20次以上,当尝试次数达到20次,仍然找不到一个合适的服务器,ip_hah策略不再尝试ip哈希值来选择server, 而在剩余的尝试中,它会转而使用RR的策略,使用轮循的方法,选择新的server。

参考: http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html

fair

      按后端服务器的响应时间来分配请求,响应时间短的优先分配。 

配置例子如下:

upstream web_pool {
server 172.23.136.148;
server 172.23.136.149;
fair;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

url_hash

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。

upstream web_pool {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}

 

一致性hash模块(淘宝 tengine特有的算法)

这个模块提供一致性hash作为负载均衡算法。

具体算法,将每个server虚拟成n个节点(根据server权重对应到n个节点),均匀分布到hash环上,每次请求,根据配置的参数计算出一个hash值,在hash环

上查找离这个hash最近的虚拟节点,对应的server作为该次请求的后端机器。

具体哈希值的计算,依赖于客户端信息(如:$ip, $uri, $args等变量)。

例子:

worker_processes  1;

http {
upstream test {
consistent_hash $request_uri; server 127.0.0.1:9001 id=1001 weight=3;
server 127.0.0.1:9002 id=1002 weight=10;
server 127.0.0.1:9003 id=1003 weight=20;
}
}

说明:该模块可以根据配置参数采取不同的方式将请求均匀映射到后端机器,比如:

  • consistent_hash $remote_addr:可以根据客户端ip映射;
  • consistent_hash $request_uri: 根据客户端请求的uri映射;
  • consistent_hash $args:根据客户端携带的参数进行映射;

上面配置中我们可以看到server id 字段,如果配置id字段,则使用id字段作为server标识,否则使用server ip和端口作为server标识,使用id字段可以手动设置server的标识,比如一台机器的ip或者端口变化,id仍然可以表示这台机器。使用id字段.可以减低增减服务器时hash的波动。

参考:

nginx(tengine)反向代理以及upstream的六种调度算法

http://itoedr.blog.163.com/blog/static/12028429720137113244975

 

 

这几种负载均衡分配方法并不是互相冲突的,我们可以组合使用。

另外还有一些其他负载算法,比如tengine支持的: Session保持模块、后端连接数限制模块、随机负载均衡模块 等就不详细描述了,参看:http://tengine.taobao.org/download/programmer-201209-Tengine.pdf

 

 

 

参考资料:

nginx 的模块及处理流程

http://www.cnblogs.com/ghj1976/p/3363039.html

Module ngx_http_upstream_module

http://nginx.org/en/docs/http/ngx_http_upstream_module.html 

upstream模块

http://tengine.taobao.org/book/chapter_05.html

nginx中upstream的设计和实现(三)

http://www.pagefault.info/?p=273

 

Nginx学习之六-nginx核心进程模型

http://blog.csdn.net/xiajun07061225/article/details/9241179

解析nginx负载均衡

http://stblog.baidu-tech.com/?p=2027

nginx 配置轮询分流 实现负载均衡的方法

http://www.jbxue.com/article/11590.html

高性能Web服务器Nginx的配置与部署研究(15)Upstream负载均衡模块

http://blog.csdn.net/poechant/article/details/7256184

Nginx中的upstream轮询机制介绍

http://www.cnblogs.com/liqiu/p/3140329.html

高性能Linux服务器构建实战:运维监控、性能调优与集群应用

http://book.51cto.com/art/201202/314644.htm

Nginx 做负载均衡的几种轮询策略

http://zhuruxin86.iteye.com/blog/1694557

nginx 负载均衡相关知识的更多相关文章

  1. 企业级Nginx负载均衡与keepalived高可用实战(一)Nginx篇

    1.集群简介 1.1.什么是集群 简单地说,集群就是指一组(若干个)相互独立的计算机,利用高速通信网络组成的一个较大的计算机服务系统,每个集群节点(即集群中的每台计算机)都是运行各自服务的独立服务器. ...

  2. 干货 | Nginx负载均衡原理及配置实例

    一个执着于技术的公众号 Nginx系列导读 给小白的 Nginx 10分钟入门指南 Nginx编译安装及常用命令 完全卸载nginx的详细步骤 Nginx 配置文件详解 理解正向代理与反向代理的区别 ...

  3. Net分布式系统之三:Keepalived+LVS+Nginx负载均衡之高可用

    上一篇写了nginx负载均衡,此篇实现高可用(HA).系统整体设计是采用Nginx做负载均衡,若出现Nginx单机故障,则导致整个系统无法正常运行.针对系统架构设计的高可用要求,我们需要解决Nginx ...

  4. Nginx负载均衡 后端服务器怎么共享Session 问题

    Nginx负载均衡 Nginx负载均衡一些基础知识: nginx 的 upstream目前支持 4 种方式的分配 1).轮询(默认)       每个请求按时间顺序逐一分配到不同的后端服务器,如果后端 ...

  5. Nginx负载均衡深入浅出

    nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态.静态页面的分离,可以按照轮询.ip哈希.URL哈希.权重等多种方式对后端服务器做负载均 ...

  6. Nginx负载均衡介绍

    Nginx真心牛逼 nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态.静态页面的分离,可以按照轮询.ip哈希.URL哈希.权重等多种方式 ...

  7. nginx负载均衡 - session失效

    最近迷上了Nginx,真实麻雀虽小,五脏俱全..功能实在强大.. nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态.静态页面的分离,可以 ...

  8. Nginx 负载均衡-加权轮询策略剖析

    本文介绍的是客户端请求在多个后端服务器之间的均衡,注意与客户端请求在多个nginx进程之间的均衡相区别(Nginx根据每个工作进程的当前压力调整它们获取监听套接口的几率,那些当前比较空闲的工作进程有更 ...

  9. Keepalived+LVS+Nginx负载均衡之高可用

    Keepalived+LVS+Nginx负载均衡之高可用 上一篇写了nginx负载均衡,此篇实现高可用(HA).系统整体设计是采用Nginx做负载均衡,若出现Nginx单机故障,则导致整个系统无法正常 ...

随机推荐

  1. QT visual stuido 集成插件不能打开ui文件的解决方法(去掉xml的UTF8标记)

    QT visual stuido 集成插件不能打开ui文件的解决方法 visual studio里不能打开这个ui文件,出现warning等解决方法是:于是将<?xml version=&quo ...

  2. SQL SERVER ->> Columnstore Index

    谈到Columnstore index就不得不提SQL SERVER的压缩技术了.Columnstore就是用到了SQL SERVER的压缩技术.Columnstore又分Columnstore和Co ...

  3. .NET在EF中使用sql,用动态类吧!

    .NET在EF中使用sql,用动态类吧! 前言 在.NET中使用Entity Framework能快速.方便地结合LINQ来对数据库进行一系列的增删改查操作.但是由于EF根据表达式最后生成通用的sql ...

  4. OpenCV4Android开发之旅

    http://blog.csdn.net/yanzi1225627/article/details/16917961

  5. webapp 开发之iScroll 学习

    demo.html <!doctype html> <html lang="en"> <head> <meta charset=" ...

  6. Windows Services windows域账户管理

    windows  域账户管理 一.什么是域账户: 域账户是域是网络对象的分组.例如:用户.组和计算机.域中所有的对象都存储在 Active Directory 下.Active Directory 可 ...

  7. Python 学习记录

    记录一些 学习python 的过程 -------------------------------------- 1. 初始学习 @2013年10月6日 今天开始学习python 了 遇到好多困难但是 ...

  8. Android内存管理(1)WRANGLING DALVIK: MEMORY MANAGEMENT IN ANDROID PART 1

    from : http://www.raizlabs.com/dev/2014/03/wrangling-dalvik-memory-management-in-android-part-1-of-2 ...

  9. BZOJ 3192 删除物品(树状数组)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3192 题意:(1)一共有N个物品,堆成M堆. (2)所有物品都是一样的,但是它们有不同的 ...

  10. MyEclipse 10离线安装PyDev插件

    PyDev for Eclipse, 经过测试,一般在线安装会失败(不能访问某些网站所致) 以下为离线安装步骤 1 下载 PyDev 2.8.2,  链接:http://sourceforge.net ...