<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>说者无意</title>
	<atom:link href="http://www.zavakid.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.zavakid.com</link>
	<description>代码如诗</description>
	<lastBuildDate>Sat, 12 May 2012 03:28:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>terminator的高效使用</title>
		<link>http://www.zavakid.com/178?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=terminator%25e7%259a%2584%25e9%25ab%2598%25e6%2595%2588%25e4%25bd%25bf%25e7%2594%25a8</link>
		<comments>http://www.zavakid.com/178#comments</comments>
		<pubDate>Sat, 05 May 2012 08:34:09 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[life]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[terminator]]></category>
		<category><![CDATA[效率]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=178</guid>
		<description><![CDATA[平时使用的是 ubuntu，难免就需要经常使用终端，之前一直用的是 ubuntu 自带的终端。后来找到了 terminator 这款非常不错的终端软件。（ 官方地址 ） 刚刚接触一款新的软件，使用上肯定比之前的慢。不过经过10分钟的使用，我发现 terminator 很容易上手，而且使用上非常方便，以致于我决定以后不管是在个人还是在公司的电脑上，都要慢慢的使用这款软，以提高自己的工作效率。 ubuntu 默认的终端 —— gnome-terminal，只有 tab 这一概念，并且支持以 alt + 数字 的快捷键对 tab 进行切换；同时，还可以使用 ctrl+shift+t 的快捷方式新建 tab。并且，还有 bash 中 readline 默认提供的 emacs 快捷键（当然，你也可以设置成 vi mode，想想可以用 vi 模式在 sh 下操作的快感吧 ）。 不过，所有 &#8230; <a href="http://www.zavakid.com/178">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>平时使用的是 ubuntu，难免就需要经常使用终端，之前一直用的是 ubuntu 自带的终端。后来找到了 terminator 这款非常不错的终端软件。（ <a href="http://software.jessies.org/terminator/">官方地址</a> ）</p>
<p>刚刚接触一款新的软件，使用上肯定比之前的慢。不过经过10分钟的使用，我发现 terminator 很容易上手，而且使用上非常方便，以致于我决定以后不管是在个人还是在公司的电脑上，都要慢慢的使用这款软，以提高自己的工作效率。</p>
<p>ubuntu 默认的终端 —— gnome-terminal，只有 tab 这一概念，并且支持以 <code>alt + 数字</code> 的快捷键对 tab 进行切换；同时，还可以使用 <code>ctrl+shift+t</code> 的快捷方式新建 tab。并且，还有 bash 中 readline 默认提供的 emacs 快捷键（当然，你也可以设置成 vi mode，想想可以用 vi 模式在 sh 下操作的快感吧 <img src='http://www.zavakid.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  ）。</p>
<p>不过，所有 gnome-terminal 有的功能， terminator 都有。出此之外，terminator 还提供了一些很方便的功能：</p>
<ul>
<li>允许在一个 tab 中打开多个终端 —— 这个可以满足我一边 <code>man</code> 一个命令，一边练习</li>
<li>允许同时操作多个终端 —— 这个功能使用的场景不多。但可以想象，如果你同时操作多台服务器，倒可以使用使用。先<code>cd</code>回到HOME，然后就进行自己的命令了。</li>
</ul>
<p>terminator默认的快捷键没有<code>alt+number</code>，所以我自己设置了一份快捷键，并放在了：<a href="https://github.com/zavakid/terminator-config">github terminator config</a> 上，欢迎大家fork之。</p>
<p>下面是使用的几张截图：</p>
<p><img src="http://pic.yupoo.com/zavakid/BXuv7KOo/medium.jpg" alt="同一tab下多个终端" /></p>
<p><img src="http://pic.yupoo.com/zavakid/BXuvasam/medium.jpg" alt="广播命令，同时操作多个终端" /></p>
<h3 class='related_post_title'>相关文章</h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/108' title='让Ubuntu32位支持4G内存的方法'>让Ubuntu32位支持4G内存的方法</a></li>
<li><a href='http://www.zavakid.com/32' title='Ubuntu下Eclipse退出，进程却还存在'>Ubuntu下Eclipse退出，进程却还存在</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/178/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tokyo Tyrant 与 Redis 的一些简单比较</title>
		<link>http://www.zavakid.com/127?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tokyo-tyrant-%25e4%25b8%258e-redis-%25e7%259a%2584%25e4%25b8%2580%25e4%25ba%259b%25e7%25ae%2580%25e5%258d%2595%25e6%25af%2594%25e8%25be%2583</link>
		<comments>http://www.zavakid.com/127#comments</comments>
		<pubDate>Thu, 17 Nov 2011 03:13:23 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[tokyo tyrant]]></category>
		<category><![CDATA[tt server]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=127</guid>
		<description><![CDATA[本文按照作者自己的理解对比了一下 tt server 和 redis 这两个产品从线程模型，存储方式，持久化，性能等进行了一些比较，得出一些启发，个人之言，希望能帮助更多人理解 tt server 和 redis 这两个产品。 <a href="http://www.zavakid.com/127">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="toc_container" class="toc_wrap_right no_bullets"><p class="toc_title">本文内容索引</p><ul class="toc_list"><li><a href="#i">1 服务端处理模型</a></li><li><a href="#i-2">2 数据存储方式、持久化比较</a></li><li><a href="#i-3">3 复制方式比较</a></li><li><a href="#i-4">4 性能方面比较</a></li><li><a href="#i-5">5 总结</a></li><li><a href="#i-6">6 相关文章</a></li></ul></div>
<p>之前简单的看了一下 <a href="http://fallabs.com/tokyotyrant/" target="_blank">Tokyo Tyrant</a>(包括 <a href="http://fallabs.com/tokyocabinet/" target="_blank">Tokyo Cabint</a>) 在 hash 存储上的一些实现，最近 <a href="http://redis.io" target="_blank">Redis</a> 又比较火热，因此，自己也尝试性的去了解了一下 Redis，并且结合 Tokyo Tyrant（以下简称 tt server），说说自己对这两种产品的看法。</p>
<h3><span id="i">服务端处理模型</span></h3>
<p>在 tt server 中，是以多线程的方式向客户端提供服务的：一个主线程负责 accept 客户端的socket，一定数目的线程（可以指定）进行读写服务，同时，也有一定数目的timer线程，专门用来负责定时的任务，比如一些定时的 <a href="http://www.lua.org/" target="_blank">Lua</a> 脚本，同时，如果是slaver，则会有专门一个timer线程，定时负责 do slave 的工作。<br />
而在 Redis 中，采用的则是单线程的模型来处理所有的客户端请求。</p>
<p>应该说这两种模型，都有各自的优点和缺点。多线程可以利用多核CPU的计算能力，但因此也会增加CAS自旋或者是锁的一些消耗，同时，如果线程过多，那么线程之间上下文的切换，也是一种消耗。</p>
<p>而如果是单线程，则可以完全避免锁的消耗，同时，上下文切换消耗也不需要过多的考虑（但仍需要考虑系统上还有其他的进程），这会让单个CPU的利用率比较高。<br />
但是，单线程服务，就意味着不能利用多核。同时，服务端对客户端过来的请求是串行执行和响应的，这也在一定程度上，会影响服务端的并发能力，特别是在有些请求执行比较耗时的情况下。想象一下，就这么一个线程，可能正在拼命的执行客户端A的一个请求，而此时客户端B，C，D的请求，还仍在等着线程执行完成之后再去搭理他们。</p>
<p>因此，像 redis 这种单线程的服务模型，如果对一些请求的处理相对较耗时，那其 TPS 也就相应的不能提高上去，也就是说其吞吐量会提不上去；但反过来想， redis 如果能控制每次请求在执行过程是简短并且快速的，那么也许使用单线程，反而会比多线程有更好的性能，毕竟单线程少了上下文切换，以及锁或者 cas 的开销。</p>
<p>而 tt server 则中规中矩：一个线程负责 accept ，一定数目的线程则进行请求的处理。因此，我们在设置 tt server 的时候，也应尽量考虑好工作线程的数目，尽量让CPU数目与工作线程数目一致或者略少。原则是最好的发挥多核CPU的作用，同时又不让工作线程之间去竞争CPU。当然，这是需要不停的去实验的。</p>
<p>所以，在使用 redis 的时候，应尽量不要去使用一些相对耗时的请求；同时，我想 redis 的作者，也应该会尽量优化每种请求的执行速度（至少是一些常用的请求）。</p>
<p>而在使用 tt server 的时候，需要仔细调整使用的工作线程数目，让每个CPU都物尽其用。</p>
<h3><span id="i-2">数据存储方式、持久化比较</span></h3>
<p>tt server 的 hash 数据库，是使用文件的方式，然后利用 <a href="http://kernel.org/doc/man-pages/online/pages/man2/munmap.2.html" target="_blank">mmap</a> 系统调用映射到内存中。<br />
这样，就可以利用操作系统的机制，不定期地将数据 flush 到磁盘中。同时，tt server 也提供了 sync 命令，可以让客户端手动将数据 flush 到磁盘中(使用 msync 系统调用)。最后，在关闭 tt server 进程的时候，应该使用 kill -15(TERM信号)，或者使用 ttserver 自带的命令：ttserver -kl pid 进行关闭。这样 ttserver 会先把数据 flush 到磁盘上，再退出进程。</p>
<p>同时， tt server 也提供了 ulog 的方式，对数据库的变更操作进行记录，同样，<a href="http://fallabs.com/tokyotyrant/spex.html#tutorial" target="_blank">可以利用 ulog 对 ttserver 进行恢复</a>，但 ulog 的主要目的，按照我的理解，应是用来实现 replication 的。</p>
<p>而 redis 则是将数据直接写在了内存中，然后利用 <a href="http://redis.io/topics/persistence" target="_blank">redis 的持久化机制</a>，将数据写到磁盘中。</p>
<p>redis 提供了两种持久化机制，分别是 RDB （redis DB） 和 AOF （appending only file）。<br />
RDB的过程是：redis 进程 fork 一个子进程，然后子进程对内存中的数据写到一个临时文件，这个时候，两个进程就利用了操作系统的 copy on write 机制，共享一份内存数据，只有当父进程（也就是 redis 进程）对原有的数据进行修改或者删除之后，操作系统才为 redis 进程重新开辟新的内存空间（以页为单位）。Redis 本身也提供了 bgsave（background save） 命令支持手动将数据持久化（ save 命令是同步的，而 redis 只有一个线程在服务，结果就是影响 redis 的性能，特别是在大数据量的情况下）。</p>
<p>AOF的过程是：在执行每次命令之后，或者每隔1秒钟之后，Redis会有一个线程将命令以 redis 协议的格式 append 到文件中，这也就是AOF名字的由来，这些命令当然是非只读的，只读不更改数据库，没有必要记录下来。<br />
这里会有两个问题：<br />
1、每次命令之后写文件，还是隔1秒之后写文件，影响会有哪些？<br />
2、这些文件总会不断的膨胀，如何对文件进行压缩呢？</p>
<p>对于第一个问题，也是一个权衡的问题，如果每次命令之后都进行一次写磁盘操作，那么IO的程度可想而知，肯定会影响服务器性能(使用 write 系统调用，会因为文件系统而进入 page buffer，并非立刻写磁盘，而调用 fsync ，则会将 page buffer 中的数据写入磁盘，进行 IO 操作)。而如果每隔1秒进行一次 fsync，那么在这一秒和上一秒之间，如果服务器突然断电，那很有可能这些数据就会丢失。对于这个问题，redis 默认给出的方案是每隔1秒进行一次write。对于1秒的给定，我想，也是基于性能和数据安全的权衡，在性能和数据安全方面都可以让人接受。</p>
<p>对于第二个问题，redis 提供了 rewrite 的机制：当 aof 过大的时候，redis可以自动的进行 rewrite （从 redis 2.4 开始）。rewrite 的过程也是 fork 一个子进程；然后打开一个临时文件，将内存中的数据写入到文件中；在此期间，主进程继续将数据写入老的 aof 文件，同时也会将数据写入到一个内存缓存中；等子进程完成之后，主进程会将缓存中的数据写入到临时文件，再将临时文件进行rename，替换掉原来的文件。这样，就实现了写 aof 过程中的rewrite。</p>
<p>从数据的存储方式来说，尽管 tt server 和 redis 都是在内存上面进行数据的读写，我但认为两个产品对数据存储方式的观点是不一样的。<br />
tt server 是将磁盘上的文件当作主要的存储方式，然后使用 mmap 将文件映射到内存中。本质上，这是数据应该存储在磁盘中的观点。<br />
而 redis ，一开始就是将数据直接存储在内存中，在之后的持久化过程中，可以理解成只是将数据的日志写入到磁盘中。本质上，这是把数据应该存储在内存中的观点。</p>
<p>可见，由于作者的观点不一样，也就造成了两种实现方式不一样的产品，这还是比较有意思的。<br />
从这个层面上来讲，我更加喜欢 redis 作者的思路，很可能作者就是受到 <a href="http://www.infoq.com/cn/news/2008/07/ram-is-disk" target="_blank">内存是新的磁盘，磁盘是新的磁带</a> 的启发。</p>
<p>redis自带实现的VM将在以后不再使用(2.4将是最后一个自带vm功能的版本)，作者认为数据就应该是放在物理内存中的，没有必要要将数据交换到磁盘中，磁盘只是作为日志的一种存储方式。这也是“内存是新的硬盘”思路的体现。</p>
<h3><span id="i-3">复制方式比较</span></h3>
<p>tt server 和 redis 都支持 master-slave 方式的通信复制。<br />
tt server 使用了 ulog，并且 slaver 使用了 rts（replication time-stamp） 文件，对上一次的复制时间戳进行保存，实现了复制的续传。</p>
<p>而 redis 则是每次 slave 重新连接到 master 时，master 会将数据进行全量的复制给 slave，而不是增量式的。redis 复制的方式与使用 RDB 持久化方式原理基本相同，也是使用子进程进行内存的dump，在此期间，父进程收集改变数据库的命令，等把子进程收集的数据传输给 slave 之后，再将此期间收集到的数据也传输给 slave。</p>
<p>如果从 slave 数据重建的角度来看，tt server 支持断点复制的实现，应该说是比 redis 先进了一步。</p>
<h3><span id="i-4">性能方面比较</span></h3>
<p>新浪的 Tim Yang 做了 <a href="http://timyang.net/data/mcdb-tt-redis/" target="_blank">memcacheDB、Redis、tt server 的性能测试</a>。这是比较早期的测试，相信随着版本的升级，两者的性能都会有所提升。不过按照这个测试的结果来看，redis 在数据量不多（500W）并且value 较小的时候，性能表现是很优越的；而对于稍大一些的 value ，tt 则在写方面表现很出色，但写的性能，相对较差。相比之下，redis的读写性能，倒是比较平衡。<br />
但觉得随着时间的迁移，这个测试的参考性可能会打折扣，如果有可能的话，希望能看到更多的测试结果。</p>
<h3><span id="i-5">总结</span></h3>
<p>1. 从服务器模型来说，tt server 使用 acceptor + workers 的方式提供服务，能够利用多核的性能，但随着而来的是一些同步、加锁的复杂和开销；而 redis 使用了单线程提供服务，利用不了多核，但如果能够将每次服务的速度控制下来，对单个CPU的利用率，反而可以提高。如果想利用机器的多核性能，也可以在一台机器上搭建多个 redis 实例，但可能更要考虑到机器的内存限制。</p>
<p>2. 从数据存储的方式来说，尽管 tt server 和 redis 都是将数据存储在内存中，但我认为两个产品对“数据是如何存储”的观点是有所不同的。tt server 认为数据是存储在文件中的，只是通过内存映射，将对文件的操作转化成对内存的操作；而 redis 是直接将数据存储到内存中，之后再通过持久化等机制，将数据备份到磁盘中。虽然之前 redis 自己实现了 vm 功能，但redis 后续会取消掉自己实现的 vm 功能，按照“内存是最新的磁盘”这种思路，也就不难理解了：除了增加复杂度之外，还有一个因素，那就是 redis 不需要 vm，能存的数据大小，只能限制在物理内存的范围以内。<br />
从这个方面来将，redis 后续的版本可能就会限制用户使用的数据库大小是要小于物理内存的，而如果使用 tt server ，则用户须让使用数据文件小于物理内存，否则，发生内存交换，是非常损性能的。<br />
总而言之，在使用内存数据库的时候，应该有意识的对数据进行容量规划，避免出现物理内存不够而引起的内存交换。</p>
<p>3. tt server 和 redis 的策略都是从 slaver 配置 master ，而不是从 master 配置 slaver 关系，这样就减轻了 master 的负担，同时，master 不必知道自己有多少个 slaver ，就可以横向的扩增 slaver 。但 tt server 支持所谓的断点复制。需要考虑到的是 redis 在做 replication 的时候，是 fork 一个子进程工作的，如果有多个 replicate 的请求，redis 依然还是一个子进程在工作。这样也会对多个 slaver 产生一定的复制延时。</p>
<p>4. redis 在工作方式上，会 fork 子进程，因此 redis 在容量规划上，需要考虑到 redis fork 出子进程所需要的内存和 CPU，在最差的情况下：bgsave时候，父子两个进程虽然可以使用 copy on write 的好处，但如果在此期间整个表记录都被修改了，那就足足需要一倍的内存，否则，此时父进程会进行 copy ，父进程很可能没有内存可用，就需要进行内存交换，由此所带来的性能代价也是非常高的；与此同时，子进程子在 bgsave 的时候，需要对数据进行压缩，压缩是计算密集型的，因此最好不要和父进程使用同一个CPU，因为父进程使用了单线程事件处理的模型，这种模型的优点是充分利用CPU的资源，如果出现子进程与父进程抢CPU，那就得不偿失了。</p>
<p>5. redis 支持较多的数据结构，但在使用 sort 等时间复杂性较多的命令时，也会稍微的降低 redis 的性能，应该对这些耗时的命令进行一定的监控。<br />
<h3 class='related_post_title'><span id="i-6">相关文章</span></h3>
<ul class='related_post'>
<li>没有相关日志</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/127/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>内存学习——虚拟内存</title>
		<link>http://www.zavakid.com/123?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%2586%2585%25e5%25ad%2598%25e5%25ad%25a6%25e4%25b9%25a0%25e2%2580%2594%25e2%2580%2594%25e8%2599%259a%25e6%258b%259f%25e5%2586%2585%25e5%25ad%2598</link>
		<comments>http://www.zavakid.com/123#comments</comments>
		<pubDate>Sat, 22 Oct 2011 07:29:24 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[物理内存]]></category>
		<category><![CDATA[物理页面]]></category>
		<category><![CDATA[虚拟内存]]></category>
		<category><![CDATA[虚拟页面]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=123</guid>
		<description><![CDATA[本文总结虚拟内存的实现，已经程序在访问虚拟内存时的过程，在页命中和缺页时候的情况。 <a href="http://www.zavakid.com/123">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>接着上次<a href="http://www.zavakid.com/119" title="内存学习——为什么需要虚拟内存" target="_blank">学习虚拟内存</a>的文章继续学习。</p>
<h3>虚拟内存如何实现</h3>
<p>虚拟内存是以虚拟页面的单位组成的。<br />
虚拟页面使用磁盘来作为自己的存储，一些经常使用到的页面，才会被load到内存中，此时，就相当于把内存看成是磁盘的一个缓存。<br />
因为每次都load到内存的是一个虚拟页面，所以对应的，内存就需要有一个物理页面能过装下这个虚拟页面。因此，物理内存也被分隔为一个一个的物理页面。虚拟页面和物理页面应该是相等的。<br />
既然要把虚拟页面和物理页面关联起来，那么就需要维护虚拟页面和物理页面之间的关系。<br />
因此，就又需要这样一张页面来维持这样的关系，通常，这张表是放在物理内存中，由操作系统来维护的,叫做页表。</p>
<p>基于这种实现，实际上虚拟内存就有能力<a href="http://www.zavakid.com/119" title="内存学习——为什么需要虚拟内存" target="_blank">解决之前所遇到的问题</a>：每个进程都可以使用相同的虚拟地址，操作系统会将虚拟地址翻译成不同的物理地址，但对进程来说，是透明的；每个进程也都不会因为物理内存受限而不能加载运行，实际上虚拟内存是存在磁盘的，而通常磁盘要比内存大很多（虚拟页面一般放在磁盘的swap分区）；同时，虚拟内存通过维护虚拟页面和物理页面的页面，可以实现权限控制，而这种权限控制，就是搭载在页面上面的，因此，一般的内存权限控制，都是以页为单位的。</p>
<h3>虚拟内存的访问过程</h3>
<p>当程序访问的虚拟地址在页表中找不到对应的物理页时，这时候，就会向磁盘读取此虚拟页面，并且将此虚拟页面与一个物理页面关联起来，并且在页面记录这种关系。当物理页面都已经被占满的时候，操作系统就会踢掉一个用的少的物理页面，从而让这个新的虚拟页面装入物理页面。 —— 这和我们使用缓存的逻辑没有什么不同 —— 操作系统将虚拟页面放入物理页面的动作，是由异常机制触发的。<br />
而当程序中访问的虚拟地址已经在页表中有对应的物理页面时，这一切就变得相当轻松了。同时，内存权限的控制，也是通过在页表中的记录进行的。</p>
<h3>总结</h3>
<p>虚拟内存通过一个存储器层次的概念，将使用物理内存碰到的几个限制，就都统统解决了。我想，这和大学时候老师教我们在解决难题时候的思路一样，进行空间的坐标转换，换个角度，问题说不定就得以迅速解决，而且简单，高效。<br />
<h3 class='related_post_title'>相关文章</h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/119' title='内存学习——为什么需要虚拟内存'>内存学习——为什么需要虚拟内存</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/123/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>内存学习——为什么需要虚拟内存</title>
		<link>http://www.zavakid.com/119?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%2586%2585%25e5%25ad%2598%25e5%25ad%25a6%25e4%25b9%25a0%25e2%2580%2594%25e2%2580%2594%25e4%25b8%25ba%25e4%25bb%2580%25e4%25b9%2588%25e9%259c%2580%25e8%25a6%2581%25e8%2599%259a%25e6%258b%259f%25e5%2586%2585%25e5%25ad%2598</link>
		<comments>http://www.zavakid.com/119#comments</comments>
		<pubDate>Sun, 16 Oct 2011 09:57:49 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[cache]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[为什么有虚拟内存]]></category>
		<category><![CDATA[内存]]></category>
		<category><![CDATA[存储器层次结构]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=119</guid>
		<description><![CDATA[关于虚拟内存，物理内存，我有蛮多概念都是很模糊的，今天下午看了一下虚拟内存，也算是有了一点小收获，本文就针对为什么需要有虚拟内存的理解写下来。 <a href="http://www.zavakid.com/119">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>关于虚拟内存，物理内存，我有蛮多概念都是很模糊的，今天下午看了一下虚拟内存，也算是有了一点小收获，本文就针对为什么需要有虚拟内存的理解写下来。</p>
<p>同时，我也希望自己能够陆续学习linux内存管理的知识，并且写出一些文章，来记录自己的一些理解。<br />
如果您觉得有任何问题，可以留下评论，我们一起讨论，毕竟越辩越明。</p>
<h3>为什么要使用虚拟内存</h3>
<p>之前的计算机系统，是使用物理地址来使用内存的，这样，CPU就根据某个寄存器中相应的值，直接到物理内存去取值了。<br />
这样的好处就是非常直接，非常容易理解。</p>
<p>而缺点是，我们需要知道物理地址的值，每次程序开始执行，也就是执行程序从磁盘被load到物理内存中之后，我们必须告诉CPU，程序是从哪一个地址开始执行的（即PC寄存器的值）；还有一个致命的缺点是：程序使用的内存会被物理内存所限制，比如我们的机器上只有512M内存，那我们的程序就不能使用需占1G内存的程序了。这点或许是催生虚拟内存产生的最主要原因。</p>
<h3>虚拟内存的概念</h3>
<p>为了解决上面的的问题，就产生了虚拟内存的概念。那什么是虚拟内存呢？这里我先说说自己对<strong>存储器层次结构</strong>的理解。</p>
<p>计算机中有一种存储器层次的原则。我的理解是，CPU使用的数据都是基于寄存器的，如果我们的寄存器足够的大和多并且足够便宜，那么也就没有后来那么多的东西产生了。而问题就是寄存器足够快，但其造价却非常昂贵，因此，考虑到成本，就有了之后的CPU高速缓存，主存（就是我们常说的内存）和硬盘，甚至磁带等存储器了。</p>
<p>那么，计算机是如何让这些速度快慢不一、容量大小不一的存储器在一起工作的呢？一个方案就是<strong>存储器层次结构</strong>。</p>
<p>对于这个存储器层次结构，我的理解是：CPU是和寄存器打交道的，但寄存器的容量毕竟有限，因此就需要高速缓存存储器来作为寄存器的缓存，当有些数据在寄存器中找不到时，CPU就可以去寻找高速缓存这个存储器中的内容，如果告诉缓存器还没有这个数据，那我就去主存中再去寻找这个数据，如果主存中也还没有，那就去磁盘中找吧。</p>
<p>这也是我对存储器层次结构的一个理解。</p>
<p>以上说了一通，但都没有提到虚拟内存，那虚拟内存究竟是什么？他在这个层次中处于哪个位置呢？</p>
<p>实际上，按照这种模型去思考的话，就可以这样理解：<strong>虚拟内存就是去解决主存到磁盘这个层次的方案</strong>。</p>
<p>没错，我认为虚拟内存就是一种方案，而且他是非常重要的，为什么呢？众所周知，CPU的速度很快，内存就是作为匹配CPU和磁盘之间速度的一个中间层，高速缓存其实也是这样一个缓存的角色，但问题是，如果高速缓存失效，那么CPU会去访问内存，这样的速度只是降低了十倍的数量级；而如果是内存失效，让CPU去访问磁盘的话，这样的速度却是降低了十万倍到百万倍的数量级。</p>
<p>可见，在寄存器、高速缓存和主存之间缓存的失效，结果还是可以让人接受的（想想java的volatile关键字），但主存和磁盘之间缓存的失效，就会给程序造成比较大的性能影响了，所以我们应该努力避免主存的失效，这也是虚拟内存所必须要解决和面对的问题之一。</p>
<h3>总结</h3>
<p>其实可以认为，程序使用的内存，都是用的虚拟内存，因此也就没有了物理内存的限制（但还是限制于计算机的寻址位数，比如32位和64位，因为虚拟内存系统需要使用到物理内存）。他可以把自己的一部分放在物理内存中，还有一部分当做缓存放到磁盘中。另外，虚拟内存有相应的虚拟地址，因此，他就可以做到对于每一个程序来说，使用的都是相同的虚拟地址，这些虚拟地址，则可以映射到不同的物理地址，也就是说每个程序都可以把自己想象成自己拥有整台机器的内存。<br />
<h3 class='related_post_title'>相关文章</h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/108' title='让Ubuntu32位支持4G内存的方法'>让Ubuntu32位支持4G内存的方法</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/119/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>阿里巴巴B2B招聘高级java工程师</title>
		<link>http://www.zavakid.com/114?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e9%2598%25bf%25e9%2587%258c%25e5%25b7%25b4%25e5%25b7%25b4b2b%25e6%258b%259b%25e8%2581%2598%25e9%25ab%2598%25e7%25ba%25a7java%25e5%25b7%25a5%25e7%25a8%258b%25e5%25b8%2588</link>
		<comments>http://www.zavakid.com/114#comments</comments>
		<pubDate>Tue, 11 Oct 2011 09:58:25 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=114</guid>
		<description><![CDATA[阿里巴巴B2B招聘高级java开发工程师 我不想列“精通xxx&#8230;熟悉xxx”，只要求，如果您： 有2年或以上java实际开发经验，或 1年以上java实际开发经验但技术能力较强 就能直接联系我: 直接在此帖留言或直接联系我！ 通过沟通我们可以谈简历的事情，走内部推荐，1.电面2.来杭面试，流程简单，全程报销路费； P.S. 年初，各大公司招聘旺季，阿里巴巴这里呢，我不想说有多好，但也绝对不算差，最实际的，薪酬待遇，各大公司基本保密，但其实业内人士大多心里也有数，秘而不宣；所以，待遇方面不用过多担心，请诸君仔细斟酌，欢迎联系！ 再P.S. 为什么我这招聘帖这么简单呢？其实你懂的，“精通xxx熟悉xxx”那只是吓唬小菜的，对“高级java开发工程师”而言没有意义，我们需要的只是充分沟通、im沟通+当面沟通。在这个有点糟糕的时代，我们人人都不仅需要money，也需要平台与机遇，更需要个人修为与成长！请给阿里和您自己一个机会，谢谢！ 版权注明： 本文的招聘文字来自 @pf_miles ，详见：http://wenyue.me/blog/292 相关文章 没有相关日志]]></description>
			<content:encoded><![CDATA[<p>阿里巴巴B2B招聘高级java开发工程师</p>
<p>我不想列“精通xxx&#8230;熟悉xxx”，只要求，如果您：</p>
<p>有2年或以上java实际开发经验，或<br />
1年以上java实际开发经验但技术能力较强<br />
就能直接联系我: 直接在此帖留言或直接<a href="http://www.zavakid.com/about" title="联系Zava">联系我</a>！</p>
<p>通过沟通我们可以谈简历的事情，走内部推荐，1.电面2.来杭面试，流程简单，全程报销路费；</p>
<p>P.S. 年初，各大公司招聘旺季，阿里巴巴这里呢，我不想说有多好，但也绝对不算差，最实际的，薪酬待遇，各大公司基本保密，但其实业内人士大多心里也有数，秘而不宣；所以，待遇方面不用过多担心，请诸君仔细斟酌，欢迎联系！</p>
<p>再P.S. 为什么我这招聘帖这么简单呢？其实你懂的，“精通xxx熟悉xxx”那只是吓唬小菜的，对“高级java开发工程师”而言没有意义，我们需要的只是充分沟通、im沟通+当面沟通。在这个有点糟糕的时代，我们人人都不仅需要money，也需要平台与机遇，更需要个人修为与成长！请给阿里和您自己一个机会，谢谢！</p>
<p>版权注明： 本文的招聘文字来自 <a href="https://twitter.com/#!/pf_miles" target="_blank">@pf_miles</a> ，详见：<a href="http://wenyue.me/blog/292" target="_blank">http://wenyue.me/blog/292</a><br />
<h3 class='related_post_title'>相关文章</h3>
<ul class='related_post'>
<li>没有相关日志</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/114/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>让Ubuntu32位支持4G内存的方法</title>
		<link>http://www.zavakid.com/108?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e8%25ae%25a9ubuntu32%25e4%25bd%258d%25e6%2594%25af%25e6%258c%25814g%25e5%2586%2585%25e5%25ad%2598%25e7%259a%2584%25e6%2596%25b9%25e6%25b3%2595</link>
		<comments>http://www.zavakid.com/108#comments</comments>
		<pubDate>Wed, 10 Aug 2011 03:30:05 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[ape]]></category>
		<category><![CDATA[内存]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=108</guid>
		<description><![CDATA[本文针对内存超过3G，但还在使用32位ubuntu的朋友们，可以让你的ubuntu支持4G内存了。 <a href="http://www.zavakid.com/108">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="toc_container" class="toc_wrap_right no_bullets"><p class="toc_title">本文内容索引</p><ul class="toc_list"><li><a href="#generic-pae">1 安装generic-pae内核</a></li><li><a href="#i">2 重启,检查系统是否识别成功</a></li><li><a href="#_generic">3 如果发现有问题,切换回 generic 内核</a><ul><li><a href="#_GRUB_1">3.1 针对 GRUB 1</a></li><li><a href="#_GRUB_2">3.2 针对 GRUB 2</a></li></ul></li><li><a href="#i-2">4 相关文章</a></li></ul></div>
<p>在Ubuntu中实现4G内存的方法很简单.</p>
<p>而且经过测试,完全符合我们一般的工作应用和开发应用.</p>
<p>当然,我们的方法不一定是最简单的,如果你有更好的方法,欢迎留下你的做法.</p>
<p>如果你实在发现在支持 pae 的内核下,你的系统不稳定,你可以做两件事情:<br />
1. 把内核切换回原来的 generic 内核；<br />
2. 去买张彩票 :）</p>
<p>下面是我们的实践方法:</p>
<ol>
<li>安装 generic-pae 内核</li>
<li>重启,检查系统是否识别成功</li>
<li>如果发现有问题,切换回 generic 内核</li>
</ol>
<h3><span id="generic-pae"><a name="让Ubuntu32位支持4G内存的方法-安装genericpae内核"></a>安装generic-pae内核</span></h3>
<p>针对 ubuntu, 可以使用如下命令:</p>
<div>
<div>
<pre>$ sudo apt-get update
$ sudo apt-get install linux-headers-server linux-image-server linux-server</pre>
</div>
</div>
<h3><span id="i"><a name="让Ubuntu32位支持4G内存的方法-重启,检查系统是否识别成功"></a>重启,检查系统是否识别成功</span></h3>
<p>可以先用 uname -a 看看内核是否变成 generic pae 了? 如果还不是 pae, 可以用 grub 切换到 pae 内核. 切换方法与下方的&lt;切换回generic内核&gt;道理一致</p>
<p>使用以下命令:</p>
<div>
<div>
<pre>free -m</pre>
</div>
</div>
<p>在 total 一栏中,看有没有识别出4G内存.</p>
<h3><span id="_generic"><a name="让Ubuntu32位支持4G内存的方法-如果发现有问题,切换回generic内核"></a>如果发现有问题,切换回 generic 内核</span></h3>
<p>如果你的系统正常,并且正确识别了4G内存,就可以不用往下看了.</p>
<p>如果你发现有问题,想切换回 generic 内核,就接着往下看吧.</p>
<p>切换回内核,这里我们使用 grub 去解决.</p>
<p>首先查看 grub 版本号: grub-install -v</p>
<p>如果是 1.9 或者以上,则表示你是 grub2 ,如果是以下,则表示你是 grub 1</p>
<h4><span id="_GRUB_1"><a name="让Ubuntu32位支持4G内存的方法-针对GRUB1"></a>针对 GRUB 1</span></h4>
<p>直接修改 /boot/grub/menu.lst 文件, 把 default 的值设置成 需要启动内核版本 的序号.</p>
<h4><span id="_GRUB_2"><a name="让Ubuntu32位支持4G内存的方法-针对GRUB2"></a>针对 GRUB 2</span></h4>
<p>我的做法是:</p>
<p>1. 查看 /boot/grub/grub/grub.cfg 文件,找到 menuentry 中所对应的内核,记住我想要启动内核的序号,从 0 开始算.</p>
<p>2. 修改 /etc/default/grub 下 GRUB_DEFAULT 的值,也就是启动项</p>
<p>3. 执行 sudo update-grub , 自动生成  grub.cfg</p>
<p>4. 重启即可.</p>
<p>5. uname -a 查看你现在的内核,如果你再不爽,可以把 generic pae 内核给删了. <br clear="all" /><br />
<h3 class='related_post_title'><span id="i-2">相关文章</span></h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/178' title='terminator的高效使用'>terminator的高效使用</a></li>
<li><a href='http://www.zavakid.com/32' title='Ubuntu下Eclipse退出，进程却还存在'>Ubuntu下Eclipse退出，进程却还存在</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/108/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于IO的同步,异步,阻塞,非阻塞</title>
		<link>http://www.zavakid.com/96?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e5%2585%25b3%25e4%25ba%258eio%25e7%259a%2584%25e5%2590%258c%25e6%25ad%25a5%25e5%25bc%2582%25e6%25ad%25a5%25e9%2598%25bb%25e5%25a1%259e%25e9%259d%259e%25e9%2598%25bb%25e5%25a1%259e</link>
		<comments>http://www.zavakid.com/96#comments</comments>
		<pubDate>Sat, 30 Jul 2011 06:55:14 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[NIO]]></category>
		<category><![CDATA[IO复用]]></category>
		<category><![CDATA[IO模型]]></category>
		<category><![CDATA[同步IO]]></category>
		<category><![CDATA[异步IO]]></category>
		<category><![CDATA[阻塞IO]]></category>
		<category><![CDATA[非阻塞IO]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=96</guid>
		<description><![CDATA[本文讲述了IO调用中的阻塞，非阻塞，同步，异步的概念和关系。是的读者可以很清楚的理解这几个概念。看了这篇文章，绝对可以很了解这几个IO调用的概念了。 <a href="http://www.zavakid.com/96">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="toc_container" class="toc_wrap_right no_bullets"><p class="toc_title">本文内容索引</p><ul class="toc_list"><li><a href="#IO">1 IO模型</a></li><li><a href="#IO-2">2 IO的两个阶段</a></li><li><a href="#i">3 同步，异步的区别</a></li><li><a href="#i-2">4 阻塞和非阻塞</a></li><li><a href="#i-3">5 结论</a></li><li><a href="#i-4">6 相关文章</a></li></ul></div>
<p>上次写了一篇文章：<a title="Unix IO模型学习" href="http://www.zavakid.com/70" target="_blank">Unix IO 模型学习</a>。恰巧在这次周会的时候，<a href="http://weibo.com/fp1203" target="_blank">@fp1203</a> (<a title="黄金档" href="http://www.goldendoc.org/" target="_blank">goldendoc</a>成员之一) 正好在讲解poll和epoll的底层实现。中途正好讨论了网络IO的同步、异步、阻塞、非阻塞的概念，当时讲下来，大家的理解各不相同，各执己见。搜索了网络上的一些文章，观点也各不相同，甚至连<a href="http://en.wikipedia.org/wiki/Asynchronous_I/O" target="_blank">wiki</a>也将异步和非阻塞当成一个概念在解释。</p>
<p>虽然网络上充斥了大量关于同步、异步、阻塞、非阻塞的文章，但大都是抄来抄去，没有一个权威的说法。但我找到了<a href="http://blog.csdn.net/historyasamirror/article/details/5778378" target="_blank">这一篇文章</a>，该文章引用了《UNIX网络编程 卷1》的介绍，这本书的作者是Richard Stevens。如果有Richard Stevens在这方面的定义或者结论，那么我想，这应该是比较有说服力的了。</p>
<p>关于《UNIX网络编程 卷1》这本书，我特意找了英文原版，也共享出来了：大家可以下载<a href="http://u.115.com/file/bh06p2sr#UNIX_Network_Programming.chm" target="_blank">《UNIX网络编程 卷1》的英文原版</a>（CHM格式）。</p>
<p>我看了6.2这节内容，这节内容就是讲IO模型的。刚刚提到的那篇文章，几乎就是翻译这个6.2节的。应该说，这个6.2节，对同步和异步的讲解，算是很清楚的。</p>
<p>下面是我自己理解的重点。</p>
<h3><span id="IO">IO模型</span></h3>
<p>目前unix存在五种IO模型（这也和上一篇文章：<a title="Unix IO模型学习" href="http://www.zavakid.com/70" target="_blank">Unix IO 模型</a> 中提到的一致），分别是：</p>
<ul>
<li>阻塞型 IO（blocking I/O）</li>
<li>非阻塞性IO（nonblocking I/O）</li>
<li>IO多路复用（I/O multiplexing）</li>
<li>信号驱动IO（signal driven I/O）</li>
<li>异步IO（asynchronous I/O）</li>
</ul>
<h3><span id="IO-2">IO的两个阶段</span></h3>
<ol>
<li>等待数据准备好</li>
<li>将数据从内核缓冲区复制到用户进程缓冲区</li>
</ol>
<h3><span id="i">同步，异步的区别</span></h3>
<p>那么究竟什么是同步和异步的区别呢？请重点读一下<a title="点此下载" href="http://u.115.com/file/bh06p2sr#UNIX_Network_Programming.chm" target="_blank">原文</a>6.2节中的信号驱动IO和异步IO中的比较。最后总结出来是：</p>
<ul>
<li>同步IO，需要用户进程主动将存放在内核缓冲区中的数据拷贝到用户进程中。</li>
<li>异步IO，内核会自动将数据从内核缓冲区拷贝到用户缓冲区，然后再通知用户。</li>
</ul>
<p>这样，同步和异步的概念就非常明显了。以上的五种IO模型，前面四种都是同步的，只有第五种IO模型才是异步的IO。</p>
<h3><span id="i-2">阻塞和非阻塞</span></h3>
<p>那么阻塞和非阻塞呢？注意到以上五个模型。阻塞IO，非阻塞IO，只是上面的五个模型中的两个。阻塞，非阻塞，是针对单个进程而言的。</p>
<p>当对多路复用IO进行调用时，比如使用poll。需注意的是，poll是系统调用，当调用poll的时候，其实已经是陷入了内核，是内核线程在跑了。因此对于调用poll的用户进程来讲，此时是阻塞的。</p>
<p>因为poll的底层实现，是去扫描每个文件描述符（fd），而如果要对感兴趣的fd进行扫描，那么只能将每个描述符设置成非阻塞的形式（对于用户进程来讲，设置fd是阻塞还是非阻塞，可以使用系统调用fcntl），这样才有可能进行扫描。如果扫描当中，发现有可读（如果可读是用户感兴趣的）的fd，那么select就在用户进程层面就会返回，并且告知用户进程哪些fd是可读的。</p>
<p>这时候，用户进程仍然需要使用read的系统调用，将fd的数据，从内核缓冲区拷贝到用户进程缓冲区（这也是poll为同步IO的原因）。</p>
<p>那么此时的read是阻塞还是非阻塞呢？这就要看fd的状态了，如果fd被设置成了非阻塞，那么此时的read就是非阻塞的；如果fd被设置成了阻塞，那么此时的read就是阻塞的。</p>
<p>不过程序已经执行到了这时候，不管fd是阻塞还是非阻塞，都没有任何区别，因为之前的poll，就是知道有数据准备好了才返回的，也就是说内核缓冲区已经有了数据，此时进行read，是肯定能够将数据拷贝到用户进程缓冲区的。</p>
<p>但如果换种想法，如果poll是因为超时返回的，而我们又对一个fd（此fd是被poll轮询过的）进行read调用，那么此时是阻塞还是非阻塞，就非常有意义了，对吧！</p>
<h3><span id="i-3">结论</span></h3>
<ol>
<li>判断IO是同步还是异步，是看谁主动将<strong>数据</strong>拷贝到用户进程。</li>
<li>select或者poll，epoll，是同步调用，进行此调用的用户进程也处于阻塞状态。</li>
<li>javaScript或者nodejs中的读取网络（文件）数据，然后提供回调函数进行处理，是异步IO。</li>
</ol>
<h3 class='related_post_title'><span id="i-4">相关文章</span></h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/70' title='Unix IO模型学习'>Unix IO模型学习</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/96/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>apache httpd worker模式工作原理及配置</title>
		<link>http://www.zavakid.com/77?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=worker%25e6%25a8%25a1%25e5%25bc%258f%25e5%25b7%25a5%25e4%25bd%259c%25e5%258e%259f%25e7%2590%2586%25e5%258f%258a%25e9%2585%258d%25e7%25bd%25ae</link>
		<comments>http://www.zavakid.com/77#comments</comments>
		<pubDate>Wed, 22 Dec 2010 09:10:07 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[httpd]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apache优化]]></category>
		<category><![CDATA[httpd优化]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=77</guid>
		<description><![CDATA[本文内容索引1 简单了解 worker模式与 prefork模式2 worker 参数配置2.0.1 下面看看 worker模式下这些参数的默认配置值 ：2.0.2 3 相关文章 httpd在linux下默认使用prefork, 我们网站的服务器，在编译httpd的时候，就指定了使用worker模式。 简单了解 worker模式与 prefork模式 worker ： httpd在启动的时候，会由root进程派生出几个子进程，每个子进程中会有固定数量的线程，到时候提供服务的，就是这些线程，也就是说一个进程能够同时提供多次服务。 prefork ： httpd使用进程来提供服务，每个进程在同一时间提供一次服务。 worker 参数配置 由于我比较关注 worker 模式， 所以就特别关注了一下 worker 的一些参数配置。 worker的参数主要有：ServerLimit，ThreadLimit，StartServers，MinSpareThreads， MaxSpareThreads，ThreadsPerChild，MaxClients，MaxRequestsPerChild。 ServerLimit 是设置httpd root进程能够产生的最大进程数限制 ThreadLimit 是设置每个httpd子进程能够产生的最大服务线程限制 StarServers 是httpd刚启动时，root进程创建的子进程数 MinSpareThreads &#8230; <a href="http://www.zavakid.com/77">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="toc_container" class="toc_wrap_right no_bullets"><p class="toc_title">本文内容索引</p><ul class="toc_list"><li><a href="#_worker_prefork">1 简单了解 worker模式与 prefork模式</a></li><li><a href="#worker">2 worker 参数配置</a><ul><li><ul><li><a href="#_worker">2.0.1 下面看看 worker模式下这些参数的默认配置值 ：</a></li><li><a href="#i">2.0.2 </a></li></ul></li></ul></li><li><a href="#i-2">3 相关文章</a></li></ul></div>
<p>httpd在linux下默认使用prefork, 我们网站的服务器，在编译httpd的时候，就指定了使用worker模式。</p>
<h3><span id="_worker_prefork"><a name="worker模式工作原理及配置-简单了解worker模式与prefork模式"></a>简单了解 worker模式与 prefork模式</span></h3>
<p>worker ： httpd在启动的时候，会由root进程派生出几个子进程，每个子进程中会有固定数量的线程，到时候提供服务的，就是这些线程，也就是说一个进程能够同时提供多次服务。</p>
<p>prefork ： httpd使用进程来提供服务，每个进程在同一时间提供一次服务。</p>
<h3><span id="worker"><a name="worker模式工作原理及配置-worker参数配置"></a>worker 参数配置</span></h3>
<p>由于我比较关注 worker 模式， 所以就特别关注了一下 worker 的一些参数配置。</p>
<p>worker的参数主要有：ServerLimit，ThreadLimit，StartServers，MinSpareThreads，<br />
MaxSpareThreads，ThreadsPerChild，MaxClients，MaxRequestsPerChild。</p>
<ul>
<li>ServerLimit 是设置httpd root进程能够产生的最大进程数限制</li>
<li>ThreadLimit 是设置每个httpd子进程能够产生的最大服务线程限制</li>
<li>StarServers 是httpd刚启动时，root进程创建的子进程数</li>
<li>MinSpareThreads 顾名思义，就是最少的空闲线程数</li>
<li>MaxSpareThreads 就是最多的空闲线程数</li>
<li>ThreadsPerChild 每个子进程产生的线程数</li>
<li>MaxClients httpd同时处理的最大请求数</li>
<li>MaxRequestsPerChild 每个子进程提供的请求服务数，如果达到该值，则该子进程结束，由root进程根据需要再次派生新的子进程</li>
</ul>
<p>其中几个参数之间的联系还是很重要的：</p>
<ul>
<li> ServerLimit 限制了 MaxClients 和 ThreadsPerChild。 因为 MaxClients / ThreadsPerChild = 子进程数， 而子进程数目是受限于 ServerLimit</li>
<li>MaxSpareThreads 需要 大于等于 MinSpareThreads + ThreadsPerChild 。  根据我的理解，这也是合理的，因为子进程产生时，线程的数目已经是固定的了，那就需要 [ MinSpareThreads,  MaxSpareThreads ] 中有一个线程数对ThreadsPerChild取余能够为0。</li>
</ul>
<h5><span id="_worker"><a name="worker模式工作原理及配置-下面看看worker模式下这些参数的默认配置值："></a>下面看看 worker模式下这些参数的默认配置值 ：</span></h5>
<div>
<div>
<pre>&lt;IfModule worker.c&gt;
     ServerLimit      16
     ThreadLimit     64
     StartServers     3
     MinSpareThreads  75
     MaxSpareThreads  250
     MaxClients       400  # 16 * 25
     ThreadsPerChild  25
     MaxRequestsPerChild   10000
&lt;/IfModule&gt;</pre>
</div>
</div>
<h5><span id="i"><a name="worker模式工作原理及配置-再看看我们的vaspool配置"></a></span></h5>
<h3 class='related_post_title'><span id="i-2">相关文章</span></h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/8' title='使用Apache Lucene搜索文本'>使用Apache Lucene搜索文本</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/77/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>百度发布SEO指南</title>
		<link>http://www.zavakid.com/73?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25e7%2599%25be%25e5%25ba%25a6%25e5%258f%2591%25e5%25b8%2583seo%25e6%258c%2587%25e5%258d%2597</link>
		<comments>http://www.zavakid.com/73#comments</comments>
		<pubDate>Sat, 14 Aug 2010 13:12:43 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[SEO]]></category>
		<category><![CDATA[百度]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=73</guid>
		<description><![CDATA[在Google的搜索引擎优化指南出来将近两年的时候，百度官方也给出了他自己的搜索引擎优化指南。 把指南下下来之后，粗略的看了一下，大概是讲了四点，核心思想还是围绕用户体验中心的： 域名的注册，服务器的租用 域名简短，让用户很容易记住；服务器这方面，就是对用户的响应速度。 网站要让用户看懂，也要让搜索引擎看懂 包括对HTML元标签的使用， 还有尽量少用Flash和JS等搜索引擎还不太懂的东东。 网站运营的优化 增强品牌化，增加用户的信任，注重用户体验。 搜索引擎惩罚 惩罚不是目的，但是谁影响了搜索引擎对用户的体验，谁就会受到不同程度的惩罚。 对于这四点，大家也都是很清楚的。但最后的FAQ却引起了我的兴趣： 自然排序和搜索排序是两个不同的部门 想想也应该是这样子，而且作为一家大公司来讲，追求的应该是长期可持续发展的收入，而不是杀鸡取卵。 更换空间需要保留旧空间一段时间 我个人觉得很有必要，而且很有可能baiduSpider会把域名DNS自己做缓存，所以需要保留旧空间一段时间，也是很有道理的。 百度是支持nofollow的 这是肯定的，就算现在支持不好，以后也肯定是这个趋势。不过这个问题应该难不倒百度的工程师。 百度对Https协议的支持很有限 可以公开的内容就公开吧。 site语法原本就不是查网站收录数的 title和description原则不要做太大的修改 URL尽量静态化 人性化的URL也是用户体验的一种表现，友好的URL甚至可以让用户直接输入URL来网站的内容。 国外空间对于排名没有影响 关键是访问速度和响应时间。 以上就是我看了百度官方的搜索引擎优化指南的一些内容，其实说起来，大家都了解了，只不过是官方发出来的，自然就更坚定了大家的想法。 相关文章 Google Toolbar 撤下 Google PR]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://www.google.com.hk/ggblog/googlewebmaster-cn/2008/12/google-seo.html" target="_blank">Google的搜索引擎优化指南</a>出来将近两年的时候，百度官方也给出了他自己的<a href="http://club.baidu.com/html/main/index.jsp" target="_blank">搜索引擎优化指南</a>。</p>
<p>把指南下下来之后，粗略的看了一下，大概是讲了四点，核心思想还是围绕用户体验中心的：</p>
<ol>
<li><strong>域名的注册，服务器的租用</strong><br />
域名简短，让用户很容易记住；服务器这方面，就是对用户的响应速度。</li>
<li><strong>网站要让用户看懂，也要让搜索引擎看懂</strong><br />
包括对HTML元标签的使用， 还有尽量少用Flash和JS等搜索引擎还不太懂的东东。</li>
<li><strong>网站运营的优化</strong><br />
增强品牌化，增加用户的信任，注重用户体验。</li>
<li><strong>搜索引擎惩罚</strong><br />
惩罚不是目的，但是谁影响了搜索引擎对用户的体验，谁就会受到不同程度的惩罚。</li>
</ol>
<p>对于这四点，大家也都是很清楚的。但最后的FAQ却引起了我的兴趣：</p>
<ol>
<li><strong>自然排序和搜索排序是两个不同的部门</strong><br />
想想也应该是这样子，而且作为一家大公司来讲，追求的应该是长期可持续发展的收入，而不是杀鸡取卵。</li>
<li><strong>更换空间需要保留旧空间一段时间</strong><br />
我个人觉得很有必要，而且很有可能baiduSpider会把域名DNS自己做缓存，所以需要保留旧空间一段时间，也是很有道理的。</li>
<li><strong>百度是支持nofollow的<br />
<span style="color: #444444;"><span style="font-weight: normal;">这是肯定的，就算现在支持不好，以后也肯定是这个趋势。不过这个问题应该难不倒百度的工程师。</span></span> </strong></li>
<li><strong>百度对Https协议的支持很有限<br />
<span style="font-weight: normal;">可以公开的内容就公开吧。</span></strong></li>
<li><strong>site语法原本就不是查网站收录数的</strong></li>
<li><strong>title和description原则不要做太大的修改</strong></li>
<li><strong>URL尽量静态化<br />
<span style="font-weight: normal;">人性化的URL也是用户体验的一种表现，友好的URL甚至可以让用户直接输入URL来网站的内容。</span></strong></li>
<li><strong>国外空间对于排名没有影响<br />
<span style="font-weight: normal;">关键是访问速度和响应时间。</span></strong></li>
</ol>
<p>以上就是我看了百度官方的搜索引擎优化指南的一些内容，其实说起来，大家都了解了，只不过是官方发出来的，自然就更坚定了大家的想法。<br />
<h3 class='related_post_title'>相关文章</h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/23' title='Google Toolbar 撤下 Google PR'>Google Toolbar 撤下 Google PR</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/73/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Unix IO模型学习</title>
		<link>http://www.zavakid.com/70?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=unix-io%25e6%25a8%25a1%25e5%259e%258b%25e5%25ad%25a6%25e4%25b9%25a0</link>
		<comments>http://www.zavakid.com/70#comments</comments>
		<pubDate>Sat, 07 Aug 2010 07:37:27 +0000</pubDate>
		<dc:creator>zava</dc:creator>
				<category><![CDATA[NIO]]></category>
		<category><![CDATA[IO复用]]></category>
		<category><![CDATA[IO模型]]></category>
		<category><![CDATA[异步IO]]></category>
		<category><![CDATA[阻塞IO]]></category>
		<category><![CDATA[非阻塞IO]]></category>

		<guid isPermaLink="false">http://www.zavakid.com/?p=70</guid>
		<description><![CDATA[本文内容索引1 阻塞IO2 非阻塞IO3 IO复用4 信号IO5 异步IO6 相关文章 这季度学习java nio及其相关的内容和框架，所以就想先看看Unix下的一些IO模型。结合网络上的资料进行学习，自己也写篇日志，加强一下理解吧。 POSIX中对同步IO和异步IO的规定： 同步IO操作：引起进程的阻塞直到IO操作完成 异步IO操作：IO操作不会引起进程阻塞 在UNIX下，有5中操作模型： 阻塞IO 非阻塞IO IO复用 信号驱动IO 异步IO 按照网络上的说法，前四种是属于同步IO，第五种才属于异步IO，对于这个结论，我的理解是根据用户进程是否阻塞来判断的（而不是内核进程）。关于同步和异步的一些讨论，可以参考http://bbs.chinaunix.net/viewthread.php?tid=947563 阻塞IO 这是我们熟悉的IO模型，一个进程在作IO操作时，非要等到数据从内核空间拷贝到用户进程空间，才会返回。这个模型的优点就是简单，而且在阻塞的时候，CPU还可以进行调度，去执行别的进程。 非阻塞IO 一开始我看是非阻塞IO，觉得应该要比阻塞IO模型先进，可是当我一看使用方法的时候，就知道这个模型是不会被实际使用的，仅仅只能作为理论上存在的IO模型。这个模型的观点是：进行IO操作的时候，不阻塞，如果没有数据准备好，就直接返回错误码（或者是别的代码）。因此，使用者就只能不断进行轮询来调用IO函数。这样的后果就是，不仅在宏观上形成了与阻塞IO一共的“阻塞”效果，而且在微观上，CPU一直被用来轮询，造成了CPU的浪费。所以，这个模型还不如阻塞IO模型实用。 IO复用 对于IO复用，我的理解有三点： 在一次系统调用中，实现了询问多个描述符的IO准备情况 —— 根据事件通知 为了实现第一点，就需要把阻塞的地方进行转移。把一次系统调用，分为两次系统调用。第一次系统调用可以询问多个描述符的IO准备情况，在这个地方进行阻塞；而第二次系统调用，是针对已经准备好IO的描述符进行调用，此时，理论上（按照我的理解），也是会发生阻塞的，只不过是此时内核已经把数据准备好了，阻塞的时间可以忽略不计罢了。 本质上，还是阻塞的。 信号IO 我们都知道，信号是UNIX提供了进程间进行通信的一种方式。我们常用的 kill -9 命令（kill是向进程传递信号量，9只是众多信号中的一个代号），或者是 Ctrl + C 的时候，就是向某个进程发出终止的信号，这样进程就退出了。 而对于信号IO的模型，我是这么理解的：进程在发起IO操作，系统调用之后，直接访问，内核会在IO数据准备好之后，以某个信号通知发起IO操作的进程，从而使得该进程的信号处理函数可以读取IO数据的操作。 &#8230; <a href="http://www.zavakid.com/70">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div id="toc_container" class="toc_wrap_right no_bullets"><p class="toc_title">本文内容索引</p><ul class="toc_list"><li><a href="#IO">1 阻塞IO</a></li><li><a href="#IO-2">2 非阻塞IO</a></li><li><a href="#IO-3">3 IO复用</a></li><li><a href="#IO-4">4 信号IO</a></li><li><a href="#IO-5">5 异步IO</a></li><li><a href="#i">6 相关文章</a></li></ul></div>
<p>这季度学习java nio及其相关的内容和框架，所以就想先看看Unix下的一些IO模型。结合网络上的资料进行学习，自己也写篇日志，加强一下理解吧。</p>
<p><strong>POSIX中对同步IO和异步IO的规定</strong>：</p>
<ul>
<li><span style="line-height: 27px;">同步IO操作：引起进程的阻塞直到IO操作完成</span></li>
<li><span style="line-height: 27px;">异步IO操作：IO操作不会引起进程阻塞</span></li>
</ul>
<p><strong>在UNIX下，有5中操作模型</strong>：</p>
<ol>
<li>阻塞IO</li>
<li>非阻塞IO</li>
<li>IO复用</li>
<li>信号驱动IO</li>
<li>异步IO</li>
</ol>
<p>按照网络上的说法，前四种是属于同步IO，第五种才属于异步IO，对于这个结论，我的理解是根据用户进程是否阻塞来判断的（而不是内核进程）。关于同步和异步的一些讨论，可以参考<a href="http://bbs.chinaunix.net/viewthread.php?tid=947563">http://bbs.chinaunix.net/viewthread.php?tid=947563</a></p>
<h3><span id="IO"><strong>阻塞IO</strong></span></h3>
<p>这是我们熟悉的IO模型，一个进程在作IO操作时，非要等到数据从内核空间拷贝到用户进程空间，才会返回。这个模型的优点就是简单，而且在阻塞的时候，CPU还可以进行调度，去执行别的进程。</p>
<h3><span id="IO-2"><strong>非阻塞IO</strong></span></h3>
<p>一开始我看是非阻塞IO，觉得应该要比阻塞IO模型先进，可是当我一看使用方法的时候，就知道这个模型是不会被实际使用的，仅仅只能作为理论上存在的IO模型。这个模型的观点是：进行IO操作的时候，不阻塞，如果没有数据准备好，就直接返回错误码（或者是别的代码）。因此，使用者就只能不断进行轮询来调用IO函数。这样的后果就是，不仅在宏观上形成了与阻塞IO一共的“阻塞”效果，而且在微观上，CPU一直被用来轮询，造成了CPU的浪费。所以，这个模型还不如阻塞IO模型实用。</p>
<h3><span id="IO-3"><strong>IO复用</strong></span></h3>
<p>对于IO复用，我的理解有三点：</p>
<ol>
<li>在一次系统调用中，实现了询问多个描述符的IO准备情况 —— 根据事件通知</li>
<li>为了实现第一点，就需要把阻塞的地方进行转移。把一次系统调用，分为两次系统调用。第一次系统调用可以询问多个描述符的IO准备情况，在这个地方进行阻塞；而第二次系统调用，是针对已经准备好IO的描述符进行调用，此时，理论上（按照我的理解），也是会发生阻塞的，只不过是此时内核已经把数据准备好了，阻塞的时间可以忽略不计罢了。</li>
<li>本质上，还是阻塞的。</li>
</ol>
<h3><span id="IO-4"><strong>信号IO</strong></span></h3>
<p>我们都知道，信号是UNIX提供了进程间进行通信的一种方式。我们常用的 kill -9 命令（kill是向进程传递信号量，9只是众多信号中的一个代号），或者是 Ctrl + C 的时候，就是向某个进程发出终止的信号，这样进程就退出了。</p>
<p>而对于信号IO的模型，我是这么理解的：进程在发起IO操作，系统调用之后，直接访问，内核会在IO数据准备好之后，以某个信号通知发起IO操作的进程，从而使得该进程的信号处理函数可以读取IO数据的操作。</p>
<p>本质上，这也是阻塞的IO模型，因为在信号处理函数中，同样也是要进行阻塞的，只是在在这个时候发起系统系统，内核已经把数据准备好了。</p>
<h3><span id="IO-5"><strong>异步IO</strong></span></h3>
<p>这是真正的异步IO了。实现的机制是：用户在发起异步IO的系统调用时，会把相应的数据处理函数作为回调函数，等到IO数据准备好，内核会主动调用此回调函数。可以看出，用户进程在这种模型下，只调用了一次系统调用，而且是立即返回的，因此，就不会出现让进程阻塞的情况，也就符合了POSIX中异步IO的定义。</p>
<p>其实我理解起来，思路是和信号IO差不多的，唯一不同的地方，对于IO数据的操作，异步IO是由内核主动发起的，而信号IO是由用户进程发起的。</p>
<p>以上是我结合网络资料，对UNIX IO模型的一些学习和理解，如果有错误或者不当的地方，请随时留言指出，谢谢！<br />
<h3 class='related_post_title'><span id="i">相关文章</span></h3>
<ul class='related_post'>
<li><a href='http://www.zavakid.com/96' title='关于IO的同步,异步,阻塞,非阻塞'>关于IO的同步,异步,阻塞,非阻塞</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zavakid.com/70/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

