从网络到分布式(集群内高并发)
高并发负载均衡:网络协议原理
想要分流实现高并发处理,需要转发到A、B、C服务器上,如何转发,需要了解网络协议原理!转发分七层协议、四层协议、二层协议,这里我们猜到了二层协议最快的事情,所消耗的资源是最小的。那么怎么去实现呢?所以,需要去了解网络协议。网络协议七层。
流程图
模拟网络请求
进入本机文件
1 | cd /proc/$$/fd |
会有一些文件,0–>输入,1–>输出,2–>报错
我们和百度建立socket连接,要知道,必须由链接才能访问
1 | exec 8<> /dev/tcp/www.baidu.com/80 |
关闭socket连接
1 | exec 8<& - |
开始通过协议请求,任何的请求必须要有协议,什么是协议,是规范
1 | echo -e 'GET / HTTP/1.0\n' >& 8 |
有request就有response,我们查看response
1 | cat 0<& 8 |
下面的东西就不展示了,就是html,上面是就是应用层http协议。
解释网络层
应用层:主要指浏览器或者tomcat容器,就是用户层。tomcat把表示层和会话层都放在了应用层。
表示层:用户层
会话层:用户层,可记录用户信息,比如session
传输控制层:分为两个协议:tcp、udp协议,其中tcp协议是一个安全的协议,面向连接的,可靠的协议,udp反之不可靠。tcp经典三次握手、四次挥手。
- 三次握手:A客户端向B客户端发送一个握手包,B客户端给A客户端回复确认包,A客户端收到确认包后给B客户端回个收到包。然后开始传输数据
- 四次挥手:A客户端给B客户端发个分手包,B客户端回个收到包,B客户端同样发个分手包,A客户端收到回个收到包,开始断开连接。
上面使用一些包的名词,是我自己定义的,反正就是包。上面总结就是,三次握手之后,才能传输数据,想要断开连接,必须四次分手,这个是最小粒度,不可被分割。
网络层:上面发送握手包,也是要往下走,经历网络层,要知道请求到哪个网络啊?经过路由,就是到需要请求到哪个网络,网络层就是干这个事情的。那么需要普及点知识
- ip地址:就是标识网路节点的id号或者坐标
- 掩码:255.255.255.0。和ip地址【与】作用,辟如:和192.168.188.100做与运算,就是192.168.188.0,然后在去路由表做匹配,看哪个能匹配上。下面匹配到192.168.188.0那么匹配上的网关的0.0.0.0,就是局域网的意思。这个就是下一跳地址。具体看下面。
- 下一跳机制:没办法直接设置需要路由的ip地址,因为太多,所以,需要下一跳机制,把非局域网的ip,转发到网关。然后开始走链路层
链路层:下一跳转发到ip后,链路层会包装一层,把链接的ip Mac地址拿出来包装三层。就Mac地址点对点的跳跃。
- 第一层:源端口号->目标端口号
- 第二层:源ip->目标ip
- 第三层:源mac地址->目标mac地址
那么mac地址如何获取,首先,遵循的是arp协议,我们网关的mac地址是已知的,需要知道,通过广播假如说广播到路由,确定目标ip是路由器ip,那么就可以获取到mac地址,这样其实就学习到了mac地址,记录下来,下次就直接发送。
假如,通过mac地址跳到路由器,通过路由器的路由表来进行匹配。如果
物理层:顾名思义
挖槽,上面概念属实空泛,太绕人了,我们做个试验
arp协议
ARP协议是什么:
我们并不知道我们想要跳转的ip地址的mac地址是什么,于是,我们会先封装数据,广播给各个网口,目标ip收到我们发的包的时候,同时会回一个包,我们就知道目标地址的mac地址。
举例:
试验环境,两台服务器
name | ip |
---|---|
node01 | 192.168.188.180 |
node02 | 192.168.188.181 |
node01想要跳转到node02,需要mac地址,不知道node02的mac地址怎么办。封装一个包:
- 源mac地址->node01@mac
- 源ip node01
- 目标mac地址 FFFFFFF
- 目标ip node02
交换机,拿到这个包,发现目标mac地址是FFFFFFF,就会在各个网口进行一次广播,有的机器可以看到不是自己的就丢弃,假如一个路由看到目标ip是自己了,自己拿到这个包,会在封装一个包:
- 源mac地址->node02@mac
- 源ip node02
- 目标mac地址 ->node01@mac
- 目标ip node01
没错,反过来了,因为我们要给回一个包啊。这里有个细节是,node02会包的时候,因为交换机会在node01发送包的时候,把node01的mac地址记录下来,那么当node02回包的时候,交换机直接就拿到node01的mac地址,直接跳转到node01。同样的,node01收到node02的mac地址,也会把node02的mac地址记录下来,这个就是arp协议。
实例测试
试验环境,两台服务器
name | ip |
---|---|
node01 | 192.168.188.180 |
node02 | 192.168.188.181 |
我们在node01新建个虚拟网卡ip
1 | ifconfig ens33:1 192.168.88.100/24 |
我们用node02去ping 192.168.88.100时候能ping通吗?
肯定ping不通,为什么呢?根据上面需要的知识,我们查看node02的路由表
发现他只能是走192,.168.188.2这个网关出去,而192.168.188.2这个网关没有192.168.88.100信息,肯定会跑丢,那么我们需要新建个路由,把192.168.88.100路由到192.168.188.180这个服务器上
1 | route add -host 192.168.88.100 gw 192.168.188.180 |
然后ping下自然是能ping通的
浅显的看是根据路由转发,深点看就是
- 通过ip匹配路由,找到网关
- 链路层:根据网关找到mac地址
- 链路层:根据mac地址跳具体的ip,点对点的关系
- 跳到具体的ip,继续通过路由匹配ip,还没匹配到具体的ip,那么继续网关转发,继续mac跳
总结发送
上面一切都ok后,我们源mac地址 ip 目标mac地址 ip都知道了,就可以发送包了,只需要封装一个包:
- 源mac地址->目标mac地址
- 源ip->目标ip
- 源端口号->目标端口号
上面就是全部网络的环节
LVS的DR,TUN,NAT模型推导
这里就是负载均衡服务器的模型推到,通过我们的网络知识。通过上面的网络知识,我们可以推导出来,我们在网络层动手,收到一个数据包,看到目标端口是,要转发的端口,就可以把ip任意替换成要负载的ip就可以,然后在发出去。
试验环境,两台服务器
name | ip | 作用 |
---|---|---|
client01 | 192.168.188.11 | 客户端ip 01 |
client02 | 192.168.188.12 | 客户端ip 02 |
node01 | 192.168.188.180 | 负载均衡服务器 |
node02 | 192.168.188.181 | 具体的、需要转发的服务1 |
node02 | 192.168.188.182 | 具体的、需要转发的服务2 |
route | 192.168.188.2 | 路由器 |
route-r | 6.6.6.6 | 路由器外网通信的ip |
NAT网络模型推导R-NAT
第一步:
我们假设client01上网,访问百度,这里假设百度ip是8.8.8.8,那么client01,扔给路由器,但是我们不知道路由器的mac地址啊,要进行一次arp,发送arp数据包
- 源mac地址->client01@mac
- 源ip:端口 client01
- 目标mac地址 FFFFFFF
- 目标ip:端口 route
第二步:
交换机经过广播,路由器看到是自己的目标ip包,然后直接回一个包
- 源mac地址->route@mac
- 源ip:端口 route
- 目标mac地址 client01@mac
- 目标ip:端口 client01
第三步:
client01拿到路由器的mac后,直接发送数据包到路由器,链路层通过mac地址直接跳到路由器
- 源mac地址->client01@mac
- 源ip:端口 client01
- 目标mac地址 route@mac
- 目标ip:端口 8.8.8.8
第四步:
路由器拿到包后,同样路由一次,因为百度是8.8.8.8,并非路由器的内网,还是走路由器的网关,就是route-r,路由器访问外网的ip,我们封装个包,这里会同样的需要拿到百度ip的mac地址
- 源mac地址->6.6.6.6@mac
- 源ip:端口 6.6.6.6
- 目标mac地址 FFFFFFF
- 目标ip:端口 8.8.8.8
第五步:
拿到百度的mac地址后直接通过链路层跳到百度服务器,封个包发送过去
- 源mac地址->6.6.6.6@mac
- 源ip:端口 6.6.6.6
- 目标mac地址 8.8.8.8@mac
- 目标ip:端口 8.8.8.8
这里有一个细节,路由器也会有一个表,记录什么呢?记录接收的包要转发出去的端口号和我要发送的包的绑定,不然我怎么知道我收到的这个包是要回给哪个ip啊。所以路由器也有一个点。
这种是Nat模式,这个Nat模式是R-Nat,不改变目标ip
NAT网络模型推导D-NAT
通过上面的流程,我们发现需要ip跳ip,那么需要目标的mac地址,所以D-NAT只需需要把目标ip变成我需要转发的ip就ok的
下面是简单的说明
- CIP–>VIP
- VIP替换数据包,就是DIP–>RIP
- RIP处理完毕后,回一个包,就是RIP–>DIP
- VIP在回个包,VIP–>CIP
就是替换目标ip。这个是为了负载均衡
DR网络模型推导
我们不希望RIP在回包的时候,还经过VIP,所以,需要RIP配置一个
DR模型的核心点是,在链路层的mac地址,是RIP的mac地址,直接跳到RIP,那么就算我们如何得到RIP的MAC地址呢?我们需要RIP里有一个VIP,因为目标ip是VIP,只需要在RIP设置个隐藏的ip,就是VIP,对外隐藏,对内可见。一定是对外隐藏,不然ip冲突。所以,得到一个结论,负载和RIP一直在同一局域网下。
TUN网络模型推导
隧道技术,就是要访问的ip被包装下,CIP->VIP 被DIP->RIP包装,DIP->RIP不断的跳,跳到RIP后,撕毁包装,就是真的ip CIP->VIP
LVS的DR模型搭建
DR模型的点是什么?RIP的VIP隐藏!因为DR换的是mac地址,目标ip是不换的,我们需要直接路由到RIP
RIP上隐藏VIP
需要对外隐藏,对内可见,既然我们需要在RIP设置一个虚拟的VIP,并且不希望他被公布出来,所以,需要设置内核网络协议arp配置。
具体路径:
1 | /proc/sys/net/ipv4/conf/*IF* |
这里需要修改两个配置:
- arp_ignore:定义收到arp收到的请求级别,默认为0
- 0:只要本地配置有相应的地址,就给与响应
- 1:仅在请求的目标(MAC)地址配置请求到达接口上的时候,才会给予响应
- arp_announce:定义将自己地址向外通告的级别,默认为0
- 0:将本地任何接口上任何地址向外通告
- 1:试图仅向目标网络通告与其网络地址匹配
- 2:仅向与本地接口上的地址匹配的网络进行通道
VIP安装lvs:
1 | yum -y install ipvsadm |
开始配置
node01设置VIP,是虚拟网卡
1 | ifconfig ens33:1 192.168.188.100/24 |
node02、node03设置arp协议配置
需要修改arp_ignore为1:
1 | echo 1 >/proc/sys/net/ipv4/conf/ens33/arp_ignore |
需要修改arp_announce为2
1 | echo 2 >/proc/sys/net/ipv4/conf/ens33/arp_announce |
因为我们想启动也是这个配置,所以需要在all目录下配置一下
1 | echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore |
1 | echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce |
配置node02、node03的虚拟ip,注意需要配置到环卫接口上,就是本地接口,掩码需要是255.255.255.255。为什么要配置到lo上呢?lo是转发给自己的,我们不能转发出去,转发出去就出问题了。
1 | ifconfig lo:1 192.168.188.100 netmask 255.255.255.255 |
node01配置lvs
关闭禁止转发:
1 | echo 1 > /proc/sys/net/ipv4/ip_forward |
添加入口:
1 | ipvsadm -A -t 192.168.188.100:80 -s rr |
添加出口,就是RIP要负载的IP
1 | ipvsadm -a -t 192.168.188.100:80 -r 192.168.188.181:80 -g -w 1 |
最终查看ipvsadm的表
1 | ipvsadm -ln |
这样就配置完成了,访问192.168.188.100会把请求分发到 node01、node02
基于keepalived的LVS高可用搭建
解决问题
问题1:
单点故障,LVS解决了高并发分流的高速转发问题,但是有一个问题,就是VS挂了会怎么办,这个时候我们需要高可用,搭建分布模式。
问题2:
转发的RS挂了,VS是不知道的,VS是不断的转发…这里肯定会出问题
架构设计
我们需要改哪些东西:
是针对VS的设计,我们并不需要改RS,需要改两个东西
- 设计一个主VS,N个备VS,只要主VS挂了,备VS马上顶上
- 需要知道RS是否挂了,如果挂了,就不转发到这个RS上了
解决主备思路:
Master通告给Backup自己还活着,Backup监听Master状态,如果Backup监听到Master挂了,一堆Backup赶紧选举一个Master
解决RS存活:
VS对后端的RS进行健康检查,如果RS挂了,赶紧踢掉,如果RS活了,就加上
代码实现
试验环境,两台服务器
name | ip | 作用 |
---|---|---|
VS1 | 192.168.166.11 | 负载均衡服务器 |
RS1 | 192.168.166.12 | 真是访问的IP |
RS2 | 192.168.166.13 | 真是访问的IP |
VS2 | 192.168.166.14 | 负载均衡服务器 |
VS | 192.168.166.100 | 虚拟的ip,访问这个ip |
有人写好了程序,我们直接安装到 VS1、VS2
1 | yum -y install keepalived |
去修改keepalived的配置
1 | cd /etc/keepalived |
里面会有keepalived.conf,下面介绍两个主要配置
vrrp_instance VI_1:虚拟路由冗余协议
1 | vrrp_instance VI_1 { |
virtual_server:
1 | virtual_server 192.168.166.100 80 { ##VIP |
修改完配置直接主备启动keepalived即可
1 | systemctl start keepalived |