• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

            對一個服務器的幾步優化

            最近寫了一個服務器,業務邏輯很簡單,每個協議包往服務器上報數據, 每個數據包中可能有N塊數據需要保存在數據庫中的.顯然, 這個業務邏輯是不能使用類似memcached這樣的緩存的, 因為每條數據都是相對獨立的, 而且必須保證每個數據都保存到數據庫中.這里拋開服務器最基本的那些IO模型之類的不說,談談對這個服務器的幾個優化步驟.

            1) 最簡單的處理
            最簡單的處理就是按部就班的,每條數據老老實實的插入到數據庫中.顯然, 這樣做的效率是低的, 如果并發量大的時候,mysql負載變大,而服務器阻塞在數據庫操作上, 導致處理連接比較慢.

            2) 第一步優化:定量插入數據
            這里基本的模型不變, 只是不是每個數據一來就插入, 而是緩存起來, 等到積累到了一定量才開始一起插入到數據庫中.這種方式比第一種方式并不能獲得太大的提高.

            3) 第二步優化:開線程處理往數據庫中插入數據
            在這里, 多開一個線程用于往數據庫中插入數據, 同時開辟了一個緩沖區, 主線程不停的往這個緩沖區中倒數據, 副線程負責將緩沖區中的數據導入數據庫.用偽代碼來表示, 這個優化就是這樣的:
            主線程:
                往緩沖區A中添加數據(注意這里不需要加鎖)

            副線程
            加鎖
                將緩沖區A,B的指針互換, 這樣緩沖區B就指向了原來緩沖區A,A指向B緩沖區
            解鎖
            將緩沖區B的數據導入數據庫
            清空B緩沖區
            這樣的優化效率獲得了極大的提高, 主線程只需要負責與客戶端之間的通信, 接收客戶端的數據, 而副線程只需要將數據導入緩沖區, 不需要關心通信問題.這樣,主線程就不會由于插入數據緩慢而導致接收數據和新的連接緩慢了.而由于是多線程, 主副線程之間的數據共享很容易做到, 主線程往緩沖區插入數據的時候甚至不需要加鎖, 而副線程倒數據的時候只需要加鎖然后把兩個緩沖區的指針互調就行了(我懷疑這個加鎖也是可以免去的).各司其職,又各不騷擾,簡單而高效.

            4)第三步優化:將向數據庫導入數據的時間盡可能的平均分布
            這一步與上一步大體相同, 只是在副線程倒數據的時候定一個量, 當計數器達到這個量時, 副線程休眠一陣(比如sleep一秒).這樣的好處是可以將向數據庫導入數據的時間盡可能的平均分布, 減小峰值時間點數據庫的壓力.

            5)第四步優化:從數據庫角度進行優化
            因為服務器只需要往數據庫中插入數據, 可以考慮在插入的時候將同一個表的數據緩存在一起, 然后寫在一條sql語句中一起插入, 這樣減少了sql語句的調用, IO減少了, 效率也提高了.我使用的是mysql, 關于mysql的優化插入數據, 可以參考這里.

            經過這幾個優化步驟之后, 服務器的效率比之最開始有了極大的提高, 不僅是服務器的效率提高了, 整個系統的IO,數據庫壓力也減少了.


            以下是分割線:
            -------------------------------------------------------------------
            我仔細想了一下,覺得似乎真的可以去掉加鎖的步驟...

            我的緩沖區是一個STL的list鏈表,主線程不停的往list中push_back.

            而交換緩沖區的時候調用的是STL中的swap操作, 也就是交換兩個鏈表的頭結點而已.

            從這里來看,確實可以省去加鎖的步驟的.

            --------------------------------------------------------------------
            第二天,我決定還是加鎖了.由于臨界區內的操作并不多, 我想效率沒有太大的影響.

            posted on 2008-10-22 20:10 那誰 閱讀(5237) 評論(18)  編輯 收藏 引用 所屬分類: 網絡編程服務器設計Linux/Unix

            評論

            # re: 對一個服務器的幾步優化  回復  更多評論   

            樓主要要是有例子代碼就好多了,希望能夠貼出代碼,那樣比較的直觀
            2008-10-22 20:17 | QQQ

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            這樣的想法記錄也已經很棒了~代碼未必能清楚的表示作者的意圖。
            2008-10-22 21:03 | Xw.Y

            # re: 對一個服務器的幾步優化  回復  更多評論   

            如果插入的數據是即時變化的,并要被其他地方(或不同客戶端、不同的進程、不同的線程...)使用的話,實時性就有問題。并且如果有一個計算是相關不同的記錄進行計算的話,計算的結果就可能會錯誤。
            2008-10-22 21:29 | wind

            # re: 對一個服務器的幾步優化  回復  更多評論   

            還有做好數據的壓縮和緩存問題,有的服務器把緩存量設的太大了。
            2008-10-22 21:34 | 金山毒霸2008

            # re: 對一個服務器的幾步優化  回復  更多評論   

            加鎖可以免去,因為Exchange有原子操作。
            2008-10-22 22:06 | 空明流轉

            # re: 對一個服務器的幾步優化  回復  更多評論   

            @QQQ
            要代碼有什么用,代碼往往是最沒用的。。。
            2008-10-22 22:06 | 空明流轉

            # re: 對一個服務器的幾步優化  回復  更多評論   

            不過我還是有個問題。如果主線程正在填充某條記錄的一半的時候就被Exchange掉怎么辦。
            2008-10-22 22:09 | 空明流轉

            # re: 對一個服務器的幾步優化  回復  更多評論   

            為啥要用A、B兩個緩沖區呢?
            可以用一個循環數組data[N]來做緩存,in_index用于主線程寫數據,指向下一個空位, out_index用于副線程讀數據,指向下一個數據位。in_index和out_index都模N運算。
            當out_index = (in_index + 1)%N時,緩沖已慢,等待。
            ---------
            2008-10-22 22:15 | ronliu

            # re: 對一個服務器的幾步優化  回復  更多評論   

            只對一個加鎖?跟沒加有區別么?
            2008-10-22 22:16 | t

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            @ronliu
            這個方法不錯,我回頭試試.
            2008-10-22 22:29 |

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   


            @t
            是的,所以我才有前面的疑問.
            2008-10-22 22:30 |

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            我仔細想了一下,覺得似乎真的可以去掉加鎖的步驟...

            我的緩沖區是一個list鏈表,主線程不停的往list中push_back.

            而交換緩沖區的時候調用的是STL中的swap操作, 也就是交換兩個鏈表的頭結點而已.

            從這里來看,確實可以省去加鎖的步驟的.
            2008-10-22 22:36 |

            # re: 對一個服務器的幾步優化  回復  更多評論   

            哦如果是這樣的話,你可以使用Windows的LIST,提供了添加和刪除節點的原子操作
            2008-10-22 23:35 | 空明流轉

            # re: 對一個服務器的幾步優化  回復  更多評論   

            摟主覺得可以“不加鎖”的想法值得商榷

            首先,STL 中list swap操作的實現是兩步:(以VC6 STL實現為例)
            std::swap(_Head, _X._Head);
            std::swap(_Size, _X._Size);
            此處不能保證兩步是原子操作。

            其次,也與std::swap的實現有關:(以VC6 STL實現為例)
            template<class _Ty> inline
            void swap(_Ty& _X, _Ty& _Y)
            {_Ty _Tmp = _X;
            _X = _Y, _Y = _Tmp; }
            不能保證編譯器能把這三步操作優化成原子操作。

            再次,與容器中的對象類型有關,現有的Exchange原子操作只針對int有效,浮點操作尚無原子操作(或許本人孤陋寡聞),更何況自定義類型乎?

            綜上所述,摟主的實現中鎖操作不可少。
            若要實現成鎖無關的數據結構,是不是應該交換的是兩個list*而不是list的內容,請參考http://blog.csdn.net/pongba/archive/2006/01/29/589864.aspx
            2008-10-23 00:34 | Cox

            # re: 對一個服務器的幾步優化  回復  更多評論   

            "而交換緩沖區的時候調用的是STL中的swap操作, 也就是交換兩個鏈表的頭結點而已." 誰說只是交換表頭.
            你看下邊STL的源碼..
            template<typename _Tp>
            inline void
            swap(_Tp& __a, _Tp& __b)
            {
            // concept requirements
            __glibcxx_function_requires(_SGIAssignableConcept<_Tp>)

            const _Tp __tmp = __a;
            __a = __b;
            __b = __tmp;
            }

            不可能不加鎖. 而且你的sleep用得也很猥瑣. 要用條件變量.做一個高水標就可以了.
            2008-10-23 10:30 | cui

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            各位,我想了想,還是改成加鎖了...
            2008-10-23 11:25 |

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            一讀一寫的話,循環buf就可以。以前寫過一個類似的,主線程寫,多個線程讀,用的線程鎖,性能不錯。
            2008-12-29 13:52 | dd

            # re: 對一個服務器的幾步優化[未登錄]  回復  更多評論   

            操作數據庫失敗會怎么樣?如果服務器都要等待數據庫返回才能進行下一步操作你這種就不行了
            2009-11-19 23:30 | xu
            中文字幕久久波多野结衣av| 欧美粉嫩小泬久久久久久久| 色欲综合久久躁天天躁蜜桃| 亚洲精品乱码久久久久久| 久久综合噜噜激激的五月天| 国内精品伊人久久久久av一坑| 国产精品女同久久久久电影院| 精品久久久久久久| 亚洲精品国产综合久久一线| 波多野结衣AV无码久久一区| 国产精品久久网| 久久强奷乱码老熟女网站| 99久久婷婷国产综合亚洲| 久久99久久成人免费播放| 日本强好片久久久久久AAA| 99久久精品免费| 亚洲色欲久久久综合网东京热| 日韩精品国产自在久久现线拍| 2021国内精品久久久久久影院| 2021久久精品国产99国产精品| 亚洲国产精品嫩草影院久久| 国产人久久人人人人爽| 久久婷婷午色综合夜啪| 国产精品久久久久久久午夜片| 久久精品中文字幕一区| 久久夜色撩人精品国产小说| 国产精品久久久天天影视| 性欧美丰满熟妇XXXX性久久久| 94久久国产乱子伦精品免费| 久久婷婷成人综合色综合| 久久久久青草线蕉综合超碰| 狠狠久久综合伊人不卡| 久久久噜噜噜www成人网| 久久久久久伊人高潮影院| 日韩精品无码久久一区二区三| 国产精品成人99久久久久91gav| 精品久久久久久中文字幕人妻最新| 欧美一区二区久久精品| 伊人久久国产免费观看视频 | 中文字幕无码精品亚洲资源网久久 | 久久中文字幕一区二区|