14 Linux网络管理

14 Linux网络管理

1. 网络基本概述

1.1 为何需要网络

  • 假设没有网络:(也就是将所有的计算机网络都关闭)
    • 如果我的计算机上有非常不错的电影,想要进行传
      输,就比较的费劲了;
    • 因为我们可能处在不同的城市、或者不同的国家;
  • 但如果有了网络:(也就是将所有计算机通过网线连
    接在一起)
    • 1.打破了地域上数据传输的限制;
    • 2.提高信息之间的传输效率,以便更好的实现”资源
      的共享“;

1.2 什么是网络

  • 网络是由"若干节点"和"连接这些节点"的链路构成,
    表示诸多对象及其相互联系。
  • 网络是信息传输、接收、共享的虚拟平台,通过它把
    各个信息联系到一起,从而实现这些资源的共享。
  • 网络将节点连接在一起,需要实现 ”信息传输“(信息
    通信)有几个大前提:
    • 1.使用物理连接的介质将所有计算机连接在一起
      (网卡、网线、交换机、路由器);
    • 2.双方在通信过程中,必须使用统一的通信标准,
      也就是通讯协议(互联网通讯协议);

2.互联网通讯协议

  • 协议其实就是规定了一堆标准,用来定义计算机如何
    接入 internet 以及接入 internet 的计算机通信的
    标准;所以计算机都需要学习此标准、遵循此标准来
    进行信息传输(信息通信);
  • 国际标准化组织:推出了 OSI 七层参考模型,将互联
    网通讯协议分成了不同的层,每一层都有专门的标
    准,以及组织数据的格式;
    • (应、表、会、传、网、数、物)
  • 对于写程序来说,通常会将七层归纳为五层协议;
    • (应、传、网、数、物)
  • 所以我们需要学习协议的规定了哪些标准;

2.1 物理层

物理层:定义物理设备的标准,如网卡网线,传输速
率;最终实现数据转成电信号传输;
问题:如果只是单纯发送电信号是没有意义的,因为没
有规定开头也没有规定结尾;要想变得有意义就必须对

电信号进行分组;比如:xx位为一组、这样的方式去传
输,这就需要“数据链路层”来完成了;

2.2 数据链路层

  • 数据链路层定义:定义了电信号的分组的标准方式,
    一组数据称之为一个数据帧,这个标准遵循
    ethernet 以太网协议,以太网规定了如下几件事;
  • 1.数据帧分为 head 和 data 两部分组成;其中 head
    长度固定18字节;
    • head :发送者/源地址、接收者/目标地址(源地址
      6字节、目标地址6字节、数据类型6字节)
      • 源地址: MAC 地址
      • 目标地址: MAC 地址
    • data :主要存放是网络层整体的数据,最长1500
      字节,超过最大限制就分片发送;
  • 2.但凡接入互联网的主机必须有一块网卡,网卡烧制
    了全世界唯一的 MAC 地址;
  • 3.有了以太网协议规定以后,它能对数据分组、也可
    以区分数据的意义,还能找到目标主机的地址、就可
    以实现计算机通信;但是计算机是瞎的,所以以太网
    通信采用的是"广播"方式;

  • 那什么是广播:
    • 假设我们都在一个小黑屋里面,大家互相通信靠
      吼,假设 oldxu 让 laowang 买包烟;
      • 1.数据:买烟(类型:干粮)
      • 2.源地址: oldxu
      • 3.目标地址: laowang
    • 此时屋子里所有人都收到了该数据包,但只有
      laowang 会接收执行,其他人收到后会丢弃;
  • 如果我们将全世界的计算机都接入在一起,理论上是
    不是就可以实现全世界通信:
    • 首先:无法将全世界计算机放在一个交换机上,因
      为没有这样的设备;
    • 其次:就算放在同一设备上,每台计算机都广播一
      下,那设备也无法正常工作;
    • 所以:我们应该将主机划区域,隔离在一个又一个
      的区域中,然后将多个区域通过"网关/路由"连接在
      一起;

2.3 网络层

  • 网络层定义:用来划分广播域,如果广播域内主机要
    往广播域外的主机发送数据,一定要有一个"网关/路
    由"帮其将数据转发到外部计算机;网关和外界通信走
    的是路由协议(这个我们不做详细阐述)。其次网络
    层协议规定了如下几件事;

    • 规定1:数据包分成: head 和 data 两部分组成;
      • head :发送者/源地址、接收者/目标地址,该
        地址为IP地址;
      • data :主要存放是传输层整体的数据;
    • 规定2: IP 地址来划分广播域,主要用来判断两台
      主机是否在同一广播域中;
      • 一个合法 IPV4 地址组成部分= ip地址/子网掩
        码 ,在线子网计算器
      • 172.16.1.100/24、172.16.1.1/24、
        172.16.1.2/24
      • 172.16.1.200/24
      • 网段:172.16.1.0
      • 主机:100台
      • 广播地址:172.16.1.255
      • 如果计算出两台地址的广播域一样,说明两台
        计算机处在同一个区域中;

  • 计算两台计算机是否在同一局域网(牵扯到如何发送数据):
  • 假设:现在计算机1要与计算机2通信,计算机1必须
    拿到计算机2的ip地址;
    • 如果它们处于同一网络(局域网) 10.0.0.1-->10.0.0.100 :
      • 1.本地电脑根据数据包检查目标 IP 如果为本地
        局域网;
      • 2.直接通过交换机广播MAC寻址;将数据包转
        发过去;
    • 如果它们处于不同网络(跨局域网) 10.0.0.1--
      39.104.16.126 :
      • 1.本地根据数据包检查目标 IP 如果不为本地局
        域网,则尝试获取网关的 MAC 地址;
      • 2.本地封装数据转发给交换机,交换机拆解发现
        目标 MAC 是网关,则送往网关设备;
      • 3.网关收到数据包后,拆解至二层后发现请求目
        标 MAC 是网关本机 MAC ;
      • 4.网关则会继续拆解数据报文到三层,发现目标
        地址不为网关本机;
      • 5.网关会重新封装数据包,将源地址替换为网关
        的 WAN 地址,目标地址不变;
      • 6.出口路由器根据自身“路由表”信息将数据包发
        送出去,直到送到目标的网关 ;

2.4 传输层

  • 传输层的由来:网络层帮我们区分子网,数据链路层
    帮我们找到主机,但一个主机有多个进程,进程之间
    进行不同的网络通信,那么当收到数据时,如何区分
    数据是那个进程的呢;其实是通过端口来区分;端口
    即应用程序与网卡关联的编号。
  • 传输层的定义:提供进程之间的逻辑通信;
  • 传输层也分成: head 和 data 两部分组成;
    • head :源端口、目标端口、协议(TCP、
      UDP);
    • data :主要存放是应用层整体的数据;
    • 80:http
    • 443:https
    • mysql:3306
    • tomcat:8080
    • redis:6379
    • dns:53
    • dhcp:67 68

2.5 应用层

  • 应用层定义:为终端应用提供的服务,如我们的浏览
    器交互时候需要用到的 HTTP 协议,邮件发送的
    SMTP,文件传输的 FTP 等。
  • 浏览器:
    • 请求百度的内容: 请求包; 请求的协议;
      http 源断口: 1234 目标端口:80

3.TCP协议

  • tcp可靠数据传输协议;为了实现可靠传输,在通信之
    前需要先建立连接,也叫"双向通路",就是说客户端
    与服务端要建立连接,服务端与客户端也需要建立连
    接,当然建立的这个双向通路它只是一个虚拟的链
    路,不是用网线将两个设备真实的捆绑在一起;
  • 虚拟链路的作用:由于每次通信都需要拿到IP和
    Port,那就意味着每次都需要查找,建立好虚拟通
    路,下次两台主机之间就可以直接传递数据;

3.1 三次握手

  • 第一次:客户端要与服务端建立连接,需要发送请求
    连接消息;
  • 第二次:服务端接收到数据后,返回一个确认操作
    (至此客户端到服务端链路建立成功);
  • 第三次:服务端还需要发送要与客户端建立连接的请求;
  • 第四次:客户端接收到数据后,返回一个确认的操作
    (至此服务端到客户端的链路建立成功);
  • 由于建立连接时没有数据传输,所以第二次确认和第
    三次请求可以合并为一次发送

  • TCP协议为了实现可靠传输,通信双方需要判断自已
    经发送的数据包是否都被接收方收到,如果没收到,
    就需要重发。为了实现这个需求,就引出序号
    (seq)和确认号(ack)的使用。
  • 举例:发送方在发送数据包时,序列号(假设为
    123),那么接收方收到这个数据包以后, 就可以回复
    一个确认号(124=123+1)告诉发送方 “我已经收到
    了你的数据包,你可以发送下一个数据包,序号从
    124 开始”,这样发送方就可以知道哪些数据被接收
    到,哪些数据没被接收到,需要重发。

3.2 四次挥手

  • 第一次挥手:客户端(服务端也可以主动断开)向服
    务端说明想要关闭连接;
  • 第二次挥手:服务端会回复确认。但不是立马关闭,
    因为此时服务端可能还有数据在传输中;
  • 第三次挥手:待到服务端数据传输都结束后,服务端
    向客户端发出消息,我要断开连接了;
  • 第四次挥手:客户端收到服务端的断开信息后,给予
    确认。服务端收到确认后正式关闭。

3.3 转换状态

  • 三次握手状态转换:
  • 1.客户端发送syn包向服务端请求建立 TCP 连接,客户
    端进入 SYN_SEND 状态;
  • 2.服务端收到请求之后,向客户端发送 SYN+ACK 的合
    成包,同时自身进入 SYN_RECV 状态;
  • 3.客户端收到回复之后,发送 ACK 信息,自身进入
    ESTABLISHED 状态;
  • 4.服务端收到ACK数据之后,进入 ESTABLISHED 状
    态。

  • 四次挥手过状态转换:

  • 1.客户端发送完数据之后,向服务器请求断开连接,
    自身进入 FIN_WAIT_1 状态;

  • 2服务端收到 FIN 包之后,回复 ACK 包表示已经收到,
    但此时服务端可能还有数据没发送完成,自身进入
    CLOSE_WAIT 状态,表示对方已发送完成且请求关闭
    连接,自身发送完成之后可以关闭连接;

  • 3.服务端数据发送完成后,发送 FIN 包给客户端,自
    身进入 LAST_ACK 状态,等待客户端 ACK 确认;

  • 4.客户端收到 FIN 包之后,回复一个 ACK 包,并进入
    TIME_WAIT 状态;

  • 注意: TIME_WAIT 状态比较特殊,当客户端收到服务
    端的 FIN 包时,理想状态下,是可以直接关闭连接
    了;但是有几个问题:

    • 问题1:网络是不稳定的,可能服务端发送的一些
      数据包,比服务端发送的 FIN 包还晚到;
    • 问题2:.如果客户端回复的ACK包丢失了,服务端
      就会一直处于 LAST_ACK 状态,如果客户端没有关
      闭,那么服务端还会重传 FIN 包,然后客户端继续
      确认;
  • 所以客户端如果 ACK 后立即关闭连接,会导致数据不
    完整、也可能造成服务端无法释放连接。所以此时客
    户端需要等待2个报文生存最大时长,确保网络中没
    有任何遗留报文了,再关闭连接;期间客户端不断给
    服务端发送ACK确认,防止服务端收不到一直处于LAST_ACK状态

  • 如果机器 TIME_WAIT 过多,会造成端口会耗尽,可以
    修改内核参数 tcp_tw_reuse=1 端口重用;

  • 为什么必须要等待2MSL?而不是4MSL?8MSL?
  • 一个MSL就是报文在网络中的最长生存时间,大白话
    的话,就是如果存在丢包的话,在MSL时间内也会触
    发重传了,这里2MSL,就相当于两次丢包,一次丢
    包概率是百分之一,连续两次丢包的概率是万分之
    一,这个概率实在是太小了,所以2MSL是足够的。

3.4 UDP协议

  • udp 是不可靠传输协议;不可靠指的是传输数据时不
    可靠;
  • udp 协议不需要先建立连接,只需要获取服务端的
    ip+port ,发送完毕也无需服务器返回 ack
  • udp 协议如果在发送在数据的过程中丢了,那就丢
    了;
  • 场景:直播;弹幕; DNS 采用; QQ早起UDP;

4. 网络配置

4.1 查询网络信息

1.使用 ifconfig 当前处于活动状态的网络接口

[root@node ~]# yum install net-tools -y
[root@node ~]# ifconfig
#仅查看eth0网卡状态信息
[root@node ~]# ifconfig eth0
#查看所有网卡状态信息, 包括禁用和启用
[root@node ~]# ifconfig -a
#UP: 网卡处于活动状态 BROADCAST: 支持广播
RUNNING: 网线已接入
#MULTICAST: 支持组播 #MTU: 最大传输单元(字节),接
口一次所能传输的最大包
eth0:
flags=4163<UP,BROADCAST,RUNNING,MULTICAST>
mtu 1500
    #inet: 显示IPv4地址行
   inet 10.0.0.100 netmask
255.255.255.0 broadcast 10.0.0.255
    #inet6: 显示IPv6地址行
    inet6 fe80::a879:62cf:396c:e7d9
prefixlen 64 scopeid 0x20<link>
   inet6 fe80::22a2:cb:8a69:bf63
prefixlen 64 scopeid 0x20<link>
    #enther: 硬件(MAC)地址 
    #txqueuelen: 传输缓存区长度大小
   ether 00:0c:29:5f:6b:8a txqueuelen
1000 (Ethernet)
    #RX packets: 接收的数据包
   RX packets 3312643 bytes
4698753634 (4.3 GiB)
   RX errors 0 dropped 0 overruns 0
frame 0
    #TX packets: 发送的数据包   
   TX packets 235041 bytes 20504297
(19.5 MiB)
   TX errors 0 dropped 0 overruns 0
carrier 0 collisions 0
#errors: 总的收包的错误数量 
#dropped: 拷贝中发生错误被丢弃
#collisions: 网络信号冲突情况, 值不为0则可能存在
网络故障

2.使用 ip 命令查看当前地址

[root@node ~]# ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,①UP,LOWER_UP>
mtu 1500 qdisc pfifo_fast state UP qlen
1000
 ②link/ether 00:0c:29:5f:6b:8a
ff:ff:ff:ff:ff:ff
 ③inet 10.0.0.100/24 brd④ 192.168.69.255
scope global ens32
   valid_lft forever preferred_lft
forever
 ⑤inet6 fe80::bd23:46cf:a12e:c0a1/64
scope link
   valid_lft forever preferred_lft
forever
  
#①: 活动接口为UP
#②: Link行指定设备的MAC地址
#③: inet行显示IPv4地址和前缀
#④: 广播地址、作用域和设备名称在此行
#⑤: inet6行显示IPv6信息

3.使用 ip -s link show eth0 命令查看网络性能的统
计信息, 比如: 发送和传送的数据包、错误、丢弃

[root@node ~]# ip -s link show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP>
mtu 1500 qdisc mq state UP mode DEFAULT
qlen 1000
 link/ether 14:18:77:35:0d:f5 brd
ff:ff:ff:ff:ff:ff
 RX: bytes packets errors dropped
overrun mcast
 518292951 4716385 0    0    0 
  709280
 TX: bytes packets errors dropped
carrier collsns
 23029861512 15391427 0    0    0
   0

4.2 修改网卡名称

  • Centos6 网卡名称是 eth0、eth1....
  • Centos7 网卡名称是 ens32、ens33...
  • 由于这种无规则的命名方式给后期维护带来了困难,
    所以需要将网卡名称修改为 eth0、eth1..

场景示例1:已经安装完操作系统,修改网卡命名规
则为 eth0 eth1

1.修改网卡配置文件

[root@node ~]# cd /etc/sysconfig/network-scripts/
[root@node network-scripts]# mv ifcfg-ens32 ifcfg-eth0
[root@node network-scripts]# vim ifcfg-eth0
NAME=eth0
DEVICE=eth0

2.修改内核启动参数,禁用预测命名规则方案,将
net.ifnames=0 biosdevname=0 参数关闭

[root@node~]# vim /etc/sysconfig/grub
GRUB_CMDLINE_LINUX="...net.ifnames=0 biosdevname=0 quiet"
[root@node~]# grub2-mkconfig -o /boot/grub2/grub.cfg

3.重启系统,然后检查网卡名称是否修改成功

[root@node~]# reboot
[root@node~]# ifconfig
  • 场景示例2:在新安装系统时,修改网卡名称规则

1.在安装系统选择 Install Centos7 按下 Tab 设定
kernel 内核参数;

2.增加内核参数: net.ifnames=0 biosdevname=0 ;

3.检查是否修改成功,成功后可继续安装系统;

4.3 配置网络地址

  • CentOS7 系统默认采用 NetworkManager 来提供网
    络服务,这是一种动态管理网络配置的守护进程,能
    够让网络设备保持连接状态。 NetworkManager 提供
    的命令行和图形配置工具对网络进行设定,设定保存
    的配置文件在 /etc/sysconfig/network-scripts
    目录下,工具有 nmcli、nmtui
  • NetworkManager 有如下两个概念需要了解:
    • device 物理设备,例如: enp2s0,virbr0,team0
    • connection 连接设置,具体网络配置方案
    • 一个物理设备 device 可以有多套逻辑连接配置,
      但同一时刻只能使用一个 connection 连接配置;

4.3.1 nmcli查看网络状态

1.使用 nmcli device 命令查看设备情况

# 查看所有设备
[root@node ~]# nmcli device
DEVICE   TYPE   STATE   CONNECTION
eth0    ethernet connected  eth0
lo     loopback unmanaged  --
# 指定查看某个设备的详细状态
[root@node ~]# nmcli dev show eth0

2.使用 nmcli connection 命令查看连接状态

#查看连接状态
[root@node ~]# nmcli connection 
NAME  UUID               
 TYPE      DEVICE
eth0  a4319b27-80dc-4d63-a693-2927ea1018e7
 802-3-ethernet eth0
# 查看所有活动连接的状态
[root@node ~]# nmcli con show --active
# 查看指定连接状态
[root@node ~]# nmcli con show "eth0"

4.3.2 nmcli配置IP地址

  • 使用 nmcli 创建一个 static 的连接,配置IP、掩
    码、网关等
    • 1、添加一个连接配置,并指定连接配置名称
    • 2、将连接配置绑定物理网卡设备
    • 3、配置网卡的类型,网卡是否开机启动
    • 4、网卡使用什么模式配置IP地址(静态、dhcp)
    • 5、配置网卡的IP地址、掩码、网关、DNS等等
[root@node ~]# nmcli connection add \
con-name eth0-static \
ifname eth0 \
type ethernet \
autoconnect yes \
ipv4.addresses 10.0.0.222/24 \
ipv4.gateway 10.0.0.2 \
ipv4.dns 223.5.5.5 \
ipv4.method manual
[root@oldxu ~]# nmcli connection add con-
name eht0-static ifname eth0 \
type ethernet autoconnect yes \
ipv4.method manual \
ipv4.addresses 10.0.0.222/24 \
ipv4.gateway 10.0.0.254 \
ipv4.dns 233.5.5.5.5 \
+ipv4.dns 8.8.8.8
#激活eht1-static的连接
[root@node ~]# nmcli connection up eht0-static
[root@node ~]# nmcli connection show
NAME     UUID             
   TYPE      DEVICE
eht0-static 6fdebe6e-5ef0-4a05-8235-
57e317fdada0  802-3-ethernet eth0

4.3.3 nmcli修改IP地址

1.取消 eht1-static 连接开机自动激活网络

[root@node ~]# nmcli connection modify eht0-static \
autoconnect no

2.修改 eht1-static 连接的 dns 配置

[root@node ~]# nmcli connection modify
eht0-static \
ipv4.dns 8.8.8.8

3.给连接再增加 dns 有些设定值通过 +/- 可以增加或则移除设定

[root@node ~]# nmcli connection modify
eht0-static \
+ipv4.dns 8.8.8.8

4.替换连接的静态IP和默认网关

[root@node ~]# nmcli connection modify
eht0-static \
ipv4.addresses 10.0.0.111/24 ipv4.gateway
10.0.0.254

5.nmlci 仅仅修改并保存了配置,要激活更改,需要重激活连接

[root@node ~]# nmcli connection down eht1-
static && \
nmcli connection up eht1-static

6.删除自建的 connection

[root@node ~]# nmcli connection delete
eht1-static

4.3.4 nmcli管理配置文件

  • 使用 nmcli 管理 /etc/sysconfig/network-
    scripts/ 配置文件,其实就是自定义一个网卡的配
    置文件,然后加入至 NetworkManager 服务进行管
    理;

    • 1、新增物理网卡
    • 2、拷贝配置文件(可以和设备名称一致)
    • 3、修改配置,UUID、连接名称、设备名称、IP地址
    • 4、重新加载网络配置
    • 5、启用连接,并检查

    1.添加一个物理设备,进入 /etc/sysconfig/network-
    script/ 目录拷贝一份网卡配置文件;

    [root@node network-scripts]# cp ifcfg-
    eth0-static ifcfg-eth1-static
    

    2.修改网卡配置文件如下

    [root@node network-scripts]# cat ifcfg-
    eth1-static
    TYPE=Ethernet
    BOOTPROTO=none # 网卡类型 none;
    static;dhcp; 硬件服务器都选择static、云主机、
    docker容器实例一般都是dhcp
    IPADDR=10.0.0.222 # IP地址
    PREFIX=24 # 子网掩码
    DEFROUTE=yes # 默认路由(明天讲
    路由)
    NAME=eth1-static # 链接的配置名称
    DEVICE=eth2 # 设备名称
    ONBOOT=yes # 开机是否启动
    

    3.重载 connetction 连接,让 NetworkManager 服务能够识别添加自定义网卡配置;

    [root@node network-scripts]# nmcli connection reload
    NAME     UUID             
       TYPE   DEVICE
    eth0     5fb06bd0-0bb0-7ffb-45f1-
    d6edd65f3e03 ethernet eth0  
    eth1-static 8f105ed6-1361-8e14-51fd-
    dedb8ef3510a ethernet eth1 
    

    4.eth1-static 连接配置已经关联了 eth1 物理设备,如果希望修改 IP 地址,可以用如下两种方式;

    # 方式一、nmcli modify方式修改然后重载配置
    [root@node ~]# nmcli modify eth1-static
    ipv4.address 10.0.0.233/24
    [root@node ~]# nmcli down eth1-static &&
    nmcli up eth1-static
    # 方式二、vim修改,先reload,然后重载
    [root@node network-scripts]# cat ifcfg-
    eth1-static
    ...
    IPADDR=10.0.0.234
    ...
    [root@node ~]# nmcli connection reload
    [root@node ~]# nmcli connection down eth1-
    static && nmcli connection up eth1-static
    
    #重启网卡
    systemctl restart network
    
    

5. 网卡绑定

  • 网卡绑定 Bonding
    • 1、可以实现网络冗余,避免单点故障;
    • 2、可以实现负载均衡,以提升网络的传输能力;
  • 网卡绑定实现模式:
    • 模式0 balance-rr 负载轮询:两网卡单独是
      100MB ,聚合为1个网络传输,则可提升为 200MB
    • 模式1 active-backup 高可用:两块网卡,其中一
      条若断线,另外的线路将会自动顶替

5.1 配置round-robin

5.1.1 eth0网卡配置

[root@node ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
DEVICE=eth0
NAME=eth0
ONBOOT=yes
MASTER=bond0
SLAVE=yes

5.1.2 eth1网卡配置

[root@node ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
DEVICE=eth1
NAME=eth1
ONBOOT=yes
MASTER=bond0
SLAVE=yes

5.1.3 bond网卡配置

[root@node ~]# cat /etc/sysconfig/network-
scripts/ifcfg-bond0
TYPE=Bond
BOOTPROTO=none
ONBOOT=yes
DEVICE=bond0
NAME=bond0
IPADDR=10.0.0.100
PREFIX=24
GATEWAY=10.0.0.2
DNS1=223.5.5.5
DEFROUTE=yes
BONDING_MASTER=yes
BONDING_OPTS="miimon=200 mode=0"   # 检查间
隔时间ms

5.1.4 bond状态检查

[root@node ~]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.7.1
(April 27, 2011)
Bonding Mode: load balancing (round-robin)
 # 模式
MII Status: up
MII Polling Interval (ms): 200
Up Delay (ms): 0
Down Delay (ms): 0
Slave Interface: eth0
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:aa:8d:2e
Slave queue ID: 0
Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:0c:29:aa:8d:42
Slave queue ID: 0

使用 ethtool 检查网卡传输速率

[root@node ~]# ethtool bond0
Settings for bond0:
Speed: 2000Mb/s   # 每秒传输速度
Duplex: Full

5.1.5 bond网卡删除

删除 bond 可以使用 nmcli 命令

[root@node ~]# nmcli connection delete
bond0

5.2 配置active-backup

5.2.1 eth0 网卡配置

[root@node ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
DEVICE=eth0
NAME=eth0
ONBOOT=yes
MASTER=bond1
SLAVE=yes

5.2.2 eth1网卡配置

[root@node ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=none
DEVICE=eth1
NAME=eth1
ONBOOT=yes
MASTER=bond1
SLAVE=yes

5.2.3 bond 网卡配置

[root@node ~]# cat /etc/sysconfig/network-scripts/ifcfg-bond1
TYPE=Bond
BOOTPROTO=none
ONBOOT=yes
DEVICE=bond1
NAME=bond1
IPADDR=10.0.0.200
PREFIX=24
GATEWAY=10.0.0.2
DNS1=223.5.5.5
BONDING_MASTER=yes
BONDING_OPTS="miimon=200 mode=1 fail_over_mac=1"
# bond1获取mac地址有两种方式
  #1、从第一个活跃网卡中获取mac地址,然后其余的
SLAVE网卡的mac地址都使用该mac地址;
  #2、使用fail_over_mac参数,是bond0使用当前
活跃网卡的mac地址,mac地址随着活跃网卡的转换而变。
# fail_over_mac参数在VMWare上是必须配置,物理机
可不用配置;

5.2.4 bond状态检查

[root@node ~]# cat /proc/net/bonding/bond1
Ethernet Channel Bonding Driver: v3.7.1
(April 27, 2011)
Bonding Mode: fault-tolerance (active-
backup) (fail_over_mac active)
Primary Slave: None
Currently Active Slave: eth0
MII Status: up
MII Polling Interval (ms): 200
Up Delay (ms): 0
Down Delay (ms): 0
Slave Interface: eth0
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:50:56:38:85:72
Slave queue ID: 0
Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:50:56:25:33:ee
Slave queue ID: 0

5.2.5 bond故障模式

关闭活跃网卡 eth0

[root@node ~]# ifdown eth0
成功断开设备 'eth0'

再次检查状态,会发现备用网卡 eth1 切换为活跃网卡

[root@node ~]# cat /proc/net/bonding/bond1
Ethernet Channel Bonding Driver: v3.7.1
(April 27, 2011)
Bonding Mode: fault-tolerance (active-
backup) (fail_over_mac active)
Primary Slave: None
Currently Active Slave: eth1
MII Status: up
MII Polling Interval (ms): 200
Up Delay (ms): 0
Down Delay (ms): 0
Slave Interface: eth1
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 00:50:56:25:33:ee
Slave queue ID: 0

尝试 ping 该主机,一切正常

64 bytes from 10.0.0.220: icmp_seq=173
ttl=64 time=0.512 ms
64 bytes from 10.0.0.220: icmp_seq=174
ttl=64 time=0.512 ms
64 bytes from 10.0.0.220: icmp_seq=175
ttl=64 time=2.11 ms

6. 网关/路由

6.1 什么是路由

  • 路由是指路由器从一个LAN接口上收到数据包,根据
    数据包的"目的地址"进行定向并转发到另一个WAN接
    口的过程。(跨网络访问的路径选择)
  • 路由工作包含两个基本的动作:
    • 1、确定最佳路径 user ---> LNA-- >route -->WAN -->选最近路线--》 传输
    • 2、通过网络传输信息
  • 在路由的过程中,后者也称为(数据)交换。交换相
    对来说比较简单,而选择路径很复杂。

6.2 为什么需要路由

如果没有路由,就没有办法实现,不同地域的主机互联互通了;

6.3 如何配置路由

  • linux系统配置路由使用 route 命令;可以使用
    route 命令来显示和管理路由表;
  • route 命令语法示例:
  • route [add|del] [-host|-net|default]
    [address[/mask]] [netmask] [gw] [dev]
    • [add|del] :增加或删除路由条目;
    • -host :添加或删除主机路由;
    • -net :添加或删除网络路由;
    • default :添加或删除默认路由;
    • address :添加要去往的网段地址 由
      ip+netmask 组成;
    • gw :指定下一跳地址,要求下一跳地址必须是能
      到达的,且一般是和本网段直连的接口。
    • dev :将添加路由与对应的接口关联,一般内核额
      会自动判断路由应该关联哪个接口;
  • route 添加路由命令示例:
[root@node ~]# route add -host 1.1.1.1/32
dev eth0
[root@node ~]# route add -net 1.1.1.1/32
dev eth1
[root@node ~]# route add -net 1.1.1.1/32
gw 1.1.1.2
[root@node ~]# route add default gw
1.1.1.2

6.4 路由的分类

6.4.1 主机路由

  • 主机路由作用:指明到某台主机具体应该怎么走;
    Destination 精确到某一台主机
  • Linux上如何配置主机路由:
# 去往1.1.1.1主机,从eth0接口出
[root@node ~]# route add -host 1.1.1.1/32
dev eth0
# 去往1.1.1.1主机,都交给10.0.0.2转发
[root@node ~]# route add -host 1.1.1.1/32
gw 10.0.0.2

6.4.2 网络路由

  • 网络路由作用:指明到某类网络怎么走;
    Destination 精确到某一个网段的主机
  • Linux上如何配置网络路由:
# 去往2.2.2.0/24网段,从eth0接口出
[root@node ~]# route add -net 2.2.2.0/24
dev eth0
# 去往2.2.2.0/24网段,都交给10.0.0.2转发
[root@node ~]# route add -net 2.2.2.0/24
gw 10.0.0.2

6.4.3 默认路由

  • 默认路由:如果匹配不到主机路由、网络路由的,全
    部都走默认路由(网关);
  • Linux上如何配置网络路由:
[root@node ~]# route add -net 0.0.0.0 gw
10.0.0.2
[root@node ~]# route add default gw
10.0.0.2

6.4.4 永久路由

  • 使用 route 命令添加的路由,属于临时添加;那如
    何添加永久路由条目;
  • 在 /etc/sysconfig/network-scripts 目录下创建
    route-ethx 的网卡名称,添加路由条目
[root@dns-master ~]# cat
/etc/sysconfig/network-scripts/route-eth0
1.1.1.0/24 dev eth0
1.1.1.0/24 via 1.1.1.2
[root@dns-master ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
1.1.1.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0
1.1.1.0     1.1.1.2    
255.255.255.0  UG   100   0     0
eth0

6.5 路由项目案例

  • 一台Linux主机能够被当成路由器用需要三大前提:
    • 1.至少有两块网卡分别连接两个不同的网段;
    • 2.开启路由转发功能 /proc/sys/net/ipv4/ip_forward ;
    • 3.在 linux 主机添加网关指向该服务器(路由);

6.5.1 环境准备

  • 实验环境

  • 虚拟机网段配置

6.5.2 虚拟机1网卡配置

1.eth0网卡

[root@vm1 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=10.0.0.100
PREFIX=24

2.eth1网卡

[root@vm1 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPADDR=1.1.1.1
PREFIX=24

3.路由信息

[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  Flags Metric Ref  Use Iface
1.1.1.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1
10.0.0.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0

6.5.3 虚拟机2网卡配置

1.eth0网卡配置

[root@vm2 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=1.1.1.2
PREFIX=24

2.eth1网卡配置

[root@vm2 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPADDR=2.2.2.2
PREFIX=24

3.路由信息

[root@vm2 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
1.1.1.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0
2.2.2.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1

6.5.4 虚拟机3网卡配置

1.eth0网卡配置

[root@vm3 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=2.2.2.3
PREFIX=24

2.eth1网卡配置

[root@vm3 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPADDR=3.3.3.3
PREFIX=24

3.路由信息

[root@vm3 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
2.2.2.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0
3.3.3.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1

6.5.5 虚拟机4网卡配置

1.eth0网卡配置

[root@vm4 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=3.3.3.4
PREFIX=24

2.eth1网卡配置

[root@vm4 ~]# cat /etc/sysconfig/network-
scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPADDR=4.4.4.4
PREFIX=24

3.路由信息

[root@vm4 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
3.3.3.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0
4.4.4.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1

6.5.6 场景示例1

  • 问:1.1.1.1地址能否与1.1.1.2 互通;

  • 可以通,因为本机1.1.1.1与目标主机1.1.1.2 两台机器

    处于一个LAN中,并且两台机器上的路由表里具有
    Destination指向对方的网段路由条目

    [root@vm1 ~]# route -n
    Kernel IP routing table
    Destination   Gateway     Genmask  
      Flags Metric Ref  Use Iface
    10.0.0.0     0.0.0.0    
    255.255.255.0  U   100   0     0
    eth0
    1.1.1.0     0.0.0.0    
    255.255.255.0  U   101   0     0
    eth1
    [root@vm2 ~]# route -n
    Kernel IP routing table
    Destination   Gateway     Genmask  
      Flags Metric Ref  Use Iface
    1.1.1.0     0.0.0.0    
    255.255.255.0  U   100   0     0
    eth0
    2.2.2.0     0.0.0.0    
    255.255.255.0  U   101   0     0
    eth1
    
    • 问:1.1.1.1地址能否与2.2.2.2地址互通
    • 答:不能;因为数据包只能送到1.1.1.2,而无法送达
      2.2.2.2
    • 所以需要添加一条去往2.2.2.0/24网段的路由,从
      eth1接口发出即可;
    [root@vm1 ~]# route add -net 2.2.2.0/24 dev
    eth1
    [root@vm1 ~]# route -n
    Kernel IP routing table
    Destination   Gateway     Genmask  
      Flags Metric Ref  Use Iface
    1.1.1.0     0.0.0.0    
    255.255.255.0  U   101   0     0
    eth1
    2.2.2.0     0.0.0.0    
    255.255.255.0  U   0    0     0
    eth1
    10.0.0.0     0.0.0.0    
    255.255.255.0  U   100   0     0
    eth0
    [root@vm1 ~]# ping 2.2.2.2
    PING 2.2.2.2 (2.2.2.2) 56(84) bytes of
    data.
    64 bytes from 2.2.2.2: icmp_seq=1 ttl=64
    time=0.602 ms
    64 bytes from 2.2.2.2: icmp_seq=2 ttl=64
    time=1.60 ms
    

6.5.7 场景示例2

  • 问:1.1.1.1地址能否与2.2.2.3地址互通;
  • 答:不能;因为数据包只能送到vmnet2交换机,送
    不到vmnet3交换机
  • 解决方案:将去往2.2.2.0/24网段的数据包交给
    1.1.1.2这台主机帮我们转发给2.2.2.3这台主机;
# vm1添加路由
[root@vm1 ~]# route add -net 2.2.2.0/24 gw
1.1.1.2
[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
1.1.1.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1
2.2.2.0     1.1.1.2    
255.255.255.0  UG   0    0     0
eth1
# vm2开启内核转发(由于vm2上有去往2.2.2.0/24网段
路由,所以添加)
[root@vm2 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward
[root@vm2 ~]# sysctl -p
# vm1测试是否能ping通
[root@vm1 ~]# ping 2.2.2.3
PING 2.2.2.3 (2.2.2.3) 56(84) bytes of
data.
64 bytes from 2.2.2.3: icmp_seq=1 ttl=63
time=0.690 ms

6.5.8 场景示例3

  • 问:1.1.1.1地址能否与3.3.3.3地址互通;
  • 答:不能;因为数据包只能送到vmnet2交换机,送
    不到vmnet3交换机
  • 解决方案:
    • 1.在vm1主机上将去往3.3.3.0/24网段的数据包交
      给1.1.1.2,由这台主机帮我们转发给3.3.3.3;
    • 2.在vm2上需要添加到3.3.3.0/24网段的路由,然
      后开启转发功能,否则数据包无法转发,会被丢弃;
    • 3.数据包到达vm3主机,但是无法送回来,所以还
      需要在vm3主机上添加去往1.1.1.0/24网段的数据
      包走2.2.2.2这台主机转发
# vm1添加路由
[root@vm1 ~]# route add -net 3.3.3.0/24 gw
1.1.1.2
[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
3.3.3.0     1.1.1.2    
255.255.255.0  UG   0    0     0
eth1
# vm2开启转发,添加路由
[root@vm2 ~]# echo "1" >
/proc/sys/net/ipv4/ip_forward
[root@vm2 ~]# sysctl -p
[root@vm2 ~]# route add -net 3.3.3.0/24
eth1
[root@vm2 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
3.3.3.0     0.0.0.0    
255.255.255.0  U   0    0     0
eth1
# vm3添加回包路由
[root@vm3 ~]# route add -net 1.1.1.0/24 gw
2.2.2.2
[root@vm3 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
1.1.1.0     2.2.2.2    
255.255.255.0  UG   0    0     0
eth0
#vm1主机测试
[root@vm1 ~]# ping 3.3.3.3
PING 3.3.3.3 (3.3.3.3) 56(84) bytes of data.
64 bytes from 3.3.3.3: icmp_seq=1 ttl=63 time=0.788 ms

6.5.9 场景示例4

  • 问:1.1.1.1地址能否与3.3.3.4地址互通;
  • 答:不能;因为数据包只能从vmnet2交换机送往
    vmnet3交换机,无法达到vmnet4交换机;
  • 解决方案:
    • 1.在vm1主机上将去往3.3.3.0/24网段的数据包交
      给1.1.1.2,由这台主机帮我们转发给3.3.3.4;
    • 2.在vm2上开启转发功能,然后添加到3.3.3.0/24
      网段的路由,由2.2.2.3帮我们转发给3.3.3.4;
    • 3.在vm3上开启转发功能;
    • 4.数据包到达vm4主机,但是无法送回来,所以还
      需要在vm4主机上添加去往1.1.1.0/24网段的数据
      包走3.3.3.3这台主机转发;
#vm1添加路由
[root@vm1 ~]# route add -net 3.3.3.0/24
gw 1.1.1.2
[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask 
   Flags Metric Ref  Use Iface
   3.3.3.0     1.1.1.2    
255.255.255.0  UG   0    0     0
eth1
 #vm2开启转发,添加路由规则
[root@vm2 ~]# echo "1" >
/proc/sys/net/ipv4/ip_forward
[root@vm2 ~]# sysctl -p
[root@vm2 ~]# route add -net 3.3.3.0/24
gw 2.2.2.3
[root@vm2 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask 
   Flags Metric Ref  Use Iface
 3.3.3.0     2.2.2.3    
255.255.255.0  UG   0    0     0
eth1
 #vm3开启转发
[root@vm3 ~]# echo "1" >
/proc/sys/net/ipv4/ip_forward
[root@vm3 ~]# sysctl -p
 #vm4添加回包路由
[root@centos7 ~]# route add -net
1.1.1.0/24 gw 3.3.3.3
[root@centos7 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask 
   Flags Metric Ref  Use Iface
   1.1.1.0     3.3.3.3    
255.255.255.0  UG   0    0     0
eth0
 #vm1测试
[root@vm1 ~]# ping 3.3.3.4
PING 3.3.3.4 (3.3.3.4) 56(84) bytes of
data.
 64 bytes from 3.3.3.4: icmp_seq=80 ttl=62
time=0.506 ms
 64 bytes from 3.3.3.4: icmp_seq=81 ttl=62
time=0.594 ms

6.6 路由条目优化

  • 以虚拟机1为例,除了第一个路由条目外,其他的路
    由条目其实都需要由1.1.1.2来转发;
  • 所以我们可以统一用一条路由规则;(配置默认路由)
    1.删除vm1上无用的路由;
[root@vm1 ~]# route del -net 2.2.2.0/24
[root@vm1 ~]# route del -net 2.2.2.0/24
# 需要删除两次;因为添加了两次;
[root@vm1 ~]# route del -net 3.3.3.0/24
[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
1.1.1.0     0.0.0.0    
255.255.255.0  U   101   0     0
eth1
10.0.0.0     0.0.0.0    
255.255.255.0  U   100   0     0
eth0

2.配置默认路由

[root@vm1 ~]# route add -net 0.0.0.0/0 gw
1.1.1.2
[root@vm1 ~]# #route add default gw 1.1.1.2
[root@vm1 ~]# route -n
Kernel IP routing table
Destination   Gateway     Genmask  
  Flags Metric Ref  Use Iface
0.0.0.0     1.1.1.2     0.0.0.0  
  UG   0    0     0 eth1

3.测试效果

[root@vm1 ~]# ping 1.1.1.2
[root@vm1 ~]# ping 2.2.2.2
[root@vm1 ~]# ping 2.2.2.3
[root@vm1 ~]# ping 3.3.3.3
[root@vm1 ~]# ping 3.3.3.4
[root@vm1 ~]# ping 4.4.4.4

4.其他虚拟机按如上方式进行优化即可;

7. Ubuntu网络配置

7.1 配置静态IP地址

  • 单网卡配置地址
root@example:~# cat /etc/netplan/00-installer-config.yaml
network:
ethernets:
 ens33:
  dhcp4: no
  dhcp6: no
  addresses: [10.0.0.130/24]
  gateway4: 10.0.0.2
  nameservers:
   addresses: [223.5.5.5]
  routes:  # 静态路由,去往172.100.0.0/24
下一跳是10.0.0.2
    - to: 172.100.0.0/24
    via: 10.0.0.2
    version: 2
root@example:~# sudo netplan apply
  • 多网卡配置地址
root@example:~# cat /etc/netplan/00-installer-config.yaml
network:
ethernets:
 ens33:
  dhcp4: no
  dhcp6: no
  addresses: [10.0.0.130/24]
  gateway4: 10.0.0.2
  nameservers:
   addresses: [223.5.5.5]
  routes:
    - to: 172.100.0.0/24
    via: 10.0.0.2
 ens38:
  dhcp4: no
  dhcp6: no
  addresses: [10.0.0.140/24]
  gateway4: 10.0.0.2
  nameservers:
   addresses: [223.5.5.5]
version: 2

7.2 配置round-robin

root@example:~# cat /etc/netplan/00-
installer-config.yaml
# This is the network config written by
'subiquity'
network:
version: 2
ethernets:
 ens33:
  dhcp4: no
  dhcp6: no
 ens38:
  dhcp4: no
  dhcp6: no
bonds:
 bond0:
  interfaces:
    - ens33
    - ens38
  addresses: [10.0.0.133/24]
  gateway4: 10.0.0.2
  nameservers:
   addresses: [223.5.5.5,223.6.6.6]
  parameters:
   mode: balance-rr
   mii-monitor-interval: 100
   
#查看状态
root@example:~# cat /proc/net/bonding/bond0
# 查看速率
root@example:~# ethtool bond0

7.3 配置active-backup

root@example:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by
'subiquity'
network:
version: 2
ethernets:
 ens33:
  dhcp4: no
  dhcp6: no
 ens38:
  dhcp4: no
  dhcp6: no
bonds:
 bond1:
  interfaces:
    - ens33
    - ens38
  addresses: [10.0.0.133/24]
  gateway4: 10.0.0.2
  nameservers:
   addresses: [223.5.5.5,223.6.6.6]
   parameters:
   mode: active-backup
   mii-monitor-interval: 100
# 应用配置
root@example:~# netplan apply
# 尝试关闭正在使用的网卡
root@example:~# ifconfig ens33 down
# 再次查看bond状态
root@example:~# cat /proc/net/bonding/bond1
Bonding Mode: fault-tolerance (active-
backup)
Primary Slave: None
Currently Active Slave: ens38    # ens38
网卡顶替
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
Peer Notification Delay (ms): 0
Slave Interface: ens38
MII Status: up
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 1
Permanent HW addr: 00:0c:29:de:3b:6f
Slave queue ID: 0
Slave Interface: ens33
MII Status: down     # 接口已经被down
Speed: 1000 Mbps
Duplex: full
Link Failure Count: 2
Permanent HW addr: 00:0c:29:de:3b:65
Slave queue ID: 0

8. 内核参数调优

  • 内核参数的调整是为了更好的利用系统资源,以便程序更好的运行;

8.1 ip_local_port_range (必调)

主动连接方(客户端)会占用本地随机端口,
TIME_WAIT 状态会占用本地端口,如果占用过多导致本
地端口不足,TCP连接不能成功建立,可以通过调整参
数来增加本地端口的范围;

1.查看客户端默认可用端口范围

[root@client ~]# sysctl -a |grep
"net.ipv4.ip_local_port_range"
net.ipv4.ip_local_port_range = 32768  60999

2.调整端口数量,测试端口不够用情况;

[root@client ~]# sysctl -w
net.ipv4.ip_local_port_range="10000 10002"

3.准备两台服务器,一台 nginx 服务器,客户端使用
curl 来访问服务器并主动关闭连接,在客户端产生
TIME_WAIT 状态的;服务器: 10.0.0.100 nginx 、客户端: 10.0.0.99 client

# 客户端脚本
[root@client ~]# cat test.sh
#!/usr/bin/bash
ip=10.0.0.100
date
for i in `seq 1 3`
do
 echo "第 $i 次 curl "
 curl -s http://$ip/ -o /dev/null
 echo "RETURN: " $?
ss -ant |grep TIME
done
# 只有当 socket 距离上次收到数据包已经超过1秒时,
端口才会被重用
sleep 2
echo "第 4 次 curl "
date
curl -s http://$ip/ -o /dev/null
echo "RETURN: " $?
ss -ant|grep TIME

4.执行脚本,从结果可见第4次 curl 时的状态为7,失
败,无法正常 curl ,说明端口已经被占用完。

[root@client ~]# sh test.sh
2021年 07月 28日 星期三 14:21:52 CST
第 1 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10000 
      10.0.0.100:80
第 2 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10002 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10000 
      10.0.0.100:80
第 3 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10002 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10000 
      10.0.0.100:80
第 4 次 curl
2021年 07月 28日 星期三 14:21:54 CST
RETURN:  7
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
      TIME-WAIT  0    0    10.0.0.99:10002 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10000 
      10.0.0.100:80

5.通过调整端口效果有限,因为 TIME_WAIT 需要等待
2MSL 时长,在这个时长内,最多也就能使用
ip_local_port_range 定义的端口范围,其实这些是
不够的,所以我们还可以使用 tcp_tw_reuse 参数来重
用 TIME_WAIT

8.2 tcp_tw_reuse

tw_reuse 表示端口重用,只有当
net.ipv4.tcp_timestamps = 1 ,
net.ipv4.tcp_tw_reuse = 1 两个选项同时开启时,
并且只有当 socket 距离上次收到数据包已经超过1秒
时, tcp_tw_reuse 端口重用才会有效
1.开启 tcp_tw_reuse 以及 tcp_timestamps 内核参数

[root@client ~]# sysctl -w
net.ipv4.tcp_timestamps=1
[root@client ~]# sysctl -w
net.ipv4.tcp_tw_reuse=1

2.再次执行脚本测试

[root@client ~]# sh test.sh
2021年 07月 28日 星期三 14:46:50 CST
第 1 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
第 2 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10003 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
第 3 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:10003 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10002 
      10.0.0.100:80
第 4 次 curl
2021年 07月 28日 星期三 14:46:52 CST
RETURN:  0  # 这里发现第4次已经return 为0了,代
表端口已经被重用;
TIME-WAIT  0    0    10.0.0.99:10003 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10001 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:10002 
      10.0.0.100:80

8.3 tcp_max_tw_buckets

net.ipv4.tcp_max_tw_buckets 参数表示操作系统允
许 TIME_WAIT 数量的最大值,如果超过这个数字,
TIME_WAIT 套接字将立刻被清除,该参数默认为
180000 ,可以对其进行调整,确保 time-wait 状态不消
耗太多的连接,以保证新连接可以正常请求;
1.参数调整

[root@client ~]# sysctl -w
net.ipv4.tcp_max_tw_buckets=2

2.测试验证

[root@client ~]# sh test.sh
2021年 07月 28日 星期三 15:20:40 CST
第 1 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:12792 
      10.0.0.100:80
第 2 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:12794 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:12792 
      10.0.0.100:80
第 3 次 curl
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:12794 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:12792 
      10.0.0.100:80
第 4 次 curl
2021年 07月 28日 星期三 15:20:42 CST
RETURN:  0
TIME-WAIT  0    0    10.0.0.99:12794 
      10.0.0.100:80
TIME-WAIT  0    0    10.0.0.99:12792 
      10.0.0.100:80
TCP: time wait bucket table overflow
TCP: time wait bucket table overflow
TCP: time wait bucket table overflow

8.4 tcp_max_syn_backlog

一般我们将 ESTABLISHED 状态的连接称为全连接,而将
SYN_RCVD 状态的连接称为半连接, backlog 定义了处
于 SYN_RECV 的 TCP 最大连接数,当处于 SYN_RECV 状态
的 TCP 连接数超过 tcp_max_syn_backlog 后,会丢弃后
续的 SYN 报文(也就是半连接池最大可接受的请求)关
闭cookies,否则容易干扰,造成不生效的情况。

当服务器收到一个 SYN 后,它创建一个子连接加入到
SYN_RCVD 队列。在收到 ACK 后,它将这个子连接移动到
ESTABLISHED 队列。最后当用户调用 accept() 时,会
将连接从 ESTABLISHED 队列取出。
1.调整服务端参数

[root@oldxu ~]# sysctl -w
net.ipv4.tcp_max_syn_backlog=2

2.客户端执行如下操作

# 禁止客户端返回ack,模拟服务端SYN_RECV状态
[root@client ~]# iptables -t filter -I
OUTPUT -p tcp --sport 22 -j ACCEPT
[root@client ~]# iptables -t filter -A
OUTPUT -p tcp -m tcp --tcp-flag SYN,ACK ACK
-j DROP
# 使用telnet连接远程主机
[root@client ~]# telnet 10.0.0.100 22 &
[1] 11913
[root@client ~]# telnet 10.0.0.100 22 &
[2] 11916
[root@client ~]# telnet 10.0.0.100 22 &
[3] 11917
[root@client ~]# telnet 10.0.0.100 22 &
[4] 12012
[root@client ~]# Trying 10.0.0.100...

3.检查服务端连接状态

[root@web01 ~]# netstat -tn
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address     
Foreign Address     State
tcp     0    0 10.0.0.100:22     
10.0.0.99:17304    SYN_RECV
tcp     0    0 10.0.0.100:22     
10.0.0.99:17302    SYN_RECV
tcp     0    0 10.0.0.100:22     
10.0.0.99:17300    SYN_RECV
# 内核会提示丢弃了一些请求
[root@web01 ~]# dmesg
[31204.380052] TCP: drop open request from
10.0.0.99/17320
[31205.382226] TCP: drop open request from
10.0.0.99/17320
  • 注意: SYN_RECV 有3条记录,我们调整的限制2,怎
    么多出了一条;是因为系统的判断条件是 > 而不是>= ,

    所以当达到3条记录时才算超过限制,所以有3
    条 SYN_RECV 记录;

8.5 core_somaxconn

net.core.somaxconn 用于定义服务端全连接队列的大
小,默认为128,对于生产环境而言,肯定是不够用;

1.调整服务端全连接队列大小为3

[root@server ~]# sysctl -w
net.core.somaxconn=2

2.服务端脚本

[root@server ~]# cat server.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BACKLOG 200
int main(int argc, char **argv)
{
 int listenfd;
 int connfd;
 struct sockaddr_in servaddr;
 listenfd = socket(PF_INET, SOCK_STREAM,
0);
 bzero(&servaddr, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr =
htonl(INADDR_ANY);
 servaddr.sin_port = htons(50001);
 bind(listenfd, (struct sockaddr
*)&servaddr, sizeof(servaddr));
 listen(listenfd, BACKLOG);
  while(1)
 {
    sleep(1);
 }
 return 0;
}

3.编译并启动服务端脚本

[root@server ~]# gcc server.c -o server
[root@server ~]# ./server

4.编写客户端脚本

[root@client ~]# cat client.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char **argv)
{
 int sockfd;
 struct sockaddr_in servaddr;
 sockfd = socket(PF_INET, SOCK_STREAM,
0);
 bzero(&servaddr, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_port = htons(50001);
 servaddr.sin_addr.s_addr =
inet_addr("10.0.0.100");
  if (0 != connect(sockfd, (struct
sockaddr *)&servaddr, sizeof(servaddr)))
{
    printf("connect failed!\n");
 }
  else
 {
    printf("connect succeed!\n");
 }
  sleep(30);
 return 1;
}

5.编译并启动客户端脚本

[root@client ~]# gcc client.c -o client
[root@client ~]# ./client &
[1] 16368
[root@client ~]# connect succeed!
./client &
[2] 16370
[root@client ~]# connect succeed!
./client &
[3] 16371
[root@client ~]# connect succeed!
./client &
[4] 16372
[root@client ~]# connect succeed!
./client &
[5] 16375
[root@client ~]# connect succeed!

5.检查服务端状态(会发现已建立连接队列就3条,其余
都在半连接池中无法进入连接队列)

[root@server ~]# netstat -nt | grep 50001
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17405    SYN_RECV
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17407    SYN_RECV
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17399    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17403    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17401    ESTABLISHED

6.调整全连接队列大小,然后再次启动多次客户端进行查看

[root@server ~]# sysctl -w
net.core.somaxconn=10
[root@web01 ~]# ./server
# 查看服务端连接状态
[root@server ~]# netstat -nt | grep 50001
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17431    SYN_RECV
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17433    SYN_RECV
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17425    ESTABLISHED
 tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17417    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17419    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17415    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17421    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17409    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17429    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17411    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17413    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17427    ESTABLISHED
tcp     0    0 10.0.0.100:50001   
 10.0.0.99:17423    ESTABLISHED
# 全连接队列11条记录,之所以会这样,是因为系统采用>
而>=所以条目会+1
[root@server ~]# netstat -nt | grep 50001
|wc -l
13

8.6 tcp_syn_retries

net.ipv4.tcp_syn_retries 表示应用程序进行发送
SYN 包时,在对方不返回 SYN + ACK 的情况下,内核默
认重试发送 6 次 SYN 包,也就是说如果一直收不到对方返
回 SYN + ACK 那么应用程序最大的超时时间就是
(1+2+4+8+16+32+64=127 秒) 这对于很多客户端而言
是很难以接受的;

  • 第 1 次发送 SYN 报文后等待 1s(2^0) ,如果超
    时,则重试
  • 第 2 次发送后等待 2s(2^1) ,如果超时,则重试
  • 第 3 次发送后等待 4s(2^2) ,如果超时,则重试
  • 第 4 次发送后等待 8s(2^3) ,如果超时,则重试
  • 第 5 次发送后等待 16s(2^4) ,如果超时,则重试
  • 第 6 次发送后等待 32s(2^5) ,如果超时,则重试
  • 第 7 次发送后等待 64s(2^6) ,如果超时,则超时
    失败
    1.服务端配置 iptables 来丢弃指定端口的 SYN 报文
# 进来流量如果syn标志位为1则拒绝
[root@server ~]# iptables -A INPUT -p tcp -
-dport 22 --syn -j DROP
# 服务端使用tcpdump抓包
[root@server ~]# tcpdump -i eth0 -n src
10.0.0.99 and dst 10.0.0.100 and port 22

2.然后客户端使用 telnet 连接服务端指定端口

[root@client ~]# date '+ %F %T'; telnet
10.0.0.100 22; date '+ %F %T';
2021-07-29 23:32:57   # 开始时间
Trying 10.0.0.100...
telnet: connect to address 10.0.0.100:
Connection timed out
2021-07-29 23:35:05   # 结束时间

3.最后分析抓包结果,从 tcpdump 的输出也可以看到,一
共发了7次SYN包(都是同一个seq号码),第一次是正常请
求,后面6次是重试,正是该内核参数设置的值.

[root@server ~]# tcpdump -i eth0 -n src
10.0.0.7 and dst 10.0.0.100 and port 22
23:32:57.809282 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:32:58.812226 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:33:00.816151 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:33:04.820449 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:33:12.837846 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:33:28.884418 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,
23:34:00.942801 IP 10.0.0.99.ndmp >
10.0.0.100.ssh: Flags [S], seq 2633109385,

4.修改客户后端重试次数,在测试

[root@client ~]# sysctl -w
net.ipv4.tcp_syn_retries=2
# 再次测试
[root@client ~]# date '+ %F %T'; telnet
10.0.0.100 22; date '+ %F %T';
2021-07-29 23:39:15   # 起始时间
Trying 10.0.0.100...
2021-07-29 23:39:22   # 结束时间
  • 注意:作为代理服务器这个值就应该调整

8.7 内核参数示例

[root@oldxu ~]# vim /etc/sysct.conf
# tcp优化
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1     # 防止
SYN Flood攻击,开启后max_syn_backlog理论上没有
最大值
net.ipv4.tcp_max_syn_backlog = 8192 # SYN半
连接队列可存储的最大值
net.core.somaxconn = 32768      # SYN全
连接队列可存储的最大值
# 修改TCP TIME-WAIT超时时间
https://help.aliyun.com/document_detail/155
470.html
# net.ipv4.tcp_tw_timeout = 5
# 重试
net.ipv4.tcp_syn_retries=2      # 发送
SYN包重试次数,默认6
net.ipv4.tcp_synack_retries = 2   # 返回
syn+ack重试次数,默认5
# 其他
# net.ipv4.ip_forward = 1 # 支持转
发功能;
# net.ipv4.ip_nonlocal_bind = 1 # 如果我
的应用程序需要绑定端口,需要指明具体的IP地址
# net.ipv4.tcp_keepalive_time = 600 # 当
keepalive启动时,TCP发送keepalive消息的频度;默
认是2小时,将其设置为10分钟,可更快的清理无效链接
# 系统中允许存在文件句柄最大数目(系统级)
fs.file-max = 204800
#
vm.swappiness = 0
posted @ 2021-08-01 16:40  GaoBeier  阅读(171)  评论(0编辑  收藏  举报