導航:首頁 > IDC知識 > select並發伺服器

select並發伺服器

發布時間:2020-12-06 20:27:16

1、實現並發伺服器,有哪幾種基於線程的實現模式

1.多進抄程並發伺服器

是指襲TCP連接後,每一個客戶機的請求並不由伺服器直接處理,而是由伺服器創建一個子進程來處理

2.多線程並發伺服器

多進程伺服器是對多進程的伺服器的改進,由於多進程伺服器在創建進程時要消耗較大的系統資源,所以用線程來取代進程,這樣服務處理程序可以較快的創建。據統計,創建線程於創建進程要快10100倍,所以又把線程稱為「輕量級」進程。進程與進程不同的是:一個進程內所有線程共享相同的全局內存,全局變數等信息。

是指TCP連接後,每一個客戶機的請求並不由伺服器直接處理,而是由伺服器創

3.多路復用I/O

I/O是為了解決線程/進程阻塞在那個I/O調用中,常用select或者pool

2、網路伺服器的幾種並發服務模型

服務程序最為關鍵的設計是並發服務模型,當前有以下幾種典型的模型:

- 單進程服務,使用非阻塞IO

使用一個進程服務多個客戶,通常與客戶通信的套接字設置為非阻塞的,阻塞只發生在select()、poll()、epoll_wait()等系統調用上面。這是一種行之有效的單進程狀態機式服務方式,已被廣泛採用。

缺點是它無法利用SMP(對稱多處理器)的優勢,除非啟動多個進程。此外,它嘗試就緒的IO文件描述符後,立即從系統調用返回,這會導致大量的系統調用發生,尤其是在較慢的位元組傳輸時。

select()本身的實現也是有局限的:能打開的文件描述符最多不能超過FD_SETSIZE,很容易耗盡;每次從select()返回的描述符組中掃描就緒的描述符需要時間,如果就緒的描述符在末尾時更是如此(epoll特別徹底修復了這個問題)。

- 多進程服務,使用阻塞IO

也稱作 accept/fork 模型,每當有客戶連線時產生一個新的進程為之服務。這種方式有時是必要的,比如可以通過操作系統獲得良好的內存保護,可以以不同的用戶身份運行程序,可以讓服務運行在不同的目錄下面。但是它的缺點也很明顯:進程比較占資源,進程切換開銷太大,共享某些信息比較麻煩。Apache 1.3就使用了這種模型,MaxClients數很容易就可以達到。

- 多線程服務,使用阻塞IO

也稱之 accept/pthread_create模型,有新客戶來時創建一個服務線程而不是服務進程。這解決了多進程服務的一些問題,比如它佔用資源少,信息共享方便。但是麻煩在於線程仍有可能消耗光,線程切換也需要開銷。

- 混合服務方式
所謂的混合服務方式,以打破服務方和客戶方之間嚴格的1:1關系。基本做法是:

新客戶到來時創建新的工作線程,當該工作線程檢測到網路IO會有延遲時停止處理過程,返回給Server一個延遲處理狀態,同時告訴 Server被延遲的文件描述符,延遲超時時間。Server會在合適的時候返回工作線程繼續處理。注意這里的工作線程不是通過 pthread_create()創建的,而是被包裝在專門用於處理延遲工作的函數里。

這里還有一個問題,工作線程如何檢測網路IO會有延遲?方法有很多,比如設置較短的超時時間調用poll(),或者甚至使用非阻塞IO。如果是套接字,可以設置SO_RCVTIMEO和SO_SNDTIMEO選項,這樣更有效率。
除了延遲線程,Server還應提供了未完成線程的支持。
如有有特別耗費時間的操作,你可以在完成部分工作後停止處理,返回給Server一個未完成狀態。這樣Server會檢查工作隊列是否有別的線程,如果有則讓它們運行,否則讓該工作線程繼續處理,這可以防止某些線程挨餓。

典型的一個混合服務模型開源實現ServerKit

Serverkit的這些線程支持功能可簡化我們的服務程序設計,效率上應該也是有保證的。

2. 隊列(queue)

ServerKit提供的隊列是一個單向鏈表,隊列的存取是原子操作,如果只有一個執行單元建議不要用,因為原子操作的開銷較大。

3. 堆(heap)

malloc()分配內存有一定的局限,比如在多線程的環境里,需要序列化內存分配操作。ServerKit提供的堆管理函數,可快速分配內存,可有效減少分配內存的序列化操作,堆的大小可動態增長,堆有引用計數,這些特徵比較適合多線程環境。目前ServerKit堆的最大局限是分配單元必須是固定大小。

4. 日誌記錄

日誌被保存在隊列,有一個專門的線程處理隊列中的日誌記錄:它或者調用syslog()寫進系統日誌,或者通過UDP直接寫到遠程機器。後者更有效。

5. 讀寫鎖

GNU libc也在pthreads庫里實現了讀寫鎖,如果定義了__USE_UNIX98就可以使用。不過ServerKit還提供了讀寫鎖互相轉換的函數,這使得鎖的應用更為彈性。比如擁有讀鎖的若干個線程對同一個hash表進行檢索,其中一個線程檢索到了數據,此時需要修改它,一種辦法是獲取寫鎖,但這會導致釋放讀鎖和獲取寫鎖之間存在時間窗,另一種辦法是使用ServerKit提供的函數把讀鎖轉換成寫鎖,無疑這種方式更有效率。

除了以上這些功能,ServerKit還提供了資料庫連接池的管理(當前只支持MySQL)和序列化(Sequences),如感興趣可參見相關的API文檔。

二、ServerKit服務模塊編寫

ServerKit由3部分組成:server程序,負責載入服務模塊、解析配置文件、建立資料庫連接池;libserver,動態鏈接庫,提供所有功能的庫支持,包括server本身也是調用這個庫寫的;API,編程介面,你編寫的服務模塊和ServerKit框架進行對話的介面。

ServerKit需要libConfuse解析配置文件,所以出了安裝ServerKit,還需要安裝libConfuse。關於libConfuse可參考 http://www.nongnu.org/confuse/ 。

下面我們看一個簡單的服務模塊FOO:

#include <confuse.h>
#include <server.h>

static long int sleep_ration;

static int FOO_construct()
{
fprintf(stderr, "FOO_construct\n");

return 1;
}

static int FOO_prestart(cfg_t *configuration)
{
fprintf(stderr, "FOO_prestart\n");

return 1;
}

static void * FOO_operator(void *foobar)
{
fprintf(stderr, "FOO_operator\n");

for(;;) sleep(sleep_ration);

return NULL;
}

static void FOO_report(void)
{
fprintf(stderr, "FOO_report\n");
}


static cfg_opt_t FOO_config[] = {
CFG_SIMPLE_INT("sleep_ration", &sleep_ration),
CFG_END()
};

static char *FOO_authors[] = {"Vito Caputo <[email protected]>", NULL};


SERVER_MODULE(FOO,0,0,1,"Example mole that does nothing but sleep")按以下方法編譯:

$ gcc -c -fPIC -pthread -D_REENTRANT -g FOO.c
$ gcc -shared -lserver -lconfuse -lpthread -g -e __server_mole_main -o FOO.so FOO.o

-e選項指定程序運行入口,這使得你可以直接在命令行敲 ./FOO.so 運行模塊。
server程序根據環境變數SERVER_PERSONALITY_PATH定位主目錄,並查找主目錄下的c11n作為配置文件,動態載入的模塊需放在主目錄下的moles目錄。

$ export SERVER_PERSONALITY_PATH=`pwd`
$ mkdir moles
$ cp FOO.so moles
$ vi c11n

c11n的內容:

identity = "any_id"

FOO {
sleep_ration = 1;
}

identity標識server實例,用ps可看到程序名稱形如server.identity,本例為server.any_id。
執行server啟動服務程序。

三、ServerKit其他功能缺陷
缺乏daemon模式;
只能運行在Linux box;
DB pool只支持MySQL;
Heap管理內存的功力有限

3、高手,sqlserver最多支持多少個並發的select讀查詢

不會出現死鎖,時間久了(指數據量持續增長) 有可能變慢,需要維護下索引。如果數據量保持不變 則不會變慢,當然這只是針對此表來講,不考慮其他條件(比如:伺服器當前負載等各種外在因素)。

4、服務端並發問題以及epoll和select的區別

問題的引出:當需要讀兩個以上的I/O的時候,如果使用阻塞式的I/O,那麼可能長時間的阻塞在一個描述符上面,另外的描述符雖然有數據但是不能讀出來,這樣實時性不能滿足要求,大概的解決方案有以下幾種:
1.使用多進程或者多線程,但是這種方法會造成程序的復雜,而且對與進程與線程的創建維護也需要很多的開銷。(Apache伺服器是用的子進程的方式,優點可以隔離用戶)
2.用一個進程,但是使用非阻塞的I/O讀取數據,當一個I/O不可讀的時候立刻返回,檢查下一個是否可讀,這種形式的循環為輪詢(polling,注意這個不是指poll函數),這種方法比較浪費CPU時間,因為大多數時間是不可讀,但是仍花費時間不斷反復執行read系統調用。
3.非同步I/O(asynchronous I/O),當一個描述符准備好的時候用一個信號告訴進程,但是由於信號個數有限,多個描述符時不適用(真的嗎???)。
4.一種較好的方式為I/O多路轉接(I/O multiplexing)(貌似也翻譯多路復用),先構造一張有關描述符的列表(epoll中為隊列),然後調用一個函數,直到這些描述符中的一個准備好時才返回,返回時告訴進程哪些I/O就緒。select和epoll這兩個機制都是多路I/O機制的解決方案,select為POSIX標准中的,而epoll為Linux所特有的。

5、Python 網路客戶端和服務端udp和select都能實現並發,有啥區別呢?!

簡單來來說:沒什麼區源別!因為UDP本來就是報文,也就是「發出後不管」,因此返回極快,根本不會阻塞進程,接收時也是檢查一下緩沖區後立刻返回,同樣不阻塞進程。既然都是不阻塞進程的,因此select也就多餘了!

6、java nio並發訪問問題,我現在利用nio框架制伺服器的並發訪問,SelectionKey多線程

其實不要太迷信nio。這個東西如果你使用不當,效率還不如io高。
而且,使用了nio會造成和以前的代碼的不兼容。
當然,你是高手,那就例外了。

7、請教Linux下伺服器用select處理一個socket對應的多個客戶端

如果客戶端並發連接數不是很大,比如50個以下,可以用如下模型:建立一個監聽主線程回,循環監聽埠。當有答客戶端連接時,建立客戶端通訊線程,並保留客戶端socket到鏈表中。當客戶端斷開連接時,從socket鏈表中刪除該socket。

8、高並發的伺服器有什麼模式

服務程序最為關鍵的設計是並發服務模型,當前有以下幾種典型的模型:

  - 單進程服務,使用非阻塞IO

使用一個進程服務多個客戶,通常與客戶通信的套接字設置為非阻塞的,阻塞只發生在select()、poll()、epoll_wait()等系統調用上面。這是一種行之有效的單進程狀態機式服務方式,已被廣泛採用。

缺點是它無法利用SMP(對稱多處理器)的優勢,除非啟動多個進程。此外,它嘗試就緒的IO文件描述符後,立即從系統調用返回,這會導致大量的系統調用發生,尤其是在較慢的位元組傳輸時。

select()本身的實現也是有局限的:能打開的文件描述符最多不能超過FD_SETSIZE,很容易耗盡;每次從select()返回的描述符組中掃描就緒的描述符需要時間,如果就緒的描述符在末尾時更是如此(epoll特別徹底修復了這個問題)。

- 多進程服務,使用阻塞IO

也稱作 accept/fork 模型,每當有客戶連線時產生一個新的進程為之服務。這種方式有時是必要的,比如可以通過操作系統獲得良好的內存保護,可以以不同的用戶身份運行程序,可以讓服務運行在不同的目錄下面。但是它的缺點也很明顯:進程比較占資源,進程切換開銷太大,共享某些信息比較麻煩。Apache 1.3就使用了這種模型,MaxClients數很容易就可以達到。

- 多線程服務,使用阻塞IO

也稱之 accept/pthread_create模型,有新客戶來時創建一個服務線程而不是服務進程。這解決了多進程服務的一些問題,比如它佔用資源少,信息共享方便。但是麻煩在於線程仍有可能消耗光,線程切換也需要開銷。

- 混合服務方式
所謂的混合服務方式,以打破服務方和客戶方之間嚴格的1:1關系。基本做法是:

新客戶到來時創建新的工作線程,當該工作線程檢測到網路IO會有延遲時停止處理過程,返回給Server一個延遲處理狀態,同時告訴 Server被延遲的文件描述符,延遲超時時間。Server會在合適的時候返回工作線程繼續處理。注意這里的工作線程不是通過 pthread_create()創建的,而是被包裝在專門用於處理延遲工作的函數里。

這里還有一個問題,工作線程如何檢測網路IO會有延遲?方法有很多,比如設置較短的超時時間調用poll(),或者甚至使用非阻塞IO。如果是套接字,可以設置SO_RCVTIMEO和SO_SNDTIMEO選項,這樣更有效率。
除了延遲線程,Server還應提供了未完成線程的支持。
如有有特別耗費時間的操作,你可以在完成部分工作後停止處理,返回給Server一個未完成狀態。這樣Server會檢查工作隊列是否有別的線程,如果有則讓它們運行,否則讓該工作線程繼續處理,這可以防止某些線程挨餓。

典型的一個混合服務模型開源實現ServerKit

Serverkit的這些線程支持功能可簡化我們的服務程序設計,效率上應該也是有保證的。

2. 隊列(queue)

ServerKit提供的隊列是一個單向鏈表,隊列的存取是原子操作,如果只有一個執行單元建議不要用,因為原子操作的開銷較大。

3. 堆(heap)

malloc()分配內存有一定的局限,比如在多線程的環境里,需要序列化內存分配操作。ServerKit提供的堆管理函數,可快速分配內存,可有效減少分配內存的序列化操作,堆的大小可動態增長,堆有引用計數,這些特徵比較適合多線程環境。目前ServerKit堆的最大局限是分配單元必須是固定大小。

4. 日誌記錄

日誌被保存在隊列,有一個專門的線程處理隊列中的日誌記錄:它或者調用syslog()寫進系統日誌,或者通過UDP直接寫到遠程機器。後者更有效。

5. 讀寫鎖

GNU libc也在pthreads庫里實現了讀寫鎖,如果定義了__USE_UNIX98就可以使用。不過ServerKit還提供了讀寫鎖互相轉換的函數,這使得鎖的應用更為彈性。比如擁有讀鎖的若干個線程對同一個hash表進行檢索,其中一個線程檢索到了數據,此時需要修改它,一種辦法是獲取寫鎖,但這會導致釋放讀鎖和獲取寫鎖之間存在時間窗,另一種辦法是使用ServerKit提供的函數把讀鎖轉換成寫鎖,無疑這種方式更有效率。

除了以上這些功能,ServerKit還提供了資料庫連接池的管理(當前只支持MySQL)和序列化(Sequences),如感興趣可參見相關的API文檔。

二、ServerKit服務模塊編寫

ServerKit由3部分組成:server程序,負責載入服務模塊、解析配置文件、建立資料庫連接池;libserver,動態鏈接庫,提供所有功能的庫支持,包括server本身也是調用這個庫寫的;API,編程介面,你編寫的服務模塊和ServerKit框架進行對話的介面。

ServerKit需要libConfuse解析配置文件,所以出了安裝ServerKit,還需要安裝libConfuse。關於libConfuse可參考 http://www.nongnu.org/confuse/ 。

下面我們看一個簡單的服務模塊FOO:

#include <confuse.h>
#include <server.h>

static long int sleep_ration;

static int FOO_construct()
{
fprintf(stderr, "FOO_construct\n");

return 1;
}

static int FOO_prestart(cfg_t *configuration)
{
fprintf(stderr, "FOO_prestart\n");

return 1;
}

static void * FOO_operator(void *foobar)
{
fprintf(stderr, "FOO_operator\n");

for(;;) sleep(sleep_ration);

return NULL;
}

static void FOO_report(void)
{
fprintf(stderr, "FOO_report\n");
}


static cfg_opt_t FOO_config[] = {
CFG_SIMPLE_INT("sleep_ration", &sleep_ration),
CFG_END()
};

static char *FOO_authors[] = {"Vito Caputo <[email protected]>", NULL};


SERVER_MODULE(FOO,0,0,1,"Example mole that does nothing but sleep")按以下方法編譯:

$ gcc -c -fPIC -pthread -D_REENTRANT -g FOO.c
$ gcc -shared -lserver -lconfuse -lpthread -g -e __server_mole_main -o FOO.so FOO.o

-e選項指定程序運行入口,這使得你可以直接在命令行敲 ./FOO.so 運行模塊。
server程序根據環境變數SERVER_PERSONALITY_PATH定位主目錄,並查找主目錄下的c11n作為配置文件,動態載入的模塊需放在主目錄下的moles目錄。

$ export SERVER_PERSONALITY_PATH=`pwd`
$ mkdir moles
$ cp FOO.so moles
$ vi c11n

c11n的內容:

identity = "any_id"

FOO {
sleep_ration = 1;
}

identity標識server實例,用ps可看到程序名稱形如server.identity,本例為server.any_id。
執行server啟動服務程序。

三、ServerKit其他功能缺陷
缺乏daemon模式;
只能運行在Linux box;
DB pool只支持MySQL;
Heap管理內存的功力有限

9、pl/sql高並發情況下的查詢問題

先說明一下我的資料庫:oracle
g11
看你是先select還是先insert。
如果是先insert:這個時候,資料庫被鎖內定,你下達select的時候,處於容等待狀態,當insert完成後,select才啟動,查詢出來的數據就有最新insert進入的數據。
先insert只有這種情況,沒有其他。
先select:
select後,並不會鎖表,而是先通過索引,記錄下總條目數量,然後在總條目數范圍內進行查詢,應次,不會查詢出新insert的數據。
補充回答:我目前使用的資料庫大小173.7G,伺服器是IBM小型機,操作系統是AIX。遠端操作的電腦是X201i,用戶數量不多,但用戶同時打開表、操作的表,數據量比較大。
速度上還算過的去,遍歷一邊最大的單表(約32G,42W條記錄)時間大概就是20秒鍾左右!

與select並發伺服器相關的知識