libev / libuv / python tornado / nginx 性能比较
来源:互联网 发布:wps mac 编辑:程序博客网 时间:2024/06/07 10:25
libev / libuv / python tornado / nginx 性能比较
最近项目要找一款web 框架,性能是一个很大的指标,在选型的同时,做了一些性能比较,现将测试代码和比较结果和大家分享一下。
说到web 框架,很多人会想到tomcat、jetty,基于java的最常用的两种web server,其性能无法与nginx相比较,在此略过
测试环境:
cpu:2.0G HZ
VMware 虚拟机
nginx
一个worker进程
ab命令:ab -c 500 -n 100000 http://10.10.73.210:80/index.html
qps:11002
我测试的机器是一台VMware 虚拟机,所以性能或许会稍差一些,不过即便如此,qps也能达到万级以上。
python tornado
tornado,在python领域,一直以来tornado的性能都被十分看好,之所以把tornado也纳入备选方案,主要从python的开发效率角度出发
测试代码如下:
import os.pathimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport sysclass MainHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): print("one test client come") self.write("Hello, world shen") self.finish()application = tornado.web.Application([ (r"/", MainHandler),])if __name__ == "__main__": port = sys.argv[1] print port application.listen(port) tornado.ioloop.IOLoop.instance().start()
ab命令:ab -c 100 -n 10000 http://10.10.73.210:6600/helloworld
qps大约在:1158
通过测试可以发现,虽说tornado性能不错,不过和nginx相比,还是差了许多
由于nginx是基于libevent,设想,如果自己单独开发一套tcp server,其性能会达到多少,当然针对tcp server的选型,epoll是首选,不过开发起来实在麻烦,libevent替代产品主要有libev 和libuv,其性能测试如下:
libev
#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/queue.h>#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>#include <math.h>#include <netinet/in.h>#include <time.h>#include <unistd.h>#include <sys/resource.h>#include <sys/time.h>#include "ev.h"#define BACKLOG 512#define LSN_PORT 8090#define BUFFER_SIZE 1024static size_tg_ses_count;typedef struct ses_t {// self infosize_t sid;}ses_t;int create_listen_fd() {// create user listen socket fdint listen_fd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listen_fd) { printf("create socket failed"); return -1;} int yes = 1;int ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); if (-1 == ret) { printf("set socket opt SO_REUSEADDR failed"); return -1; }struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(struct sockaddr_in)); server_addr.sin_family= AF_INET;// host byte orderserver_addr.sin_port= htons(LSN_PORT);// short, network byte order server_addr.sin_addr.s_addr = INADDR_ANY;// automatically fill with my IP memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero)); ret = bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret) { printf("bind failed"); return -1;} ret = listen(listen_fd, BACKLOG); if (-1 == ret) { printf("listen failed"); return -1;} return listen_fd;}void close_ses(struct ev_loop *loop, struct ev_io *watcher, ses_t * ses) {if (watcher->fd > 0) {close(watcher->fd);}// free watcherif (watcher) {ev_io_stop(loop, watcher);free(watcher);}free(ses);}void user_cb_test(struct ev_loop *loop, struct ev_io *watcher, int revents) {ses_t * ses = (ses_t *)watcher->data; if(EV_ERROR & revents) { printf("[%lu]: error event in user_cb", ses->sid); return ; }if (EV_READ & revents) {ssize_t buf_tmp_len = 0;charbuf_tmp[BUFFER_SIZE] = {0};buf_tmp_len = recv(watcher->fd, buf_tmp, BUFFER_SIZE, 0);if(buf_tmp_len <= 0) {printf("[%lu]: recv error, will close ses", ses->sid);close_ses(loop, watcher, ses);return;}printf("%s", buf_tmp);if (strstr((char *)buf_tmp, "\r\n\r\n")) {#if 0int i = 0;int c = 0;for (i = 0; i <= 1000000; i++) {int a = 0;int b = 1;c = a + b + i;}printf("[%lu][%d]: new user has came\n", ses->sid, c);#endifchar * resp = "HTTP/1.1 200 OK\r\n\Server: nginx/1.9.3\r\n\Date: Thu, 13 Aug 2015 03:04:20 GMT\r\n\Content-Type: text/plain\r\n\Content-Length: 17\r\n\Connection: keep-alive\r\n\r\n\hello_world, shen";send(watcher->fd, resp, strlen(resp), 0);close_ses(loop, watcher, ses);return;}}if (EV_WRITE & revents) {// ad_rp_send_data_to_user(ses);}return;}void accept_cb_test(struct ev_loop *loop, struct ev_io *watcher, int revents) { if(EV_ERROR & revents) { printf("error event in accept_cb_test"); return; } struct sockaddr_in user_addr;memset(&user_addr, 0, sizeof(struct sockaddr_in)); socklen_t user_len = sizeof(user_addr); int user_fd = accept(watcher->fd, (struct sockaddr*)&user_addr, &user_len); if(user_fd < 0) { printf("accept return error"); return; }int flags = fcntl(user_fd, F_GETFL, NULL);if (flags == -1) {printf("failed in fcntl");return;}flags |= O_NONBLOCK;if (fcntl(user_fd, F_SETFL, flags) == -1) {printf("failed in fcntl");return;}struct ev_io * user_w = (struct ev_io*)calloc(1, sizeof(struct ev_io));ses_t * new_ses = calloc(1, sizeof(ses_t));new_ses->sid= g_ses_count++;user_w->data= new_ses;ev_io_init(user_w, user_cb_test, user_fd, EV_READ);ev_io_start(loop, user_w);printf("new user accept\n");return;}int main(int argc, char *argv[]) {printf("=========main start=============\n"); struct ev_loop *loop = ev_default_loop(0);int listen_fd = create_listen_fd();if (listen_fd < 0) {printf("failed in create user listen fd");return -1;}struct ev_io lst_w; ev_io_init(&lst_w, accept_cb_test, listen_fd, EV_READ); ev_io_start(loop, &lst_w);ev_run(loop, 0);return 1;}
ab命令:ab -c 500 -n 100000 http://10.10.73.210:8090/helloworld
qps:15960
libuv
#include "uv.h"#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct { uv_write_t req; uv_buf_t buf;} write_req_t;static uv_tcp_t tcpServer;static uv_loop_t* loop;static uv_handle_t* server;static void echo_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {printf("echo alloc called, size[%d]\n", suggested_size); buf->base = malloc(suggested_size); buf->len = suggested_size;}static void after_write(uv_write_t* req, int status) { write_req_t* wr; /* Free the read/write buffer and the request */ wr = (write_req_t*) req; // free(wr->buf.base); free(wr); printf("after_write is called\n"); if (status == 0) return; fprintf(stderr, "uv_write error: %s - %s\n", uv_err_name(status), uv_strerror(status));}static void on_close(uv_handle_t* peer) { free(peer);}static void after_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { int i; write_req_t *wr; uv_shutdown_t* sreq; free(buf->base); printf("1111---after_read is called\n"); if (nread == UV_EOF) { printf("22222---after_read is called\n"); return; } printf("3333---after_read is called\n");char * resp = "HTTP/1.1 200 OK\r\n\Server: nginx/1.9.3\r\n\Date: Thu, 13 Aug 2015 03:04:20 GMT\r\n\Content-Type: text/plain\r\n\Content-Length: 17\r\n\Connection: keep-alive\r\n\r\n\hello_world, shen"; wr = (write_req_t*) malloc(sizeof *wr); wr->buf = uv_buf_init(resp, strlen(resp)); if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { printf("uv_write failed\n"); }printf("4444---after_read is called\n"); uv_close((uv_handle_t*)handle, on_close);}static void on_connection(uv_stream_t* server, int status) { uv_stream_t* stream; int r; if (status != 0) { fprintf(stderr, "Connect error %s\n", uv_err_name(status)); }stream = malloc(sizeof(uv_tcp_t));r = uv_tcp_init(loop, (uv_tcp_t*)stream); /* associate server with stream */ stream->data = server; r = uv_accept(server, stream); r = uv_read_start(stream, echo_alloc, after_read);}int main() {loop = uv_default_loop();struct sockaddr_in addr; int r; int port = 7700; uv_ip4_addr("0.0.0.0", port, &addr); server = (uv_handle_t*)&tcpServer; r = uv_tcp_init(loop, &tcpServer); if (r) { /* TODO: Error codes */ fprintf(stderr, "Socket creation error\n"); return 1; } r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0); if (r) { /* TODO: Error codes */ fprintf(stderr, "Bind error\n"); return 1; } r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection); if (r) { /* TODO: Error codes */ fprintf(stderr, "Listen error %s\n", uv_err_name(r)); return 1; }printf("start loop\n");uv_run(loop, UV_RUN_DEFAULT); return 0;}ab命令:ab -c 500 -n 100000 http://10.10.73.210:7700/helloworld
qps:15879
结论
qps比较:libev(15960) > libuv(15879) > nginx(11002) > tornado(1158)
1、前三个性能不相上下,nginx略差也不能说明问题,毕竟nginx其处理流程会稍微复杂些(从消息进入到消息返回,会经过若干个module)
2、tornado版本:version 4.1,750+ qps。version 3.2,1100+ qps,版本3.2 要比 4.1 性能略好。
- libev / libuv / python tornado / nginx 性能比较
- libevent/libev/libuv/redisev比较
- libuv 与 libev 的对比
- libuv 与 libev 的对比
- libuv 与 libev 的对比
- libuv与libev的对比
- libev和libuv的区别
- libuv和libev的区别
- Libev和Libuv的区别
- libuv 和 libev的对比
- python+Tornado + Supervisor + nginx部署
- python+Tornado + Supervisor + nginx部署
- python+Tornado + Supervisor + nginx部署
- python+Tornado + Supervisor + nginx部署
- thinkphp 与 tornado 性能测试比较
- 库-libuv 和 libev的对比
- 网络库libevent、libev、libuv对比
- 网络库libevent、libev、libuv对比
- Java之网络爬虫WebCollector+selenium+phantomjs(三)
- 通过js实现编辑功能ruby on rails 弹出层
- 关于Javascript中执行上下文的理解
- IOS——UITextField自动适应键盘弹出
- 分段OTSU处理图像数据
- libev / libuv / python tornado / nginx 性能比较
- bat 截取字符
- JAVA多线程实现的三种方式
- Ubuntu14.04 安装配置Opencv3.0和Python2.7
- Spring AOP 实现原理
- c++学习笔记(十五):函数指针
- Android-Universal-Image-Loader三大组件DisplayImageOptions、ImageLoader、ImageLoaderConfiguration详解
- vs2013使用git代码
- 菜鸟去实习——在500强互联网部门做前端