如何拦截http请求看请求是http还是http/2

关于 Nginx 开启 HTTP/2 的问题
20:36:17 +08:00 · 5911 次点击
Nginx 版本为 1.11.1 , http_v2 和 http_ssl 这两个模块都有,然后配置文件写了 llisten 443 ssl http2;重启无数次了 但是就是无法启动 http2 这是为什么
30 回复 &| &直到
22:47:37 +08:00
& & 20:37:50 +08:00
chrome 51 的话需要 openssl 1.0.2
& & 20:50:15 +08:00 via Android
typo: listen
& & 20:52:32 +08:00
错误信息呢
& & 21:03:07 +08:00
& & 21:13:22 +08:00 via iPhone
直接上网址让大家看看啊。
& & 21:17:40 +08:00
1L 正解
OpenSSL1.02 才支持 ALPN
& & 21:31:02 +08:00
@ 用 openssl 1.0.2 重新编译了下成功了 谢谢
& & 21:33:35 +08:00 via iPhone
你这分也太低了吧
& & 21:40:03 +08:00
@ A-很差么 QAQ
& & 21:43:47 +08:00 via iPhone
@ 我刚看还是 F ,应该是你刚升级了 OpenSSL 。
& & 21:45:40 +08:00
@ 嘛还是谢谢大触了
& & 21:52:15 +08:00
chrome51 以后需要支持 ALPN
需要编译新版本的 openssl
& & 22:17:52 +08:00
server {
listen 80;
listen 443 ssl http2;
server_
index index.php index.
root /data/wwwroot/
ssl_certificate /path/to/your-domain.
ssl_certificate_key /path/to/your-domain.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #允许的协议
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; #加密算法(CloudFlare 推荐的加密套件组)
ssl_prefer_server_ #优化 SSL 加密套件
ssl_session_timeout 10m; #客户端会话缓存时间
ssl_session_cache builtin:1000 shared:SSL:10m; #SSL 会话缓存类型和大小
ssl_buffer_size 1400; # 1400 bytes to fit in one MTU
#add_header X-Frame-Options SAMEORIGIN; #拒绝被嵌入框架(iframe …)
#add_header Strict-Transport-Security &max-age=; includeSubD preload&; #强制 SSL(包含子域名),并加入 hsts 列表
add_header X-UA-Compatible &IE=edge,chrome=1&; #IE 用最新内核渲染页面
if ($host != '' ) { return 301 ; } #把根域名 301 到 www 开头的域名
if ($ssl_protocol = &&) { return 301 https://$host$request_ } #如果非 ssl 就 301 到 https
access_log /data/wwwlogs/your-domain.com_nginx.
#error_page 404 /404.
if ( $query_string ~* &.*[\;'\&\&].*& ){
return 404;
location ~ [^/]\.php(/|$) {
fastcgi_pass unix:/dev/shm/php-cgi.
fastcgi_index index.
include fastcgi.
location ~ .*\.(gif|jpg|jpeg|png|js|css|ico)$ {
expires 30d;
chrome 51 以上要使用 openssl 1.0.2 来编译才支持 ALPN 来协商 HTTP2 ,
可以使用 openssl 1.1.0 版本(目前是测试版) ,或者 LibreSSL 来支持 chacha20 加密套件
nginx 可以参考上面的这样配置, 80 和 443 端口不用分开两次写。
& & 22:39:59 +08:00
终于从 F 刷到了 A.
& & 23:03:53 +08:00
@ 谢谢,学习了
& & 23:08:35 +08:00 via Android
& & 23:16:42 +08:00
@ 域名前几位应该是浙江杭州的拼音缩写?我也在哈尔滨,不知道有没有机会面基吖= =
& & 23:22:52 +08:00
@ 博客没法评论啊
另外 CDN 用的是啥?
& & 23:32:06 +08:00
@ 无法评论问题解决了, CDN 用七牛
& & 23:40:11 +08:00
根据 qu 大大的教程一步步来就能到 A+。。
& & 23:57:54 +08:00 via iPhone
@
Bingo ~ 你是杭州的吗?
你想怎么面基?
& & 01:15:51 +08:00
@ 如果你开启 HSTS 会到 A+,开启 HSTS 后,以后在支持 HSTS 的浏览器中,你无法临时切换到普通的 http ,基本以后都只能是 https
& & 06:31:06 +08:00 via iPhone
@ 不敢开 HSTS ,保持 A 丢在那。
对了 BoringSSL 支持 ALPN 嘛
& & 07:34:40 +08:00
@ 话说工大有类似于 LUG(Linux User Group)之类的社团或者组织吗?
& & 09:22:35 +08:00
@ 不知道~
倒是有一个 run.hit.edu.cn. 应该有一个 LUG 在维护吗?
& & 12:52:18 +08:00 via Android
& & 12:53:12 +08:00 via Android
& & 14:28:13 +08:00
用 h2o 吧,效率更高,且原生 http/2
& & 21:47:50 +08:00 via Android
@ HTTPSECURITYREPORT 这个站 98 分简直 6 。。
& & 22:47:37 +08:00
Firebase Hosting 是 A+.
CloudFlare 是 A.
& · & 551 人在线 & 最高记录 3541 & · &
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.0 · 59ms · UTC 18:22 · PVG 02:22 · LAX 10:22 · JFK 13:22? Do have faith in what you're doing.wireshark 监听非80端口的HTTP请求 / 新手园地 / Arch Linux 中文论坛
您尚未登录。
注册时间:
wireshark 监听非80端口的HTTP请求
我现在用wireshark监听端口是80的HTTP请求时, 挺好的。 不过, 如果HTTP服务的端口改成别的后, wireshark就监听不到了。 怎么设置下呢? 虽说,可以通过改HTTP端口方式来变相地协调, 但总不是从根上解决 。
a.k.a. 百合仙子
所在地: 一个等待妹纸出现的地方
注册时间:
帖子: 4,507
Re: wireshark 监听非80端口的HTTP请求
不明白你指的是什么。wireshark 默认的 filter 是捕获所有指定网卡上的数据的。如果你是指 wireshark 没有把指定的流识别为 HTTP 请求的话,请点击那个流中的某一报文,选择「Decode As...」菜单,然后将其设置为 HTTP 协议。
注册时间:
Re: wireshark 监听非80端口的HTTP请求
百合仙子 说:不明白你指的是什么。wireshark 默认的 filter 是捕获所有指定网卡上的数据的。如果你是指 wireshark 没有把指定的流识别为 HTTP 请求的话,请点击那个流中的某一报文,选择「Decode As...」菜单,然后将其设置为 HTTP 协议。多谢, 按您的方法, 对单个TCP请求, decode后, 可以以HTTP形式显示。 这里再按“http.request”来过滤时, 也能正常地捕获到针对那个端口的HTTP请求了。 感觉, 还不是很透彻, 会针对这个做后续的跟进。
注册时间:
Re: wireshark 监听非80端口的HTTP请求
这个纯粹是wireshark的使用方法,看wireshark的help吧
Powered byHTTP请求头详解
HTTP由两部分组成:请求和响应。当你在Web浏览器中输入一个URL时,浏览器将根据你的要求创建并发送请求,该请求包含所输入的URL以及一些与浏览器本身相关的信息。当服务器收到这个请求时将返回一个响应,该响应包括与该请求相关的信息以及位于指定URL(如果有的话)的数据。直到浏览器解析该响应并显示出网页(或其他资源)为止。
HTTP请求的格式如下所示:
在HTTP请求中,第一行必须是一个请求行(request
line),用来说明请求类型、要访问的资源以及使用的HTTP版本。紧接着是一个首部(header)小节,用来说明服务器要使用的附加信息。在首部之后是一个空行,再此之后可以添加任意的其他数据[称之为主体(body)]。
在HTTP中,定义了多种请求类型,通常我们关心的只有GET请求和POST请求。只要在Web浏览器上输入一个URL,浏览器就将基于该URL向服务器发送一个GET请求,以告诉服务器获取并返回什么资源。对于www.baidu.com的GET请求如下所示:
/ HTTP/1.1
Host: www.baidu.comUser-Agent:
Mozilla/5.0 (W U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/ Firefox/1.0.1
Connection: Keep-Alive
请求行的第一部分说明了该请求是GET请求。该行的第二部分是一个斜杠(/),用来说明请求的是该域名的根目录。该行的最后一部分说明使用的是HTTP
1.1版本(另一个可选项是1.0)。那么请求发到哪里去呢?这就是第二行的内容。
第2行是请求的第一个首部,HOST。首部HOST将指出请求的目的地。结合HOST和上一行中的斜杠(/),可以通知服务器请求的是www.baidu.com/(HTTP
1.1才需要使用首部HOST,而原来的1.0版本则不需要使用)。第三行中包含的是首部User-Agent,服务器端和客户端脚本都能够访问它,它是浏览器类型检测逻辑的重要基础。该信息由你使用的浏览器来定义(在本例中是Firefox
1.0.1),并且在每个请求中将自动发送。最后一行是首部Connection,通常将浏览器操作设置为Keep-Alive(当然也可以设置为其他值)。注意,在最后一个首部之后有一个空行。即使不存在请求主体,这个空行也是必需的。
要发送GET请求的参数,则必须将这些额外的信息附在URL本身的后面。其格式类似于:
name1=value1&name2=value2&..&nameN=valueN
该信息称之为查询字符串(query
string),它将会复制在HTTP请求的请求行中,如下所示:
/books/?name=Professional Ajax HTTP/1.1
Host: www.baidu.comUser-Agent:
Mozilla/5.0 (W U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/ Firefox/1.0.1
Connection: Keep-Alive
注意,为了将文本“Professional
Ajax”作为URL的参数,需要编码处理其内容,将空格替换成 ,这称为URL编码(URL
encoding),常用于HTTP的许多地方(JavaScript提供了内建的函数来处理URL编码和解码)。“名称—值”(name—value)对用
隔开。绝大部分的服务器端技术能够自动对请求主体进行解码,并为这些值的访问提供一些逻辑方式。当然,如何使用这些数据还是由服务器决定的。
另一方面,POST请求在请求主体中为服务器提供了一些附加的信息。通常,当填写一个在线表单并提交它时,这些填入的数据将以POST请求的方式发送给服务器。
以下就是一个典型的POST请求:
/ HTTP/1.1
Host: www.baidu.comUser-Agent:
Mozilla/5.0 (W U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/ Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
name=Professional
Ajax&publisher=Wiley
从上面可以发现,
POST请求和GET请求之间有一些区别。首先,请求行开始处的GET改为了POST,以表示不同的请求类型。你会发现首部Host和User-Agent仍然存在,在后面有两个新行。其中首部Content-Type说明了请求主体的内容是如何编码的。浏览器始终以application/
x-www-form-
urlencoded的格式编码来传送数据,这是针对简单URL编码的MIME类型。首部Content-Length说明了请求主体的字节数。在首部Connection后是一个空行,再后面就是请求主体。与大多数浏览器的POST请求一样,这是以简单的“名称—值”对的形式给出的,其中name是Professional
Ajax,publisher是Wiley。你可以以同样的格式来组织URL的查询字符串参数。
下面是一些最常见的请求头:
Accept:浏览器可接受的MIME类型。
Accept - Charset:浏览器可接受的字符集。
Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。
Accept - Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
Authorization:授权信息,通常出现在对服务器发送的WWW - Authenticate头的应答中。
Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep - Alive”,或者看到请求使用的是HTTP
1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content
Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。
Content - Length:表示请求消息正文的长度。
Cookie:这是最重要的请求头信息之一,参见后面《Cookie处理》一章中的讨论。
From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。
Host:初始URL中的主机和端口。
If - Modified - Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not
Modified”应答。
Pragma:指定“no -
cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。
Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。
User - Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。
UA - Pixels,UA - Color,UA - OS,UA -
CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。
如下所示,HTTP响应的格式与请求的格式十分类似:
正如你所见,在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status
line)通过提供一个状态码来说明所请求的资源情况。以下就是一个HTTP响应的例子:
HTTP/1.1 200 OK
Date: Sat, 31 Dec :59 GMT
Content-Type: text/charset=ISO-8859-1
Content-Length: 122
在本例中,状态行给出的HTTP状态代码是200,以及消息OK。状态行始终包含的是状态码和相应的简短消息,以避免混乱。最常用的状态码有:
&# (OK): 找到了该资源,并且一切正常。
&# (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。
&# (UNAUTHORIZED):
客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器。
&# (FORBIDDEN): 客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。
&# (NOT FOUND): 在指定的位置不存在所申请的资源。
在状态行之后是一些首部。通常,服务器会返回一个名为Data的首部,用来说明响应生成的日期和时间(服务器通常还会返回一些关于其自身的信息,尽管并非是必需的)。接下来的两个首部大家应该熟悉,就是与POST请求中一样的Content-Type和Content-Length。在本例中,首部Content-Type指定了MIME类型HTML(text/html),其编码类型是ISO-8859-1(这是针对美国英语资源的编码标准)。响应主体所包含的就是所请求资源的HTML源文件(尽管还可能包含纯文本或其他资源类型的二进制数据)。浏览器将把这些数据显示给用户。
注意,这里并没有指明针对该响应的请求类型,不过这对于服务器并不重要。客户端知道每种类型的请求将返回什么类型的数据,并决定如何使用这些数据。
附录:使用Java套接字实现一个可以处理get和post请求的小HTTP服务器程序
import java.io.*;
import java.net.*;
import java.util.StringT
public class SimpleHttpServer implements Runnable {
ServerSocket serverS//服务器Socket
public static int PORT=80;//标准HTTP端口
public SimpleHttpServer() {
serverSocket=new ServerSocket(PORT);
} catch(Exception e) {
System.out.println("无法启动HTTP服务器:"+e.getLocalizedMessage());
if(serverSocket==null) System.exit(1);//无法开始服务器
new Thread(this).start();
System.out.println("HTTP服务器正在运行,端口:"+PORT);
public void run() {
while(true) {
Socket client=//客户Socket
client=serverSocket.accept();//客户机(这里是 IE 等浏览器)已经连接到当前服务器
if(client!=null) {
System.out.println("连接到服务器的用户:"+client);
// 第一阶段: 打开输入流
BufferedReader in=new BufferedReader(new InputStreamReader(
client.getInputStream()));
System.out.println("客户端发送的请求信息: ***************");
// 读取第一行, 请求地址
String line=in.readLine();
System.out.println(line);
resource=line.substring(line.indexOf('/'),line.lastIndexOf('/')-5);
//获得请求的资源的地址
resource=URLDecoder.decode(resource, "UTF-8");//反编码 URL 地址
String method = new
StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者
读取所有浏览器发送过来的请求参数头部信息
while( (line = in.readLine()) != null) {
System.out.println(line);
if(line.equals(""))
// 显示 POST 表单提交的内容, 这个内容位于请求的主体部分
if("POST".equalsIgnoreCase(method)) {
System.out.println(in.readLine());
System.out.println("请求信息结束 ***************");
System.out.println("用户请求的资源是:"+resource);
System.out.println("请求的类型是: " + method);
图片就读取一个真实的图片数据并返回给客户端
if(resource.endsWith(".gif")) {
fileService("images/test.gif", client);
closeSocket(client);
// 请求 JPG 格式就报错 404
if(resource.endsWith(".jpg")) {
PrintWriter out=new
PrintWriter(client.getOutputStream(),true);
out.println("HTTP/1.0 404 Not found");//返回应答消息,并结束应答
out.println();// 根据 HTTP 协议, 空行将结束头信息
out.close();
closeSocket(client);
// 用 writer 对客户端 socket 输出一段 HTML 代码
PrintWriter out=new
PrintWriter(client.getOutputStream(),true);
out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答
out.println("Content-Type:text/charset=GBK");
out.println();// 根据 HTTP 协议, 空行将结束头信息
out.println("
Hello Http
out.println("你好, 这是一个 Java HTTP 服务器 demo 应用.
out.println("您请求的路径是: " + resource + "
out.println("这是一个支持虚拟路径的图片:
out.println("
这是个会反馈 404 错误的的图片:
out.println("
out.close();
closeSocket(client);
} catch(Exception e) {
System.out.println("HTTP服务器错误:"+e.getLocalizedMessage());
//System.out.println(client+"连接到HTTP服务器");//如果加入这一句,服务器响应速度会很慢
} catch(Exception e) {
System.out.println("HTTP服务器错误:"+e.getLocalizedMessage());
void closeSocket(Socket socket) {
socket.close();
} catch (IOException ex) {
ex.printStackTrace();
System.out.println(socket + "离开了HTTP服务器");
void fileService(String fileName, Socket socket)
PrintStream out = new PrintStream(socket.getOutputStream(),
File fileToSend = new File(fileName);
if(fileToSend.exists() && !fileToSend.isDirectory())
out.println("HTTP/1.0 200 OK");//返回应答消息,并结束应答
out.println("Content-Type:application/binary");
out.println("Content-Length:" + fileToSend.length());//
返回内容字节数
out.println();// 根据 HTTP 协议, 空行将结束头信息
FileInputStream fis = new FileInputStream(fileToSend);
byte data[] = new byte[fis.available()];
fis.read(data);
out.write(data);
out.close();
fis.close();
catch(Exception e)
System.out.println("传送文件时出错:" + e.getLocalizedMessage());
private static void usage() {
System.out.println("Usage: java HTTPServer Default port is
public static void main(String[] args) {
if(args.length != 1) {
} else if(args.length == 1) {
PORT = Integer.parseInt(args[0]);
} catch (Exception ex) {
System.err.println("Invalid port arguments. It must be a integer
that greater than 0");
new SimpleHttpServer();
* 在用Java语言实现HTTP服务器时,首先启动一个java.net.ServerSocket在提供服务的端口上监听连接.向客户返回文本时,可以用PrintWriter,但是如果返回二进制数据,则必须使用OutputStream.write(byte[])方法,返回的应答消息字符串可以使用String.getBytes()方法转换为字节数组返回,或者使用PrintStream的print()方法写入文本,用write(byte[])方法写入二进制数据.
* @author 刘长炯 * @version 1.0
Sunday */ public
class SimpleHttpServer implements Runnable { ServerSocket
serverS//服务器Socket public static int PORT=80;//标准HTTP端口
public SimpleHttpServer() { try { serverSocket=new
ServerSocket(PORT); } catch(Exception e) {
System.out.println("无法启动HTTP服务器:"+e.getLocalizedMessage()); }
if(serverSocket==null) System.exit(1);//无法开始服务器 new
Thread(this).start(); System.out.println("HTTP服务器正在运行,端口:"+PORT); }
public void run() { while(true) { try { Socket
client=//客户Socket client=serverSocket.accept();//客户机(这里是 IE
等浏览器)已经连接到当前服务器 if(client!=null) {
System.out.println("连接到服务器的用户:"+client); try { // 第一阶段: 打开输入流
BufferedReader in=new BufferedReader(new InputStreamReader(
client.getInputStream())); System.out.println("客户端发送的请求信息:
***************"); // 读取第一行, 请求地址 String line=in.readLine();
System.out.println(line); String
resource=line.substring(line.indexOf('/'),line.lastIndexOf('/')-5);
//获得请求的资源的地址 resource=URLDecoder.decode(resource, "UTF-8");//反编码
URL 地址 String method = new
StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者
POST // 读取所有浏览器发送过来的请求参数头部信息 while( (line = in.readLine()) != null)
{ System.out.println(line); if(line.equals("")) } // 显示 POST
表单提交的内容, 这个内容位于请求的主体部分 if("POST".equalsIgnoreCase(method)) {
System.out.println(in.readLine()); } System.out.println("请求信息结束
***************"); System.out.println("用户请求的资源是:"+resource);
System.out.println("请求的类型是: " + method); // GIF
图片就读取一个真实的图片数据并返回给客户端 if(resource.endsWith(".gif")) {
fileService("images/test.gif", client); closeSocket(client);
} // 请求 JPG 格式就报错 404 if(resource.endsWith(".jpg")) {
PrintWriter out=new PrintWriter(client.getOutputStream(),true);
out.println("HTTP/1.0 404 Not found");//返回应答消息,并结束应答
out.println();// 根据 HTTP 协议, 空行将结束头信息 out.close();
closeSocket(client); } else { // 用 writer 对客户端 socket
输出一段 HTML 代码 PrintWriter out=new
PrintWriter(client.getOutputStream(),true); out.println("HTTP/1.0
200 OK");//返回应答消息,并结束应答
out.println("Content-Type:text/charset=GBK"); out.println();//
根据 HTTP 协议, 空行将结束头信息 out.println("
Hello Http Server
"); out.println("你好, 这是一个 Java HTTP 服务器 demo 应用.
"); out.println("您请求的路径是: " + resource + "
"); out.println("这是一个支持虚拟路径的图片:
" + ""); out.println("
这是个会反馈 404 错误的的图片:
"); out.println("
"); out.close(); closeSocket(client); } } catch(Exception e) {
System.out.println("HTTP服务器错误:"+e.getLocalizedMessage()); } }
//System.out.println(client+"连接到HTTP服务器");//如果加入这一句,服务器响应速度会很慢 }
catch(Exception e) {
System.out.println("HTTP服务器错误:"+e.getLocalizedMessage()); } } }
void closeSocket(Socket socket) { try { socket.close(); } catch
(IOException ex) { ex.printStackTrace(); }
System.out.println(socket + "离开了HTTP服务器"); } void
fileService(String fileName, Socket socket) { try { PrintStream out
= new PrintStream(socket.getOutputStream(), true); File fileToSend
= new File(fileName); if(fileToSend.exists() &&
!fileToSend.isDirectory()) { out.println("HTTP/1.0 200
OK");//返回应答消息,并结束应答 out.println("Content-Type:application/binary");
out.println("Content-Length:" + fileToSend.length());// 返回内容字节数
out.println();// 根据 HTTP 协议, 空行将结束头信息 FileInputStream fis = new
FileInputStream(fileToSend); byte data[] = new
byte[fis.available()]; fis.read(data); out.write(data);
out.close(); fis.close(); } } catch(Exception e) {
System.out.println("传送文件时出错:" + e.getLocalizedMessage()); } }
private static void usage() { System.out.println("Usage: java
HTTPServer Default port is 80."); } public static void
main(String[] args) { try { if(args.length != 1) { usage(); } else
if(args.length == 1) { PORT = Integer.parseInt(args[0]); } } catch
(Exception ex) { System.err.println("Invalid port arguments. It
must be a integer that greater than 0"); } new SimpleHttpServer();
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。如何生成每秒百万级别的 HTTP 请求? - 文章 - 伯乐在线
& 如何生成每秒百万级别的 HTTP 请求?
第一篇:《》
第二篇:《》
第三篇:《》
本文是构建能够每秒处理 3 百万请求的高性能 Web 集群系列文章的第一篇。它记录了我使用负载生成器工具的一些经历,希望它能帮助每一个像我一样不得不使用这些工具的人节省时间。
负载生成器是一些生成用于测试的流量的程序。它们可以向你展示服务器在高负载的情况下的性能,以及让你能够找出服务器可能存在的问题。通过负载测试了解服务器的缺点,是测试服务器弹性以及未雨绸缪的好方法。
负载生成工具(Load-Generating Tools)
在进行负责测试时要牢记一件重要的事:你能在 Linux 上建立多少个 socket 连接。这个限制是硬编码在内核里的,最典型的就是。(在某种程度上)你可以在 /etc/sysctl.conf 里扩展它。但是基本上,一台 Linux 机器只能同时打开大约 64,000 个 socket 。因此在负载测试时,我们不得不通过在单一的连接上尽可能多地发出请求来充分利用 socket 。 除此之外,我们还需要不止一台的机器来产生负载。否则,负载生成器会把可用的 socket 占用导致不能产生足够的负载。
我一开始用的是‘ab’,Apache Bench 。它是我所知道的 http 基准测试工具中最简单、最通用的。并且它是 Apache 附带的产品,因此它可能已经存在于你的系统中。不幸的是,我在使用它的时候每秒大约只能生成 900 个请求。虽然我见过其他人使用它每秒能达到 2,000 个请求,但我可以立即告诉你,‘ab’并不适合我们的基准测试。
接着,我尝试了 ‘httperf’。这个工具更强大,但是它依然相对简单并且功能有限。要算出每秒生产了多少个请求并不是仅传递参数那么简单。经过我的多次尝试,获取了每秒超过几百请求的结果。例如:
它以每秒 1,000 个的速率创建了 100,000 个会话(session)。每次会话发起 5 次请求,时间间隔为 2 秒。
httperf --hog --server=192.168.122.10 --wsess=,2 --rate 1000 --timeout 5
httperf --hog --server=192.168.122.10 --wsess=100000,5,2 --rate 1000 --timeout 5
Total: connections 117557 requests 219121 replies 116697 test-duration 111.423 s
Connection rate: 1055.0 conn/s (0.9 ms/conn, &=1022 concurrent connections)
Connection time [ms]: min 0.3 avg 865.9 max 7912.5 median 459.5 stddev 993.1
Connection time [ms]: connect 31.1
Connection length [replies/conn]: 1.000
Request rate: 1966.6 req/s (0.5 ms/req)
Request size [B]: 91.0
Reply rate [replies/s]: min 59.4 avg 1060.3 max 1639.7 stddev 475.2 (22 samples)
Reply time [ms]: response 56.3 transfer 0.0
Reply size [B]: header 267.0 content 18.0 footer 0.0 (total 285.0)
Reply status: 1xx=0 2xx=xx=0 4xx=0 5xx=0
CPU time [s]: user 9.68 system 101.72 (user 8.7% system 91.3% total 100.0%)
Net I/O: 467.5 KB/s (3.8*10^6 bps)
1234567891011121314151617
Total: connections 117557 requests 219121 replies 116697 test-duration 111.423 s&Connection rate: 1055.0 conn/s (0.9 ms/conn, &=1022 concurrent connections)Connection time [ms]: min 0.3 avg 865.9 max 7912.5 median 459.5 stddev 993.1Connection time [ms]: connect 31.1Connection length [replies/conn]: 1.000&Request rate: 1966.6 req/s (0.5 ms/req)Request size [B]: 91.0&Reply rate [replies/s]: min 59.4 avg 1060.3 max 1639.7 stddev 475.2 (22 samples)Reply time [ms]: response 56.3 transfer 0.0Reply size [B]: header 267.0 content 18.0 footer 0.0 (total 285.0)Reply status: 1xx=0 2xx=116697 3xx=0 4xx=0 5xx=0&CPU time [s]: user 9.68 system 101.72 (user 8.7% system 91.3% total 100.0%)Net I/O: 467.5 KB/s (3.8*10^6 bps)
最终,我使用这些设置达到了每秒 6,622 个连接:
httperf --hog --server 192.168.122.10 --num-conn 100000 --ra 20000 --timeout 5
httperf --hog --server 192.168.122.10 --num-conn 100000 --ra 20000 --timeout 5
(总共创建了 100,000 个连接,并且以每秒 20,000 个连接的固定速率创建)
它还有一些潜在的优势,并且拥有比‘ab‘更多的特性。但它不是我要用在这个项目里的重量级工具。我需要的是能够支持分布式多负载测试节点的工具。因此,我的下一个尝试是:Jmeter。
Apache Jmeter
这是一个功能齐全的 web 应用测试套件,它可以模拟真实用户的所有行为。你可以使用 Jmeter 的代理去访问你的网站,进行点击、登陆、模仿用户可以做的所有行为。Jemeter 会把这些行为记录下来作为测试用例。然后 Jmeter 会反复执行这些动作来模拟你想要的用户数量。尽管 Jmeter 比 ‘ab‘ 和 ’httperf‘ 复杂得多,但它是一个很有趣的工具!
根据我的测试,它每秒可以产生 14,000 个请求!这绝对是一个好的进展。
上的一些插件,并且使用它们的“Stepping Threads”和“HTTP RAW”请求,最终每秒大约可以产生 30,000 个请求!但这已经达到极限了,所以还要寻找另一个工具。这里有一个我之前的,希望可以帮助到其他人。虽然这个配置离完美相差甚远,但有时它可以满足你的要求。
Tsung: 重型的(heavy-duty)、分布式的、多协议测试工具
它每秒基本可以产生 40,000 个请求,这绝对是我们想要的工具。类似于 Jmeter,你可以把一些行为记录下来在测试时运行,并且可以测试大多数的协议。比如 SSL、HHTP、WebDAV、SOAP、PostgreSQL、MySQL、LDAP 和 Jabber/XMPP。与 Jmeter 不同的是,它没有让人感到迷茫的 GUI 设置,它仅有一个 XML 配置文件,和一些你选择的分布式节点的 SSH 密钥。它的简洁和效率对我的吸引力,完全不亚于它的健壮性和可扩展性。我发现它是一个很强大的工具,在正确的配置下它可以每秒产生百万级的 HTTP 请求。
除此之外,Tsung 还可以在 html 上产生图表以及输入你的测试的详细报告。测试的结果通俗易懂,并且你甚至可以把这些图片展示给你的 boss 看!
在这个系列文章的剩余部分,我还会讲解这个工具。现在你可以继续浏览下面的配置说明,或者直接跳到下一页。
在 CentOS 6.2 上安装 Tsung
首先,你要安装(Erlang 需要的) EPEL 源。因此,在进行下一步之前要把它安装好。安装完后,继续安装你用来产生负载的每个节点需要的包。如果你还没有在节点之间建立无密码 SSH 密钥(passwordless SSH key),那么请建立之。
yum -y install erlang perl perl-RRD-Simple.noarch perl-Log-Log4perl-RRDs.noarch gnuplot perl-Template-Toolkit firefox
yum -y install erlang perl perl-RRD-Simple.noarch perl-Log-Log4perl-RRDs.noarch gnuplot perl-Template-Toolkit firefox
从 Github 或者 Tsung 的官网上下载最新的 Tsung。
wget http://tsung.erlang-projects.org/dist/tsung-1.4.2.tar.gz
wget http://tsung.erlang-projects.org/dist/tsung-1.4.2.tar.gz
解压并且编译。
tsung-1.4.2.tar.gz
cd tsung-1.4.2
./configure && make && make install
tar zxfv&&tsung-1.4.2.tar.gzcd tsung-1.4.2./configure && make && make install
把示例配置复制到 ~/.tsung 目录里。这是 Tsung 的配置文件和日志文件的存放地方。
/usr/share/doc/tsung/examples/http_simple.xml /root/.tsung/tsung.xml
cp&&/usr/share/doc/tsung/examples/http_simple.xml /root/.tsung/tsung.xml
你可以根据你的需求去编辑这个配置文件,或者使用我的配置文件。经过大量的尝试以及失败后,我目前的配置文件在使用 7 个分布式节点时可以每秒产生 5 百万个 HTTP 请求。
&?xml version=&1.0&?&
&!DOCTYPE tsung SYSTEM &/usr/share/tsung/tsung-1.0.dtd&&
&tsung loglevel=&notice& version=&1.0&&
&client host=&localhost& weight=&1& cpu=&10& maxusers=&40000&&
&ip value=&192.168.122.2&/&
&client host=&loadnode1& weight=&1& cpu=&9& maxusers=&40000&&
&ip value=&192.168.122.2&/&
&client host=&loadnode2& weight=&1& maxusers=&40000& cpu=&8&&
&ip value=&192.168.122.3&/&
&client host=&loadnode3& weight=&1& maxusers=&40000& cpu=&9&&
&ip value=&192.168.122.21&/&
&client host=&loadnode4& weight=&1& maxusers=&40000& cpu=&9&&
&ip value=&192.168.122.11&/&
&client host=&loadnode5& weight=&1& maxusers=&40000& cpu=&9&&
&ip value=&192.168.122.12&/&
&client host=&loadnode6& weight=&1& maxusers=&40000& cpu=&9&&
&ip value=&192.168.122.13&/&
&client host=&loadnode7& weight=&1& maxusers=&40000& cpu=&9&&
&ip value=&192.168.122.14&/&
&/clients&
&server host=&192.168.122.10& port=&80& type=&tcp&/&
&/servers&
&arrivalphase phase=&1& duration=&10& unit=&minute&&
&users maxnumber=&15000& arrivalrate=&8& unit=&second&/&
&/arrivalphase&
&arrivalphase phase=&2& duration=&10& unit=&minute&&
&users maxnumber=&15000& arrivalrate=&8& unit=&second&/&
&/arrivalphase&
&arrivalphase phase=&3& duration=&30& unit=&minute&&
&users maxnumber=&20000& arrivalrate=&3& unit=&second&/&
&/arrivalphase&
&sessions&
&session probability=&100& name=&ab& type=&ts_http&&
&for from=&1& to=&& var=&i&&
&request& &http url=&/test.txt& method=&GET& version=&1.1&/& &/request&
&/session&
&/sessions&
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
<?xml version="1.0"?><!DOCTYPE tsung SYSTEM "/usr/share/tsung/tsung-1.0.dtd"><tsung loglevel="notice" version="1.0">&<clients><client host="localhost" weight="1" cpu="10" maxusers="40000"><ip value="192.168.122.2"/></client><client host="loadnode1" weight="1" cpu="9" maxusers="40000"><ip value="192.168.122.2"/></client><client host="loadnode2" weight="1" maxusers="40000" cpu="8"><ip value="192.168.122.3"/></client><client host="loadnode3" weight="1" maxusers="40000" cpu="9"><ip value="192.168.122.21"/></client><client host="loadnode4" weight="1" maxusers="40000" cpu="9"><ip value="192.168.122.11"/></client><client host="loadnode5" weight="1" maxusers="40000" cpu="9"><ip value="192.168.122.12"/></client><client host="loadnode6" weight="1" maxusers="40000" cpu="9"><ip value="192.168.122.13"/></client><client host="loadnode7" weight="1" maxusers="40000" cpu="9"><ip value="192.168.122.14"/></client></clients>&<servers><server host="192.168.122.10" port="80" type="tcp"/></servers>&<load><arrivalphase phase="1" duration="10" unit="minute"><users maxnumber="15000" arrivalrate="8" unit="second"/></arrivalphase>&<arrivalphase phase="2" duration="10" unit="minute"><users maxnumber="15000" arrivalrate="8" unit="second"/></arrivalphase>&<arrivalphase phase="3" duration="30" unit="minute"><users maxnumber="20000" arrivalrate="3" unit="second"/></arrivalphase>&</load>&<sessions><session probability="100" name="ab" type="ts_http"><for from="1" to="" var="i"><request> <http url="/test.txt" method="GET" version="1.1"/> </request></for></session></sessions></tsung>
刚开始的时候有很多东西要理解,但你一旦理解了它们后就会变得很简单。
&client& 只是简单地指定了运行 Tsung 的主机。你可以指定 Tsung 使用的 IP 和 CPU 的最大数。你可以使用 maxusers 设置节点能够模拟的用户数量上限。每一个用户都会执行我们之后定义的操作。
&servers& 指定了你要测试的 HTTP 服务器。我们可以使用这个选项去测试一个 IP 集群,或者一个单一的服务器。
&load& 定义了我们的模拟用户将会在什么时候“到达”我们的网站。以及它们达到的有多快。
&arrivalphase& 在持续了 10 分钟的第一个阶段里,以 每秒 8 个用户的速率到达了 15,000 个用户。
&arrivalphase phase=”1″ duration=”10″ unit=”minute”&
&users maxnumber=”15000″ arrivalrate=”8″ unit=”second”/&
这里还有两个 arrivalphases,它们的用户都以同样的方式达到。
这些 arrivalphases 一起组成了一个 &load&,它控制了我们可以每秒产生多少个请求。
&session& 这部分定义了一旦这些用户达到了你的网站,它们将会执行什么动作。
probability 允许你定义用户可能会做的随机事件。有时他们可能点击这里,有时他们可能点击那里。所有的Probability 加起来一定要等于 100% 。
在上面的配置里,用户只做一件事,所以它的 probability 等于 100% 。
&for from=”1″ to=”″ var=”i”& 这就是用户在 100% 的时间里做的事情。它们循环遍历 10,000,000 次并且 &request& 一个网页:/test.txt 。
这个循环结构允许我们使用少量的用户连接去获取比较大的每秒请求数量。
一旦你已经很好地理解了它们,你就可以创建一个便利的别名,去快速观察 Tsung 报告。
vim ~/.bashrc
alias treport="/usr/lib/tsung/bin/tsung_stats. firefox report.html"
vim ~/.bashrcalias treport="/usr/lib/tsung/bin/tsung_stats. firefox report.html"
source ~/.bashrc
source ~/.bashrc
然后启动 Tsung
[root@loadnode1 ~] tsung start
Starting Tsung
"Log directory is: /root/.tsung/log/4"
[root@loadnode1 ~] tsung startStarting Tsung"Log directory is: /root/.tsung/log/4"
结束后观察报告
cd /root/.tsung/log/4
cd /root/.tsung/log/-1004treport
使用 Tsung 去规划你的集群构造
现在我们拥有了一个足够强大的负载测试工具,我们可以规划余下的集群构造了:
1. 使用 Tsung 去测试一个单一的 HTTP 服务器。获取一个基本的基准。
2. 对 web 服务器进行调优,定期使用 Tsung 进行测试提高性能。
3. 对这些系统的 TCP 套接字进行调优,获取最佳的网络性能。再来一次,测试,测试,不停地测试。
4. 构造 LVS 集群,它包含了这些充分调优过的 web 服务器。
5. 使用 Tsung IP 集群对 LVS 进行压力测试。
在之后的两篇文章里,我将会向你展示如何使你的 web 服务器获取最高性能,以及怎样用 LVS 集群软件把它们整合起来。
关于作者:
可能感兴趣的话题
好文章点赞,为嘛我点不了赞
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2018 伯乐在线

我要回帖

更多关于 如何减少http请求 的文章

 

随机推荐