MTR命令的使用和nGeniusPulse的设置
1.mtr命令
网络运维人员一般使用ping和traceroute(在Windows中是tracert)命令来判断网络的连通性。ping可以用来判断网络的丢包率; traceroute可以用来跟踪路由,其实在Linux中有一个更好的网络连通性判断工具,它结合了ping、traceroute 和nslookup来判断网络的相关特性,这个命令就是mtr。
a.基本使用说明
-r:以报告模式显示,不设则为动态显示结果
-c 20:每秒发送数据包数量20,缺省为10
-n:不对IP地址做域名解析
Loss%:每跳对应IP的丢包率
Snt:发送数据包数量,对应-c的设置
Last:最后一次的响应时延
Avg:平均响应时延
Best:最短响应时延
Wrst:最长响应时延
StDev:标准偏差(Standard Deviation)
b.更多参数设置说明
-s :用来指定ping数据包的大小,包含IP层,缺省为64个字节
-a :来设置发送数据包的IP地址 这个对一个主机由多个IP地址是有用的
-i :使用这个参数来设置ICMP返回之间的要求默认是1秒
-g:使用X11的窗口显示测试,如:Xming
-o:测试结果的列项显示及顺序
L | Loss ratio | 丢包率 |
D | Dropped packets | 丢包数量 |
R | Received packets | 收到包数 |
S | Sent Packets | 发出包数 |
N | Newest RTT(ms) | 最后一次的响应时延 |
B | Min/Best RTT(ms) | 最小响应时延 |
A | Average RTT(ms) | 平均响应时延 |
W | Max/Worst RTT(ms) | 最大响应时延 |
V | Standard Deviation | 标准偏差 |
G | Geometric Mean | 几何平均 //不懂 |
J | Current Jitter | 抖动 |
M | Jitter Mean/Avg. | 平均抖动 |
X | Worst Jitter | 最大抖动 |
I | Interarrival Jitter | [RFC3550] section 6.4.1 //不懂 |
例:mtr 58.217.200.15 -r -c 20 -n -o "SRDL ABW MX"
-u & -P:-u设置为UDP数据包,-P设置端口号
例:mtr 114.114.114.114 -u -P 53 -r -c 10 -n -o "SRDL ABW MX"
因为UDP是面向无连接的,所以这里的响应,应该是目的设备或路由上节点回应ICMP reply数据包,但大多数设备是关闭回复这种ICMP reply数据包的。
-T & -P:-T设置为TCP数据包,-P设置端口号
例:mtr 58.217.200.15 -T -P 443 -r -c 1 -n -o "SRDL ABW MX"
TCP使用的SYN数据包来探测目的主机的接通性,这个例子中,可以看到只发送一个SYN数据包,但时延似乎有点长,我们抓包来看看这个响应时延的算法是什么?
在pcap文件中,发现有4个SYN数据包(很奇怪,不是应该只有一个吗?)除了第一个SYN(TTL=1)没有响应,其它三个都是有响应的。看一下第2个SYN的会话(其它2个也类似)。
SYN和SYN ACK数据包间隔只有11.751ms,但mtr结果是201.6ms,如果把时延计算到三次握手后客户端发的第一个数据包(第8个数据包),总时延有201.842ms。但这其中,客户端的时延占了大部分。所以mtr中的TCP时延并一定能表示目的主机的真正响应时延。
·mtr在TCP和UDP的分析中结果并不理想,TCP可以测量丢包率,但对目的主机及链路的响应时延计算似乎不准确。还有mtr也不支持SCTP协议的测试。
c.脚本编制
我们可以用mtr命令来测试网络中关键设备(如路由器和关键主机等)的连通性和响应性能,但这只是当前的测量值,如果要做到24x7的不间断的监控,可以将mtr命令编辑到脚本中,并执行。
例1:每个60s执行一次测量,并将结果保存在./test-batch-txt文本文件中
例2:利用crontab,定时执行测量
编辑一个脚本mtr-test-crontab.sh,执行一次测量任务
编辑/etc/crontab,添加以下内容,表示每小时的0分、10分、20分、30分、40分、50分执行测量任务mtr-test-crontab.sh。
d.下一步
现在已经设置好mtr测量任务,并将结果保存在文本文件中,平时可以观察这个文本记录,观察网络联通性和性能,当然这个方式依旧有很多问题,使用界面并不友好,没有告警,对多设备的测量,还需增加更多的脚本。正好nGeniusPulse可以帮助我们集成这个mtr监测任务,并且能提供一个友好的UI和告警系统。
2.nGeniusPulse集成mtr
a.nGeniusPulse介绍
nGeniusPulse是一个主动测试的解决方案,来帮助用户监测端到端的基础网络架构、关键服务/设备、云端服务等的性能和可用性。它是用动态的方法模拟信号去测试,而不是用监测方法,这种测试可以对云计算的应用来做,当然在内网也可以用同样的工具去做,反馈的结果可以是一个趋势图,也可以是单一的按需测试的结果。
nGeniusPulse 2.0除了主动监测外,又增加了SNMP/WinRM方式的服务器监测、基础网络架构监测、系统Log记录排障功能,结合nGeniusONE的被动监测系统,做到主动到被动、被动到主动全方位的网络监测。
在这里我们只使用nGeniusPulse的主动拨测功能中的用户自定义Python脚本功能,把前一节中提到的mtr命令,集成到nGeniusPulse中。
b.使用Python脚本编辑mtr
在使用nGeniusPulse前,我们先编辑一个包含mtr测试的Python脚本mtr-loss-lantency-jitter-ori.py。内容如下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import time
import subprocess
import re
def def_process_windows(server, protocol, port, count):
# TBD
print "TBD"
def def_process_linux(server, protocol, port, count):
#1) combine mtr command
mtr_command_line = "mtr " + server + " "
if protocol == 'UDP':
mtr_command_line += "-u "
elif protocol == 'TCP':
mtr_command_line += "-T "
if protocol != 'ICMP' and (port > 0 and port <= 65535):
mtr_command_line += "-P " + str(port) + " "
mtr_command_line += "-r "
mtr_command_line += "-c " + str(count) + " "
mtr_command_line += "-n -o "SRDL ABW MX""
#print mtr_command_line
# 2) run the command
process = subprocess.Popen(mtr_command_line, shell=True, stdout=subprocess.PIPE)
last_line = process.stdout.read().splitlines(False)[-1]
#print last_line
res={}
res['Avail']=0
res['Drop']=0
res['Loss%']=0.0
res['Avg']=0.0
res['Best']=0.0
res['Wrst']=0.0
res['Javg']=0.0
res['Jmax']=0.0
if ( last_line.find('-- ???') == -1 ):#if unreachable, give up
#m = re.search('s+([0-9]+)s+.s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
#m = re.search('s+.s+([0-9]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
m = re.search('s+([0-9]+)s+([0-9]+)s+([0-9]+)s+([0-9.]+)%s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
res['Avail'] = 1
res['Drop'] = m.group(3)
res['Loss%'] = m.group(4)
res['Avg'] = m.group(5)
res['Best'] = m.group(6)
res['Wrst'] = m.group(7)
res['Javg'] = m.group(8)
res['Jmax'] = m.group(9)
print "|Avail |Drop |Loss% |Avg |Best |Wrst |Javg |Jmax "
print "|" + str(res['Avail']) + " |" + str(res['Drop']) + " |" + str(res['Loss%']) + " |" + str(res['Avg']) + " |" + str(res['Best']) + " |" + str(res['Wrst']) + " |" + str(res['Javg']) + " |" + str(res['Jmax'])
def main():
server = raw_input("Server? ")
protocol = raw_input("Protocol? (TCP/UDP/ICMP, default is ICMP) ")
if ((protocol != "TCP") and (protocol != "UDP")):
protocol = "ICMP"
port = input("Port? (Integer, 1-65535)" )
if port < 1 or port > 65535:
port = 0
count = input("Count? (integer, 1-30, default is 10)")
if count < 1 and count > 30:
count = 10
print server + " " + protocol + " " + str(port) + " " + str(count)
bContinue = raw_input("Process? [y/n]")
while bContinue != "y" and bContinue != "n":
bContinue = raw_input("Process? [y/n]")
if bContinue == "y":
print "Processing..."
if os.name == 'nt':
def_process_windows(server, protocol, port, count)
else:
def_process_linux(server, protocol, port, count)
else:
print "Bye!"
if __name__ == '__main__':
main()
# vim:set nu et ts=4 sw=4 cino=>4:
这段脚本可以让用户输入目的IP或域名、协议(ICMP/TCP/UDP)、端口以及每秒测试包数量等参数。执行效果如下:
最后,把目的地址的测试结果打印在屏幕上,当然,也可以修改脚本同时把测试结果存储在一个log文件。
c.nGeniusPulse设置
如果要把上述脚本导入到nGeniusPulse,还需要按nGeniusPulse的要求修改部分脚本内容,我们把新的脚本存在mtr-lantency-loss-jitter-ngp.txt中。
修改后的脚本内容如下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import os
import time
import subprocess
import re
def def_process_windows(server, protocol, port, count):
# TBD
# print "TBD"
return
def def_process_linux(server, protocol, port, count):
#1) combine mtr command
mtr_command_line = "mtr " + server + " "
if protocol == 'UDP':
mtr_command_line += "-u "
elif protocol == 'TCP':
mtr_command_line += "-T "
if protocol != 'ICMP' and (port > 0 and port <= 65535):
mtr_command_line += "-P " + str(port) + " "
mtr_command_line += "-r "
mtr_command_line += "-c " + str(count) + " "
mtr_command_line += "-n -o "SRDL ABW MX""
#print mtr_command_line
# 2) run the command
process = subprocess.Popen(mtr_command_line, shell=True, stdout=subprocess.PIPE)
last_line = process.stdout.read().splitlines(False)[-1]
#print last_line
res={}
res['Avail']=0
res['Drop']=0
res['Loss%']=0.0
res['Avg']=0.0
res['Best']=0.0
res['Wrst']=0.0
res['Javg']=0.0
res['Jmax']=0.0
if ( last_line.find('-- ???') == -1 ):#if unreachable, give up
#m = re.search('s+([0-9]+)s+.s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
#m = re.search('s+.s+([0-9]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
m = re.search('s+([0-9]+)s+([0-9]+)s+([0-9]+)s+([0-9.]+)%s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)s+([0-9.]+)', last_line)
res['Avail'] = 1
res['Drop'] = m.group(3)
res['Loss%'] = m.group(4)
res['Avg'] = m.group(5)
res['Best'] = m.group(6)
res['Wrst'] = m.group(7)
res['Javg'] = m.group(8)
res['Jmax'] = m.group(9)
#print "|Avail |Drop |Loss% |Avg |Best |Wrst |Javg |Jmax "
#print "|" + str(res['Avail']) + " |" + str(res['Drop']) + " |" + str(res['Loss%']) + " |" + str(res['Avg']) + " |" + str(res['Best']) + " |" + str(res['Wrst']) + " |" + str(res['Javg']) + " |" + str(res['Jmax'])
return res
'''
def main():
server = raw_input("Server? ")
protocol = raw_input("Protocol? (TCP/UDP/ICMP, default is ICMP) ")
if ((protocol != "TCP") and (protocol != "UDP")):
protocol = "ICMP"
port = input("Port? (Integer, 1-65535)" )
if port < 1 or port > 65535:
port = 0
count = input("Count? (integer, 1-30, default is 10)")
if count < 1 and count > 30:
count = 10
print server + " " + protocol + " " + str(port) + " " + str(count)
bContinue = raw_input("Process? [y/n]")
while bContinue != "y" and bContinue != "n":
bContinue = raw_input("Process? [y/n]")
if bContinue == "y":
print "Processing..."
if os.name == 'nt':
def_process_windows(server, protocol, port, count)
else:
def_process_linux(server, protocol, port, count)
else:
print "Bye!"
if __name__ == '__main__':
main()
'''
def run(testConfig):
config = json.loads(testConfig)
server = config['server']
protocol = config['protocol']
port = config['port']
count = config['count']
if os.name == 'nt':
return json.dumps(def_process_windows(server, protocol, port, count))
else:
return json.dumps(def_process_linux(server, protocol, port, count))
# vim:set nu et ts=4 sw=4 cino=>4:
接下来,在nGeniusPulse中导入这个脚本并设置这个测试模板:
ü新建一个测试MTR-Loss-Lantency-Jitter,并UPLOAD SCRIPT刚才写的Python脚本
ü设置Metrics
ü设置Chart
ü设置Test Instance Template
üSave
最后,根据测试模板设置测试任务:
ü新建测试任务,选择执行测试的nPoint(Pulse)
ü设置测试模板中入口函数的参数
d.nGeniusPulse结果
2个测试点(nPoint)的图形测试结果
其中一个测试点(nPoint)的测试log记录
3.小结
通过mtr命令的使用和将mtr命令集成到nGeniusPulse中,完成对网络中关键设备(如路由器等)和关键服务器的性能和可用性的主动监测。我们也可以利用其它常用网络测试命令如:iPerf、nmap等,集成到nGeniusPulse中,形成长期,自动化的、24x7不间断的监测。