本次实验的内容是开发简单 web 服务程序 cloudgo,了解 web 服务器工作原理
知识准备
1、go服务器工作原理
计算机之间协作通常是C/G架构,也就是一个进程扮演 Server 提供服务,一个或多个进程扮演 Client 发起服务请求。有点像古代两个人往来信件,一方发出(发起服务请求),另一方接受(收到服务请求)并回信(提供服务)。而web服务也是采取这种架构
我们可以把web服务器的工作原理简单归纳为:
- 客户机通过 TCP/IP 协议与服务器建立 TCP 连接
- 客户端向服务器发送 HTTP 协议请求包,请求服务器里的资源文档
- 服务器向客户机发送 HTTP 协议应答包
- 客户机与服务器断开,由客户端解释 HTML 文档,在客户端屏幕上渲染图形结果
2、curl 工具
curl 是 web 开发者所用的工具,它是一个控制台程序,可以精确控制 HTTP 请求的每一个细节。实战中,配合 shell 程序,我们可以简单,重复给服务器发送不同的请求序列,调试程序或分析输出。curl 是 linux 系统自带的命令行工具
使用curl --help
可以查看curl的使用方法。因为内容实在太多了,这里我就不详细展示了,放一些常用的:
参数 | 选项 | 作用 |
---|---|---|
-A | –user-agent | 设置用户代理发送给服务器 |
-b | –cookie <name=string|file> | cookie字符串或文件读取位置 |
-c | –cookie-jar | 操作结束后把cookie写入到这个文件中 |
-C | –continue-at | 断点续转 |
-D | –dump-header | 把header信息写入到该文件中 |
-e | –referer | 来源网址 |
-f | –fail | 连接失败时不显示http错误 |
-o | –output | 把输出写到该文件中 |
-O | –remote-name | 把输出写到该文件中,保留远程文件的文件名 |
-r | –range | 检索来自HTTP |
-s | –silent | 静音模式。不输出任何东西 |
-T | –upload-file | 上传文件 |
-u | –user <user[:password]> | 设置服务器的用户和密码 |
-w | –write-out [format] | 什么输出完成后 |
-x | –proxy <host[:port]> | 在给定的端口上使用HTTP代理 |
-# | –progress-bar | 进度条显示当前的传送状态 |
3、压力测试
在ubuntu上安装apache2的命令是:
sudo apt-get install apache2-utils
程序实现
服务端使用的框架是:negroni和mux。代码:
main.go
package main
import (
"os"
"./service"
flag "github.com/spf13/pflag"
)
const (
PORT string = "8080"
)
func main() {
port := os.Getenv("PORT")
if len(port) == 0 {
port = PORT
}
pPort := flag.StringP("port", "p", PORT, "PORT for httpd listening")
flag.Parse()
if len(*pPort) != 0 {
port = *pPort
}
server := service.NewServer()
server.Run(":" + port)
}
service/server.go
package service
import (
"net/http"
"github.com/codegangsta/negroni"
"github.com/gorilla/mux"
"github.com/unrolled/render"
)
// NewServer configures and returns a Server.
func NewServer() *negroni.Negroni {
formatter := render.New(render.Options{
IndentJSON: true,
})
n := negroni.Classic()
mx := mux.NewRouter()
initRoutes(mx, formatter)
n.UseHandler(mx)
return n
}
func initRoutes(mx *mux.Router, formatter *render.Render) {
mx.HandleFunc("/hello/{id}", testHandler(formatter)).Methods("GET")
}
func testHandler(formatter *render.Render) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
id := vars["id"]
formatter.JSON(w, http.StatusOK, struct{ Test string }{"Hello " + id})
}
}
使用命令go run main.go -p9090
运行服务器
打开另一个终端,使用 curl 工具访问 web 程序
对 web 执行压力测试。输出很长,就没有截图,将输出复制粘贴了下来:
$ ab -n 1000 -c 100 http://localhost:9090/hello/your This is
ApacheBench, Version 2.3 <$Revision: 1807734 $> Copyright 1996 Adam
Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The
Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient) Completed 100 requests Completed
200 requests Completed 300 requests Completed 400 requests Completed
500 requests Completed 600 requests Completed 700 requests Completed
800 requests Completed 900 requests Completed 1000 requests Finished
1000 requestsServer Software: Server Hostname: localhost Server
Port: 9090Document Path: /hello/your Document Length: 27 bytes
Concurrency Level: 100 Time taken for tests: 0.442 seconds
Complete requests: 1000 Failed requests: 0 Total
transferred: 150000 bytes HTML transferred: 27000 bytes
Requests per second: 2261.85 [#/sec] (mean) Time per request:
44.212 [ms] (mean) Time per request: 0.442 [ms] (mean, across all concurrent requests) Transfer rate: 331.33 [Kbytes/sec]
receivedConnection Times (ms)
min mean[+/-sd] median max Connect: 0 4 7.7 0 34 Processing: 0 39 20.6 36 122 Waiting: 0 38 20.9 35 122 Total: 0 43
20.4 42 126Percentage of the requests served within a certain time (ms) 50%
42 66% 48 75% 56 80% 59 90% 69 95% 81
98% 90 99% 90 100% 126 (longest request)
解释:
参数-c 100
指的是100个用户同时访问
参数-n 1000
指的是100个用户总共访问1000次
从结果中我们可以看出1000次访问都被成功处理
其他输出:
项 | 内容 |
---|---|
Server Software | 服务器软件名称及版本信息 |
Server Hostname | 服务器主机名 |
Server Port | 服务器端口 |
Document Path | 供测试的URL路径 |
Document Length | 供测试的URL返回的文档大小 |
Concurrency Level | 并发数 |
Time taken for tests | 压力测试消耗的总时间 |
Complete requests | 压力测试的总次数 |
Failed requests | 失败的请求数 |
Write errors | 网络连接写入错误数 |
Total transferred | 传输的总数据量 |
HTML transferred | HTML文档的总数据量 |
Requests per second | 平均每秒的请求数 |
Time per request | 所有并发用户请求一次的平均时间 |
Time per request | 单个用户请求一次的平均时间 |
Transfer rate | 传输速率,单位:KB/s |
通过这次实验,我学会了测试服务器的两个工具:curl和apache2。借助工具的帮助,程序员能够更快地了解服务器的性能