通过 laravel horizon 和 telescope 加强队列的管理

原文链接:Laravel HorizonとLaravel Telescopeでできること オープンロジにおけるQueueの運用管理 ,扫盲向而且挺实用,转载过来记录几个要点。

PPT地址: https://cdn.kelu.org/blog/2020/06/20190318-Laravue8-OPENLOGI.pdf

大家好,我是Open Logic的Igarashi。关于Vue和前台的大家讨论了很多,接下来我谈谈服务器端。

上个月我在 OpenLogi 的 Laravel 分享会中谈到 “Laravel 队列操作与管理”,今天我就这个话题进一步展开。

CgJcYXTTVMGJpoYfyyoAva

首先做个自我介绍…// (介绍他们公司的,主要做物流的,就不转了。)

SKkNfG6v4j24cRM83coW8F

我们的技术栈去年有分享过,在Qiita上可以找到。简单来说,服务器端是Laravel,前端是React。我将Vue用于新产品。

job 基础

20多年前,Bertrand Meyer在他的《Object-Oriented Software Construction》一书中提出了CQS(Command Query Seperation,命令查询分离)的概念,后来,Greg Young在此基础上提出了CQRS(Command Query Resposibility Segregation,命令查询职责分离),将CQS的概念从方法层面提升到了模型层面,即“命令”和“查询”分别使用不同的对象模型来表示。

采用CQRS的驱动力除了从CQS那里继承来的好处之外,还旨在解决软件中日益复杂的查询问题,比如有时我们希望从不同的维度查询数据,或者需要将各种数据进行组合后返回给调用方。此时,将查询逻辑与业务逻辑糅合在一起会使软件迅速腐化,诸如逻辑混乱、可读性变差以及可扩展性降低等等一些列问题。

对于Web应用程序,处理中要做的主要事情是读取或写入信息。

6j1pZKdkokWfBPAaEdKBgj

上图是一个简单的配置,读取意味着通过Web服务器从数据库读取数据并将结果返回给客户端。

如果有要写入的内容,则可以通过POST等方法通过Web服务器将其写入数据库,如果成功,则将结果返回给客户端。

原则上,我们不应在同一台Web服务器上进行读写。做到这一点的方法是利用工作。首先,以Command 的形式将其扔到 Web 服务器。Web 服务器将其加入队列。然后,执行可变处理的作业服务器使队列出队并执行写处理。

img

将结果返回给客户端的方式有很多种选择,可以使用Pusher 和 Redis。我们使用 Pusher 来实现。即使 Pusher 服务器不同,也可以正确地异步发送反馈。

看起来非常困难,但是由于Laravel从一开始就考虑到DDD和CQRS的设计,因此实现起来非常容易。

img

在Controller上有一个方法,例如 updateItem,CQRS 的做法就是创建一个名为updateItem的作业并将其分派。

job的状态管理

img

这是 Laravel Horizon和Laravel Telescope。 它们很相似。

img

Telescope 是一个开发调试工具,用于了解 Laravel 中的状态。虽然我们有了 Laravel Debugbar 这样的工具用于开发,但是 Laravel 中会发生各种事件,例如请求,查询和作业状态以及通知事件的结果,Telescope 可以将这些状态集中起来看。

从这里可以看到,有各种参数,例如Exception,log,query,model,event等。

Horizon 是用于生产环境的监视工具,而 Telescope 是用于给开发人员使用的工具。

两者都支持队列,不过 Horizon 仅支持 Redis。Telescope 不仅限于Redis,它还支持 DB 队列、SQS队列,并且可以看到所有同步作业的状态。

Horizon 主要是用于调试和监视。

img

如上图,在OpenLogi中,我们单独记录了job的状态,通过将所有更新处理整合到job中来,我们还可以跟踪谁进行了什么操作以及何时进行。

img

Telescope 也做了类似的事情,它会记录用户使用哪些参数运行的作业。这种记录会增加数据库的负担,不过它仅用于调试,线上不运行,但这是我想要的。

img

您可以看到针对查询,职位和电子邮件发出了什么样的查询,因此我认为这对开发很有用。

重新执行失败的作业也是操作中的常见情况。

img

img

关于这一点,Laravel Horizon 中有一个类似的页面,但是我们在Horizon 之前就设计了这类工具。

img

我需要像 Horizon 这样的监视工具,但同时我也希望能够像 Telescope 这样正确地记录日志,有点鱼和熊掌不可得兼的感觉。我正在寻找一种可以管理的工具,但是现在我们打算自己实现它。

总结

img


阿里的一些论文

google,Facebook等国外大佬经常在顶级会议上(SOSP/PLDI/NSDI等等)发论文,阿里也发表了好些的论文。以前整理了相关东西,不成章法,凑了这篇文章,以后研究的话再捡起来。

SIGCOMM 2020

《VTrace: Automatic Diagnostic System for Persistent Packet Loss in Cloud-Scale Overlay Network》

超大规模下的云网络异常定位、

传统网络工具 VS 大数据染色报文分析

云网络碰到类似问题只能用网工三板斧来处理: 抓包,ping, trace。

阿里云网络团队首次采用大数据结合染色报文的方式,通过大数据技术给这个交警配备了一个超强的大脑,让他能实时处理千万级网络数据,同时,结合染色报文技术让所有网络里面的数据包信息实时传递给我们的云网络交警。最后的结果就是这个云网络交警能实时感知到整个云网络每台设备的丢包和拥塞情况。阿里云网络给这个交警取了一个名字,叫vTrace。当用户在上网过程中碰到网络问题时,vTrace能很快找到对应链路上出现问题的节点在哪里,解决了云网络排查问题难的痛点,加快用户网络问题恢复过程。

SIGCOMM2019

来自阿里云智能的两篇论文

  • 《HPCC: High Precision Congestion Control》 高速网络拥塞控制协议HPCC
    • 阿里巴巴此前已通过对RDMA网络的改造,从网卡底层开始设计,结合自研交换机能力,建成全球最大规模的“RDMA高速网络”。
    • 在这次的论文中,阿里巴巴就提出了一种全新的网络协议——新一代高速网络拥塞控制协议HPCC(High Precision Congestion Control),不仅保证传输性能快,还能保证传输稳定,真正适用于当下的网络需求。
  • 《Safelyand Automatically Updating In-Network ACL Configurations with Intent Language》 使用意图语言安全且自动地更新网络内ACL配置

FAST2020

存储行业顶级国际会议FAST2020(18th USENIX Conference on File and Storage Technologies)在美国圣克拉拉举行,大会公开论文名单显示,阿里巴巴3篇第一作者论文入选,是全球入选数最多的企业。

在《POLARDB结合可计算存储: 高效支持云原生关系数据库的复杂查询操作》一文中,阿里团队针对PolarDB,把SQL和存储引擎的计算逻辑下推到底层共享存储,并通过定制SSD内部的FPGA进一步下推计算至存储节点的SSD内部,完成更高效率计算的同时,大幅降低主机和网络带宽占用,为PolarDB在复杂查询场景下带来4~5倍的吞吐提升。

另两篇文章,聚焦键值存储(KVS)。

在《FPGA加速Compactions操作,基于 LSM-tree的键值存储》一文中,研究团队首次引入异构硬件FPGA,实现KVS核心操作Compaction加速,较仅CPU处理能力提升2~5倍,整体吞吐性能提升23%,能效提升31.7%。

在《HotRing:热点感知的无锁内存键值系统》一文中,阿里团队提出新型热点感知内存KVS — HotRing,采用轻量级的热点识别策略,在未增加元数据存储开销的同时,还对幂率分布的热点场景进行大量优化,使得HotRing的引擎吞吐性能可达600M ops/s,单次访问平均只需100ns,比目前最快KVS性能提升2.58倍。

ASPLOS’19

摘要: 阿里云首次在ASPLOS上发表论文,第24届ACM编程语言和操作系统(ASPLOS’19),于2019年4月13日至17日,在普罗维登斯召开,阿里云高级技术专家郑晓代表团队在会上发表了技术报告。

第24届ACM编程语言和操作系统(ASPLOS’19),于2019年4月13日至17日,在普罗维登斯召开,阿里云高级技术专家郑晓代表团队在会上发表了技术报告。

论文主题为《Fast and Scalable VMM Live Upgrade in Large Cloud Infrastructure》,作者是张献涛,郑晓,沈益斌等。这篇论文被计算机系统结构的顶级会议ASPLOS’19接受,是业界对于VMM热升级这项突破性技术的认可。

论文ACM下载地址:https://dl.acm.org/citation.cfm?id=3304034 PDF下载地址:https://yq.aliyun.com/download/3532

该论文系统的阐述了当前云计算领域面临的基础架构带业务热升级问题。提出了一种新型的,比热迁移更行之有效的方法,特别适合超大规模集群范围的使用,解决了困扰云计算行业多年的问题。该方案在阿里云大规模采用,服务百万级别的客户虚拟机数量。论文解决了在客户业务不中断的情况下以毫秒级的速度更换底层虚拟化组件。

阿里云热升级技术特点决定了可以同时热升级任意数量任意规格的虚拟机,并且升级时间恒定。更难得的是,在业界尚未有异构计算设备热迁移方案的情况下,阿里云热升级技术同时支持异构计算等以设备直通方式工作的虚拟机。帮助ECS在过去五年进行了快速的升级迭代,保障了产品和业务的快速奔跑。

ASPLOS(编程语言和操作系统的体系结构支持会议)会议全称为ACM International Conference on Architectural Support for Programming Languages and Operating Systems,是综合体系结构、编程语言和操作系统三个方向的计算机系统领域顶级会议,为CCF A类会议。从1982年创办至今的三十多年里,ASPLOS推动了多项计算机系统技术的发展,包括(但不限于)RISC、RAID、大规模多处理器、Cluster架构和网络存储等。


查看并记录服务器硬件信息

查了相关的文章做个记录,从CPU、内存、网卡、硬盘、主板、BIOS、操作系统几个方面。

一、硬件

1.1 服务器型号、序列号

dmidecode|grep "System Information" -A9|egrep  "Manufacturer|Product|Serial" 

image-20210604175015800

1.2 主板型号

dmidecode |grep -A16 "System Information$" 

image-20210604175154526

1.3 查看BIOS信息

 dmidecode -t bios

image-20210604175234570

1.4 查看内存槽及内存条

dmidecode -t memory | more

image-20210604175550817

1.5 查看主板所有硬件槽信息

lspci # 可列出每个pci总线上的设备, 通过grep过滤后可得到网卡设备列表

image-20210604180408326

1.6 查看网卡信息

lspci | grep -i net

image-20210604180408326

二、CPU

(1)查看 cpu 核数和型号,主频等

cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

image-20210604180928552

(2)查看系统有几颗CPU

grep 'physical id' /proc/cpuinfo | sort | uniq | wc -l
1

(3)CPU的逻辑个数(开启超线程时1个core相当于2个逻辑cpu)

cat /proc/cpuinfo |grep 'processor'|wc -l
8

(4)查看每颗 CPU 中的内核个数

cat /proc/cpuinfo |grep "cores"|uniq 
cpu cores : 4

(5)查看CPU的主频

cat /proc/cpuinfo |grep MHz|uniq 

cpu MHz         : 4102.000
cpu MHz         : 4105.465
cpu MHz         : 4100.059
cpu MHz         : 4147.903
cpu MHz         : 4100.493
cpu MHz         : 4100.521
cpu MHz         : 4160.260
cpu MHz         : 4138.348

(6)查看CPU的详细信息

cat /proc/cpuinfo
processor : 0 //逻辑处理器的ID
vendor_id : GenuineIntel
cpu family : 6
model : 158
model name : Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz   //CPU型号
stepping : 9
microcode : 0x84
cpu MHz : 4070.787
cache size : 8192 KB
physical id : 0
siblings : 8 //相同物理封装处理器中逻辑处理器数
core id : 0
cpu cores : 4 //相同物理封装处理器中的内核数

image-20210605161138951

(7)查看CPU的相关信息

lscpu

(8)查看 cpu 是32位还是64位

[root@Master ~]# getconf LONG_BIT
64

三、内存

free -mh                 								# 概要查看内存情况
dmidecode -t memory      								# 查看内存硬件信息
dmidecode|grep -P 'Maximum\s+Capacity' 	# 最大支持多少内存

image-20210605161653092

dmidecode|grep -A5 "Memory Device"|grep Size | grep -v Range # Linux 查看内存已经使用插槽数

image-20210605161857039

dmidecode|grep -A16 "Memory Device"|grep 'Speed' # 内存频率

image-20210605162129768

cat /proc/meminfo |head -20 # 内存详细信息

image-20210605162344913

free -mh # 内存使用情况

image-20210605162459550

四、网卡

ifconfig
ethtool bond0
ethtool bond1

ifconfig -a
ip link show

五、硬盘

lsblk  # fdisk一般用来磁盘分区,也可以用来查看磁盘分区情况
fdisk -l # 硬盘和分区的详细信息

image-20210607163611855

image-20210607163644643

# lsblk命令用于列出所有可用块设备的信息,而且还能显示他们之间的依赖关系
lsblk

image-20210608230402740

image-20210608230420949

# 其他命令

mount | column -t
swapon -s Filename Type Size Used Priority
df -hT
du --max-depth=1 -ah 2> /dev/null | sort -hr | head
smartctl -a /dev/sda

操作系统

uname -a
cat /etc/redhat-release
dmidecode -s system-serial-number # 系统序列号

一个简单的脚本

#!/usr/bin/env bash

if  [ ! -e '/usr/bin/wget' ]; then
    echo "Error: wget command not found. You must be install wget command at first."
    exit 1
fi

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;36m'
PLAIN='\033[0m'

get_opsy() {
    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}

next() {
    printf "%-70s\n" "-" | sed 's/\s/-/g'
}

calc_disk() {
    local total_size=0
    local array=$@
    for size in ${array[@]}
    do
        [ "${size}" == "0" ] && size_t=0 || size_t=`echo ${size:0:${#size}-1}`
        [ "`echo ${size:(-1)}`" == "K" ] && size=0
        [ "`echo ${size:(-1)}`" == "M" ] && size=$( awk 'BEGIN{printf "%.1f", '$size_t' / 1024}' )
        [ "`echo ${size:(-1)}`" == "T" ] && size=$( awk 'BEGIN{printf "%.1f", '$size_t' * 1024}' )
        [ "`echo ${size:(-1)}`" == "G" ] && size=${size_t}
        total_size=$( awk 'BEGIN{printf "%.1f", '$total_size' + '$size'}' )
    done
    echo ${total_size}
}

cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo )
freq=$( awk -F'[ :]' '/cpu MHz/ {print $4;exit}' /proc/cpuinfo )
tram=$( free -m | awk '/Mem/ {print $2}' )
uram=$( free -m | awk '/Mem/ {print $3}' )
swap=$( free -m | awk '/Swap/ {print $2}' )
uswap=$( free -m | awk '/Swap/ {print $3}' )
up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60} {printf("%d days, %d hour %d min\n",a,b,c)}' /proc/uptime )
load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' )
opsy=$( get_opsy )
arch=$( uname -m )
lbit=$( getconf LONG_BIT )
kern=$( uname -r )
#ipv6=$( wget -qO- -t1 -T2 ipv6.icanhazip.com )
disk_size1=($( LANG=C df -hPl | grep -wvE '\-|none|tmpfs|devtmpfs|by-uuid|chroot|Filesystem|udev|docker' | awk '{print $2}' ))
disk_size2=($( LANG=C df -hPl | grep -wvE '\-|none|tmpfs|devtmpfs|by-uuid|chroot|Filesystem|udev|docker' | awk '{print $3}' ))
disk_total_size=$( calc_disk "${disk_size1[@]}" )
disk_used_size=$( calc_disk "${disk_size2[@]}" )

clear
next
echo -e "CPU                  : ${BLUE}$cname${PLAIN}"
echo -e "核心数               : ${BLUE}$cores${PLAIN}"
echo -e "CPU 主频             : ${BLUE}$freq MHz${PLAIN}"
echo -e "硬盘                 : ${BLUE}$disk_total_size GB ($disk_used_size GB Used)${PLAIN}"
echo -e "内存                 : ${BLUE}$tram MB ($uram MB Used)${PLAIN}"
echo -e "交换分区             : ${BLUE}$swap MB ($uswap MB Used)${PLAIN}"
echo -e "OS                   : ${BLUE}$opsy${PLAIN}"
echo -e "Arch                 : ${BLUE}$arch ($lbit Bit)${PLAIN}"
echo -e "内核                 : ${BLUE}$kern${PLAIN}"
echo -e "运行时间             : ${BLUE}$up${PLAIN}"
echo -e "平均负载             : ${BLUE}$load${PLAIN}"
next

附:dmidecode 是什么

dmidecode可以让你在Linux系统下获取有关硬件方面的信息。

dmidecode的作用是将DMI数据库中的信息解码,以可读的文本方式显示。由于DMI信息可以人为修改,因此里面的信息不一定是系统准确的信息。

dmidecode遵循SMBIOS/DMI标准,其输出的信息包括BIOS、系统、主板、处理器、内存、缓存等等。

DMI(Desktop Management Interface,DMI)就是帮助收集电脑系统信息的管理系统,DMI信息的收集必须在严格遵照SMBIOS规范的前提下进行。SMBIOS(System Management BIOS)是主板或系统制造者以标准格式显示产品管理信息所需遵循的统一规范。SMBIOS和DMI是由行业指导机构Desktop Management Task Force(DMTF)起草的开放性的技术标准,其中DMI设计适用于任何的平台和操作系统。

DMI充当了管理工具和系统层之间接口的角色。它建立了标准的可管理系统更加方便了电脑厂商和用户对系统的了解。DMI的主要组成部分是Management Information Format(MIF)数据库。这个数据库包括了所有有关电脑系统和配件的信息。通过DMI,用户可以获取序列号、电脑厂商、串口信息以及其它系统配件信息。

参考资料


Debian 9/10 安装 WireGuard 备忘

不升级内核,或者内核ok但没有头文件,都有可能会遇到这样的错误:

RTNETLINK answers: Operation not supported

升级内核先参考我先前这篇文章:《debian 升级内核》

安装

sudo apt-get install libmnl-dev linux-headers-$(uname -r) build-essential make git # 安装必要的包

# 如果无法安装headlers,那么应该是内核偏老,先升级到比较新的内核

echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee /etc/apt/sources.list.d/unstable.list
echo -e "Package: *\nPin: release a=unstable\nPin-Priority: 150\n" | tee /etc/apt/preferences.d/limit-unstable

apt-get update
apt-get upgrade
apt-get install wireguard-dkms wireguard-tools

配置

sudo mkdir -p /etc/wireguard
cd /etc/wireguard
sudo umask 077

# 快速生成密钥
sudo wg genkey | tee privatekey | wg pubkey > publickey

新建配置文件 wg0.conf

注意修改监听端口ListenPort,如果启用了防火墙,还需要开通相关端口

[Interface]
PrivateKey = #服务端的密钥
Address = 10.0.0.1/24, fd86:ea04:1115::1/64 #服务端的地址
ListenPort = 28472 #服务端的端口
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
SaveConfig = true

启动

快速启动:

sudo wg-quick up wg0

开机启动:

systemctl enable wg-quick@wg0

查看运行状况:

wg

配置客户端

其实 wireguard 中没有严格的客户端服务端的区别,配置客户端过程和服务端过程一样。只要把服务端的公钥和自己的公钥写入配置文件中,再填好对端的IP,会自动连接配对好。

以下是配置参考:

[Interface]
PrivateKey = #客户端的密钥
Address = 100.100.100.2/32 #客户端的内网地址
MTU = 1420
[Peer]
PublicKey = #服务端的公钥
Endpoint = 12.32.42.52:28472 #服务端的IP和端口
AllowedIPs = 100.100.100.0/24, 10.64.0.0/10, 10.128.0.0/10 #允许走wireguard的目的IP
PersistentKeepalive = 25

把这个配置连同客户端的公钥密钥一起放到客户端的/etc/wireguard文件夹中,就能启动了。

如果希望生成二维码,方便iOS和android刷二维码,还可以使用qrencode命令:

qrencode -t ansiutf8 < wg0.conf

Debian 10安装

  1. 增加源信息

    echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
    printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' > /etc/apt/preferences.d/limit-unstable
    
  2. 更新源然后安装相关软件,用来编译 wireguard内核模块

    apt update
    apt install wireguard-dkms wireguard-tools
    

仍然报错

[#] ip link add wg0 type wireguard
RTNETLINK answers: Operation not supported
Unable to access interface: Protocol not supported
[#] ip link delete dev wg0
Cannot find device "wg0"

还是升级内核吧:

apt-get dist-upgrade
update-grub
/sbin/reboot

不过很奇怪,我重启之后内核其实并没有升级,但是 wireguard 能跑起来了。可能是中途某些步骤需要重启系统。下次遇到再补充了。


什么叫网元?

时常在文章里看到“网元”这个词,一看到就害怕,因为完全不知道是什么东西。

一番谷歌就理解了,如果你知道它的英文可能瞬间就理解了——Network Element。

网元就是网络中的元素,网络中的设备。

在GSM网络系统中, 一个基站就是一个网元。

交换机 路由器等也是一个网元。


BGP中的 Keepalive time 和 hold time

http://www.jiancenj.com/2209.aspx

在BGP学习中,我们了解到,BGP有个keepalive time,默认是60秒,还有hold time,是keepalive time的3倍关系,也就是180秒。同时我们也了解到,hold time的值是协商值,那这个值是怎么协商的呢?我们来看一下:

图片1.jpg

拓扑如上:两台设备之间建立IBGP连接。

我们可以通过display bgp peeripv4 verbose 命令查看keepalive time和hold time,如下图:

图片2.jpg

我们可以看到,在没有修改的情况下,keepalive和hold时间都是默认值。

在路由器2上的BGP进程中,修改keepalive和hold值。用timer keepalive +时间 hold +时间修改。注意:修改时间值时,holdtime ≥ 3*keepalive time。

首先我们先修改hold time =3*keepalive time:

图片3.jpg

然后去路由器1上查看协商的hold值。注意:查看之前要重新启用bgp进程,使用reset bgp 100 ipv4命令。因为协商参数的传递由open报文负责,而在BGP邻居状态使能的情况下,只有keepalive和update报文交互。reset之后,再去查看。我们可以看到:

图片4.jpg

路由器1上协商的hold time,为60秒,keepalive time为20秒。

接下来我们再路由器2上继续修改,hold time > 3*keepalive time。

图片5.jpg

再次到路由器1上查看:

图片6.jpg

这时候我们发现,协商的hold time为100秒,keepalive time是33秒。这时候的keepalive time并不是我们设置的20秒。这是因为在open报文中只携带hold time值,不携带keepalive值,keepalive是根据与hold 值的三倍关系计算出来的。

那我们继续做一个修改:在路由器1 上设置keepalive time为30秒,hold time为90秒,路由器2上keepalive time 为20秒 hold time 为100秒保持不变。

这时候我们发现:

路由器1上:

图片7.jpg

路由器2上:

图片8.jpg

我们发现,路由器1和路由器2上hold 值是一致的,为90秒。但是keepalive 值,路由器1上是30秒,路由器2上是20秒。这是因为,当路由器接收到对方传来的hold值时,首先与自己的做比较,如果接收到的hold值小,则hold值修改为接收到的值,在比较keepalive值,若自己的keepalive值小于接收到的(hold值/3),则用自己的keepalive值,若自己的keepalive值大于接收到的(hold值/3),则使用接收到的(hold值/3);当路由器接收到的hold值比自己的hold值大时,则不做任何修改。

参考