|
| 1 | +## page fault带来的性能问题 |
| 2 | + |
| 3 | +### 作者 |
| 4 | +digoal |
| 5 | + |
| 6 | +### 日期 |
| 7 | +2016-07-25 |
| 8 | + |
| 9 | +### 标签 |
| 10 | +PostgreSQL , Linux , page fault , major , minor |
| 11 | + |
| 12 | +---- |
| 13 | + |
| 14 | +## 背景 |
| 15 | +## Linux进程如何访问内存 |
| 16 | +Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源。 |
| 17 | + |
| 18 | +原因后面会讲到。 |
| 19 | + |
| 20 | +## 为什么需要虚拟内存地址空间 |
| 21 | +假设某个进程需要4MB的空间,内存假设是1MB的,如果进程直接使用物理地址,这个进程会因为内存不足跑不起来。 |
| 22 | + |
| 23 | +既然进程不是直接访问物理内存,那么进程中涉及的内存地址当然也不是物理内存地址。 |
| 24 | + |
| 25 | +而是虚拟的内存地址,虚拟的内存地址和物理的内存地址之间保持一种映射关系,这种关系由MMU进行管理。 |
| 26 | + |
| 27 | +每个进程都有自己独立的虚拟地址空间。 |
| 28 | + |
| 29 | +## 什么是MMU |
| 30 | + |
| 31 | + |
| 32 | +MMU全称是内存管理单元,它将物理内存分割成多个pages,MMU管理进程的虚拟地址空间中的PAGE和物理内存中的PAGE之间的映射关系。 |
| 33 | + |
| 34 | +因为是映射,所以随时都可能发生变化,例如某个进程虚拟内存空间中的PAGE1,在不同的时间点,可能出现在物理内存中的不同位置(当发生了页交换时)。 |
| 35 | + |
| 36 | +## 什么是page fault |
| 37 | +当进程访问它的虚拟地址空间中的PAGE时,如果这个PAGE目前还不在物理内存中,此时CPU是不能干活的, |
| 38 | + |
| 39 | +Linux会产生一个hard page fault中断。 |
| 40 | + |
| 41 | +系统需要从慢速设备(如磁盘)将对应的数据PAGE读入物理内存,并建立物理内存地址与虚拟地址空间PAGE的映射关系。 |
| 42 | + |
| 43 | +然后进程才能访问这部分虚拟地址空间的内存。 |
| 44 | + |
| 45 | +page fault 又分为几种,major page fault、 minor page fault、 invalid(segment fault)。 |
| 46 | + |
| 47 | +major page fault也称为hard page fault, 指需要访问的内存不在虚拟地址空间,也不在物理内存中,需要从慢速设备载入。从swap回到物理内存也是hard page fault。 |
| 48 | + |
| 49 | +minor page fault也称为soft page fault, 指需要访问的内存不在虚拟地址空间,但是在物理内存中,只需要MMU建立物理内存和虚拟地址空间的映射关系即可。 |
| 50 | + |
| 51 | +(通常是多个进程访问同一个共享内存中的数据,可能某些进程还没有建立起映射关系,所以访问时会出现soft page fault) |
| 52 | + |
| 53 | +invalid fault也称为segment fault, 指进程需要访问的内存地址不在它的虚拟地址空间范围内,属于越界访问,内核会报segment fault错误。 |
| 54 | + |
| 55 | +## 什么是进程的working set |
| 56 | +进程的working set是指当前在物理内存中,属于该进程的pages组成的集合。 |
| 57 | + |
| 58 | +这个集合中的page数随着系统的运行,可能扩大也可能缩小。 |
| 59 | + |
| 60 | +扩大working set是指进程正在访问更多的内存时。 |
| 61 | + |
| 62 | +缩小working set是指其他进程正在访问更多的内存,并且整个物理内存的空间不足,需要将某些干净的内存页free掉或者一些脏的内存页swap到交换分区去,如果这个操作设计到当前进程,对当前进程来说就是shrink working set。 |
| 63 | + |
| 64 | +缩小working set需要遵循lru (内核的内存老化)算法,并不是随便挑选PAGE进行shrink的。 |
| 65 | + |
| 66 | +## 什么是swap |
| 67 | +swap和前面提到的shrink working set有关,如果是干净页(即从读入虚拟地址空间后,没有修改过的页),则直接标记为free,不需要写盘,也不会发生swap。 |
| 68 | + |
| 69 | +如果是脏页,那么它需要写盘,或者需要swap 到交换分区。 |
| 70 | + |
| 71 | +## 如何优化swap |
| 72 | +建议使用IOPS和读写带宽很高的盘作为SWAP分区,例如PCI-E SSD。 |
| 73 | + |
| 74 | +## 什么时候需要加内存 |
| 75 | +如果你发现经常发生swap in , out。 |
| 76 | + |
| 77 | +说明进程的脏页被换出到swap后,紧接着这些页可能又需要被进程访问,从而这些页需要从swap写入物理内存,发生了hard page fault。 |
| 78 | + |
| 79 | +这种情况下,你就需要加内存了,确实是内存不够用了。 |
| 80 | + |
| 81 | +hard page fault非常损耗性能,因为发生page fault时,是需要等待的,而且IO通常来说都是比较慢的,容易成为性能瓶颈。 |
| 82 | + |
| 83 | +## 什么是oom, 为什么会发生OOM |
| 84 | +前面讲到了shrink working set,是指系统在内存调度时,使用的一种手段,尽可能的让系统能使用有限的内存资源,支撑更多的并发任务。 |
| 85 | + |
| 86 | +oom是指系统已经没有足够的内存给进程使用,即能free的都已经free了,能swap out的也已经swap out了,再也不能挤出物理内存的情况。 |
| 87 | + |
| 88 | +如果遇到这种情况就会发生OOM,表示系统内存以及不足,Linux会挑选并KILL一些进程,来释放内存。 |
| 89 | + |
| 90 | +## Linux page相关统计信息 |
| 91 | +sar |
| 92 | + |
| 93 | +``` |
| 94 | +de > -B Report paging statistics. The following values are displayed: |
| 95 | + |
| 96 | + pgpgin/s |
| 97 | + Total number of kilobytes the system paged in from disk per second. |
| 98 | + |
| 99 | + pgpgout/s |
| 100 | + Total number of kilobytes the system paged out to disk per second. |
| 101 | + |
| 102 | + fault/s |
| 103 | + Number of page faults (major + minor) made by the system per second. This is not a count of page faults that generate I/O, because some page faults can be resolved without I/O. |
| 104 | + |
| 105 | + majflt/s |
| 106 | + Number of major faults the system has made per second, those which have required loading a memory page from disk. |
| 107 | + |
| 108 | + pgfree/s |
| 109 | + Number of pages placed on the free list by the system per second. |
| 110 | + |
| 111 | + pgscank/s |
| 112 | + Number of pages scanned by the kswapd daemon per second. |
| 113 | + |
| 114 | + pgscand/s |
| 115 | + Number of pages scanned directly per second. |
| 116 | + |
| 117 | + pgsteal/s |
| 118 | + Number of pages the system has reclaimed from cache (pagecache and swapcache) per second to satisfy its memory demands. |
| 119 | + |
| 120 | + %vmeff |
| 121 | + Calculated as pgsteal / pgscan, this is a metric of the efficiency of page reclaim. If it is near 100% then almost every page coming off the tail of the inactive list is being reaped. If it gets too low (e.g. |
| 122 | + less than 30%) then the virtual memory is having some difficulty. This field is displayed as zero if no pages have been scanned during the interval of time. |
| 123 | +de> |
| 124 | +``` |
| 125 | + |
| 126 | +## 一些CASE |
| 127 | +1\. 如果PostgreSQL 设置了非常大的shared buffer, 为什么会有一段性能低潮(指全力压测时,平时估计感觉不到) |
| 128 | + |
| 129 | +在PostgreSQL shared buffer设得非常大的情况下,Shared buffer作为进程的虚拟地址空间中的一部分,刚启动时这些虚拟地址空间还没有在物理内存中,所以填充过程中会发生page fault,性能较低。 |
| 130 | + |
| 131 | +当shared buffer被快速填满后,page fault减少,性能会上来。 |
| 132 | + |
| 133 | +例如在压测持续高并发的COPY数据入库时,看这个case https://yq.aliyun.com/articles/8528 |
| 134 | + |
| 135 | +在前面几百GB,page fault较多,产生较多的中断(这个case是软的,因为是在shared buffer中进行extend block,么有落盘),性能比shared buffer填满后有一定的差异。 |
| 136 | + |
| 137 | +240GB shared buffer, |
| 138 | + |
| 139 | +shared buffer 填满前,2.8GB/s 导入速度 |
| 140 | + |
| 141 | +``` |
| 142 | +de >12:13:46 AM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff |
| 143 | +12:13:47 AM 8.08 1699410.10 40058.59 0.00 142064.65 137696.97 0.00 137632.32 99.95 |
| 144 | +12:13:48 AM 15.84 1634396.04 38605.94 0.00 412391.09 411564.36 0.00 411627.72 100.02 |
| 145 | + |
| 146 | + 22 44 33 0 0 0| 32k 2763M| 239B 364B| 0 0 | 184k 335k |
| 147 | + 22 44 34 0 0 0| 12k 2791M| 120B 544B| 0 0 | 184k 336k |
| 148 | + 22 45 33 0 0 0| 12k 2768M| 471B 1198B| 0 0 | 185k 341k |
| 149 | + 22 44 33 0 0 0| 16k 2764M| 210B 454B| 0 0 | 183k 336k |
| 150 | + 22 44 34 0 0 0| 16k 2777M| 239B 364B| 0 0 | 185k 341k |
| 151 | +de> |
| 152 | +``` |
| 153 | + |
| 154 | +shared buffer 填满后, 4.7GB/s导入速度 |
| 155 | + |
| 156 | +``` |
| 157 | +de >12:14:40 AM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff |
| 158 | +12:14:41 AM 16.33 2831730.61 823.47 0.00 735045.92 725126.53 0.00 724985.71 99.98 |
| 159 | +12:14:42 AM 12.00 2760160.00 743.00 0.00 738037.00 728352.00 0.00 728370.00 100.00 |
| 160 | +12:14:43 AM 11.88 2751279.21 326.73 0.00 720171.29 715310.89 0.00 715374.26 100.01 |
| 161 | +12:14:44 AM 20.00 2788468.00 338.00 0.00 727221.00 720480.00 0.00 720480.00 100.00 |
| 162 | +12:14:45 AM 12.50 2858970.83 425.00 0.00 753507.29 740266.67 0.00 740166.67 99.99 |
| 163 | + |
| 164 | + 24 18 56 0 0 1| 28k 4703M| 120B 364B| 0 0 | 366k 655k |
| 165 | + 24 18 57 0 0 1| 16k 5031M| 892B 994B| 0 0 | 382k 690k |
| 166 | + 24 19 56 0 0 0| 12k 4833M| 120B 364B| 0 0 | 374k 672k |
| 167 | + 24 19 56 0 0 1|8192B 4737M| 239B 544B| 0 0 | 371k 668k |
| 168 | + 24 19 56 0 0 1| 20k 4826M| 120B 454B| 0 0 | 375k 674k |
| 169 | +de> |
| 170 | +``` |
| 171 | + |
| 172 | +## 参考 |
| 173 | +https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/3/html/Introduction_to_System_Administration/s1-memory-virt-details.html |
| 174 | + |
| 175 | +https://en.wikipedia.org/wiki/Page_fault |
| 176 | + |
| 177 | +http://www.cnblogs.com/xelatex/p/3491305.html |
| 178 | + |
| 179 | +https://en.wikipedia.org/wiki/Memory_management_unit |
| 180 | + |
| 181 | +http://pages.cs.wisc.edu/~remzi/OSTEP/vm-segmentation.pdf?spm=5176.100239.blogcont55820.33.KDVPoF&file=vm-segmentation.pdf |
| 182 | + |
| 183 | +http://www.tldp.org/LDP/tlk/mm/memory.html?spm=5176.100239.blogcont55820.44.tOZ1UX |
| 184 | + |
| 185 | +[Count](http://info.flagcounter.com/h9V1) |
0 commit comments