编程实践-哈希负载均衡算法-IP-C (编程实践心得体会)
Nginx 是一个高性能的开源 Web 服务器和反向代理服务器,因其高效处理高并发的请求而闻名。以下是一些 Nginx 用于处理高并发的主要特点和技术:
- 事件驱动架构: Nginx 使用事件驱动架构,允许它在单个线程中处理多个请求,从而最大限度地提高吞吐量和降低延迟。
- 非阻塞 I/O: Nginx 使用非阻塞 I/O,这意味着它不会等待 I/O 操作完成,而是继续处理其他请求,从而进一步提高了性能。
- 工作进程模型: Nginx 使用主工作进程模型,其中主进程管理工作进程,而工作进程处理请求。这可以极大地提高稳定性和可扩展性。
- 内存缓存: Nginx 具有内置的内存缓存,允许它存储经常请求的响应,从而减少服务器负载并提高响应时间。
- 负载均衡: Nginx 提供了各种负载均衡算法,用于将请求分发到多个后端服务器,从而提高可用性和性能。
IP 哈希负载均衡算法
IP 哈希是一种负载均衡算法,用于根据客户端的 IP 地址将请求分发到后端服务器。其基本原理是将客户端的 IP 地址通过一个哈希函数计算得到一个哈希值,然后将该哈希值与后端服务器列表的长度取模,以确定应该将请求发送到哪个后端服务器。
以下是 IP 哈希算法的简要步骤:
- 将客户端的 IP 地址转换为哈希值。
- 将哈希值与后端服务器列表的长度取模。
- 将请求发送到获得模数结果的后端服务器。
IP 哈希算法的优点是,对于相同的 IP 地址,无论何时何地发起的请求,都会被分发到同一个后端服务器,这可以在一定程度上保持会话的连续性和稳定性。但同时,它可能导致负载不均衡的问题,因为一些 IP 地址可能会集中在某些特定的后端服务器上,从而使得某些服务器负载过重。
在 Nginx 中配置 IP 哈希负载均衡
在 Nginx 中,配置 IP 哈希算法的负载均衡策略非常简单。只需在配置文件中使用
ip_hash
指令即可启用 IP 哈希算法。以下是一个示例配置:
http { upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com; } server { listen 80; location / { proxy_pass} } }
在上面的示例中,
ip_hash
指令被用于定义
backend
这个后端服务器组。请求会根据客户端的 IP 地址进行哈希运算,并将其分发到相应的后端服务器。
结论
IP 哈希算法是 Nginx 中一种常用的负载均衡算法,可以根据客户端的 IP 地址将请求分发到后端服务器,维护会话的连续性和稳定性。Nginx 的高性能、可扩展性以及丰富的功能使其成为处理高并发流量的理想选择,广泛用于互联网领域,特别是大型网站、应用服务器集群和 CDN(内容分发网络)等场景中。
基于lvs实现4层负载均衡
章文嵩:研发,原就职alibaba公司,目前就职滴滴;
lvs:2部分组成 ipvsadm:用户空间的命令行工具;用于管理集群服务及集群服务上的RS; ipvs:是内核中的框架;工作于内核上的netfilter的INPUT钩子上的程序,可根据用户定义的集群实现请求转发;
注意:在lvs主机上,不允许在INPUT链上添加规则,一般不建议与ipvs一同使用filter规则;更不能使用nat规则,任何链接追踪功能都不能开启,链接会话表就限制了会话能力,否则,并发响应能力将大大受到限制;
支持基于TCP UDP SCTP AH EST AH_EST等协议及端口进行调度;
以下部分内容摘自于:多目标的DNAT;通过将请求报文中的目标地址和目标端口修改为挑选出的某RS的RIP和PORT实现转发;
ipvs工作在INPUT链上,所以只有在INPUT链上才能判断出集群服务,然后才能向后转发,转发时,基于某种调度算法,ipvs自动从后端主机中挑选出一个来响应用户请求,挑选出的主机IP会成为报文目标IP的修改对象; 定义负载均衡集群服务时,要定义集群服务,集群服务的真实主机;
上图为lvs-nat的常见的使用场景,其工作流程如下: 1、客户端的请求发往Director 的VIP。 2、Director发到客户端请求报文后,将报文中的目标Ip修改为集群中的选定的RIP,目标端口80也修改成8080,然后将请求报文发往RS。 3、当RS收到请求报文后,在检查报文的目标IP为自己的RIP后,会接受报文并进行处理响应。响应的源Ip为RIP,目标IP为CIP,端口不变。 4、Director收到RS的响应报文,修改响应报文的源IP为VIP,端口为80,然后转发给客户端。 5、客户端接受响应报文,其源IP为VIP,端口为80,整个过程对于客户端来说是透明无感知的。
通过修改请求报文的MAC地址,重新封装一个MAC首部进行转发;源MAC是DIP所在接口的MAC地址,目标MAC是挑选出的某RS的RIP所在接口的MAC地址;IP首部不会发生变化(依然是CIP<-->VIP)
lvs服务主机与后端服务器主机接在同一交换机上,且每个后端主机都配有vip,为了避免地址冲突,把各后端主机配置的vip进行隔离;
隔离的方法有3种
(1)确保前端路由器将目标IP为VIP的请求报文转发往Director;
(2)RS的RIP可以使用私有地址,也可以使用公网地址; (3)RS跟Director必须在同一物理网络(基于MAC地址转发);RS的网关必须不能指向DIP; (4)请求报文必须由Directory调度,但响应报文必须不能经由Director; (5)不支持端口映射; (6)RS可以使用大多数的OS;一般都为Linux系统;
上图为lvs-dr的常见的使用场景,其工作流程如下: 1、客户端的请求会发往Director,此时,客户端请求报文的源Ip为CIP,目标Ip为Director的VIP。 2、当Director接受到客户端的请求报文后,Director会在请求报文外封装一个MAC首部,其源MAC为Director接口的MAC地址,目标MAC为选定RS的MAC地址; 3、当RS收到Director转发过来的请求报文后,检查发现请求报文的目标Ip为本地环回接口上配置的VIP,因此会接受报文进行响应处理。另外由于对ARP响应规则做了修改,因此RS不会把响应报文响应给director ,而是响应给GW; 4、客户端接收响应报文,完成通信。
请求报文源IP为cip,目标IP为vip,到达lvs服务进入INPUT链上,在整个ip报文外又加了一层ip首部,即IP报文传输IP报文所以叫IP隧道,此时外层源IP为dip,目标IP为某一个被挑选出来远端的rip,远端的服务主机收到报文经过不断拆包后,将响应报文发给客户端,构建响应报文的源IP为rip,目标IP为cip;
(1)RIP,DIP,VIP全得是公网地址; (2)RS网关不能指向也不可能指向DIP; (3)请求报文经由Director转发,但响应报文将直接发往CIP; (4)不支持端口映射; (5)RS的OS必须支持隧道功能;
(1)VIP是公网地址,RIP和DIP一般是私网地址,且通常不再同一网络中,但需要经由路由器互通; (2)RS收到的请求报文源IP为DIP,因此响应报文将直接响应给DIP; (3)请求和响应报文都经由Director; (4)支持端口映射; (5)RS可以使用大多数的OS;
负载均衡集群中会话保持的方式 (1)原地址哈希; (2)会话集群; (3)会话服务器;
如上图所示: 1.客户端的请求会发往Director,此时,客户端请求报文的源IP为CIP,目标IP为Director的VIP 2.当Director收到客户端的请求报文时,会将源IP修改为本机的DIP,同时将请求报文中的目标IP修改为后端某个RS的RIP,具体为哪个RS的RIP,取决于LVS使用的具体算法 3.当RS收到对应的请求报文时,会发现报文的目标IP就是自己的RIP,于是就会接收报文并处理后进行响应。响应报文的源IP则为RIP,目标IP则为DIP 4.当Director收到对应的响应报文时,Director会将响应报文的源IP修改为VIP,目标IP修改为CIP,于是响应报文被发往客户端。 5.客户端则会收到响应报文,源IP为VIP,端口为80,而LVS相对于客户端而言,转换过程是透明的。
根据其调度时是否考虑后端主机的当前负载,可分为 静态方法 和 动态方法 两类
基于客户端瘦cookie+服务器端的session机制,在负载均衡时,同一用户被调度不同后端服务器时,为了保持会话连接功能不丢失;当第一次用户请求时,通过调度机制给该用户分配了一个负责响应后端服务器,以后来自该用户的请求就由这个服务器负责响应了,而不再调度,这就叫 源地址哈希 ;
在调度器上有会话追踪表,在这个会话追踪模板中,把用户的IP地址和挑选的后端服务器对应的记录下来,而且定义一个超时时长,在定义的时间内该条目不会删除;所以,用户请求到来时,先检查这个表,把原IP当做k查找,因为哈希就是k/v数据,对应的v就是后端的真实服务器;如果检查有用户的IP对应的记录,则直接将请求报文发给记录中对应的后端真实服务器,而不通过调度;
缺陷 :当记录的真实服务器挂了时,就没有会话保持记录了;当内网用户同过同一IP地址访问外网时,可能会把内网用户的所有请求都发往会话记录表上的真实服务器,这样负载均衡能力是受到损害的;
解决办法
内网用户请求的目标地址,在调度器上把目标地址绑定到一个代理缓存服务器上,以后,任何用户访问的是该目标地址就发往绑定的代理服务器,代理服务器收到请求后,再发往后端服务器主机,从而实现正向代理负载均衡的作用;
ipvs功能特别强大,一般网站用到的可能性比较小,但面试必会问到; 如果负载不是特别大,使用配置比较麻烦,维护成本较大;
ipvs/ipvsadm的关系相当于netfilter/iptables的关系; 真正提供lvs服务的是ipvs;
因为是根据请求的目标ip地址和目标端口(能识别协议)进行转发;一个ipvs(Director)主机就可同时为多个集群提供服务进行调度;这就是四层交换的原因;只不过一个Director很有可能成为负载均衡的瓶颈;
注意:单个Director可同时为多个集群提供调度服务;
在centos 7系统上: 判断内核是否支持ipvs:
判断ipvsadm程序包是否安装
ipvsadm -A|E -t|u|f service-address [-s scheduler] -A:增,添加 -E:修改
ipvsadm -D -t|u|f service-address -D:删除集群服务;
service-address:定义集群服务的地址 -t:tcp,把tcp端口定义成集群服务,vip:tcp_port; -u:udp,把udp端口定义成集群服务,vip:udp_port; -f:Firewalls mark防火墙标记,是一个数字;
-s scheduler:定义集群服务的调度方法,默认为wlc加权最少连接;
ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight] -a:增,添加RS; -e:改,修改RS;
ipvsadm -d -t|u|f service-address -d:删除
-rserver-address:向已存在的service-address(集群服务)添加RS的地址; rip[:port] 端口省略时,表示不做端口映射,与请求服务的端口为同一端口;有些集群服务不支持端口映射,如lvs-dr,lvs-tun,只要响应报文不经过Director都不支持;
查看:ipvsadm -L|l [options] -L,--list:列出集群服务; -n, --numeric:数字格式显示,不反解主机名到ip地址,服务到端口号; --exact:精确显示数值,不进行单位换算; -c, --connection:显示当前ipvs连接;可查看后端服务器是否连接; --stats:统计数据; --rate:速率;
清空 :clearipvsadm -C
保存和重载 保存:输出重定向ipvsadm -S > /PATH/TO/SOME_RULE_FILE ipvsadm-save > /PATH/TO/SOME_RULE_FILE
重载:输入重定向ipvsadm -R < /PATH/TO/SOME_RULE_FILE ipvsadm-restore < /PATH/TO/SOME_RULE_FILE
清空计数器:ipvsadm -Z [-t|u|f service-address]
例如:
例如:
添加集群服务,vip为172.18.11.111提供web服务,指明调度方法为rr;不指明为默认wlc;
在集群服务中添加RS地址为192.168.255.2,类型为lvs-nat,权重为1此值无意义,因为前面已经指明使用rr调度算法
再次添加一个RS
再次添加一个集群服务
在另一个集群服务上添加2个RS
修改集群服务的调度方法为wrr
注意:修改只能改属性,不能改IP地址;只有删除集群服务才能从新改IP地址;
修改RS的权重值为10
保存集群服务规则至指定路径
查看保存的内容:
清空集群服务
重载集群服务配置文件
下次开机时会自动载入集群服务规则: 所以,可把规则保存在/etc/sysconfig/ipvsadm文件中;[root@VM_0_2_centos ~]# ipvsadm-save > /etc/sysconfig/ipvsadm 一般手动保存后(确保保存无误),下次开机时,会自动重载此文件;
需要开机自动有效:[root@VM_0_2_centos ~]# systemctl enable
lvs-nat设计要点: (1)DIP与RIP要在同一IP网络,RIP的网关要指向DIP; (2)支持端口映射; (3)是否用到共享存储,取决于业务需要;
1、配置RS1
2、配置RS2
3、配置Director
打开网卡核心转发功能;永久有效:
查看内核参数是否打开核心转发功能
此时,在Director测试,访问RS1、RS2;
添加ipvs集群:
在另一台虚拟机上测试,调度是否起作用: 测试主机为:172.18.11.111
修改Director上的调度方式为wrr
再到测试主机为:172.18.11.111,测试wrr的调度效果
经过多次请求测试后,有明显wrr调度效果; 其RS服务器响应权重比是1:2,即RS1响应1次后RS响应2次;
数据同步:rsync+inotify
响应报文不用经过Director,每个RS必须配置VIP,为了避免地址冲突,有3种方式:
在各主机(Director,RS)均需要配置VIP,因此,要解决地址的冲突的问题,目标是让各RS上的VIP不可见,仅用接收目标地址为VIP的报文,同时可作为响应报文的源地址; (1)在前端的网关接口上静态绑定(vip+mac); 缺陷:一旦Director挂了,基于高可用转移另外节点上无法实现;而且,要在网关上有权限操作; (2)在各RS上使用arptables;添加规则,拒绝自己的VIP地址向外通告及响应arp解析地址的请求; (3)在各RS上修改内核参数,来限制arp响应和通告; 注意:要将VIP配置在lo的别名上,不能配置在网卡的别名上;
在各RS上设置arp通告级别即修改两个内核参数arp_ignore、arp_announce,因为地址是属于内核的,所以在Linux主机默认的通告方式是所有本机的可用IP地址通告给每个接口;
arp_announce要限制通告级别,每一个网卡仅在把自己的网络地址向所在物理网络中通告,即各网卡间地址绝不交叉通告;arp_announce设置为2;
arp_ignore是限制响应别人arp请求的级别;默认响应请求是无论从哪个接口接收到arp请求,只要本机有这个地址都会响应;限制arp响应级别后可实现,从哪个网卡接收的arp请求, 必须与该接口属于同一网络时才响应;arp_ignore`设置为1
lvs-dr设计要点: (1)各主机一个接口即可,但需要在同一物理网络中; (2)RIP的网关不能指向DIP,RIP和DIP通常应在同一网络,但此二者未必会与VIP在同一网络; (3)各RS需要先设置内核参数,再设置VIP和路由;
搭建网络环境
1、配置Director
2、配置RS1
3、配置RS2
4、访问测试
在RS2主机运行
在报文进入时,进行打标记,例如目标IP是VIP端口80,把这类报文分拣出来打标,标记一般为十六进制整数,例如标记1;在input链上定义集群服务时,就可判定如果防火墙标记为1,则为集群服务;把本来在input链上完成识别、定义集群服务分成了两步,识别在prerouting做,定义在ipvs(inputing)上实现;
在mangle表上的prerouting链上,目标ip(VIP)为172.18.11.7,目标端口为80,打标记为1;
mark标记里包含了IP地址和端口;定义集群服务时使用mark即可;
打标记的方法: iptables -t mangle -A PREROUTING -d $vip -p $protocol --dport $clusterserverport -j MARK --set-mark # #:代表十六进制整数;
打标作用 :提供辅助持久连接功能;在多个端口定义服务时,可把相关作为一个集群来调度;
配置RS1:
配置RS2:
在Director创建CA:
在RS1主机:
在CA服务上签证并传回给RS1:
在各RS主机重启web服务并查看443端口是否监听:
手动测试直接访问RS的IP:
测试请求,OK可以响应页面;-k表示可接受不受信任的页面响应;
单机测试ok,下面绑定80和443服务,打标记:
nginx 负载均衡之一致性hash,普通hash
哈希负载均衡原理 ngx_http_upstream_hash_module支持普通的hash及一致性hash两种负载均衡算法,默认的是普通的hash来进行负载均衡。 nginx 普通的hash算法支持配置http变量值作为hash值计算的key,通过hash计算得出的hash值和总权重的余数作为挑选server的依据;nginx的一致性hash(chash)算法则要复杂一些。这里会对一致性hash的机制原理作详细的说明。 一致性hash算法的原理 一致性hash用于对hash算法的改进,后端服务器在配置的server的数量发生变化后,同一个upstream server接收到的请求会的数量和server数量变化之间会有变化。尤其是在负载均衡配置的upstream server数量发生增长后,造成产生的请求可能会在后端的upstream server中并不均匀,有的upstream server负载很低,有的upstream server负载较高,这样的负载均衡的效果比较差,可能对upstream server造成不良的影响。由此,产生了一致性hash算法来均衡。那么为什么一致性hash算法能改善这种情况呢?这里引用网上资料的一致性hash算法的图例。 因为对于hash(k)的范围在int范围,所以我们将0~2^32作为一个环。其步骤为: 1,求出每个服务器的hash(服务器ip)值,将其配置到一个 0~2^n 的圆环上(n通常取32)。 2,用同样的方法求出待存储对象的主键 hash值,也将其配置到这个圆环上,然后从数据映射到的位置开始顺时针查找,将数据分布到找到的第一个服务器节点上。 其分布如图:
除了上边的优点,其实还有一个优点:对于热点数据,如果发现node1访问量明显很大,负载高于其他节点,这就说明node1存储的数据是热点数据。这时候,为了减少node1的负载,我们可以在热点数据位置再加入一个node,用来分担热点数据的压力。 雪崩效应
接下来我们来看一下,当有节点宕机时会有什么问题。如下图:
如上图,当B节点宕机后,原本存储在B节点的k1,k2将会迁移到节点C上,这可能会导致很大的问题。如果B上存储的是热点数据,将数据迁移到C节点上,然后C需要承受B+C的数据,也承受不住,也挂了。。。。然后继续CD都挂了。这就造成了雪崩效应。 上面会造成雪崩效应的原因分析: 如果不存在热点数据的时候,每台机器的承受的压力是M/2(假设每台机器的最高负载能力为M),原本是不会有问题的,但是,这个时候A服务器由于有热点数据挂了,然后A的数据迁移至B,导致B所需要承受的压力变为M(还不考虑热点数据访问的压力),所以这个失败B是必挂的,然后C至少需要承受1.5M的压力。。。。然后大家一起挂。。。 所以我们通过上面可以看到,之所以会大家一起挂,原因在于如果一台机器挂了,那么它的压力全部被分配到一台机器上,导致雪崩。
怎么解决雪崩问题呢,这时候需要引入虚拟节点来进行解决。 虚拟节点
虚拟节点,我们可以针对每个实际的节点,虚拟出多个虚拟节点,用来映射到圈上的位置,进行存储对应的数据。如下图:
如上图:A节点对应A1,A2,BCD节点同理。这时候,如果A节点挂了,A节点的数据迁移情况是:A1数据会迁移到C2,A2数据迁移到D1。这就相当于A的数据被C和D分担了,这就避免了雪崩效应的发送,而且虚拟节点我们可以自定义设置,使其适用于我们的应用。
ngx_http_upstream_consistent_hash 该模块可以根据配置参数采取不同的方式将请求均匀映射到后端机器,比如:
指令 语法:consistent_hashvariable_name 默认值:none 上下文:upstream
配置upstream采用一致性hash作为负载均衡算法,并使用配置的变量名作为hash输入。
参考文档:
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。