<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    京山游俠

    專注技術,拒絕扯淡
    posts - 50, comments - 868, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    Web 2.0時代,決戰效率之巔

    Posted on 2009-04-18 22:17 京山游俠 閱讀(3876) 評論(9)  編輯  收藏 所屬分類: Linux和Java
    在這個博客上晃悠的,大部分都是Java的忠實粉絲。大家都知道Java開發Web應用的眾多優點,有大量開源的穩定的應用服務器,有大量開源的穩定的開發庫。以前在開發效率上Java比不上動態語言,但是現在出現了數都數不清的開發框架,讓我們使用Java進行Web開發的效率突飛猛進,直逼動態語言。

    然而在Web 2.0時代,Java一定是最優秀的嗎?

    在Web 2.0時代,大家都有點在效率方面的偏執,不斷有人在挑戰極限,他們追求更大的并發鏈接數,他們追求更加快的處理速度。操作系統覺得select不夠快,于是出現了IOCP、epoll、kqueue等系統調用;Web服務器的開發者們覺得Apache httpd不夠快,于是出現了lighttpd、nginx。使用上Fedora 10之后,我就不斷用yum list命令企圖發現一些驚奇。在這樣的探索中,我發現了Fedora 10中安裝lighttpd和nginx是多么簡單,也發現使用Fast CGI開發也是那么順手。下圖中是我用yum list命令發現的一些軟件包
    yum_list.png


    于是,在我的心中出現了一個疑問:httpd、lighttpd、nginx、tomcat哪一個更快呢?

    我使用PHP寫了一個小程序,以便測試上面的Web服務器哪一個更快,tomcat是Java的服務器,不能運行PHP,只能運行JSP。我的程序是這樣設計的:先生成1個長度為1000個單詞、每個單詞長度為1-10個字母的字符串,再生成1000個長度為10個單詞、每個單詞長度為1-10個字母的字符串,然后對這些字符串排序,輸出。為什么這么設計呢?因為我覺得這比較接近Web 2.0的真實使用環境,一個1000字長度的文章加上1000個10字長度的評論,這不是我們最常見的嗎?而且這個程序中會多次調用rand()函數,會多次進行字符串連接操作,會對字符串進行排序,這些操作對語言的執行速度也是一個考驗。

    先來看代碼,test.php:
    <?php
    ??
    //?定義隨機生成字符串的函數
    ??function?make_string($word_count,$word_length){
    ????
    $letters?=?range('a','z');
    ??????
    $temp_string?=?'';
    ??????
    for($i=0;?$i<$word_count;?$i++){
    ????????
    $temp_word?=?'';
    ????????
    for($j=0;?$j<$word_length;?$j++){
    ??????????????
    $temp_word?=?$temp_word.$letters[rand(0,25)];
    ????????}
    ????????
    $temp_string?=?$temp_string.'?'.$temp_word;
    ??????}
    ??????
    return?$temp_string;
    ??}
    ??
    ??
    //?定義隨機數種子,以便每次運行測試,都生成相同的內容
    ??srand(1);
    ??
    ??
    //?首先生成一個包含一千個單詞的字符串,每個單詞長度為1到10個字母
    ??$strings[0]?=?make_string(1000,rand(1,10));
    ??
    ??
    //?再生成1000個包含10個單詞的字符串,每個單詞的長度為1到10個字母
    ??for($i=0;?$i<1000;?$i?++){
    ??????
    $strings[$i+1]?=?make_string(10,rand(1,10));
    ??}
    ??
    ??
    //?排序,輸出
    ??sort($strings);
    ??
    for($i=0;?$i<1001;?$i++){
    ????
    echo?$strings[$i].'<br><br>';
    ??}
    ?>

    執行情況如何呢?先讓大家看三個圖。這是我分別使用httpd、lighttpd、nginx做為服務器時,使用
    ab?-c?100?-n?10000?http://localhost/test.php
    命令進行測試所得到的結果:
    015.png

    006.png

    009.png

    其中,httpd是以mod_php的方式運行PHP,而其它兩個用的是FastCGI的方式運行PHP。從速度上來講,httpd略占優勢。但是httpd占用的資源太多,而且很難支持大的并發連接數。當并發數增加到1000的時候,httpd就反應不過來了,出現超時;而lighttpd和nginx都可以輕松支持到30000的并發。注意,如果使用超過1000的并發來進行測試,千萬別忘了使用ulimit命令來設置進程可以打開的最大文件數。

    到了這里我就想,如果使用C++編寫Fast CGI程序,運行的速度是不是更快呢。使用Java呢?于是我用C++和Java分別實現了和上面功能相同的程序。代碼如下:
    #include?<fcgi_config.h>
    #include?
    <unistd.h>
    #include?
    <cstdlib>
    #include?
    <string>
    #include?
    <vector>
    #include?
    <algorithm>
    #include?
    <fcgi_stdio.h>?/*?fcgi?library;?put?it?first*/

    using?namespace?std;

    string?make_string(int?word_count,int?word_length){
    ????
    char?letters[]?=?"abcdefghijklmnopqrstuvwxyz";
    ????
    string?temp_string;
    ????
    for?(int?i?=?0;?i?<?word_count;?i++)?{
    ????????
    string?temp_word;
    ????????
    for?(int?j?=?0;?j?<?word_length;?j++)?{
    ????????????
    int?index?=?rand()?%?26;
    ????????????temp_word.append(
    1,?letters[index]);
    ????????}
    ????????temp_string.append(
    "?");
    ????????temp_string.append(temp_word);
    ????}
    ????
    return?temp_string;
    }

    int?main?()
    {
    ????
    while?(FCGI_Accept()?>=?0)?{

    ????????
    char?*contentLength?=?getenv("CONTENT_LENGTH");
    ????????
    int?len;

    ????????printf(
    "Content-type:?text/html\r\n"
    ????????????
    "\r\n");

    ????????
    if?(contentLength?!=?NULL)?{
    ????????????len?
    =?strtol(contentLength,?NULL,?10);
    ????????}?
    else?{
    ????????????len?
    =?0;
    ????????}

    ????????
    if?(len?<=?0)?{
    ????????????printf(
    "No?data?from?standard?input.<p>\n");
    ????????}?
    else?{
    ????????????
    int?i,?ch;

    ????????????printf(
    "Standard?input:<br>\n<pre>\n");
    ????????????
    for?(i?=?0;?i?<?len;?i++)?{
    ????????????????
    if?((ch?=?getchar())?<?0)?{
    ????????????????????printf(
    ????????????????????????????
    "Error:?Not?enough?bytes?received?on?standard?input<p>\n");
    ????????????????????
    break;
    ????????????????}
    ????????????????putchar(ch);
    ????????????}
    ????????????printf(
    "\n</pre><p>\n");
    ????????}

    ????????vector
    <string>?strings;
    ????????strings.push_back(make_string(
    1000,?rand()?%?10?+?1));
    ????????
    for?(int?i?=?0;?i?<?1000;?i++)?{
    ????????????strings.push_back(make_string(
    10,?rand()?%?10?+?1));
    ????????}

    ????????sort(strings.begin(),?strings.end());

    ????????
    for?(vector<string>::iterator?it?=?strings.begin();?it?!=?strings.end();?it++)?{
    ????????????printf(
    "%s<br><br>",?(*it).c_str());
    ????????????printf(
    "\r\n");
    ????????}

    ????}?
    /*?while?*/

    ????
    return?0;
    }

    JSP:
    <%@?page?language="java"?contentType="text/html;?charset=UTF-8"
    ????pageEncoding
    ="UTF-8"%>
    <%@?page?import="java.util.Random"?%>
    <%@?page?import="java.util.Arrays"?%>
    <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN"?"http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta?http-equiv="Content-Type"?content="text/html;?charset=UTF-8">
    <title>Insert?title?here</title>
    </head>
    <body>
    <%!
    public?String?make_string?(?int?word_count,int?word_length)?{
    ????Random?rand?
    =?new?Random();
    ????
    char?letters[]?=?"abcdefghijklmnopqrstuvwxyz".toCharArray();
    ????String?temp_string?
    =?"";
    ????
    for?(int?i?=?0;?i?<?word_count;?i++)?{
    ????????String?temp_word?
    =?"";
    ????????
    for?(int?j?=?0;?j?<?word_length;?j++)?{
    ????????????
    int?index?=?rand.nextInt(26);
    ????????????temp_word?
    +=?Character.toString(letters[index]);
    ????????}
    ????????temp_string?
    +=?"?";
    ????????temp_string?
    +=?temp_word;
    ????}
    ????
    return?temp_string;
    }
    %>
    <%
    Random?rand?
    =?new?Random();

    String[]?strings?
    =?new?String[1001];
    strings[
    0]?=?make_string(1000,rand.nextInt(10)+1);
    for(int?i=1;?i<1001;?i++){
    ????strings[i]?
    =?make_string(10,rand.nextInt(10)+1);
    }
    Arrays.sort(strings);

    for(int?i=0;?i<1001;?i++){
    %>
    <%=strings[i]%><br><br>
    <%
    }

    %>
    </body>
    </html>

    這時候,我使用lighttpd作為服務器運行PHP和Fast CGI,使用Tomcat運行JSP,得到如下的測試結果:

    先看JSP,我使用的測試命令是ab -c 100 -n 10000 http://localhost:8080/test.jsp,測試的結果只有29.30req/s,如下圖
    java_result.png
    這個時候的資源占用是多少呢,請看top命令的截圖:
    java_top.png
    java進程只占用了470兆的內存,CPU基本占滿了,那是因為我寫的這個程序對CPU使用比較高。

    再來看看PHP執行的情況,測試命令為ab -c 100 -n 10000 http://localhost/test.php,測試結果有48.73req/s,如下圖:
    php_result.png

    資源占用有多少呢,再來看看top命令的截圖
    php_top.png

    每個php-cgi進程用4M內存,lighttpd服務器占用5M內存,而我的機器上跑了72個php-cgi進程,如下圖:

    php_procs.png

    總內存占用293M,CPU占用也比較高。

    使用C++寫的Fast CGI,測試命令為ab -c 100 -n 10000 http://localhost/test.fcgi,結果為266.47req/s,是PHP的5倍多,是JSP的9倍。
    fcgi_result.png

    top截圖,發現C++寫的test.fcgi每個進程只占1M內存:
    fcgi_top.png

    總共有64個test.fcgi進程:

    fcgi_procs.png

    總內存占用只有79M,CPU占用也比較低,沒有達到滿載。

    討論:

    先來說說服務器,對于Web 2.0的應用來說,httpd基本上可以淘汰了,資源占用太高,支持不了上千的并發請求。lighttpd和nginx在FastCGI上的表現都很不錯,從性能上說,nginx似乎還要強一些,但是缺點就是文檔不完善,nginx需要lighttpd提供的spawn-fcgi程序來啟動Fast CGI進程,而且不知道對Fast CGI負載均衡的支持怎么樣,因為我在網上找了很久都沒有找到相關的文檔。而lighttpd的文檔就完善多了,雖然是英文的,但讀起來不難。我已經把lihgttpd的文檔都讀了一遍了,對于fastcgi.txt和performance.txt我還反復閱讀,這些文檔對于Fast CGI的配置和功能有不錯的描述。所以,如果選擇Web服務器,我的答案是lighttpd。

    再來說說編程語言。速度最快的無疑是C++,它是Java的9倍,是PHP的5倍。這里就有一點奇怪了,Java是編譯型語言,而PHP是解釋的,在我的測試中,沒有對PHP使用字節碼緩存,結果編譯型的語言居然跑不過解釋型的。有人也許會說,PHP開了70幾個進程,而Tomcat只有一個進程,但是不管怎么樣,CPU都是滿載的,就算多開幾個Tomcat進程,也不可能把一個CPU當兩個用。當然,躲開Tomcat進程對提高并發和提高穩定性肯定是有好處的。大家都知道,httpd可以通過mod_jk來和Tomcat服務器集成,而lighttpd沒有mod_jk,但是可以通過mod_proxy實現相同的功能,也就是讓lighttpd做前端服務器,把動態請求分別發送到后端的Tomcat,并實現負載均衡和緩存。

    上面的測試還有一個問題,那就是純代碼的測試,而在實際應用中,除了運行動態代碼,還有數據庫操作,數據庫操作也是非常費時間的。我在想,應該再寫一個測試代碼,就把上面生成的這1001個字符串寫入數據庫再取出,看看運行速度如何。

    C++雖然運行速度快,但是用來寫Web應用還是比較難的,我讀了FastCGI develep kit的源代碼,它只實現了很底層的功能:讀入環境變量,標準輸入輸出。很顯然,它對多字節字符支持是沒有的,所有對于網絡上千奇百怪的字符編碼,我們普通程序員是沒有辦法處理的。在Web開發領域,更缺少基于C++的頁面模板引擎、MVC引擎、IOC引擎、ORM引擎、SOA引擎,等等。如果有哪個高手立志于C++ Web開發,寫一個基于C++的超級牛B的框架,說不定可以創立一番大事業。

    PHP應該是個不錯的選擇,因為lighttpd的作者還有另外一個作品,那就是XCache,是用來緩存PHP的字節碼的,據說可以提高PHP的執行速度3-5倍。這么說來,PHP甚至可以達到和C++相同的性能。PHP也有不錯的開發框架Zend,PHP有豐富的庫可供使用。PHP是動態語言,寫起代碼來沒有Java死板。看來是不錯的選擇。

    Java也不錯,不過目前Java領域的應用服務器都很龐大,而且大部分都是基于Java語言開發出來的,比起C++開發的lihgttpd和nginx,性能自然是要差一點點。不過對于企業開發,Java依然是利器,正是因為應用服務器的存在,讓我們少考慮很多底層的細節,讓我們很方便開發分布式的應用,穩定的企業級應用。Java的庫和框架那也是如漫天繁星、數之不盡的。

    總之,具體怎么選擇,還是要看大家的,我已經有點迷茫了。

    評論

    # re: Web 2.0,決戰效率之巔  回復  更多評論   

    2009-04-18 22:56 by SearchFull
    怎么沒有寫完呢?

    # re: Web 2.0,決戰效率之巔  回復  更多評論   

    2009-04-19 13:24 by fireflyc
    這樣不公平吧?
    java有NIO的。你把tomcat的NIO開啟看看是效果如何的。我想你會驚訝的發現原來“IOCP、epoll、kqueue”可以不依賴操作系統的——Java的NIO。

    # re: Web 2.0,決戰效率之巔  回復  更多評論   

    2009-04-20 09:15 by r
    你java寫的不好,用StringBuilder

    # re: Web 2.0,決戰效率之巔[未登錄]  回復  更多評論   

    2009-04-20 10:05 by 海邊沫沫
    用StringBuffer就不公平了,因為PHP中也是用的字符串連接,大量創建消毀字符串對象是肯定的。只有c++最占便宜

    # re: Web 2.0時代,決戰效率之巔  回復  更多評論   

    2009-04-20 12:29 by 海邊沫沫
    最新測試結果:
    Tomcat開啟NIO后:28.33req/s
    JSP代碼改用StringBuffer后:193.05req/s

    根據樓上兩位的回復,我先是對開啟了Tomcat的NIO,結果發現性能基本沒有改變,理論上講NIO應該不可能一點性能提升都沒有的,有可能是Tomcat默認就已經開啟了NIO,不需要顯式配置。

    然后我優化了一下代碼,該用了StringBuffer,結果不得了,性能提升了5-6倍。和C++的性能以經很接近了。由此可見,在Java中創建對象開銷還是很高的。另外,我把Random rand = new Random()換了個地方,這樣每運行一次JSP只需要創建一個Random對象。

    請看截圖,上面一張是開啟NIO后的結果,下面一張是優化代碼后的結果。






    下面是優化后的代碼:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ page import="java.util.Random" %>
    <%@ page import="java.util.Arrays" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    <%!
    Random rand = new Random();
    public String make_string ( int word_count,int word_length) {

    char letters[] = "abcdefghijklmnopqrstuvwxyz".toCharArray();
    StringBuffer temp_string = new StringBuffer();
    for (int i = 0; i < word_count; i++) {
    StringBuffer temp_word = new StringBuffer();
    for (int j = 0; j < word_length; j++) {
    int index = rand.nextInt(26);
    temp_word.append(letters[index]);
    }
    temp_string.append(" ");
    temp_string.append(temp_word);
    }
    return temp_string.toString();
    }
    %>
    <%
    String[] strings = new String[1001];
    strings[0] = make_string(1000,rand.nextInt(10)+1);
    for(int i=1; i<1001; i++){
    strings[i] = make_string(10,rand.nextInt(10)+1);
    }
    Arrays.sort(strings);

    for(int i=0; i<1001; i++){
    %>
    <%=strings[i]%><br><br>
    <%
    }

    %>
    </body>
    </html>

    # re: Web 2.0時代,決戰效率之巔  回復  更多評論   

    2009-04-20 18:10 by 海邊沫沫
    下面再增加一個比較項目,那就是對靜態文件的響應速度。我把前面用PHP生成的頁面保存下來,作為test.html,文件大小是80多k,然后使用
    ab -c 1000 -n 10000 http://localhost/test.html
    ab -c 1000 -n 10000 http://localhost:8080/test.html
    進行測試。

    結果:
    Apache httpd:3276 req/s
    lighttpd:5633 req/s
    nginx: 6080 req/s
    Tomcat:1015 req/s

    結果表明,Tomcat只有nginx的六分之一,而且Tomcat的Failed Request字段的值太高,其余三個服務器該字段的值都是0,說明Tomcat面對大量并發連接時還不夠穩定。所以,使用lighttpd或nginx做Tomcat的反向代理,并進行緩存,應該可以獲得不錯的性能。

    下面上圖:






    # re: Web 2.0時代,決戰效率之巔  回復  更多評論   

    2009-05-30 14:40 by 虎嘯龍吟
    樓主強啊,什么都會啊

    # re: Web 2.0時代,決戰效率之巔  回復  更多評論   

    2009-06-24 17:58 by ycmhn
    這種簡單并且cpu密集的任務肯定是java比php占優勢
    因為畢竟是半編譯語言
    但是復雜的任務php最大的好處是擴展多~而且很容易用c語言寫擴展,
    如果把你這個寫成c擴展的話~~~嘿嘿 那就難說了~
    java。。。我看了幾年都很少看到用C寫擴展的,因為java對自己速度比較自信,且編寫擴展比較繁雜
    上面說看到nio會很驚訝的同學,,,可能是對別的語言了解比較少~其實說的就是一個跨平臺問題~
    以前我也為java宣稱的跨平臺激動過~可是呢~名不符實~不如很多腳本好

    # re: Web 2.0時代,決戰效率之巔  回復  更多評論   

    2009-06-30 11:29 by aDuan
    web 2.0
    nginx + php + mysql.
    主站蜘蛛池模板: 日韩高清在线免费看| 久久久久亚洲精品影视| 一个人看的免费视频www在线高清动漫 | 久久精品国产精品亚洲人人 | 中文字幕在线视频免费| 亚洲网站免费观看| 日韩成全视频观看免费观看高清| jizz日本免费| 久久亚洲精品专区蓝色区| 夜色阁亚洲一区二区三区| 一级成人a毛片免费播放| 亚洲精品无码久久久久APP| 亚洲国产精品国自产拍AV| 好先生在线观看免费播放| 拍拍拍无挡视频免费观看1000 | 精品亚洲福利一区二区| 婷婷亚洲久悠悠色悠在线播放| 手机在线毛片免费播放| 国产成人无码区免费网站| 亚洲欧洲AV无码专区| 久久亚洲精品无码| 亚洲VA综合VA国产产VA中| 可以免费看黄的网站| 三级毛片在线免费观看| 亚洲JIZZJIZZ妇女| 亚洲精品一区二区三区四区乱码| 四虎永久免费影院| 国产免费毛不卡片| 久久精品免费视频观看| 窝窝影视午夜看片免费| 亚洲人成欧美中文字幕| 亚洲色欲色欲综合网站| 三上悠亚亚洲一区高清| 国产精品高清全国免费观看| 亚洲国产精品免费在线观看| 中文字幕版免费电影网站| 免费在线观看一区| 亚洲国产成人精品无码区花野真一| 无码欧精品亚洲日韩一区| 亚洲热妇无码AV在线播放| www亚洲精品少妇裸乳一区二区|