lvs和keepalived

网络基础#

先复习一下大一的计算机基础,OSI七层参考模型和TCP五层协议

OSI七层模型#

image-20200915085154185

TCP五层模型#

OSI的七层里面,表示层是说格式、安全、压缩,如JPEGASCll、加密方式。会话层是用来控制连接的建立、管理和断开。

这两层和原始的应用层在TCP/IP协议中被统一到了的应用层。

image-20200915085327275

TCP/IP协议的每一层常见协议:

image-20200915085625199

TCP/IP通讯基础原理#

OSI基础模型#

提到IO,首先是OSI参考模型,计算机网络基础,一共七层

image-20200521180941467

这7层是一个虚的东西,是一个规范。TCP/IP协议给精简到4层,把上面的应用层-表示层-会话层统一归结到新的应用层用户称,把下面的传输控制层-网络层-链路层-物理层视为内核层

OSI七层网络模型 TCP/IP四层概念模型 对应网络协议
应用层(Application) HTTP、TFTP, FTP, NFS, WAIS、SMTP
表示层(Presentation) Telnet, Rlogin, SNMP, Gopher
会话层(Session) SMTP, DNS
传输层(Transport) 传输层 TCP, UDP
网络层(Network) 网络层 IP, ICMP, ARP, RARP, AKP, UUCP
数据链路层(Data Link) 数据 FDDI, Ethernet, Arpanet, PDN, SLIP, PPP
物理层(Physical) 链路层 IEEE 802.1A, IEEE 802.2到IEEE 802.11

TCP/IP通讯过程#

网络概述#

  • 假设红色的计算机1是192.168.1.4,子网掩码是255.255.255.0处于192.168.1.0这个子网。路由器网关是192.168.1.1.
  • 另一个机器4是192.168.3.4,子网掩码是255.255.255.0处于192.168.3.0这个子网,路由器网关是192.168.3.1
  • 路由器有两个网卡,一个是192.168.1.1,另一个网卡ip是192.168.3.1,连接到两个网络上

image-20200915131007251

初始路由#

初始的时候计算机1的路由表至少有2条:

路由表和子网掩码做一次按位与运算,就能找到下一跳。至少有两个路由route -n

目标 网关 子网掩码 使用 接口 说明
192.168.1.0 0.0.0.0 255.255.255.0 eth0 # 任何192.168.1.x的请求和255.255.255.0按位与之后都是192.168.1.0,匹配上,然后因为是0.0.0.0,说明在一个子网,直接发给eth0去处理。
0.0.0.0 192.168.1.1 0.0.0.0 eth0 # 其他任何请求和0.0.0.0按位与之后都是0.0.0.0,匹配上,就会发送到
  • 上面第一行网关里面0.0.0.0被称为默认网关,只有一个。代表和前面的目标是同一局域网,不需要下一跳转发,直接请求。
  • 如果网关不是0.0.0.0,就说明不是直连的,需要下一跳才能访问。

计算机3对应的有两个路由:

目标 网关 子网掩码 使用 接口
192.168.3.0 0.0.0.0 255.255.255.0 eth0
0.0.0.0 192.168.3.1 0.0.0.0 eth0

此时记住路由器有两个网卡,一个是192.168.1.1,另一个网卡ip是192.168.3.1

数据包封装#

  • 此时计算机1请求计算机3,发送的数据包,ip是计算机3的192.168.3.4,端口8080,但是计算机1不知道计算机3在哪里,只能通过路由表192.168.3.4和0.0.0.0按位与,结果是0.0.0.0和第二条匹配,就走下一跳的网关192.168.1.1
  • 数据包上面会写上下一跳192.168.1.1的MAC地址,表示我要去下一跳是这里。

ARP协议#

arp协议用于完成ip和mac的映射。

初始的时候,计算机1和计算机3都不知道网络中其他机器的MAC,这时候arp协议就上场了。arp

地址 类型 硬件 接口
192.168.x.x ether 00:12:32:16:14:23 eth0

刚开机的时候arp里面是空的,网络激活的时候,arp发送mac为全FF:FF:FF的广播,目标ip是网关192.168.1.1,源ip是1.4。交换机会给广播到所有的节点。只有目标的网关会响应。会回复给计算机1,也就是1.4自己的mac。此时计算机1就有了一条记录。

同时交换机也会学习记录mac信息,回去的时候会成功返回给1.1。

数据包封装2#

经过上面的arp协议,现在计算机1可以把目标ip为192.168.3.4,mac是下一跳是192.168.1.1的包发出去了。

1.1的网关接收到之后,继续在路由里面匹配,然后只修改包里面的mac,继续往下一跳走。

如此往复就完成了数据包的传递。

结论#

  • TCP/IP是一个基于下一跳机制的传输协议
  • IP是两个端点,发送方和接收方。
  • mac地址是节点之间,下一跳的信息。
  • 端口是对应接收方的一个进程

流程回顾#

  • 上层的应用无论是http请求还是ftp还是ssh等等,想请求需要先向底层传输控制层去获取一个socket。

  • 假如是tcp的,需要三次握手。下层的传输控制层先去构建一个握手包,握手包通过下层的网络层通过路由下一跳的方式发出去。

  • 下一跳怎么发出去呢?链路层的arp协议获取了下一跳的mac地址,重新包装握手包,通过物理层发出去。

数据包包括:

  • 源端口号,目标端口号(代表进程)

  • 源IP地址,目标IP地址(决定端点)

  • 源Mac地址,和目标Mac地址(决定下一跳找哪个服务器),每跳一次,源mac地址和目标mac地址都会改变。但是源和目标ip不变。

  • 以上三点就可以决定从源到目标的数据包发送

image-20200521181257025

linux命令测试讲解TCP#

创建一个到baidu的文件描述符(内核层)#

  • linux一切皆文件,每一个程序都有自己的IO流。程序里面的IO流也会被描述成文件(数字)。没一个程序都有3个自带的文件描述符:
    • 0:system.in
    • 1: system.out
    • 2: system.err
    • 用户创建的IO就从3开始

**【举例】**执行一个bash命令创建一个到baidu的socket,IO流重定向到当前进程的8号文件描述符中:

  • exec 8<> /dev/tcp/www.baidu.com/80

  • 上面面创建了一个文件描述符“8”,是一个socket指向了百度,

  • 8是文件描述符fd(就像代码的变量),<>是一个双向输入输出流,可以看到

  • echo $$  # 打印当前命令行的进程号
    16199
    # 也可以ps -ef 然后grep出来
    tree     16199  9368  0 4月15 pts/1   00:00:01 /bin/bash
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    - 可以去当前进程的目录看一眼

    - ```bash
    cd /proc/16199/fd # 进入当前进程的fd目录
    ls # 看一眼
    lrwx------ 1 tree tree 64 5月 21 18:31 0 -> /dev/pts/1
    lrwx------ 1 tree tree 64 5月 21 18:31 1 -> /dev/pts/1
    lrwx------ 1 tree tree 64 5月 21 18:31 2 -> /dev/pts/1
    lrwx------ 1 tree tree 64 5月 21 18:31 255 -> /dev/pts/1
    lrwx------ 1 tree tree 64 5月 21 18:31 8 -> 'socket:[1037956]'
    # 每个进程都有0,1,2三个fd文件描述符。分别是stdin、stdout、stderr

向文件描述符中写东西通信(用户层态)#

1
2
3
4
5
6
echo -e "GET / HTTP/1.0\n" 1>& 8  
# 打印一个字符串到标准输出(所以是1)重定向>到文件描述符(所以是&,重定向到文件不用&)8中

cat 0<& 8
# 从文件描述符(所以是&,文件的话不用&)8中标准输入<
# 。。。。。下面打印一大堆百度的html

传输控制层TCP协议#

TCP和UDP是传输控制层协议。

什么是socket套接字?#

  • ip+port <---------> ip+port 是一【套】,客户端和服务端的ip+port 4个要素决定唯一的一个socket

  • 客户端的ip是B,可以和baidu建立多少个链接?65535个

  • 此时客户端B还能继续和163建立链接吗?也可以继续再次建立65535个,因为socket是【一套】4个要素,server换了就是另外一个socket了。

  • 对于类似如下netstat -anp出来的socket链接,每一个established都有一个文件描述符(fd目录下)数字和他对应并交给一个进程。程序只用和这个文件描述符进行读写就可以进行socket通信了。【如果多个socket对应一个进程:就是多路复用器selector或者epoll】

    下面的192.168.150.12:22建立了两个到192.168.150.1socket

    image-20200521191000694

什么是TCP协议?#

是一个面向连接可靠的传输协议。因为三次握手保证了可靠传输。

连接:不是物理连接,是三次握手实现的逻辑连接,完成双向确认。

为啥可靠:通信前三次握手双方分配资源,为未来的通讯做好了准备。所有数据包发送的时候有个确认机制保证了可靠。

DDOS:发握手包,但是不回。造成服务器有一大堆接受TCP的等待队列。使得真正想进来的连接进不来。

三次握手的细节?#

image-20200521185513169

C-----------syn----------->S # “我要跟你连接了,标识是syn”

C<----------syn+ack-------S # “好的,我知道了” 让客户端知道Server已经响应了

C------------ack----------->S # 好的,我知道你知道了。让Server知道发出的消息客户端收到了

然后双方开始开辟资源(内存,结构体,线程),建立连接。

谁触发三次握手?目的?#

应用层的程序先告诉内核,我要和一个地址建立连接。内核去尝试三次握手。

三次握手成功后会在双方服务器开辟资源(线程、内存结构体等等)来为对方提供响应服务。

三次握手完毕后,双方才有资源开辟,才能开始传输。

tcpdump 查看三次握手#

tcpdump -nn 显示ip断开 -i 显示哪个网卡接口 port 显示哪个端口

image-20200521194049682

四次分手的细节,为啥要四次?#

因为握手是三次,开辟了资源。分手是双方一起释放资源,对对方有义务的,所以是四次(双方都要同时释放,不能轻易单方面释放了)

image-20200521192102157

分手的C只是先说断开的人

C-----------fin----------->S # “我要跟你分手了,标识是fin”给Server一个结束标识

C<----------fin+ack-------S # “好的,我知道了” 让客户端知道Server已经响应了(但是我要确认一下真的没事儿了)

C<-----------fin------------S # “好吧,分吧,标识是fin”确认真的没事儿了,给客户端一个结束标识

C------------ack----------->S # “好的,”让Server知道发出的消息客户端收到了

然后双方把给对方准备的资源都释放了。

三次握手和四次分手是不可分割的最小粒度#

  • LVS作为一个工作在四层的负载均衡,是无法知晓数据包的具体内容的!

  • LVS是否可以随意把数据给后端进行负载?-可以负载,但是受制于协议约束!

    • C ----- lvs ----- S1/S2 的时候,LVS必须要把握手的三次给到一对C—S,不能给到另外一个S,否则无法建立连接。

网络和路由#

上面的TCP协议只管传输和控制,也就是发什么内容,怎么发。但是发送的路径不管,是下层寻址ARP协议管理的。

网络设置要ipgatewaymaskdns4个东西

  • 如果几个设备ip:192.168.1.10192.168.1.11,他们只要成功联网,肯定知道他们的下一跳路由器地址(静态或者DHCP),如192.168.1.1
  • 客户端向发送一个ARP广播包,带着路由器的ip和全FFFFFFFFFF的mac地址,路由器收到后看到是自己的ip,就把自己的mac地址返回给客户机。
  • 然后客户端才知道路由器的mac,包装后就能往百度发了三次握手的包了。
  • 通过路由表往下一跳发

【测试】``

下面会先去请求ARP,收到路由器返回mac后,包装三次握手的包发出去。最后四次分手。

每次发送的包和接受的包都有一个seq和seq+1的关系,保证了不会错乱。

image-20200610234329384

image-20200915084831252

  • socket是一层规范,屏蔽内核里面的四层握手等细节。应用7层只用拿到socket就能通讯,不用管里层实现。
  • 四层只能看到ip和端口,看不到类似url这种七层的东西。
  • lvs快就是因为是四层,但是不会和客户端握手,直接转给后面的服务集群。

负载均衡模式#

假设现在有很多的客户端,很多的server,需要中间有一个负载均衡软件去做分发。

负载均衡

image-20200917153510318

D-NAT#

  • 客户端需要请求负载均衡,负载均衡转给server
  • 客户端的网卡IP假设为CIP
  • 负载均衡的入口网卡是VIP,出口分发网卡是DIP
  • 服务端ip是RIP真实IP
  • 流程:
    • 不处理和client的握手,直接透传给后端server
    • 多个客户端会产生CIPx:随机port -->VIP:Vport 的数据包
    • VIP为了把报给server正常处理,必须把目标IP改为某个server的RIP
    • server拿到包处理完之后,返回RIPx--->CIPx的包,不过还是会丢给负载均衡DIP去处理。
    • 负载均衡DIP网卡拿到包之后,根据目标CIPx的信息,修改来源为VIPx--->CIPx再发回去
  • 特点:
    • 来回都经过负载均衡,通讯是不对称的(请求经常很小,但是响应经常很大),带宽成为瓶颈
    • 负载均衡需要经过计算,去映射
    • 同时因为server的包回去的时候要给到负载均衡才能正确映射到Client,所以要求server的默认网关指向负载均衡服务器。

image-20200917133808460

DR模式(Direct Route)#

IP和上面相同,为了解决D-NAT模式来回的非对称网络给负载均衡的压力,同时为了降低负载均衡的计算开销。

一句话:基于二层链路层的MAC地址欺骗,速度快、成本低。不过要求负载和server在同一局域网。----企业数据中心最常用

关键点:

  • 第一个问题:
  • 现在只要server能直接返回包给client的CIP问题就解决了。但是客户端过来的时候是CIP--->VIP的包,回去的时候要是VIP--->CIP的包客户端才能处理。
  • 比如natstat -natp的时候有本地和对端的 ip:port <---->ip:port映射,我们要在server上伪造一个隐藏的负载均衡IP不被网络发现。就可以伪造一对socket映射。
  • 同理所有的server内部原本都是RIP,现在都伪造了一块隐藏的VIP网卡。
  • 第二个问题:
  • 负载均衡要把包发给各个server的时候无需在三层网络层IP的层面去解开然后修改IP,只需要修改下一跳的二层链路层的MAC地址为某一个server的MAC即可。
  • 回忆上面TCP/IP基于下一跳机制,这里是一样的,因为VIP接收到的数据包就是CIP--->VIP,server又有隐藏的VIP网卡。所以负载均衡直接进行MAC地址欺骗,篡改MAC为某个server的MAC,链路层就能把包发给对应的server去处理。(如果不改,这个数据包就会又发给负载均衡器自己)
  • 数据包的IP是两个端点的,MAC是下一跳的。
  • 这样在二层直接改链路的MAC,非常快。但是缺点是只能是同一个局域网内。也就是要求负载均衡和server是同一个局域网内。
  • 然后server处理完之后,直接就把包从server返回给CIP客户端,无需再次经过负载均衡。
  • 图上看不清的右边红色部分是netstat -natp

image-20200917151846506

TUN隧道技术#

实现:

  • 隧道,通俗理解即一个数据包背着另外一个数据包。也就是外层数据包,里面包裹着一个内层数据包。
  • 比如client访问server其实先访问负载均衡的VIP,负载均衡的VIP使用分发网卡DIP去往真正的serverRIP,里面包装了一个CIP-->VIP客户端请求包。
  • 然后又可以继续不停地经过下一跳机制,到达server的RIP。server拆掉外面的数据包,就看到了里面的CIP-->VIP的包,进行处理。
  • 处理完毕server直接返回给客户端(server上有VIP的隐藏网卡)
  • 常规的VPN和科学地上网都是类似的原理。

image-20200917155016958

https://www.cnblogs.com/qishui/p/5428938.html