=== 测试环境 ===
192.168.8.161 测试发起服务器 192.168.8.91 被测试Linux服务器 192.168.8.8 被测试Windows服务器
其中被测试机器的配置一样
=== 测试类型 ===
192.168.8.8:9000 Windows+IIS+Asp.net
使用asp.net技术,写了一个Handler.ashx,内容如下:
<%@ WebHandler Language="C#" Class="Handler" %>
using System;
using System.Web;
public class Handler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable {
get {
return false;
}
}
}
192.168.8.91:1337 Linux+Nodejs
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(9702, '127.0.0.1');
console.log('Server running at http://127.0.0.1:9702/');
192.168.8.91:1338 Linux+Nodejs+Express+Cluster
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
});
app.listen(1338);
console.log('listen on 1338');
}
192.168.8.91:1339 Linux+Nodejs+Cluster
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1339, '192.168.8.161');
console.log('Server running at http://127.0.0.1:1339/');
}
192.168.8.91:1340 Ubuntu+Proxygen
DEFINE_int32(http_port, 11000, "Port to listen on with HTTP protocol");
DEFINE_int32(spdy_port, 11001, "Port to listen on with SPDY protocol");
DEFINE_string(ip, "localhost", "IP/Hostname to bind to");
DEFINE_int32(threads, 0, "Number of threads to listen on. Numbers <= 0 "
"will use the number of cores on this machine.");
class EchoHandlerFactory : public RequestHandlerFactory {
public:
void onServerStart() noexcept override {
stats_.reset(new EchoStats);
}
void onServerStop() noexcept override {
stats_.reset();
}
RequestHandler* onRequest(RequestHandler*, HTTPMessage*) noexcept override {
return new EchoHandler(stats_.get());
}
private:
folly::ThreadLocalPtr<EchoStats> stats_;
};
int main(int argc, char* argv[]) {
std::vector<HTTPServer::IPConfig> IPs = {
{SocketAddress(FLAGS_ip, FLAGS_http_port, true), Protocol::HTTP},
{SocketAddress(FLAGS_ip, FLAGS_spdy_port, true), Protocol::SPDY},
};
if (FLAGS_threads <= 0) {
FLAGS_threads = sysconf(_SC_NPROCESSORS_ONLN);
CHECK(FLAGS_threads > 0);
}
HTTPServerOptions options;
options.threads = static_cast<size_t>(FLAGS_threads);
options.idleTimeout = std::chrono::milliseconds(60000);
options.shutdownOn = {SIGINT, SIGTERM};
options.handlerFactories = RequestHandlerChain()
.addThen<EchoHandlerFactory>()
.build();
HTTPServer server(std::move(options));
server.bind(IPs);
// Start HTTPServer mainloop in a separate thread
std::thread t([&] () {
server.start();
});
t.join();
return 0;
}
Ubuntu+apache+mod
/* Include the required headers from httpd */
#include "httpd.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_request.h"
/* Define prototypes of our functions in this module */
static void register_hooks(apr_pool_t *pool);
static int example_handler(request_rec *r);
/* Define our module as an entity and assign a function for registering hooks */
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
NULL, // Per-directory configuration handler
NULL, // Merge handler for per-directory configurations
NULL, // Per-server configuration handler
NULL, // Merge handler for per-server configurations
NULL, // Any directives we may have for httpd
register_hooks // Our hook registering function
};
/* register_hooks: Adds a hook to the httpd process */
static void register_hooks(apr_pool_t *pool)
{
/* Hook the request handler */
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
/* The handler function for our module.
* This is where all the fun happens!
*/
static int example_handler(request_rec *r)
{
/* First off, we need to check if this is a call for the "example" handler.
* If it is, we accept it and do our things, it not, we simply return DECLINED,
* and Apache will try somewhere else.
*/
if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED);
// The first thing we will do is write a simple "Hello, world!" back to the client.
ap_rputs("Hello, world!<br/>", r);
return OK;
}
=== 测试结果 ===
测试方法1:ab -r -c [10000 1000 100] -n 100000 http://xxx
16core+8G
类型 | RPS(c=10000) | RPS(c=1000) | RPS(c=100) | |||||
Windows+IIS+Asp.net | 6770.54 | 9996.72 | 10381.01 | |||||
CentOS+Nodejs | X | 6036.13 | 6641.44 | |||||
CentOS+Nodejs+Express+Cluster | 4354.29 | 12757.53 | 11832.70 | |||||
CentOS+Nodejs+Cluster | 5214.44 | 12170.55 | 12501.20 | |||||
CentOS+DE | 2330.63 | 14022.68 | 13397.61 | |||||
CentOS+Nodejs+Dsp | 4945.00 | 6772.59 | 7157.34 |
4core+4G
类型 | RPS(c=10000) | RPS(c=1000) | RPS(c=100) | |||||
Ubuntu+Nodejs+Express+Cluster | 4157.49 | 6920.84 | 8935.38 | |||||
Ubuntu+Proxygen | 3272.74 | 9051.58 | 7332.77 | |||||
Ubuntu+Apache+Mod | 3272.74 | 9176.34 | 10618.78 | |||||
Ubuntu+Nodejs+Dsp(POST) | 3436.93 | 6231.99 | 6676.61 |