從零開始一個http伺服器(六)-多路複用和壓力測試

flamedancer發表於2018-12-23

從零開始一個http伺服器(六)-多路複用和壓力測試

程式碼地址 : https://github.com/flamedancer/cserver
git checkout step6
執行:
make clean && make && ./myserver.out
測試
瀏覽器開啟 http://127.0.0.1:9734/action/show_date

多路複用和壓力測試

  • 多路複用
  • 壓力測試

多路複用

多路複用意義

到目前為止,伺服器的基本業務功能我們是實現了。但好的伺服器不止要能完成業務邏輯,沒有好的執行效率和高的併發數,根本無法在生成環境中使用。現在我們開始考慮優化我們的伺服器使之接近能應付生成環境的水平。

提高伺服器效能有很多方法,我們先來考慮第一個改進,採用多路複用。

我們之前的程式,當server_sockfd accpet 一個 client_sockfd 後,程式read等待client_sockfd發來的資料,

然後再解析request。然而如果client_sockfd遲遲不傳送資料,我們的程式就卡在read上,後面客戶端發的請求全部無法響應了。”多路複用”可以簡單理解為“誰有事執行誰”, 運用多路複用可以解決上面這個問題。當accpet 一個 client_sockfd後,將client_sockfd放在一個事件池中,直到事件池察覺這個client_sockfd可以read了,才對這個client_sockfd進行read操作。

步驟可以總結為

1. 建立事件池
2. 建立事件,將事件加入到事件池
3. 事件池監測所有事件,若有事件被觸發,執行被觸發事件的後續邏輯

多路複用封裝

由於mac和linux所用的事件複用庫不一樣,mac下為kqueue,linux下為epoll,為了相容性,我們封裝了一個事件庫poll.h。
主要結構體和函式為:

1 . 事件池結構體
struct PollEvent {
    int epfd;
    void * eventItems;
    int maxEventCnt;
};

epfd 為事件池控制程式碼
eventItems 當前被觸發的事件陣列
maxEventCnt 為最大可容納被觸發事件數

2 . 新增事件
void updateEvents(struct PollEvent* event, int fd, int eventFLags, int modify, void* udata);

event 事件池
fd 需要監聽的控制程式碼
eventFLags 需要監聽fd的什麼事件 我們初略的只定義讀和寫事件

#define Readtrigger 1
#define Writetrigger 2
#define Emptytrigger 0

modify 如果為 0 時 為fd新增eventFLags事件, 為1時 修改fd的事件為eventFLags

3. 監聽事件池

當有事件被觸發時返回被觸發的事件數,被觸發的事件放在event->eventItems裡

int doPoll(struct PollEvent* event);

修改main函式

  1. 建立事件池
  2. 將sever_socket read 事件加入事件池
  3. 監聽事件池
  4. 當事件池發現有觸發的事件時,判斷觸發的事件型別:
    1. 若為 sever_socket read 事件,建立client_socket, 將client_socket read 事件加入事件池
    2. 若為 client_socket read 事件, 解析reques,生成 response,並將client_socket write 事件加入事件池
    3. 若為 client_socket write 事件, 將response寫入client_socket,關閉client_socket(事件池會清理關閉了的fd)
  5. 繼續第4步

壓力測試

ab -c 5 -n 2000 http://127.0.0.1:9734/action/show_date

Concurrency Level:      5
Time taken for tests:   14.089 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      218000 bytes
HTML transferred:       58000 bytes
Requests per second:    141.95 [#/sec] (mean)
Time per request:       35.223 [ms] (mean)
Time per request:       7.045 [ms] (mean, across all concurrent requests)
Transfer rate:          15.11 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    10   35  14.6     38      83
Waiting:       10   35  14.6     38      83
Total:         10   35  14.6     39      83

我們用ab測試5併發總共2000個/show_date請求,可以看到 平均每個請求花費35毫秒。下一節我們將採用執行緒池技術來繼續改進我們的執行效率。

相關文章