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

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

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

    聶永的博客

    記錄工作/學習的點點滴滴。

    100萬并發連接服務器筆記之Erlang完成1M并發連接目標

    前言

    使用Erlang語言也寫一個測試和前面大同小異的測試,在100萬個并發連接用戶情況下,就是想觀察一下極顯情況下的表現。
    這個測試使用了優秀的Erlang界的明星框架cowboy,加單易用的接口,避免了我們對HTTP棧再次進行閉門造車。

    測試Erlang服務器

    運行在VMWare Workstation 9中,64位Centos 6.4系統,分配14.9G內存左右,雙核4個線程,服務器安裝Erlang/OTP R16B,最新版本支持異步代碼熱加載,很贊。

    下載安裝

    本系統已經提前安裝JDK,只需要安裝Erlang好了。

    安裝依賴

    
    
    yum install build-essential m4
    yum install openssl
    yum install openssl-devel
    yum install unixODBC
    yum install unixODBC-devel
    yum -y install openssl make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel
    yum install xsltproc fop

    源代碼安裝

    #wget https://elearning.erlang-solutions.com/binaries/sources/otp_src_R16B.tar.gz
    #tar xvf otp_src_R16B.tar.gz
    cd otp_src_R16B
    ./configure --prefix=/usr/local/erlang --enable-hipe --enable-threads --enable-smp-support --enable-kernel-poll
    make
    make install
    

    添加到環境變量中(/etc/profile)

    export ERL_HOME=/usr/local/erlang export PATH=$ERL_HOME/bin:$PATH
    

    保存生效

    source /etc/profile
    

    測試進程創建

    這里拷貝《Erlang程序設計》一書提供的processes.erl源碼,稍作修改。

    創建一百萬個進程,看看大概花費多少時間。

    [yongboy@base erlang]$ erl +P 10240000
    Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
    Eshell V5.10.1 (abort with ^G)
    1> processes:max(200000).
    Maxmium allowed process is 16777216 Process spawn time=1.1 (2.68) microseconds ok
    2> processes:max(200000).
    Maxmium allowed process is 16777216 Process spawn time=1.7 (2.33) microseconds ok
    3> processes:max(200000).
    Maxmium allowed process is 16777216 Process spawn time=1.55 (2.12) microseconds ok
    4> processes:max(1000000).
    Maxmium allowed process is 16777216 Process spawn time=2.97 (3.967) microseconds ok
    5> processes:max(1000000).
    Maxmium allowed process is 16777216 Process spawn time=2.4 (2.729) microseconds ok
    6> processes:max(1000000).
    Maxmium allowed process is 16777216 Process spawn time=2.19 (2.735) microseconds ok
    7> processes:max(10000000).
    Maxmium allowed process is 16777216 Process spawn time=3.328 (4.2777) microseconds ok
    8> processes:max(10000000).
    Maxmium allowed process is 16777216 Process spawn time=3.144 (3.1361) microseconds ok
    9> processes:max(10000000).
    Maxmium allowed process is 16777216 Process spawn time=3.394 (3.2051) microseconds ok
    

    恩,創建1000萬個進程,每一個進程花費3.4微秒(μs)的CPU時間,相當于4.3微秒(μs)的消耗時間(亦即消耗的真實時間),在一定量的區間內,其值變化,可以看做是一個常量。

    初始化小問題

    Cowboy初始化需要事項

    我們做的簡單程序,使用了非常受歡迎的cowboy框架,其啟動函數:

    cowboy:start_http(my_http_listener, 100,
    [{port, 8000}],
    [{env, [{dispatch, Dispatch}]}]
    ),
    

    Cowboy默認支持1024個連接,服務器端輸出:

    online user 1122 online user 1123 

    停滯于此,后續的連接只能排隊等候了。

    這里設置支持無限個連接好了。

    {max_connections, infinity}
    

    話說,Cowboy為Erlang世界的明星產品,絕對值得一試!

    Erlang默認創建進程限制

    Erlang在我的機器上默認允許創建的線程也是有限的:

    erlang:system_info(process_limit).
    262144
    

    才26萬個,不夠用。在啟動腳本(start.sh)處添加允許創建的最大線程支持:

    #!/bin/sh
    erl +K true +P 10240000 -sname testserver -pa ebin -pa deps/*/ebin -s htmlfilesimple\
    -eval "io:format(\"Server start with port 8000 Success!~n\")."

    腳本啟動后現在在erl shell中測試一下:

    erlang:system_info(process_limit).
    16777216
    

    數量完全夠用了。

    開啟erlang的epoll屬性

    +K true | false 是否開啟kernel poll,就是epoll;
    

    不開啟,測試過程中,在內存完好情況下,經常會有連接失敗情況。

    使用cowboy_req:compact降低內存占用

    一旦你從request對象中獲取到足夠的信息,以后不再獲取其附加屬性時,調用compact/1函數可去除無用屬性,起到節省內存作用。
    程序里面調用如下:

    init(_Any, Req, State) -> NowCount = count_server:welcome(),
    io:format("online user ~p :))~n", [NowCount]),
    output_first(Req),
    Req2 = cowboy_req:compact(Req),
    {loop, Req2, State, hibernate}.
    

    在本例中精測壓縮內存效果不明顯,因為 ,測試端輸出的HTTP頭部壓根就沒有幾個。

    Cowboy無法處理沒有header的HTTP請求

    這里需要牢記,也不能算是BUG,前面的client2.c源碼,就未曾設置HTTP Header元數據,需要做些簡單修改,修改之后的測試端程序文件名為client5.c, 可以到這里 下載client.c

    Cowboy處理長連接

    Cowboy很貼心的提供了cowboy_loop_handler behaviour。在init/3函數中,可以進入休眠狀態,節省內存,消息到達時,被喚醒,值得一贊! 其定義如下: 注意hibernatetimeout參數,按照實際需求返回即可。

    htmlfile_handler示范代碼如下:

    100萬并發連接達成

    測試過程跌跌撞撞的,雖然這中間因為內存問題拋出若干的異常,但也達到100W連接的數量

    online user 1022324 :))
    online user 1022325 :))
    online user 1022326 :))
    online user 1022327 :))
    online user 1022328 :))
    online user 1022329 :))
    online user 1022330 :))
    online user 1022331 :))
    online user 1022332 :))
    online user 1022333 :))
    online user 1022334 :))
    online user 1022335 :))
    online user 1022336 :))
    online user 1022337 :))
    online user 1022338 :))
    

    可以看到狀態信息

    算一下: 14987952K = 14636M
    14987952/1022338 = 14.7K/Connection

    未啟動時的內存情況:

     total used free shared buffers cached
    Mem: 14806 245 14561 0 12 60
    -/+ buffers/cache: 172 14634
    Swap: 3999 0 3999
    

    啟動后的內存占用情況:

     total used free shared buffers cached
    Mem: 14806 435 14370 0 12 60
    -/+ buffers/cache: 363 14443
    Swap: 3999 0 3999
    

    用戶量達到1022338數量后的內存一覽:

     total used free shared buffers cached
    Mem: 14806 14641 165 0 1 5
    -/+ buffers/cache: 14634 172
    Swap: 3999 1068 2931
    

    可以看到,當前內存不夠用了,需要虛擬內存配合了。

    查看一下當前進程的內存占用

    ps -o rss= -p `pgrep -f 'sname testserver'`
    4869520
    

    這樣算起來,系統為每一個進程持有 4869520/1022338 = 4.8K 內存。 這個值只是計算物理內存,實際上連虛擬內存都占用了,估計在4.8K-6.8K之間吧。

    和C語言相比,內存占用相當大,我虛擬機器分配的15G內存,也僅僅處理達到100萬的連接,已經接近極限時,會發現陸陸續續的有連接失敗。

    不得不說的代碼熱加載

    運行時系統的代碼熱加載功能,在這個實例中,通過vi修改了htmlfile_handler.erl文件,主要修改內容如下:

    io:format("online user ~p :))~n", [NowCount]),
    ......
    io:format("offline user ~p :(( ~n", [NowCount]).
    

    執行make,編譯

    [root@base htmlfilesimple]# make
    ==> ranch (get-deps)
    ==> cowboy (get-deps)
    ==> htmlfilesimple (get-deps)
    ==> ranch (compile)
    ==> cowboy (compile)
    ==> htmlfilesimple (compile)
    src/htmlfile_handler.erl:5: Warning: record status is unused
    src/htmlfile_handler.erl:29: Warning: variable 'Reason' is unused
    Compiled src/htmlfile_handler.erl
    

    很好,非常智能的rebar,自動只編譯了htmlfile_handler.erl一個文件,然后通知Erlang的運行環境進行代碼熱替換吧。

    (testserver@base)4> code:load_file(htmlfile_handler). 

    查看日志輸出控制臺,可以看到已經生效,同時也保存著到狀態數據等。

    非常利于運行時調試,即不傷害在線狀態數據,又能即時修改,贊!但生產環境下,一般都是版本切換,OTP的版本切換,測試或馬上修改bug時,著實有些復雜。

    小結

    和C相比,處理相同的事情(100萬并發連接),及其簡單,但Erlang會需要更多的內存,廉價的內存可以滿足,只是我的搭建在Vmware中的虛擬機器已經達到了它所要求的極限。
    完整的源代碼,可點擊這里下載

    posted on 2013-04-28 17:17 nieyong 閱讀(16890) 評論(1)  編輯  收藏 所屬分類: C1M

    評論

    # re: 100萬并發連接服務器筆記之Erlang完成1M并發連接目標 2014-02-20 10:17 西嶺風清

    真巧,去年我用C++開發了一個推送服務器,4月份測完上線使用。

    測試的時候測到了110w并發(2.6.2以下最多能到1024k,在這個之上的kernel單機有辦法改到超過1024k句柄),沒有出現博主出現的掉線情況,內存消耗貌似要小一點,一個連接平均均攤8-10k左右。

    不過C++開發起來真累,維護起來也很麻煩,我看到此文后,深深陷入到造HTTP輪子的自責當中。

    我今年一開始想把它變成JNI+Java方式,碰巧看到博主的做法,到時候試試,謝謝博主。  回復  更多評論   

    公告

    所有文章皆為原創,若轉載請標明出處,謝謝~

    新浪微博,歡迎關注:

    導航

    <2013年4月>
    31123456
    78910111213
    14151617181920
    21222324252627
    2829301234
    567891011

    統計

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個人收藏

    最新隨筆

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 一级成人a毛片免费播放| 国产A在亚洲线播放| 亚洲愉拍一区二区三区| 91在线老王精品免费播放| 亚洲国产美女精品久久久久∴| 猫咪免费人成网站在线观看入口 | 色爽黄1000部免费软件下载| 女人18毛片a级毛片免费视频| 亚洲一级毛片中文字幕| 59pao成国产成视频永久免费| 亚洲av无码乱码国产精品| baoyu122.永久免费视频| 久久亚洲色一区二区三区| 男女超爽视频免费播放| 国产精品免费看久久久无码| 亚洲AV永久无码精品网站在线观看| 免费无码又黄又爽又刺激| 亚洲伊人久久大香线焦| 日本妇人成熟免费中文字幕| 亚洲第一页在线视频| 91在线老王精品免费播放| 亚洲综合久久1区2区3区 | 成人黄18免费视频| 亚洲一区二区三区在线观看网站 | 久久久久亚洲?V成人无码| 一区二区视频免费观看| 亚洲一区无码精品色| 好湿好大好紧好爽免费视频| 国产av无码专区亚洲av果冻传媒| 国产精品视频全国免费观看| 亚洲色欲一区二区三区在线观看| a级毛片免费播放| 午夜亚洲国产理论秋霞| 91精品国产免费久久国语麻豆| 亚洲综合激情九月婷婷| 四虎在线最新永久免费| 色婷五月综激情亚洲综合| 成人免费a级毛片无码网站入口 | 国产福利在线观看永久免费| 亚洲人成77777在线播放网站| 日本免费中文字幕|