做架構設計,難免有時候被人問及系統的瓶頸在哪,那首先來了解下什麼是瓶頸?
打個形象的比方,人的嘴巴可以吞下一整個麵包,但是卻嚥不下去,因為食管不給力,它比較細,所以嘴巴能吞下的食物大小要受到食管的粗細限制。
城市內部每天會產生幾十萬件跨城快遞,可是跨城的交通不給力,只允許走小型卡車,一卡車一次就能裝幾千件,一天下來也不一定能投送的完。
人在一定時間內能嚥下多少食物,貨運公司在一天運送多少貨物,物理上叫做吞吐量,系統整體的吞吐量等於最小區域的吞吐量。
下面這張圖能夠反映:
土黃色管子的流量要受到紅色部分的制約。
伺服器上也是這樣,好一點的設計框架結合物理高配可以處理高達幾十萬的併發,像土黃色的管子,可是偏偏有一些模組像圖中紅色的管子那樣,一秒中只能同時處理幾百次,這樣就嚴重拖慢了伺服器的效能,成了瓶頸。
現實開發中有時可能會要加上資料庫模組,如mysql,雖然mysql號稱每秒處理幾十萬的查詢根本沒問題,但那只是運算能力。
伺服器連mysql 是要通過tcp網路的,有連線就需要時間,再加上資料量如果大點,自然就成了瓶頸。
相似的情況,一些特殊的業務,比如加解密服務,金鑰和隨機數的產生依賴加密機,中介軟體的效能就是我們圖中的紅管子。
系統架構的設計是爭對業務的,業務裡如果存在這些紅管子,就必須要有相應的解決辦法。
不同人的處理方法不同,據我經驗,可以將瓶頸子分成兩類:
1.阻塞序列處理
2.非同步並行處理
mysql,中介軟體的處理屬於第一類,非同步閘道器查詢屬於第二類。
對於第一類,一種通用的解決方法是增加處理程序,其實是橫向擴容的思想,打個比方,乙個程序的併發是600,10個程序就可以達到6000了,如何才能將請求均勻地分配到這10個程序是關鍵。
多個程序同時監聽乙個埠,負載均衡的方法很多,這裡介紹nginx的做法,直接上**:
[cpp]view plain
copy
?
//接收握手後連線
void ngx_event_accept(ngx_event_t *ev)
//事件模型處理函式
void ngx_process_events_and_timers(ngx_cycle_t *cycle)
else
if (ngx_accept_mutex_held) else
} }
...
} //取得埠監聽的鎖
ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
...
} //啟動埠監聽
static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle)
if (ngx_event_flags & ngx_use_rtsig_event)
} else
} }
return ngx_ok;
}
從上面的**可以看出,nginx用乙個全域性變數ngx_accept_disabled 來控制單個程序的負載,當負載達到一定值的時候,不再接受新的負載。
對於第二類情況,解決的方法就像名字一樣,非同步並行解決。
拿跨網查詢為例:
建立乙個查詢的請求,將請求放進事件模型中,等待服務端的返回,非同步處理。
熟悉nginx的就知道nginx的upstream反向**,這個解決方案跟反向**很像,只不過在與上游伺服器互動的前後分別還有其他的業務處理,而且可能還會有多次互動。
相應的流水圖是這樣的:
當客戶端請求量大時,事件模型的容量會成為瓶頸,這樣仍然需要橫向擴容的方式來解決,增加處理程序。
這兩種情況的處理方法大致如此,有時候特殊問題特殊對待,比哪資料庫的瓶頸可以借助快取解決,有些高配伺服器的記憶體128g,甚至幾台高配伺服器只為乙個業務,這樣的情況下,不吃點記憶體難免對不起老闆的money
**:
linux c 高併發tcp伺服器架構
from epoll 接受資料到佇列,執行緒池處理佇列裡的資料 具體實現方式 只使用使用std的的資料結構,未使用boost thread pool.cpp include include include thread pool.h include thread process.h include ...
高併發伺服器邏輯處理瓶頸,如何解決?
高併發伺服器邏輯處理瓶頸,如何解決?首先我們先了解什麼是併發!併發,在作業系統中,是指乙個時間段中有幾個程式都處於已啟動執行到執行完畢之間,且這幾個程式都是在同乙個處理機上執行,但任乙個時刻點上只有乙個程式在處理機上執行。百科 顧名思義,高併發就是在指定時間內,系統同時能夠處理大量的請求 連線數 那...
併發伺服器的設計
併發 即同時 併發伺服器 實現多客戶端同時連線,同時處理多個請求。利用多程序或多執行緒的方式處理連線成功後的任務,主程式繼續等待連線。多程序 建立子程序,任務函式交給子程序執行 listen sockfd,5 允許連線的客戶機數目5 while 1 else if pid 0 printf fork...