linux 內核參數圖解


 

https://www.suse.com/documentation/sles11/book_sle_tuning/data/part_tuning_kernel.html 

http://blog.csdn.net/maimang1001/article/details/34941471

https://www.suse.com/documentation/sles11/book_sle_tuning/data/sec_tuning_network_buffers.html

http://dirtysalt.info/os.html

 

Linux

1 vmlinuz

vmlinuz是可引導的、壓縮的內核。“vm”代表“Virtual Memory”。Linux 支持虛擬內存,不像老的操作系統比如DOS有640KB內存的限制。Linux能夠使用硬盤空間作為虛擬內存,因此得名“vm”。vmlinuz是可執行的Linux內核,它位於/boot/vmlinuz,它一般是一個軟鏈接。vmlinux是未壓縮的內核,vmlinuz是vmlinux的壓縮文件。

vmlinuz的建立有兩種方式。一是編譯內核時通過“make zImage”創建,然后通過:“cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage /boot/vmlinuz”產生。zImage適用於小內核的情況,它的存在是為了向后的兼容性。二是內核編譯時通過命令make bzImage創建,然后通過:“cp /usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz”產生。bzImage是壓縮的內核映像,需要注意,bzImage不是用bzip2壓縮的,bzImage中的bz容易引起誤解,bz表示“big zImage”。 bzImage中的b是“big”意思。

zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip壓縮的。它們不僅是一個壓縮文件,而且在這兩個文件的開頭部分內嵌有gzip解壓縮代碼。所以你不能用gunzip 或 gzip –dc解包vmlinuz。內核文件中包含一個微型的gzip用於解壓縮內核並引導它。兩者的不同之處在於,老的zImage解壓縮內核到低端內存(第一個640K),bzImage解壓縮內核到高端內存(1M以上)。如果內核比較小,那么可以采用zImage或bzImage之一,兩種方式引導的系統運行時是相同的。大的內核采用bzImage,不能采用zImage。

2 TCP IO

2.1 create connection

下面摘自 "Linux TCP隊列相關參數的總結":

tcp-create-connection.png

簡單看下連接的建立過程,客戶端向server發送SYN包,server回復SYN+ACK,同時將這個處於SYN_RECV狀態的連接保存到半連接隊列。客戶端返回ACK包完成三次握手,server將ESTABLISHED狀態的連接移入accept隊列,等待應用調用accept()。可以看到建立連接涉及兩個隊列:

  • 半連接隊列,保存SYN_RECV狀態的連接。隊列長度由net.ipv4.tcp_max_syn_backlog設置。
  • accept隊列,保存ESTABLISHED狀態的連接。隊列長度為min(net.core.somaxconn, backlog). # listen(sockfd, backlog)

另外,為了應對SYN flooding(即客戶端只發送SYN包發起握手而不回應ACK完成連接建立,填滿server端的半連接隊列,讓它無法處理正常的握手請求),Linux實現了一種稱為SYN cookie的機制,通過net.ipv4.tcp_syncookies控制,設置為1表示開啟。簡單說SYN cookie就是將連接信息編碼在ISN(initial sequence number)中返回給客戶端,這時server不需要將半連接保存在隊列中,而是利用客戶端隨后發來的ACK帶回的ISN還原連接信息,以完成連接的建立,避免了半連接隊列被攻擊SYN包填滿。對於一去不復返的客戶端握手,不理它就是了。

2.2 packet reception

tcp-packet-reception.png

整個流程大致如下:

  • linux里面使用sk_buff數據結構來描述packet.
  • NIC檢測到packet到達,從Kernel Memory(sk_buffs)分配sk_buff數據結構,調用DMA Engine將packet放到sk_buff數據結構里面 #note: NIC檢測有packet到達和有packet發送,都不是觸發而是主動poll的方式來完成的
  • 將sk_buff並且加入rx_ring這個ring_buffer里面。如果rx_ring滿了的話那么將packet丟棄。
  • 當DMA Engine完成處理之后, NIC通過向CPU發起中斷 通知kernel進行處理。
  • kernel將這個packet傳遞給IP層進行處理。IP層需要將信息組裝成為ip packet。如果ip packet是tcp的話那么放到socket backlog里面。如果socket backlog滿了的話那么將ip packet丟棄。 copy packet data to ip buffer to form ip packet #note: 這個步驟完成之后IP layer就可以釋放sk_buffer結構
  • tcp layer從socket backlog里面取出tcp packet, copy ip packet tcp recv buffer to form tcp packet
  • tcp recv buffer交給application layer處理, copy tcp recv buffer to app buffer to form app packet
  • 其中內核參數有
    • /proc/sys/net/ipv4/tcp_rmem # tcp recv buffer大小
    • /proc/sys/net/core/netdev_max_backlog # 圖中socket backlog大小,和accept系統調用的backlog區分開。

下面這些是從文章摘取出來的

Linux在2.6.17以后增加了recv Buffer自動調節機制,recv buffer的實際大小會自動在最小值和最大值之間浮動,以期找到性能和資源的平衡點,因此大多數情況下不建議將recv buffer手工設置成固定值。

當net.ipv4.tcp_moderate_rcvbuf設置為1時,自動調節機制生效,每個TCP連接的recv Buffer由下面的3元數組指定:net.ipv4.tcp_rmem = (min, default, max). 最初recv buffer被設置為<default>,同時這個缺省值會覆蓋net.core.rmem_default的設置。隨后recv buffer根據實際情況在最大值和最小值之間動態調節。在緩沖的動態調優機制開啟的情況下,我們將net.ipv4.tcp_rmem的最大值設置為BDP(Bandwidth-Delay Product)。

當net.ipv4.tcp_moderate_rcvbuf被設置為0,或者設置了socket選項SO_RCVBUF,緩沖的動態調節機制被關閉。recv buffer的缺省值由net.core.rmem_default設置,但如果設置了net.ipv4.tcp_rmem,缺省值則被覆蓋。可以通過系統調用setsockopt()設置recv buffer的最大值為net.core.rmem_max。在緩沖動態調節機制關閉的情況下,建議把緩沖的缺省值設置為BDP。

發送端緩沖的自動調節機制很早就已經實現,並且是無條件開啟,沒有參數去設置。如果指定了tcp_wmem,則net.core.wmem_default被tcp_wmem的覆蓋。send Buffer在tcp_wmem的最小值和最大值之間自動調節。如果調用setsockopt()設置了socket選項SO_SNDBUF,將關閉發送端緩沖的自動調節機制,tcp_wmem將被忽略,SO_SNDBUF的最大值由net.core.wmem_max限制。

2.3 packet transmission

tcp-packet-transmission.png

整個流程大致如下:

  • application layer將數據copy到tcp send buffer里面,如果空間不夠的話那么就會出現阻塞。 copy app buffer to tcp send buffer as app packet
  • tcp layer等待tcp send buffer存在數據或者是需要做ack的時候,組裝ip packet推送到IP layer copy tcp send buffer to ip send buffer as tcp packet
  • IP layer從kernel memory申請sk_buffer,將ip data包裝成為packet data,然后塞到qdisc(txqueuelen控制隊列長度)里面(指針)。如果隊列滿的話那么就會出現阻塞,反饋到tcp layer阻塞。copy ip send buffer to packet data as ip packet
  • NIC driver如果檢測到qdisc有數據的話,調用NIC DMA Engine將packet發送出去。發送完成之后NIC向CPU發起中斷釋放packet data內存到Kernel Memory
  • 其中內核參數有:
    • /proc/sys/net/ipv4/tcp_wmem 這個和rmem非常類似
    • #note: 與上面類比,相關參數還有net.core.wmem_default和net.core.wmem_max.

#note: 在wangyx的幫助下, qdisc隊列長度參數txqueuelen這個配置在ifconfig下面找到了. txqueuelen = 1000.

➜  ~  ifconfig
eth0      Link encap:Ethernet  HWaddr 12:31:40:00:49:d1
          inet addr:10.170.78.31  Bcast:10.170.79.255  Mask:255.255.254.0
          inet6 addr: fe80::1031:40ff:fe00:49d1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13028359 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9504902 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2464083770 (2.4 GB)  TX bytes:20165782073 (20.1 GB)
          Interrupt:25

下面摘自: Linux TCP隊列相關參數的總結

QDisc(queueing discipline )位於IP層和網卡的ring buffer之間。我們已經知道,ring buffer是一個簡單的FIFO隊列,這種設計使網卡的驅動層保持簡單和快速。而QDisc實現了流量管理的高級功能,包括流量分類,優先級和流量整形(rate-shaping)。可以使用tc命令配置QDisc。

QDisc的隊列長度由txqueuelen設置,和接收數據包的隊列長度由內核參數net.core.netdev_max_backlog控制所不同,txqueuelen是和網卡關聯

2.4 congestion control

tcp-congestion-control.png

  • 初始狀態是slow start
  • cwnd(congestion window) 擁塞窗口,表示一次最多發送的數據包多少。
  • ssthresh(slow start threshold) 慢速啟動閾值。
  • MSS(maximum segment size) 最大分節大小,和傳輸網絡的MTU相關。
  • 為什么多 TCP 連接分塊下載比單連接下載快?

3 kernel panic

kernel-panic-not-syncing-attempted-to-kill-init.png

5 程序返回值問題

首先看下面一段Java程序

/* coding:utf-8
 * Copyright (C) dirlt
 */

public class X{
  public static void main(String[] args) {
    System.exit(1);
  }
}

然后這個Java程序被Python調用,判斷這個打印值

#!/usr/bin/env python
#coding:utf-8
#Copyright (C) dirlt

import os
print os.system('java X')

返回值不為1而是256,對此解釋是這樣的

a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.

但是下面這段Python程序,使用echo $?判斷返回值為0而不是256

#!/usr/bin/env python
#coding:utf-8
#Copyright (C) dirlt

code=256
exit(code)

6 dp8網卡問題

當時dp8的網絡流量從一個非常大的值變為非常小的值,檢查/proc/net/netstat,以下幾個統計數值dp8和其他機器差距較大(相差1-2個數量級):

  • TCPDirectCopyFromPrequeue
  • TCPHPHitsToUser
  • TCPDSACKUndo
  • TCPLossUndo
  • TCPLostRetransmit
  • TCPFastRetrans
  • TCPSlowStartRetrans
  • TCPSackShiftFallback

之后在dmesg上面發現如下線索:

dp@dp8:~$ dmesg | grep eth0
[ 15.635160] eth0: Broadcom NetXtreme II BCM5716 1000Base-T (C0) PCI Express f
[ 15.736389] bnx2: eth0: using MSIX
[ 15.738263] ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 37.848755] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex
[ 37.850623] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 1933.934668] bnx2: eth0: using MSIX
[ 1933.936960] ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 1956.130773] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex
[ 1956.132625] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[4804526.542976] bnx2: eth0 NIC Copper Link is Down
[4804552.008858] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex

日志 [4804552.008858] bnx2: eth0 NIC Copper Link is Up, 100 Mbps full duplex 表明dp8上的網卡速度被識別成100 Mbps了。

可能的原因如下:

  • 網線、水晶頭質量太差或老化、水晶頭沒壓好,從而導致網線接觸不良或短路等,可以重新壓水晶頭或更換網線,建議用質量可靠的六類網線六類水晶頭
  • 本地連接―右鍵―屬性―配置―高級―速度和雙工,這里設置錯誤,改為自動感應或1000Mbps全雙工即可
  • 網卡所接的交換機或路由器等硬件設備出現故障,或者這些設備是百兆的(千和百連在一起,千變百向下兼容)
  • 電磁場干擾有時也會變百兆,所以說網線盡量別與電線一起穿管(論壇會員tchack友情提供)

我們的網線都是由 世xx聯 提供的,質量應該不錯,有兩種情況需要優先排除。

  • 網線問題(測試方法:換根網線試試)
  • 交換機dp8連接的口壞了(測試方法:把dp8的網線換一個交換機的口)

7 修改資源限制

臨時的修改方式可以通過ulimit來進行修改,也可以通過修改文件/etc/security/limits.conf來永久修改

hadoop - nofile 102400
hadoop - nproc 40960

8 CPU溫度過高

這個問題是我在Ubuntu PC上面遇到的,明顯的感覺就是運行速度變慢。然后在syslog里面出現如下日志:

May  2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717609] CPU1: Core temperature/speed normal
May  2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717612] CPU0: Package temperature above threshold, cpu clock throttled (total events = 137902)
May  2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717615] CPU2: Package temperature above threshold, cpu clock throttled (total events = 137902)
May  2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717619] CPU1: Package temperature above threshold, cpu clock throttled (total events = 137902)
May  2 18:24:21 umeng-ubuntu-pc kernel: [ 1188.717622] CPU3: Package temperature above threshold, cpu clock throttled (total events = 137902)

9 sync hangup

10 更換glibc

@2013-05-23 https://docs.google.com/a/umeng.com/document/d/12dzJ3OhVlrEax3yIdz0k08F8tM8DDQva1wdrD3K49PI/edit 懷疑glibc版本存在問題,在dp45上操作但是出現問題。

我的操作順序計划是這樣的:

  1. 將dp20的glibc copy到自己的目錄下面/home/dp/dirlt/libc-2.11.so
  2. 將dp45的glibc backup. mv /lib64/libc-2.12.so /lib64/libc-2.12.bak.so(補充一點,就是在lib64下面還有軟鏈接 libc.so.6 -> libc-2.12.so,這個文件應該是被程序查找使用的)
  3. cp /home/dp/dirlt/libc-2.11.so /lib64/libc-2.12.so

但是進行到2之后就發現cp不可用了,並且ls等命令也不能夠使用了。原因非常簡單,就是因為2之后libc.so.6沒有對應的文件了,而cp,ls這些基本的命令依賴於這個動態鏈接庫。

~ $ ldd /bin/cp
	linux-vdso.so.1 =>  (0x00007fff9717f000)
	libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f5efb804000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f5efb5fc000)
	libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f5efb3f3000)
	libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f5efb1ee000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5efae2f000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5efac2a000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5efba2d000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5efaa0d000)

@2013-08-03

A copy of the C library was found in an unexpected directory | Blog : http://blog.i-al.net/2013/03/a-copy-of-the-c-library-was-found-in-an-unexpected-directory/

上面的鏈接給出了升級glibc的方法

  • sudo su - root # 首先切換到root賬號下面
  • mv libc.so librt.so /root # 將glibc等相關的so移動到root賬號下面,主要不要移動軟連接文件。
  • LD_PRELOAD=/root/libc.so:/root/librt.so bash # 這個時候如果執行bash是找不到glibc等so了,所以需要使用LD_PRELOAD來預先加載
  • apt-get install # 在這個bash下面使用apt-get來安裝和升級glibc.

11 允許不在tty上執行sudo

修改/etc/sudoers文件,注釋掉

Defaults requiretty

12 ssh proxy

http://serverfault.com/questions/37629/how-do-i-do-multihop-scp-transfers

  • 目的機器是D,端口是16021,用戶是x
  • 跳板機器是T,端口是18021,用戶是y
  • client需要和x@D以及y@T建立信任關系
  • 方法A
    • 從T上和D建立鏈接並且配置轉發端口p, 所有和T:p的數據交互都會轉發到D:16021
    • 在T上執行 ssh -L "*:5502:D:16021" x@D # 轉發端口是5502
      • -o ServerAliveInterval=60 # 我才想單位應該是s。這樣每隔60s可以和server做一些keepalive的通信,確保長時間沒有數據通信的情況下,連接不會斷開。
    • ssh -p 5502 x@T 或者 scp -P 5502 <file> x@T:<path-at-D>
  • 方法B
    • scp可以指定proxyCommand配合D上nc命令完成
    • scp -o ProxyCommand="ssh -p 18021 y@T 'nc D 16021'" <file> x@D:<path-at-D>

13 修改最大打開文件句柄數

首先需要修改系統上限

  • /proc/sys/fs/file-max # 所有進程打開文件句柄數上限
  • /proc/sys/fs/nr_open # 單個進程打開文件句柄數上限
  • /proc/sys/fs/file-nr # 系統當前打開文件句柄數

然后修改用戶(進程)使用上限

  • /etc/security/limits.conf
  • ulimit

14 apt-get hang

在使用ubuntu的apt-get時候,可能會出現一些異常的狀況,我們直接終止了apt-get。但是這個時候apt-get軟件本身出於一個不正常的狀態,導致之后不能夠啟動apt-get。如果觀察進程的話會出現下面一些可疑的進程

dp@dp1:~$ ps aux | grep "apt"
root      3587  0.0  0.0  36148 22800 ?        Ds   Oct08   0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/sgml-data_2.0.4_all.deb
root      9579  0.0  0.0  35992 22744 ?        Ds   Oct19   0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/iftop_0.17-16_amd64.deb
root     25957  0.0  0.0  36120 22796 ?        Ds   Nov05   0:00 /usr/bin/dpkg --status-fd 50 --unpack --auto-deconfigure /var/cache/apt/archives/iftop_0.17-16_amd64.deb /var/cache/apt/archives/iotop_0.4-1_all.deb
dp       30586  0.0  0.0   7628  1020 pts/2    S+   08:59   0:00 grep --color=auto apt

這些進程的父進程都是init進程,並且狀態是uninterruptible sleep,給kill -9也沒有辦法終止,唯一的辦法只能reboot機器來解決這個問題。關於這個問題可以看stackoverflow上面的解答 How to stop 'uninterruptible' process on Linux? - Stack Overflow http://stackoverflow.com/questions/767551/how-to-stop-uninterruptible-process-on-linux

  • Simple answer: you cannot. Longer answer: the uninterruptable sleep means the process will not be woken up by signals. It can be only woken up by what it's waiting for. When I get such situations eg. with CD-ROM, I usually reset the computer by using suspend-to-disk and resuming.
  • The D state basically means that the process is waiting for disk I/O, or other block I/O that can't be interrupted. Sometimes this means the kernel or device is feverishly trying to read a bad block (especially from an optical disk). Sometimes it means there's something else. The process cannot be killed until it gets out of the D state. Find out what it is waiting for and fix that. The easy way is to reboot. Sometimes removing the disk in question helps, but that can be rather dangerous: unfixable catastrophic hardware failure if you don't know what you're doing (read: smoke coming out).

15 使用自選鎖來實現信號量

typedef struct sema { lock_t lock; int count; queue q; } sema_t; void init_sema(sema_t* sema, int init_cnt) { init_lock(&sema->lock); init_queue(&sema->q); sema->count=init_cnt; } void p(sema_t* sema) { lock(&sema->lock); sema->count--; if (sema->count < 0) { q.push(current_process_context()); unlock(&sema->lock); swtch(); // switch to another process. return; } unlock(&sema->lock); } void v(sema_t* sema) { lock(&sema->lock); sema->count++; if (sema->count <= 0) { pcs_ctx* ctx = q.pop(); unlock(&sema->lock); enqueue(&running_queue, ctx); return ; } unlock(&sema->lock); }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM