testing-04

Linux

  • 每次深入了解一个技术问题,随着挖据的深入,都发现其背后总非常深的背景知识,甚至需要深入到很多底层系统,这个过程有时会让自己迷失,会让自己忘了当初的目的。

    前篇中介绍系统启动时内存的使用情况,本篇将介绍简要Linux如何接管主机的物理内存、组织内存,最后会较为详细的介绍Linux分配内存的一段代码。

    前面说了,Linux MM系统细节非常多,自己在探究的时候,也是尝试尽量抓住主线,这里也只能抽取了一些“主线剧情”介绍,其中还可以扩展出很多细节,看客感兴趣可以自己深究,后续如果兴趣还在,我也还会继续写出来。内核版本如果没有特别说明,就是使用2.6.33版本。

    1. 物理内存组织

    先声明一下,这里说的Linux都是运行Intel X86架构的。从80386开始,为了更好支持内存管理、虚拟内存技术,x86架构开始支持处理器的分页模式(分页是基于分段)。系统将内存分为一个个固定大小的块,称作“page frames”,x86架构每一个“page frames”大小为4096字节。Linux中使用struct page结构来描述一个“page frames”【链接中给出了2.6.18内核下的Page结构】,一个Page结构对应了一个物理内存页。

    在Linux中,所有的struct page对象都放在一个数组mem_map,mem_map每一个元素对应一个Page。

    2. NUMA下的内存结构

    在NUMA架构下,系统根据CPU的物理颗数,将内存分成对应的Node。例如,两颗物理CPU,16GB内存的硬件:系统则将内存分成两个8GB,分别分配给两颗CPU:

    my111.cm3:/root>#numactl –hardware
    available: 2 nodes (0-1)
    node 0 size: 8065 MB
    node 1 size: 8080 MB

    每一个Node,系统又将其分为多个Zone,64位x86架构下(参考:8.1.5),分为两个ZONE_DMA(低16MB,)、ZONE_NORMAL(其余内存)。所以NUMA架构下的内存分配,也就是在各个zone分配内存。

    3. 内存分配函数栈

    从底层系统的角度,内存分配有如下函数(这里介绍的底层函数,和上层函数的关系,以后再介绍):

    这里来调查一下函数alloc_pages都做了些什么,都调用了哪些函数:

    free_area是一个底层保存空闲内存页的数组,有着特殊的结构,它也是内存分配Buddy system的核心变量。

    4. get_page_from_freelist和zone_reclaim_mode

    上面函数get_page_from_freelist【mm/page_alloc.c】通过遍历系统中各个zone,来寻找可用内存,根据Linux系统中zone_reclaim_mode的设置不同,遍历时的行为略有不同。zone_reclaim_mode是Linux中的一个可配置参数,为了解该参数如何影响内存分配,那就打开get_page_from_freelist的代码,仔细看看遍历各个zone的流程:

    上面看到,zone_reclaim_mode非零时,如果某个zone内存不够,则会尝试出发一次内存回收工作(zone_reclaim),等于零时,则直接尝试写一个zone。

    上面是2.6.33内核的代码流程图,2.6.18(RHEL5.4的内核)中则因为没有zcl相对简单一些:

    流程图中可以看到,zone_reclaim_mode非零时,get_page_from_freelist【mm/page_alloc.c】函数中会调用zone_watermark_ok扫描free_area,如果当面有没有足够的可用内存,就会调用zone_reclaim【mm/vmscan.c】函数回收内存,zone_reclaim实际调用zone_reclaim【mm/vmscan.】收回内存。

    最后

    每次深入了解一个技术问题,随着挖据的深入,都发现其背后总非常深的背景知识,甚至需要深入到很多底层系统,这个过程有时会让自己迷失,会让自己忘了当初的目的。如果是Linux方面的技术问题,一般最后会收缩到“体系结构”、“Linux原理”和“算法”,这恰恰对应了计算机系考研时候的三门课程:体系结构、操作系统、和数据结构

    参考:

    Managing physical memory

    Understanding the Linux Kernel, 3rd Edition

    广告时间:工作机会–MySQL Hacker

  • 随着要维护的服务器增多,遇到的各种稀奇古怪的问题也会增多,要想彻底解决这些“小”问题往往需要更深的Linux方面的知识。越专业、分工越细的工程师,在这方面的要求也就越高。这次,对MySQL Swap的问题的探索过程,就一不小心掉进了Linux Memory Managemant(Linux MM)的研究中去了,爬了很久才出来,这里做一个系列笔记。

    笔记中很多内容都是参考《Understanding the Linux Kernel, 3rd Edition》、Linux Source Code等地方,自己再做了一些总结,觉得有意义的总结这里记录一下,供参考。

    1. 写在前面

    Linux MM是一个比较猥琐的体系,虽然理论不太多,但是细节非常多。要从底层物理内存管理到上层虚拟内存管理整个关节打通,一方面需要较多底层架构知识、还需要很深的Linux知识。既然是学习笔记,先说一下我的学习资料:

    1. Linux Memory Management David A Rusling 这本书很老了,当时的Kernel还是2.0.33版本的;这本书的优点在于抽象得很到位,把Linux_MM的基本模块、思想都通俗易懂的介绍了一遍。这也是kernel-docs.txt中推荐的读物之一;

    2. 《Understanding the Linux Kernel, 3rd Edition》中的第二、八、十七章 这是基于2.6内核,非常有参考价值,介绍得非常细致,可以结合内核的源代码一起来看。

    3. Linux Source Code 只看了几个自己关心的函数,没那么难:)

    我不是计算机科班出身,体系结构的基础比较差,所以刚开始入门的时间相对较长,前后大概历时一个月,实际伏案时间约50小时,而这也只是一个开始

    2. 基本框架

    上面是一幅简图,后面会分别介绍,Kernel如何使用内存、Kernel如何管理分配内存、用户空间的内存管理。对于其中的一些细节则会单独介绍,例如大页内存,内存回收算等等。

    2. Linux启动与内存管理

    开机的第一个过程是BIOS自检,BIOS使用0x00000000到0x10000(1MB)内存,这1MB内存包括了自检程序、自检结果、还留一部分给显示设备使用;自检完成后,开始载入Linux内核,Linux从1MB开始使用物理内存,一般5MB就足够了,在内核的符号信息中可以看到,Linux内核从_text开始,_edata处结束

    $more /boot/System.map-2.6.9-55.ELsmp|grep “\ _text$\|_etext$\| _edata$\| _end$”
    ffffffff80100000 A _text
    ffffffff80310399 A _etext
    ffffffff80456aa8 A _edata

    简图:

    这里不涉及x86架构下的分页、分段细节,后面会单独介绍之。

    这一篇很简单,是一个开始:)

    【update 2011-03-29】

    64位系统中,Linux(2.6.18)从2MB开始使用物理内存。(32位系统,仍然是从1MB开始)

    file: ./arch/x86_64/defconfig
    CONFIG_PHYSICAL_START=0x200000
    //This gives the physical address where the kernel is loaded.

    参考文献:

    [1]. http://cateee.net/lkddb/web-lkddb/PHYSICAL_START.html

    广告时间:工作机会–MySQL Hacker

  • Linux Top命令学习

    ·

    也忘了第一次用Top观察Linux运行状态是什么时候了,不过最近吧Top的文档收获不少。

    1. 有用的命令top-z-x
    z    :打开/关闭彩色显示
    x    :高亮显示排序列
    

    在使用top命令后,“先按z键,再按x键”,这时屏幕会彩色显示输出,白色显示的列是当前排序的列;偶尔还会有一些白色显示行,这些行是当前正在运行进程。使用该参数可以帮助我们更清楚的看到排序列。例如,我想按照cpu使用排序来查看进程:

    top-z-x

    使用了top-z-x命令后是不是看得清晰了一些:)

    2. 有用的命令top-1
    1    :SMP的系统,会单独显示各个CPU的运行状态
    

    top-1

    3. 选择排序列top-z-x-<
    <    :改变排序列
    >    :改变排序列
    

    top-z-x-< 试试就知道是什么意思了:) 。例如,默认是按照cpu使用率排序的,现在我想看看安装使用的虚拟内存排序看看,使用命令top-z-x-<-<-<-<-< :

    top-z-x-lt

    4. 其他技巧
    W    :把当前配置文件到home目录下.toprc配置文件中
    F or O :支持更强的选择排序列的方式
    
    -b   :参数可以帮你在脚本中使用top命令
    -n   :配合-b使用,表示重新刷新一定次数后退出
    -d   :刷新延时时间。例如-d 5 表示top每隔5秒刷新一次。(默认是3秒)
    

    就这些吧,更多请查看top-h或者RTFM

    最后,各位看官,工作之余别忘了多多运动,没什么比健康更重要了:)

  • Flashcache配置

    ·

    前面写了两篇文章,分别介绍了Flashcache的基本原理和编译安装,本文介绍一下Flashcache的配置。

    假设现在你已经编译好了Flashcache,已经装好了ssd盘(假设是/dev/sdb)和sas盘(假设需要使用的是分区/dev/sda12,这可能是一个RAID组)。接下来,看看如何使用Flashcache将上面两个设备虚拟成一个带缓存的块设备。

    1. 首次创建Flashcach设备

    注:请备份你的数据先!!!特别是/dev/sdb,这个设备上的数据将会被清空;理论上/dev/sda12上的数据不会有任何丢失。

    首先确保sda12没有被挂载,如果挂载了,使用umount卸载之,然后使用flashcache_create创建设备:

    ./flashcache_create cachedev /dev/sdb /dev/sda12

    如果是sudo帐号可能会遇到如下的报错: (more…)

  • 一个有趣的perl函数

    ·

    入职已经489天了,新鲜事很多,不过更多应该是无趣、枯燥的日常:装很多的数据库、反复的测试、写很多的脚本…… 不过,在这繁忙工作中,还是希望自己能够保持一份趣味。

    下面这个perl函数就是帮你保持脚本有趣的一个办法。

    在你的Perl脚本中下面的函数,并在脚本的第一行调用之。函数会在你的输出前随机的输出一条“名言”,让你在枯燥的调试程序时,仍然保持一份清醒:

    use MIME::Base64; ####################################################### # This is a interesting function by orczhou@gmail.com # It outputs a random quote ####################################################### sub randomQuote{ my @quote; push(@quote,"S2VlcCBpdCBzaW1wbGUsIFN0dXBpZA=="); push(@quote,"VG9tb3Jyb3cgaXMgYW5vdGhlciBkYXk="); push(@quote,"TGlmZSBpcyBsaWtlIGEgYm94IG9mY2hvY29sYXRlcw=="); push(@quote,"VGhlIGFuZ3J5IGlzIHRoYXQgdGFraW5nIHRoZSBvdGhlcidzIG1pc3Rha2UgdG8gcHVuaXNoIG9uZXNlbGY="); push(@quote,"VGhlIGhvcGUgb2YgdG9tb3Jyb3cgbGV0cyB1cyBmb3JnZXQgdG9kYXkncyBwYWlu"); push(@quote,"VGhlIHBsYWNlIHdoaWNoIHRoZSBpZGVhbCBpcyBpbiwgdGhlIGhlbGwgbWF5YmUgYSBoZWF2ZW4="); push(@quote,"Rm9yIGhpcyBsb25nIGFuZCBub24tdmlvbGVudCBzdHJ1Z2dsZSBmb3IgZnVuZGFtZW50YWwgaHVtYW4gcmlnaHRzIGluIENoaW5h"); push(@quote,"V2hhdCBpcyBkb25lIGJ5IG5pZ2h0IGFwcGVhcnMgYnkgZGF5"); push(@quote,"SWYgeW91IHdhbnQgdG8gaGF2ZSB0aGUgcGVyZmVjdCBmcmllbmRzaGlwLCBwb3NzaWJseSB5b3UgbWF5IGZpbmQgbm8gZnJpZW5kIGZvciBhbGw gbGlmZXRpbWU="); push(@quote,"VGhlIGV4cGVyaWVuY2UgdGFrZXMgb3V0IGJ5IHRoZSBlc3NlbmNlIG9mIHBhaW4="); push(@quote,"VGhlIGJpZ2dlc3QgbWlzdGFrZSBpbiBsaWZlIGlzIHRoZSB1bmNlYXNpbmdseSB3b3JyaWVkIGFib3V0IG1ha2luZyBtaXN0YWtl"); push(@quote,"TGF6aW5lc3Mgd2lsbCBjYXVzZSB5b3UgcGFpbg=="); push(@quote,"S2VlcCB0aGUgcGFzc2lvbiBmb3IgeW91ciBqb2I="); push(@quote,"VGhlcmUgaXMgb2Z0ZW4gbGVzcyBkYW5nZXIgaW4gdGhlIHRoaW5ncyB3ZSBmZWFyIHRoYW4gaW4gdGhlIHRoaW5ncyB3ZSBkZXNpcmU="); push(@quote,"WW91IGNhbiB1c2Ugc2NyaXB0IGRvIG1vcmUgd29yayxidXQgc2FkZGx5IGl0IG1ha2UgbW9yZSBqb2JzIGNvbWUgdG8gdQ=="); push(@quote,"TXkgbmFtZSBpcyBteXNxbGRhdXRvLkkgd2FzIGNyZWF0ZWQgYnkgb3JjemhvdQ=="); #push(@quote,""); my $count = scalar(@quote); my $rand_num = int(rand($count)); print decode_base64($quote[$rand_num])."\n"; } randomQuote();

    如果觉得上面的代码,破坏了脚本的输出,可以使用参数控制其是否输出。

  • Flashcace安装 How-to

    ·

    Flashcache的安装在其READMEREADME-CentOS5.4已经有一个很详细的说明了,但是实际操作并不是很顺利,而且有些同事表示在编译过程中仍遇到了一些问题,这里详细的记录一下自己的编译、安装过程。

    1. 环境说明

    使用的是RHEL5.4的系统:

    $cat /etc/issue
    Red Hat Enterprise Linux Server release 5.4 (Tikanga)
    $uname -a
    Linux myhost 2.6.18-164.el5 #1 SMP Tue Aug 18 15:51:48 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

    (more…)