日期:2014-05-16 浏览次数:20877 次
本文转自: http://blog.csdn.net/dog250??天地有如此静穆,我不能大笑而且歌唱
?
曾经读过n多个开源的代码,包括linux内核,apache,openssl,memcache,libevent,vsftpd,xinetd等等其 中我最喜欢的就是linux内核了,除了linux内核排第二的就是apache,本文我就把欣赏的心得记录下来。
????? apache中我最喜欢的有两个模块,一个就是它的MPM,一个就是内存管理,mem使得它可以最高效得挖掘操作系统固有的优势,而不用为了接口兼容或者 接口一致而必须提供低效的模拟层,比如windows的进程创建过于低效,但是线程却是操作系统内置的,那么在windows平台上,apache就使用 线程作为mpm的机制,在linux2.6内核上,可以使用线程+进程的方式,而在linux2.4以前可以使用纯进程的经典unix方式来进行多处理。 mpm独立作为一个模块支撑着apache的运行,它是支撑模块,因此它是必须的,典型的,apache要么使用进程,要么使用线程来处理请求,但是绝对 不是进程就是为了稳定,而线程就是高效,而是不同的操作系统拥有不同的选择策略,它很灵活,管理员可以灵活地进行配置,当然线程+进程的方式拥有高效+稳 定的双重优势,最常用的mpm模块就是prefork和worker,具体的内容我就不讨论了,读源代码是最好的方式,另外还可以看一个博 客:http://blog.csdn.net/tingya。在mpm中还有一个很有趣的就是记分板,通过它负责管理的父进程就可以更快捷的管理实际进 行web服务的子进程,这实在是必用管道高效,因为记分板用的是共享内存机制,实际绕开了文件系统,具体工作的时候就是父进程查询记分板得到子进程的状 态,之所以可以如此轻松的完成这样的工作就是因为记分板的构造,每个子进程在记分板上都有一个插槽,父进程可以通过子进程的pid来检索到子进程的插槽从 而得到子进程的信息,子进程同样也需要记分板,它可以将需要通报给父亲的信息写到记分板然后由父进程读取,也可以读取父进程设置进去的信息,比如父进程需 要杀死自己的孩子,它不需要给孩子发送信号,而是通过写自杀信息到该孩子的记分板,等待该孩子看到这个信息以后采取自杀策略,这样的话不需要任何内核机 制,直接靠所有操作系统都提供的东西就可以完成父子通信,另外还可以进行兄弟通信,共享内存机制比管道或者信号来的更好,因为它减少了对操作系统的依赖, 提高了apache的跨平台特性,而且共享内存更加高效,可以做到父子进程内存的零拷贝。?
在通信方面,apache可以创建很多套接字排入一个队列或者放入一个池,每次只有一个监听,当监听到用户连接请求的时候,马上就可以将自己转换到服务套 接字,然后从队列或者池中选出下一个套接字进行监听,如此反复,这里讨论的仅仅是通信模型,当然,每个套接字可以是一个进程也可以是一个线程,归根结底要 想高效,还要用到上面提到的mpm机制,这里进程或者线程可以和套接字相对应,但是这种对应不是确定以及一定的,传统的通信模型在apache里面都可以 看到,它非常灵活,曾几何时,只有一个套接字进程监听,只要来一个马上fork一个进程,在子进程里面处理新的连接,但是那个日子一去不复返了,看看 apache吧,看完了你就知道如何进程多处理了。?
????? apache的内存池模型令我陶醉,这是真的,我读过很多源码,可是读每个源码的时候,我都感觉大同小异,只要是网络方面的,必然是select,只要是 进程方面的,必然是...,可是当我开读apache的时候,我改变了这种想法,apache的内存管理就是与众不同,如果你仅仅把目光停留在它的内存管 理算法上,你会发现它和boost没有什么太大的区别,甚至有时都不如stl的,但是它却实现一种思想,一种事务的思想,你再也不用关注于编程细节,只要 知道你的程序在干什么事情就可以了,apache内存管理采用了内存池的思想,在进行内存分配之前,你必须首先创建一个内存池,然后所有的事情就不用你操 心了,一切都在池中进行,内存池的管理是apache里面进行的,用户不必涉及,在分配策略了,内部用到了很多链表等数据结构,还用到了很多巧妙的算法, 比如用内存的大小索引化,在查找的时候从最大的开始,减少了查找的脱靶次数从而提高了效率,但是这些都不是我这里要强调的。传统的看来,谁分配内存谁释放 这已经成了一个成文的规则,但是虽然规则如此严明的写了出来,代码的作者却还是造成了内存泄露,因为这种说法是以内存为中心的,而不是以人的思维为中心 的,因此程序员很容易犯一些错误,哪怕是最低级的错误,想想我们为何写程序,程序肯定是为了帮助人来完成一些事情,而这件事情肯定是很“人性化”的,比如 查询,比如删除,比如恐怖袭击,既然程序执行的都是人的事儿,那么为何不用点人的方式呢?我们人做事从来没有那么小的粒度,我们总是把一个事务作为一个整 体来看待,这不,apache里面的内存池就非常好,如果谁要用内存,那就只管用吧,用内存才是你的事,怎么管理内存不是你的事,而是你上级的事,这个现 象很好理解,举个例子,我在一家电脑公司任职,我平时要用电脑,打印机,打印纸等等,这些资源并不需要我自己管理,而是我的上级帮我管理,比如我的上级给 了我一台台式机和一台笔记本的份额,那么我根本不用管别的,份额内直接用就是了。在apache中,内存分配都在内存池中,一段代码代表一个业务逻辑,它 需要内存的话并不需要负责释放,而是这段代码的上级来负责释放,实际上apache中根本没有显式的释放给操作系统的内存释放,所有内存释放都是释放给内 存池的,如果要开始一个业务逻辑,那么必然需要先申请有一个内存池,在这个业务逻辑中所有的内存需求都从这个池中分配,业务逻辑本身并不需要和操作系统交 互,而由池的管理代码负责交互,内存释放时,释放到池中,这些内存还可以被该业务逻辑重新利用,等到这个业务逻辑结束的时候,内存池被销毁,池销毁的时 候,池中的内存将全部还给操作系统,这丝毫不用业务逻辑本身操任何心。内存池就好像一个封装,你只需要大胆的用内存就可以了,不够了池可以帮你从操作系统 要,多余了可以先存着,等到业务逻辑结束的时候,池销毁的时候,所有内存一并销毁,而销毁操作对用户即业务逻辑来说是不可见的。?
????? apache的内存池管理方式使我想到了操作系统的内存管理方式,apache的libapr本身就好像一个操作系统,它分配资源不会被业务逻辑看到,业 务逻辑只需要等待结果就可以了,可是现在的任何操作系统却美誉这么“人性化”,可以这么说,apache是以业务逻辑即事务为中心的,其实它就是以人为本 的,而传统的操作系统由于收到强大的unix的影响,还是以任务为中心的,unix创立的时代是个必须以任务为中心的时代,但是现在还是那样的吗?虽然我 不很喜欢windows,但是我发现windows已经迈出了超越unix的第一步,当然linux早就超越了unix。?
???? apache在我心中就是老二,linux内核永远是老大,不过如果单挑某个方面的话,不能否认apache远远超越了linux内核,在你想远离人群的时候,读读linux内核,当你想融入喜欢你的人的时候,读读apache,试试看。