|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大家知道,在linux操作系统中,写操作是异步的,即写操作返回的时候数据并没有真正写到磁盘上,4 C/ [2 }" e% m: i' G
7 D4 P% n$ }! r4 v9 j
而是先写到了系统cache里,随后由pdflush内核线程将系统中的脏页写到磁盘上,在下面几种情况下,
/ D, ?9 t: r/ E/ D$ K& @0 Z系统会唤醒pdflush回写脏页:. N; N$ r" T6 ?* X; s* d* ]
1 、定时方式:3 s, H: p @. C: L
定时机制定时唤醒pdflush内核线程,周期为/proc/sys/vm/dirty_writeback_centisecs ,单位
2 o8 M4 ]$ x! }' ^; u7 x. N是(1/100)秒,每次周期性唤醒的pdflush线程并不是回写所有的脏页,而是只回写变脏时间超过
( }. T/ w9 }. F& Q' P/ \+ T @/proc/sys/vm/dirty_expire_centisecs(单位也是1/100秒)。
/ i. r' F4 c# L! A注意:变脏的时间是以文件的inode节点变脏的时间为基准的,也就是说如果某个inode节点是10秒前变脏的,% A. a& f! Z: e. H8 v. _
pdflush就认为这个inode对应的所有脏页的变脏时间都是10秒前,即使可能部分页面真正变脏的时间不到10秒," Y! ^4 f1 `% q+ G& |
细节可以查看内核函数wb_kupdate()。
" g' W4 g" V7 C7 U6 T) s3 M% U) V" E _! \5 u+ \6 c- N1 x
2、 内存不足的时候:8 g) y4 s- J5 G. [$ @3 L
这时并不将所有的dirty页写到磁盘,而是每次写大概1024个页面,直到空闲页面满足需求为止。
. G: j7 P1 \8 X, s
- S/ z: _+ |- k) {3 、写操作时发现脏页超过一定比例:
# k/ g) Q2 s/ i% r( N n; u3 k8 Y 当脏页占系统内存的比例超过/proc/sys/vm/dirty_background_ratio 的时候,write系统调用会唤醒3 ]+ C! t1 k' d1 h
pdflush回写dirty page,直到脏页比例低于/proc/sys/vm/dirty_background_ratio,但write系统调! g' E6 T7 o5 p3 e/ K7 I4 v
用不会被阻塞,立即返回。当脏页占系统内存的比例超过/proc/sys/vm/dirty_ratio的时候, write系
% l/ y7 H+ G* H) y6 `统调用会被被阻塞,主动回写dirty page,直到脏页比例低于/proc/sys/vm/dirty_ratio,这一点在
, U2 X7 K2 V3 O% y% t0 V/ l2.4内核中是没有的。
, ?) x Q& ?7 \* `1 F, w
) W" E2 F# a- l: I# |4 、用户调用sync系统调用:
) D. S: f' X; f) c 这是系统会唤醒pdflush直到所有的脏页都已经写到磁盘为止。# E$ a) q# x* }! L. d
6 {4 [/ o) \4 @: p& b$ b6 m6 `' _
( b4 o1 ]6 C4 a9 h3 d' B一、简介 ) F! j% n8 h0 p, N
由于页高速缓存的缓存作用,写操作实际上会被延迟。
; k7 i2 l4 l, r% v; Y" h当页高速缓存中的数据比后台存储的数据更新时,那么该数据就被称做脏数据。
[ ]! E) y6 G$ k3 ^- h在内存中累积起来的脏页最终必须被写回磁盘。
9 w- s2 W# K4 Q+ s, r: ~+ I. B+ F( `: r3 @; p! P) P
在以下两种情况发生时,脏页被写回磁盘:0 N' N8 r8 z! _6 C. ^8 A
. 当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。 6 U2 v& w# u. v: j* ]% C2 I
. 当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘,7 b. ]- Y) _; P+ ?
以确保脏页不会无限期地驻留在内存中。
* s8 i+ f" J. x7 f1 Q, _
D( j% ^+ X3 |) d3 r! k) Z1 h上面两种工作的目的完全不同。
# J: t7 B0 e' n& a( v( g6 l9 ^实际上,在老内核中,这是由两个独立的内核线程分别完成的。
# f* j' S/ z+ k7 ~0 j7 \3 l' Y但是在2.6内核中,由一群内核线程—pdflush后台回写例程—统一执行两种工作。
! b$ ~& {$ o* O
: }8 \9 ~- y# w; v; ~. S+ T我们来看看这两个目标是如何具体实现的。7 D( x- T) o& {3 Y
首先,当系统中的空闲内存低于一个特定的阈值时,pdflush线程将脏页刷新回磁盘。
. g4 M' N% h3 t3 R5 J2 e该后台回写例程的目的在于在可用物理内存过低时,释放脏页以重新获得内存。, ]- y8 X4 x+ U! x$ D8 y
特定的内存阈值可以通过dirty_background_ratio参数设置。. c! ]; f# ^5 U! T p
当空闲内存比阈值dirty_ background_ratio还低时,内核便会调用函数wakeup_bdflush()唤醒一个pdflush线程,* {' G8 n/ \! m: c" f
随后pdflush线程进一步调用函数background_writeout()开始将脏页写回磁盘。, A) e7 q$ ]+ u$ K8 w: q+ W# v6 e
函数background_ writeout()需要一个长整型参数,该参数指定试图回写的页面数目。
/ F# Q0 H, g6 ^, V2 n- b4 M3 h4 S& y+ D, W1 X' i& P! U
函数background_writeout()会连续地写出数据,直到满足以下两个条件:
; l" e0 }0 O* A; Y. 已经有指定的最小数目的页被写出到磁盘。 ; ]- U3 O. C$ H; o: h3 [( L
. 空闲内存数已经回升,超过了阈值dirty_background_ratio。
# F: K8 Y9 z! C$ ^, {# M/ X$ K2 n+ h
上述条件确保了pdflush操作可以减轻系统中内存不足的压力。
- z" K; G2 h: h8 z回写操作不会在达到这两个条件前停止,除非pdflush写回了所有的脏页,没有剩下的脏页可再被写回了。5 _" a3 |' R' m( J
2 ]4 O7 n7 ^! H. v, V; ]# q要满足第二个目标,pdflush后台例程会被周期性唤醒(和空闲内存是否过低无关),
; r" Q: l+ i) S5 {: I0 k' A3 M5 d将那些在内存中驻留时间过长的脏页写出,确保内存中不会有长期存在的脏页。
C. A H' V8 k) E# F0 w5 E加入系统发生崩溃,则内存会处于混乱之中,而那些在内存中还没来得及写回磁盘的脏页就会丢失,
0 N/ A/ g- ~* S: X所以周期性同步回写非常重要。9 z8 _0 l% o4 A! B' s8 o2 D
. p; U4 a. a9 d& ]5 L! P6 k: O( P在系统启动时,内核初始化一个定时器,让它周期地唤醒pdflush线程,随后使其运行函数wb_kupdate()。
. ~/ P5 q! v/ W u1 _该函数将把所有驻留时间超过百分之dirty_expire_centisecs秒的脏页写回。
9 d. X% F$ {4 f) ~- `; a然后定时器将再次被初始化为百分之dirty_expire_ centisecs秒后唤醒pdflush线程。2 o! S9 l9 j4 [/ B7 E* F$ w- [1 r; Y
总而言之,pdflush线程周期地被唤醒并且把超过特定期限的脏页写回磁盘。
! B: u* K3 b% C' S( ~3 t+ a9 u: N8 C$ A6 ~: X' {
二、proc下的相关控制参数( Y9 S3 T0 C( t4 i+ D3 U
系统管理员可以在/proc/sys/vm中设置回写相关的参数,也可以通过sysctl系统调用设置它们。
) O3 E, d* \' f' U/ v5 {0 S, r
1. /proc/sys/vm/dirty_ratio
) Z: M9 d& O9 ^/ w! x/ p这个参数控制一个进程在文件系统中的文件系统写缓冲区的大小,单位是百分比,表示系统内存的百分比,
9 |/ ^& R4 q, A) n* f% i表示当一个进程中写缓冲使用到系统内存多少的时候,再有磁盘写操作时开始向磁盘写出数据。' q5 @0 o) ?8 c4 T' [# ^
增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。
?( x# v! V: d& J$ G$ l但是,当你需要持续、恒定的写入场合时,应该降低其数值.- o" q, ?# G+ N; L A' T# O
一般缺省是 40。, S! \3 `: X6 E) u
设置方法如下:
0 j5 X' I# l, v; f/ m3 eecho 30 >/proc/sys/vm/dirty_ratio
2 h7 A& w6 j" I0 }) g8 r" X# C
5 ^$ w; d) q; ?/ _3 w+ f5 o2. /proc/sys/vm/dirty_background_ratio7 @; W- Z T2 b: F* \( r/ q7 p
这个参数控制文件系统的pdflush进程,在何时刷新磁盘。单位是百分比,表示系统总内存的百分比,5 v3 x" G# h% F
意思是当磁盘的脏数据缓冲到系统内存多少的时候,pdflush开始把脏数据刷新到磁盘。
+ Y% v7 _1 z! e9 u$ m增大会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。
8 W/ a! A }" a" [( {- `8 x6 F但是,当你需要持续、恒定的写入场合时,应该降低其数值.
9 d7 O* U% [( h! a一般缺省是10。
/ f5 \& g! ?/ ?设置方法如下:; T: S' \% e6 C
echo 8 >/proc/sys/vm/dirty_background_ratio3 O1 O" G; k% G( a
9 _; Y, Y6 a: F0 q, \1 U) r( x. s+ z
3. /proc/sys/vm/dirty_writeback_centisecs( J: ]7 w! Q% }4 c" x
Pdflush写后台进程每隔多久被唤醒并执行把脏数据写出到硬盘。单位是 1/100 秒。
% T( R7 O2 }. {如果你的系统是持续地写入动作,那么实际上还是降低这个数值比较好,这样可以把尖峰的写操作削平成多次写操作。$ c+ w) E( L% |6 @
缺省数值是500,也就是 5 秒。4 `# R. b0 s; R( n) Z* M3 j4 G
设置方法如下:* B5 L; S* s( x, ~" s: Q* H$ ^
# echo 200 >/proc/sys/vm/dirty_writeback_centisecs7 O: z5 g4 p& y# a% Y" t: k. T
0 y1 _# U& ~& E+ s
4. /proc/sys/vm/dirty_expire_centisecs( g% B x9 T" R: K
这个参数声明Linux内核写缓冲区里面的脏数据多“旧”了之后,pdflush 进程就开始考虑写到磁盘中去。3 R/ y0 F, P. ?
单位是 1/100秒。
( ~' A- z8 l: O$ E对于特别重载的写操作来说,这个值适当缩小也是好的,但也不能缩小太多,因为缩小太多也会导致IO提高太快。
$ G H2 V8 r$ ?9 s, P I4 r3 [缺省是 30000,也就是 30 秒的数据就算旧了,将会刷新磁盘。3 ~+ L8 P4 {' q. J) j4 d/ D: ]
建议设置为 1500,也就是15秒算旧。0 k, R' u, q+ Z7 i5 F0 A/ h
设置方法如下:1 Q i. ~. [9 \2 t+ r' q
echo 1500 >/proc/sys/vm/dirty_expire_centisecs
: L, B. a8 J% W0 w. H3 ^; E! r
. a- V W+ R/ X$ k三、内核参数修改后的生效
1 r* `0 I/ A! s& W' N3 |# v, j" lLinux在系统运行时修改内核参数(/proc/sys与/etc/sysctl.conf),而不需要重新引导系统,& k: r8 W; E& `' _- j% B, J6 I
这个功能是通过/proc虚拟文件系统实现的。
2 L, ?, N3 C: I: u0 k& Y4 q: N2 Y1 ^- K
在/proc/sys目录下存放着大多数的内核参数,并且设计成可以在系统运行的同时进行更改, + c# G! _8 n+ T0 D( g4 R& F
可以通过更改/proc/sys中内核参数对应的文件达到修改内核参数的目的(修改过后,保存配置文件就马上自动生效),7 t% B- d, p4 ]% d: O: ~: n
不过重新启动机器后之前修改的参数值会失效,所以只能是一种临时参数变更方案。
: F0 C" ]6 C2 W$ N% @: t! G(适合调试内核参数优化值的时候使用,如果设置值有问题,重启服务器还原原来的设置参数值了。简单方便。)9 F6 q4 l4 y% x& ~; v- H/ ?" u7 r9 K: i
- f/ O! c8 e1 m& f! r但是如果调试内核参数优化值结束后,需要永久保存参数值,8 W$ I) F7 l( P# X" F- N
就要通过修改/etc/sysctl.conf内的内核参数来永久保存更改。
( |& e2 N9 {! D. e7 Q7 Y但只是修改sysctl文件内的参数值,确认保存修改文件后,设定的参数值并不会马上生效,
" r4 @" B. }4 y3 ?$ _如果想使参数值修改马上生效,并且不重启服务器,可以执行下面的命令:
6 B9 ?7 n& x) }% O: _2 @ # sysctl –p
; a5 k# R+ o1 k# `! l5 a9 p3 h5 }* B% T/ w& ]9 r
下面介绍一下/proc/sys下内核文件与配置文件sysctl.conf中变量的对应关系:
+ g. u& @$ j$ |2 R: s7 ^& \由于可以修改的内核参数都在/proc/sys目录下,所以sysctl.conf的变量名省略了目录的前面部分(/proc/sys)。- \/ q! B$ ]4 a8 ^- \& q, {
即将/proc/sys中的文件转换成sysctl中的变量依据下面两个简单的规则:
6 b1 |! ]( p- S9 J1.去掉前面部分/proc/sys: A/ Q6 E! p+ m% e! w# t( |0 v
2.将文件名中的斜杠变为点9 V8 f5 w6 z! S& v. j( E
; u( M. r; R/ R) H
这两条规则可以将/proc/sys中的任一文件名转换成sysctl中的变量名。
C4 w; f3 f. W( x( g0 E例如:8 _2 k4 x0 c# f7 n/ v
/proc/sys/net/ipv4/ip_forward =》 net.ipv4.ip_forward
' b7 S. u/ J& \$ e" j, w6 t- l/proc/sys/kernel/hostname =》 kernel.hostname" u% S% e# C) a/ t" F
! N8 m& P+ u- Z+ v
可以使用下面命令查询所有可修改的变量名
3 A, G8 ` ?- u1 B # sysctl –a9 i- v- U9 @! j0 o
* x8 V; I* T* j/ j
" f9 C, K. L( C$ I
|
|