1. 产品说明
Web应用系统是现代互联网产业应用的重要实现形式,开发者通过适配浏览器,综合采用html/css/js等前端技术,构建高度易用的Web页面,实现人机交互。为探测网络质量,计算应用可用率,拨测节点模拟人工访问,其基本原理是,在保证网络可达和不违反组织安全规范的前提下,构造一个http/https客户端,以特定时间频率,向被检测对象发起访问。
因单页面检测功能模拟人工操作,从请求发起、执行到结果解析,都有严格、清晰的规范可依,检测结果准确,流程也不复杂,是拨测类工具最重要的一种的检测手段(本文后续代码说明,均使用Golang语言)
2. 检测指标
从一次http(s)请求发起到接收到响应,理论上有DNS解析、TCP建联、SSL解析、客户端总耗时、首包耗时、重定向、静态内容下载等环节,依照这个流程,就可以构建一套完整的metric(指标)系统,将每次拨测结果上报存储,为后续数据分析提供原始材料。
3. 任务配置
一个单一页面检测任务,至少应包含以下配置选项:
- url访问地址
- 超时时间
- 允许的重定向次数
- 执行频率
- 拨测节点网络域选择
此外,完善的监控系统还会提供任务起止时间、告警时间段、告警方式、告警接收人、页面关键字匹配等额外选项,在拨测任务执行失败后,可以执行Ping、Traceroute、Tcpdump、Nslookup等系统命令,辅助排查问题。
4. 代码实现
构造http请求客户端
Golang语言中创建http请求非常方便,为了提高灵活性,这里使用"http.NewRequest"的方式。
import (
"net"
"net/http"
"net/url"
.....
)
// 初始化关键参数,后续计算时会用到
var (
dnsStartTime time.Time
dnsDoneTime time.Time
connectStartTime time.Time
connectDoneTime time.Time
tlsHandshakeStartTime time.Time
tlsHandshakeDoneTime time.Time
gotConnTime time.Time
gotFirstResponseByteTime time.Time
requestStartTime time.Time
requestDoneTime time.Time
)
// 编写一个方法,实现http请求
// method: 请求类型
// uri: 请求地址
// header: 设置http请求头
// body: http请求体,单页面一般是GET请求,nil值
func NewHTTPRequest(method string, uri string, header map[string]string, body io.Reader) (req *http.Request, err error) {
req, err = http.NewRequest(method, uri, body)
if err != nil {
return
}
//设置http请求的冗余信息,这样看起来更像是一个浏览器
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
req.Header.Set("Accept-Language", "zh,zh-CN;q=0.9")
req.Header.Set("Cache-Control", "no-cache")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Pragma", "no-cache")
req.Header.Set("Upgrade-Insecure-Requests", "1")
req.Header.Set("UA", "patech-dialing")
req.Header.Set("User-Agent", "/patech-dialing/Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36")
if header == nil {
return
}
for k, v := range header {
// Set Header Host
if strings.EqualFold(k, "host") {
req.Host = v
continue
}
req.Header.Set(k, v)
}
return
}
Golang中,"net/http/httptrace"包提供了完善的http请求跟踪机制,基本可以满足对一次tcp通信的跟踪和反馈。下面,利用这个工具包展示部分代码实现。
// 定义返回数据结构
type response struct {
Common ....
}
.....
trace := &httptrace.ClientTrace{
DNSStart: func(_ httptrace.DNSStartInfo) {
dnsStartTime = time.Now()
},
DNSDone: func(info httptrace.DNSDoneInfo) {
dnsDoneTime = time.Now()
if info.Err != nil {
response.Common.StatusCode = common.StatusDNSResolveFail
logger.Warnf("httptrace dns err:%v", info.Err)
}
},
ConnectStart: func(_, _ string) {
connectStartTime = time.Now()
},
ConnectDone: func(_, addr string, err error) {
response.RemoteAddr = addr
connectDoneTime = time.Now()
if err != nil {
response.Common.StatusCode = common.StatusConnRefused
logger.Warnf("httptrace connect err:%v", err)
}
},
GotConn: func(_ httptrace.GotConnInfo) {
gotConnTime = time.Now()
},
GotFirstResponseByte: func() {
gotFirstResponseByteTime = time.Now()
},
TLSHandshakeStart: func() {
tlsHandshakeStartTime = time.Now()
},
TLSHandshakeDone: func(_ tls.ConnectionState, err error) {
tlsHandshakeDoneTime = time.Now()
if err != nil {
response.Common.StatusCode = common.StatusInsecureCert
logger.Warnf("httptrace tls err:%v", err)
}
},
}
// 设置任务执行上下文、超时时间等
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
httpRequest = httpRequest.WithContext(httptrace.WithClientTrace(ctx, trace))
......
以上,记录各请求环节的时间戳,基本可以获取想要的metric指标。