《LINUX教程:快速記住Linux內(nèi)核的基本概念》要點:
本文介紹了LINUX教程:快速記住Linux內(nèi)核的基本概念,希望對您有用。如果有疑問,可以聯(lián)系我們。
打算給我們部門弄個內(nèi)部分享.發(fā)現(xiàn)大家對一些底層知識的認知停留在一句一句的,好比聽說JVM使用-XX:-UseBiasedLocking取消偏向鎖可以提高性能,因為它只適用于非多線程高并發(fā)應(yīng)用.使用數(shù)字對象的緩存-XX:AutoBoxCacheMax=20000比默認緩存-128~127要提高性能.對于JVM和Linux內(nèi)核,操作系統(tǒng)沒有系統(tǒng)的概念,遇到實際問題往往沒有思路.所以我的內(nèi)部分享,主要分為Linux部分,jvm部分和redis部分.這篇是Linux篇.學習思路為主,知識為輔.我也是菜鳥一枚~~不過是個鉆石心的菜鳥,不怕別人知道我有多菜.
先說為什么我要去學習Linux內(nèi)核.我在上家公司負責整個公司的搜索引擎.有一次很純熟的在一臺虛擬機上新搭建了一套,壓測到8000,額,報了一個NIO異常,說是:too many open files.當時查了一下,那臺機器太破,和很多服務(wù)公用,內(nèi)存快滿了.所以換了臺好點的機器就沒有這個問題了.但是句柄超限到底是個什么東西呢?先來看看Linux內(nèi)核的一些基本概念.
大局觀嘛,先來看看unix的體系布局.
簡單解釋一下:任何計算機系統(tǒng)都包括一個基本的程序集合,它控制計算機硬件資源,提供程序運行環(huán)境.稱為操作系統(tǒng).在這個集合里,最重要的程序被稱為內(nèi)核,在系統(tǒng)啟動時被裝載.因為它相對較小,而且位于環(huán)境的核心.內(nèi)核的接口被稱為系統(tǒng)調(diào)用(system call).公用函數(shù)庫構(gòu)建在系統(tǒng)調(diào)用接口之上,也可使用系統(tǒng)調(diào)用.shell是一個特殊的應(yīng)用程序,為運行其他應(yīng)用程序提供一個接口.
一些操作系統(tǒng)允許所有的用戶程序直接與硬件部分進行交互,如MS-DOS.但是類Unix操作系統(tǒng)在胡勇應(yīng)用程序前把與計算機物理組織相關(guān)的所有底層細節(jié)隱藏了.當程序想使用硬件資源時,必須向操作系統(tǒng)發(fā)出一個哀求,內(nèi)核對這個哀求進行評估,如果允許使用這個資源,內(nèi)核代表應(yīng)用程序與相關(guān)的硬件部分進行交互.為了實施這種機制,現(xiàn)代操作系統(tǒng)依靠特殊的硬件特性來禁止用戶程序直接與底層硬件部分打交道,或者直接訪問任意的物理地址.硬件為CPU引入了至少兩種不同的執(zhí)行模式:用戶程序的非特權(quán)模式和內(nèi)核的特權(quán)模式.Unix把他們分別稱為用戶態(tài)(User Mode)和內(nèi)核態(tài)(Kernel Model).
我們平時敲的一些Linux命令,實際上都是對應(yīng)的內(nèi)核的C語言函數(shù).比如cat xxx | grep 'x'.這里面兩個命令用|連接起來,這個叫做“管道”.先用男孩紙慣用的職業(yè)一點的語言介紹一下:管道是一個廣泛應(yīng)用的進程間通信手段.其作用是在具有親緣關(guān)系的進程之間傳遞消息,所謂有親緣關(guān)系,是指有同一個祖先.可以是父子,兄弟或者祖孫等等.反正只要共同的祖先調(diào)用了pipe函數(shù),打開的管道文件會在fork之后,被各個后代所共享.其本色是內(nèi)核維護了一塊緩沖區(qū)與管道文件相關(guān)聯(lián),對管道文件的操作,被內(nèi)核轉(zhuǎn)換成對這塊緩沖區(qū)內(nèi)存的操作.分為匿名管道和命名管道.
這里面包括了一些概念.進程的概念大家都應(yīng)該很清楚:程序的執(zhí)行實例被稱為進程.UNIX系統(tǒng)確保每個進程都有一個唯一的數(shù)字表示符,稱為進程ID(process ID),它是一個非負數(shù).Linux很多命令都會將其顯示出來.有3個用于進程控制的主要函數(shù):fork,exec和waitpid.其中fork函數(shù)用來創(chuàng)建一個新進程,此進程是調(diào)用進程的一個副本,稱為子進程.fork對父進程返回新的子進程的進程ID(一個非負整數(shù)),對子進程則返回0.因為fork創(chuàng)建一個新進程,所以說它被調(diào)用一次,但返回兩次.
一個進程內(nèi)的所有線程共享同一地址空間,文件描述符,棧以及進程相關(guān)的屬性.因為它們能拜訪同一存儲區(qū),所以各線程在拜訪共享數(shù)據(jù)時需要采取同步措施以避免不一致性.說到這里大家都應(yīng)該多少有些概念了:為什么進程開銷大,線程涉及鎖.
匿名管道是一個未命名的,單向管道,通過父進程和一個子進程之間傳輸數(shù)據(jù).只能實現(xiàn)當?shù)貦C器上兩個進程之間的通信,而不能實現(xiàn)跨網(wǎng)絡(luò)的通信.常用的比如Linux命令.
定名管道是進程間單向或雙向管道,建立時指定一個名字,任何進程都可以通過該名字打開管道的另一端,可跨網(wǎng)絡(luò)通信.
這是一個jvisualvm調(diào)試的截圖,藍框部門就相當于一個命名管道.
好,現(xiàn)在來答復一個問題:用戶進程間通信主要哪幾種方式?
剛才說的匿名管道和命名管道都算一種.除此之外,還有:信號,消息隊列,共享內(nèi)存,信號量和套接字.不消頭疼,看到最后你很可能會有豁然開朗的感覺,學的東西終于可以串在一起了.
信號(signal):其實是軟中斷信號的簡稱.用來通知進程發(fā)生了異步事件.在軟件層次上是對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一個中斷哀求是一樣的.信號是進程間通信機制中唯一的異步通信機制,一個進程不必通過任何操作來等待信號的到達.
收到信號的進程對各種信號有不同的處理辦法,主要是三類:
1>類似中斷的處理程序,對于必要處理的信號,進程可以指定處理函數(shù),由該函數(shù)來處理.
2>忽略某個信號,對該信號不做任何處置.
3>對該信號的處理保存系統(tǒng)的默認值,這種缺省操作,對大部分的信號的缺省操作是讓進程終止.進程通過系統(tǒng)調(diào)用signal來指定進程對某個信號的處理行為.
下面是window的旌旗燈號列表
Linux也是用kill -l敕令:
1) SIGHUP? ? ? 2) SIGINT? ? ? 3) SIGQUIT? ? ? 4) SIGILL
?5) SIGTRAP? ? ? 6) SIGABRT? ? ? 7) SIGBUS? ? ? 8) SIGFPE
?9) SIGKILL? ? 10) SIGUSR1? ? 11) SIGSEGV? ? 12) SIGUSR2
13) SIGPIPE? ? 14) SIGALRM? ? 15) SIGTERM? ? 17) SIGCHLD
18) SIGCONT? ? 19) SIGSTOP? ? 20) SIGTSTP? ? 21) SIGTTIN
22) SIGTTOU? ? 23) SIGURG? ? ? 24) SIGXCPU? ? 25) SIGXFSZ
26) SIGVTALRM? 27) SIGPROF? ? 28) SIGWINCH? ? 29) SIGIO
30) SIGPWR? ? ? 31) SIGSYS? ? ? 34) SIGRTMIN? ? 35) SIGRTMIN+1
36) SIGRTMIN+2? 37) SIGRTMIN+3? 38) SIGRTMIN+4? 39) SIGRTMIN+5
40) SIGRTMIN+6? 41) SIGRTMIN+7? 42) SIGRTMIN+8? 43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8? 57) SIGRTMAX-7? 58) SIGRTMAX-6? 59) SIGRTMAX-5
60) SIGRTMAX-4? 61) SIGRTMAX-3? 62) SIGRTMAX-2? 63) SIGRTMAX-1
64) SIGRTMAX
我在用gdb命令運行調(diào)試C語言程序的時候常常可以看到這些信號量.
再來看消息隊列.消息隊列提供了一種從一個進程向另一個進程發(fā)送一個數(shù)據(jù)塊的辦法.每個數(shù)據(jù)塊都被認為含有一個類型,接收進程可以獨立的接收含有不同類型的數(shù)據(jù)結(jié)構(gòu).可以通過發(fā)送消息來避免命名管道的同步和阻塞問題.但是消息隊列和命名管道一樣,每個數(shù)據(jù)塊都有一個最大長度的限制.
共享內(nèi)存就是允許兩個不相關(guān)的進程訪問同一個邏輯內(nèi)存.共享內(nèi)存是在兩個正在運行的進程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式.不同進程之間共享的內(nèi)存通常支配為同一段物理內(nèi)存.進程可以將同一段共享內(nèi)存連接到他們自己的地址空間中,所有進程都可以訪問共享內(nèi)存中的地址.
信號量:為了防止出現(xiàn)因多個程序同時拜訪一個共享資源而引發(fā)的一系列問題,我們需要一種方法,它可以通過生成并使用令牌來授權(quán),在任一時刻只能有一個執(zhí)行線程拜訪代碼的臨界區(qū)域.臨界區(qū)域是指執(zhí)行數(shù)據(jù)更新的代碼需要獨占式的執(zhí)行.而信號量就可以提供這樣的一種拜訪機制.讓一個臨界區(qū)同一時間只有一個線程在拜訪它,也就是說信號量是用來協(xié)調(diào)對共享資源拜訪的.
套接字:這種通信機制使得客戶端/服務(wù)器的開發(fā)工作既可以在當?shù)貑螜C上進行,也可以跨網(wǎng)絡(luò)進行.它的特性有三個屬性確定:域(domain),類型(type)和協(xié)議(protocol).簡單的說:源IP地址和目的IP地址以及源端口號和目的端口號的組合成為套接字.
下面介紹一下通信過程,里面涉及一些C語言的函數(shù),不消怕,眼熟即可.如果你學習過nio,你會發(fā)現(xiàn)這些是很常接觸的.
要想使不同主機的進程通信,就必需使用套接字,套接字是用socket()函數(shù)創(chuàng)建,如果需要C/S模式,則需要把server的套接字與地址和端口綁定起來,使用bind(),當上述操作完成后,便可使用listen()來監(jiān)聽這個端口,如果有其他程序來connect,那么server將會調(diào)用accept()來接受這個申請并為其服務(wù).client是調(diào)用connect()來建立與server之間的連接,這時會使用三次握手來建立一條數(shù)據(jù)鏈接.當連接被建立后,server與client便可以通信了,通信可以使用read()/write(),send()/recv(),sendto()/recvfrom()等函數(shù)來實現(xiàn),但是不同的函數(shù)作用和使用位置是不同的.當數(shù)據(jù)傳送完后,可以調(diào)用close()來關(guān)閉server與client之間的鏈接.
到此,本篇文章的主要內(nèi)容就沒有了,基本就在介紹一個東西:linux內(nèi)核的進程通信.這是學習任何高級編程語言nio部門的基礎(chǔ).下面引入一些輔助理解的概念.
文件句柄:在文件I/O中,要從一個文件讀取數(shù)據(jù),應(yīng)用程序首先要調(diào)用操作系統(tǒng)函數(shù)并傳送文件名,并選一個到該文件的路徑來打開文件.該函數(shù)取回一個順序號,即文件句柄(file handle),該文件句柄對于打開的文件是唯一的識別依據(jù).一個句柄就是你給一個文件,設(shè)備,套接字(socket)或者管道的一個名字,以便幫助你記住你證處理的名字,并暗藏某些緩存等的復雜性.說白了就是文件指針啦.
文件描述符:內(nèi)核利用文件描述符來拜訪文件.打開現(xiàn)存文件或新建文件時,內(nèi)核會返回一個文件描述符.讀寫文件也需要使用文件描???符來指定待讀寫的文件.文件描述符形式上是非負整數(shù),實際上它是一個索引值,指向內(nèi)核為每一個進程所維護的該進程打開文件的記錄表.當程序打開一個現(xiàn)有文件或者創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符.在程序設(shè)計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開.但是文件描述符往往值適用于unix,linux這樣的操作系統(tǒng).習慣上,標準輸入的文件描述符是0,標準輸出是1,標準錯誤是2.
`/letv/apps/jdk/bin/java -DappPort=4 $JAVA_OPTS -cp $PHOME/conf:$PHOME/lib/* com.letv.mms.transmission.http.VideoFullServerBootstrap $1 $3 > /dev/null 2>&1 &`
本身部署過java后臺程序的話,對上面的shell命令應(yīng)該都能理解. /dev/null 2>&1 這里面的2就是文件描述符,這個是將錯誤輸出到文件.
這兩個概念比較繞,不用過多區(qū)分,可以當成一回事來理解.打開文件(open files)包含文件句柄但不僅限于文件句柄,由于lnux所有的事務(wù)都以文件的形式存在,要使用諸如共享內(nèi)存,信號量,消息隊列,內(nèi)存映射等都會打開文件,但這些不會占用文件句柄.查看進程允許打開的最大文件句柄數(shù)的linux命令:ulimit -n
好了,本日的概念都介紹完了,回到最初的問題:too many open files. 當時的機器破,內(nèi)存快滿了.所以搜索引擎走的是索引文件,有很多的IO操作,共享內(nèi)存和內(nèi)存映射這塊的文件肯定是供不上的,報錯了.縈繞在心頭兩年的問題稍微有點認知了.
本文永遠更新鏈接地址:
歡迎參與《LINUX教程:快速記住Linux內(nèi)核的基本概念》討論,分享您的想法,維易PHP學院為您提供專業(yè)教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/9034.html