隨著(zhù)互聯(lián)網(wǎng)的普及,應用的用戶(hù)群體幾何倍增長(cháng),此時(shí)服務(wù)器性能問(wèn)題就出現。最初的服務(wù)器是基于進(jìn)程/線(xiàn)程模型。新到來(lái)一個(gè)TCP連接,就需要分配一個(gè)進(jìn)程。假如有C10K,就需要創(chuàng )建1W個(gè)進(jìn)程,可想而知單機是無(wú)法承受的。那么如何突破單機性能是高性能網(wǎng)絡(luò )編程必須要面對的問(wèn)題,進(jìn)而這些局限和問(wèn)題就統稱(chēng)為C10K問(wèn)題,最早是由Dan Kegel進(jìn)行歸納和總結的,并且他也系統的分析和提出解決方案。
C10K問(wèn)題的本質(zhì)上是操作系統的問(wèn)題。對于Web 1.0/2.0時(shí)代的操作系統,傳統的同步阻塞I/O模型處理方式都是requests per second。當創(chuàng )建的進(jìn)程或線(xiàn)程多了,數據拷貝頻繁(緩存I/O、內核將數據拷貝到用戶(hù)進(jìn)程空間、阻塞,進(jìn)程/線(xiàn)程上下文切換消耗大, 導致操作系統崩潰,這就是C10K問(wèn)題的本質(zhì)。
可見(jiàn), 解決C10K問(wèn)題的關(guān)鍵就是盡可能減少這些CPU資源消耗。
從網(wǎng)絡(luò )編程技術(shù)的角度來(lái)說(shuō),主要思路:
每個(gè)連接分配一個(gè)獨立的線(xiàn)程/進(jìn)程
同一個(gè)線(xiàn)程/進(jìn)程同時(shí)處理多個(gè)連接
該思路最為直接,但是申請進(jìn)程/線(xiàn)程是需要系統資源的,且系統需要管理這些進(jìn)程/線(xiàn)程,所以會(huì )使資源占用過(guò)多,可擴展性差
select方式:使用fd_set結構體告訴內核同時(shí)監控那些文件句柄,使用逐個(gè)排查方式去檢查是否有文件句柄就緒或者超時(shí)。該方式有以下缺點(diǎn):文件句柄數量是有上線(xiàn)的,逐個(gè)檢查吞吐量低,每次調用都要重復初始化fd_set。
poll方式:該方式主要解決了select方式的2個(gè)缺點(diǎn),文件句柄上限問(wèn)題(鏈表方式存儲)以及重復初始化問(wèn)題(不同字段標注關(guān)注事件和發(fā)生事件),但是逐個(gè)去檢查文件句柄是否就緒的問(wèn)題仍然沒(méi)有解決。
epoll方式:該方式可以說(shuō)是C10K問(wèn)題的killer,他不去輪詢(xún)監聽(tīng)所有文件句柄是否已經(jīng)就緒。epoll只對發(fā)生變化的文件句柄感興趣。其工作機制是,使用'事件'的就緒通知方式,通過(guò)epoll_ctl注冊文件描述符fd,一旦該fd就緒,內核就會(huì )采用類(lèi)似callback的回調機制來(lái)激活該fd, epoll_wait便可以收到通知, 并通知應用程序。而且epoll使用一個(gè)文件描述符管理多個(gè)描述符,將用戶(hù)進(jìn)程的文件描述符的事件存放到內核的一個(gè)事件表中, 這樣數據只需要從內核緩存空間拷貝一次到用戶(hù)進(jìn)程地址空間。而且epoll是通過(guò)內核與用戶(hù)空間共享內存方式來(lái)實(shí)現事件就緒消息傳遞的,其效率非常高。但是epoll是依賴(lài)系統的(Linux)。
異步I/O以及Windows,該方式在windows上支持很好,這里就不具體介紹啦。
聯(lián)系客服