在F5的monitor中我们总会看到两个计时器选项interval和timeout,通俗的讲就是每隔interval时间执行探测一次,如果timeout时间之内没有应答(回复),则认为失败。
但这里面有不少细节,这里的timeout到底是指的什么,是指每一次探测所要等待的时间还是总时间,如果针对第一次的探测响应在第二次探测发出后才回来,会是什么结果?应用层的行为是否会反过来影响探测?
事实上monitor用两个维度来看待上述两个计时器,当0s monitor开始工作时,系统将开始维持两个监控状态,一个是interval的,一个是timeout的。 系统不管每次的探测成功与否,都会按照interval的间隔触发每一次的探测;而timeout从monitor开始工作时候启动计时,并在探测成功时或超时时间到达时被重置,每次被重置后将随着下一次探测的启动开始进行新的timeout计时:
0s-------------------5s-------------------10s-------------------15s----16s---------------20s
探测: 发 -------------------发-------------------发----------------------发--------------------------发
timeout:成功则重置-------成功0s----------成功0s-----------------成功0s------------------成功0s
timeout: 不成功则持续计时------------------------------------------->直到第16s,记探测失败
timeout: 新计时
1. 在系统缺省状态下(bigd.reusesocket enable),对于有data发送的TCPmonitor,或者HTTP monitor 在一个timeout计时时间之内,系统始终维持一个连接TCP连接,并在此连接之内重复发送探测数据,这timeout时间之内任意一次探测得到了正确 结果,则将标记结果为UP,并关闭连接,待下一个interval时间到达后开始一次新的tcp连接,并开始新的timeout计时。若timeout时 间之内没有任何回复,则在timeout时间到达时标记结果为down,在等到下一个interval到达时,开始新的 timeout计时, 系统在执行三次重复探测后关闭连接并在下一次探测时重新建立连接。
如果是纯端口的没有实际数据发送的monitor,则每个间隔的三次握手后关闭。
设想一个情形,系统内置的http monitor默认使用HTTP 0.9发送GET请求,假设当前服务器的响应延迟每次都大于interval时间,会导致什么结果?
---由于系统在每个interval到达时,服务器都无法响应response,因此从服务器角度看,服务器将从同一个tcp通道中的每interval时间收到一个0.9的GET请求,而服务器的http server会认为这不是一个合法的pipeline请求,因此导致服务器始终不给与回复,从而导致monitor最终在timeout时间内无法收到响应。因此建议对http的monitor我们使用HTTP/1.1版本,详细见 https://support.f5.com/kb/en-us/solutions/public/2000/100/sol2167.html?sr=40355086
2. 若将bigd.reusesocket 这个db key的值设置为 disable,那么将改变monitor对socket的使用行为,disable后,monitor在每一次interval发起探测时候都会新建一个tcp连接,之前的tcp连接将被关闭。timeout与interval之间的关系保持上图不变。 所以,若服务器始终无法在下一次(interval时间)探测到来之前回复的话,将导致monitor在timeout时间到达后标记结果为down。
关于为什么要改变reusesocket,请移步https://support.f5.com/kb/en-us/solutions/public/13000/800/sol13820.html?sr=40355414
下面这个脚本可以用来模拟服务器延迟响应:
mycisco@ubuntu-jmeter:/var/tmp$ cat httpresponse.py
#!/usr/bin/python
import socket
import sys
import time
import random
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
#conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'HTTP/1.1 200 OK\nContent-Type: text/html\nContent-Length: 4\n\nf5up'
if not data:
break
# delay 10s before sending response.
time.sleep(10)
#if you want to use random sleep,comment the above and use below
#delaytime = random.randint(1,9)
#time.sleep(delaytime)
conn.sendall(reply)
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
s.close()