[phvia/firman] PHP多進程服務器模型中的驚羣

 

[ 典型場景 ]html

典型的多進程服務器模型是這樣的,主進程綁定ip,監聽port,fork幾個子進程,子進程安裝信號處理器,隨後輪詢資源描述符檢查是否可讀可寫;git

子進程的輪詢又涉及到 IO複用,accept鏈接,事件處理 系列操做。github

如下用僞碼錶示這個過程:服務器

Master: bind -> listen -> fork {
  // Child 
  install signal
  select loop
  accept connection
  event callback
} -> monitor

 

[ 存在缺陷 ]框架

主進程監聽port,存在驚羣問題,客戶端鏈接請求到來時,全部子進程被喚醒,嘗試接受鏈接,但只有一個鏈接成功,其他產生EAGAIN錯誤,並繼續進入輪詢。socket

經過 strace -p pid 能夠看到空閒進程的執行過程:oop

$ select(7, [6], [6], [], {5, 0}) = 0 (Timeout)
$ select(7, [6], [6], [], {5, 0}) = 1 (in [6], left {2, 22060})
$ poll([{fd=6, events=POLLIN|POLLERR|POLLHUP}], 1, 10000) = 1 ([{fd=6, revents=POLLIN}])
$ accept(6, 0x7ffe34ffe390, 0x7ffe34ffe380) = -1 EAGAIN (Resource temporarily unavailable)
$ poll([{fd=6, events=POLLIN|POLLERR|POLLHUP}], 1, 10000) = 0 (Timeout)
$ select(7, [6], [6], [], {5, 0}) = 0 (Timeout)

可想而知,當子進程數量較多時,進程調度(上下文切換)須要耗費的資源很是多。spa

 

[ 解決方式 ]3d

在PHP7,啓用 socket 的 so_reuseport 選項以後,子進程就能夠在每一個端口上監聽了,有鏈接時才被喚醒。
如下用僞碼錶示這個過程:code

Master: fork {
    // Child 
    install signal
    bind
    listen
    select loop
    accept connection
    event callback
} -> monitor

 

[ 框架應用 ]

phvia/firmanhttps://github.com/phvia/firman/commit/bace0b2ffda915cc8cf5c73dc009d78a215637d3

 

Link:http://www.cnblogs.com/farwish/p/8747314.html

相關文章
相關標籤/搜索