<?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>Erlang非业余研究</title>
	<atom:link href="http://blog.yufeng.info/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.yufeng.info</link>
	<description>Erlang系统深度探索和应用</description>
	<lastBuildDate>Sat, 12 May 2012 07:17:15 +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>MySQL和IO(下）</title>
		<link>http://blog.yufeng.info/archives/2216</link>
		<comments>http://blog.yufeng.info/archives/2216#comments</comments>
		<pubDate>Sat, 12 May 2012 07:16:45 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[体系结构]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[调优]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2216</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: MySQL和IO(下） MySQL和IO(下） View more PowerPoint from Feng Yu MySQL和IO(上）在这里可以看到。 Post Footer automatically generated by wp-posturl plugin for wordpress.]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2216">MySQL和IO(下）</a></p>
</div>
<div style="width:425px" id="__ss_12891222"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mryufeng/mysqlio" title="MySQL和IO(下）" target="_blank">MySQL和IO(下）</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12891222" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/thecroaker/death-by-powerpoint" target="_blank">PowerPoint</a> from <a href="http://www.slideshare.net/mryufeng" target="_blank">Feng Yu</a> </div>
</p></div>
<p>MySQL和IO(上）在<a href="http://www.slideshare.net/mryufeng/mysqlio-12891332">这里</a>可以看到。
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2216/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>了解Cpu</title>
		<link>http://blog.yufeng.info/archives/2214</link>
		<comments>http://blog.yufeng.info/archives/2214#comments</comments>
		<pubDate>Sat, 12 May 2012 07:14:44 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[体系结构]]></category>
		<category><![CDATA[cpu]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2214</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: 了解Cpu 了解Cpu View more PowerPoint from Feng Yu Post Footer automatically generated by wp-posturl plugin for wordpress.]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2214">了解Cpu</a></p>
</div>
<div style="width:425px" id="__ss_12876167"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mryufeng/cpu-12876167" title="了解Cpu" target="_blank">了解Cpu</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12876167" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/thecroaker/death-by-powerpoint" target="_blank">PowerPoint</a> from <a href="http://www.slideshare.net/mryufeng" target="_blank">Feng Yu</a> </div>
</p></div>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2214/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Erlang虚拟机基础设施dtrace探测点介绍和使用</title>
		<link>http://blog.yufeng.info/archives/2198</link>
		<comments>http://blog.yufeng.info/archives/2198#comments</comments>
		<pubDate>Sat, 28 Apr 2012 13:42:55 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[Erlang探索]]></category>
		<category><![CDATA[dtrace]]></category>
		<category><![CDATA[static marker]]></category>
		<category><![CDATA[systemtap]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2198</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Erlang虚拟机基础设施dtrace探测点介绍和使用 最新的Erlang虚拟机（R15B01）很大的一个改进就是加入了对dtrace探测点的支持了， 具体参见这里, 主要目标是方便在生产实践中定位复杂的性能问题。 目前Erlang的虚拟机的探测点支持Linux的systemtap和freebsd的dtrace，我们刚好能够享受的到。 作者Scott Lystig Fritchie在去年的euc中做了个很有意思的报告，参见这里，该PPT很详细的介绍了利用dtrace的探测点可以观察到erlang的行为如下： Processes: spawn, exit, hibernate, scheduled, &#8230; Messages: send, queued, received, exit signals Memory: GC minor &#038; major, proc heap grow &#038; shrink Data copy: within heap, across heaps Function calls: function &#038; BIF &#038; NIF, entry &#038; return Network distribution: monitor, port busy, output [...]]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2198">Erlang虚拟机基础设施dtrace探测点介绍和使用</a></p>
</div>
<p>最新的Erlang虚拟机（R15B01）很大的一个改进就是加入了对dtrace探测点的支持了， 具体参见<a href="http://https://github.com/erlang/otp/commit/5957a8338fe1f4e79a39277174094bbd9e978896">这里</a>, 主要目标是方便在生产实践中定位复杂的性能问题。</p>
<p>目前Erlang的虚拟机的探测点支持Linux的systemtap和freebsd的dtrace，我们刚好能够享受的到。</p>
<p>作者Scott Lystig Fritchie在去年的euc中做了个很有意思的报告，参见<a href="http://www.erlang-factory.com/upload/presentations/462/euc2011-draft2.pdf">这里</a>，该PPT很详细的介绍了利用dtrace的探测点可以观察到erlang的行为如下：</p>
<blockquote><p>Processes: spawn, exit, hibernate, scheduled, &#8230;<br />
Messages: send, queued, received, exit signals<br />
Memory: GC minor &#038; major, proc heap grow &#038; shrink<br />
Data copy: within heap, across heaps<br />
Function calls: function &#038; BIF &#038; NIF, entry &#038; return<br />
Network distribution: monitor, port busy, output events<br />
Ports: open, command, control, busy/not busy<br />
Drivers: callback API 100% instrumented<br />
efile_drv.c fifile I/O driver: 100% instrumented</p></blockquote>
<p>这些探测点基本上属于IO，进程调度，消息发送，driver等虚拟机最底层的和操作系统耦合的部分，对性能的影响巨大。</p>
<p>目前Erlang自己的基础设施并没有涵盖到这部分内容，如dbg,trace机制都无法了解到这些数据，导致在大型的集群系统里面一旦发现性能问题无法很好的展开调查，所以这些探测点刚好填补了空白。</p>
<p>目前这些dtrace probe点是用static marker实现的，细节可以参看<a href="http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps">这里</a> 和 <a href="http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation">这里</a>，好处是不用这些特性的时候，不会对性能有任何的影响，只需要为使用付代价。目前支持这种机制的语言和系统有java,python,mysql,pgsql等，可见威力强劲。</p>
<p>好拉，废话少说，我们来体验下。<br />
<span id="more-2198"></span><br />
下载最新的otp, 目前是R15B01， 简单的运行：</p>
<pre class="brush: bash; title: ; notranslate">
$ uname -r
2.6.32-131.21.1.tb477.el6.x86_64
$ git clone git://github.com/erlang/otp.git
$ cd otp
</pre>
<p>源码目录下有个README.systemtap.md，会简单的教你如何编译和使用。</p>
<p>由于我们用的是RHEL 6U2, 在编译之前你要确保你的systemtap和systemtap-sdt-devel已经安装,　直接运行</p>
<blockquote><p>yum -y install systemtap systemtap-sdt-devel</p></blockquote>
<p> 就搞定了，实在搞不懂的可以参考作者的<a href="http://www.snookles.com/slf-blog/2011/11/19/systemtap-and-erlang-a-tutorial/">这篇教程</a></p>
<p>我简单的演示下：</p>
<pre class="brush: bash; title: ; notranslate">
$ ./otp_build autoconf
$ ./configure --with-dynamic-trace=systemtap
$ make
...
#出错
</pre>
<p>由于这个版本的实现存在bug, 在实现DTRACE_GLOBAL_CALL功能的时候，没搞好细节，编译的时候会出错：<br />
beam_emu.c：L1562， L1578， L1592，简单的把这几行注释掉，继续编译就好了，就是global函数的trace功能不能使用而已，无伤大雅。</p>
<p>好了，如果不出意外，带dtrace功能的beam就生成了，我们如何确认呢？</p>
<pre class="brush: bash; title: ; notranslate">
$ stap -L 'process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;*&quot;)'
process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;aio_pool__add&quot;) $arg1:long $arg2:long
process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;aio_pool__get&quot;) $arg1:long $arg2:long
process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;bif__entry&quot;) $arg1:long $arg2:long
process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;bif__return&quot;) $arg1:long $arg2:long
process(&quot;bin/x86_64-unknown-linux-gnu/beam&quot;).mark(&quot;copy__object&quot;) $arg1:long $arg2:long
...
#或者
$ bin/erl
Erlang R16B (erts-5.10) 1 [64-bit] [smp:16:16] [async-threads:0] [hipe] [kernel-poll:false] [systemtap]

Eshell V5.10  (abort with ^G)
1&gt; %%在shell的能力里面看到 [systemtap]
</pre>
<p>这样就说明DTRACE的功能已经启用，接着演示下如何使用.<br />
该发行版带了不少的例子程序位于：</p>
<pre class="brush: bash; title: ; notranslate">
$ ls lib/runtime_tools/examples/*.systemtap
lib/runtime_tools/examples/dist.systemtap                lib/runtime_tools/examples/messages.systemtap
lib/runtime_tools/examples/driver1.systemtap             lib/runtime_tools/examples/port1.systemtap
lib/runtime_tools/examples/efile_drv.systemtap           lib/runtime_tools/examples/process-scheduling.systemtap
lib/runtime_tools/examples/function-calls.systemtap      lib/runtime_tools/examples/spawn-exit.systemtap
lib/runtime_tools/examples/garbage-collection.systemtap  lib/runtime_tools/examples/user-probe.systemtap
lib/runtime_tools/examples/memory1.systemtap
#运行我们的脚本，开始体验
$ PATH=bin/x86_64-unknown-linux-gnu/:$PATH sudo stap lib/runtime_tools/examples/spawn-exit.systemtap
pid &lt;0.0.0&gt; mfa otp_ring0:start/2
pid &lt;0.1.0&gt; mfa erlang:apply/2
pid &lt;0.2.0&gt; mfa erlang:apply/2
pid &lt;0.3.0&gt; mfa erlang:apply/2
pid &lt;0.4.0&gt; mfa heart:init/2
pid &lt;0.4.0&gt; reason normal
pid &lt;0.5.0&gt; mfa proc_lib:init_p/5
pid &lt;0.6.0&gt; mfa erlang:apply/2
pid &lt;0.7.0&gt; mfa application_controller:init_starter/4
pid &lt;0.8.0&gt; mfa proc_lib:init_p/5
pid &lt;0.9.0&gt; mfa application_master:start_it/4
pid &lt;0.10.0&gt; mfa proc_lib:init_p/5
pid &lt;0.11.0&gt; mfa proc_lib:init_p/5
pid &lt;0.12.0&gt; mfa proc_lib:init_p/5
pid &lt;0.13.0&gt; mfa erlang:apply/2
pid &lt;0.14.0&gt; mfa erlang:apply/2
pid &lt;0.15.0&gt; mfa proc_lib:init_p/5
pid &lt;0.16.0&gt; mfa proc_lib:init_p/5
pid &lt;0.17.0&gt; mfa proc_lib:init_p/5
pid &lt;0.18.0&gt; mfa erlang:apply/2
pid &lt;0.19.0&gt; mfa proc_lib:init_p/5
pid &lt;0.20.0&gt; mfa erlang:apply/2
pid &lt;0.21.0&gt; mfa proc_lib:init_p/5
pid &lt;0.22.0&gt; mfa user_drv:server/2
pid &lt;0.23.0&gt; mfa group:server/3
pid &lt;0.24.0&gt; mfa group:server/3
pid &lt;0.25.0&gt; mfa erlang:apply/2
pid &lt;0.26.0&gt; mfa proc_lib:init_p/5
pid &lt;0.27.0&gt; mfa proc_lib:init_p/5
pid &lt;0.1.0&gt; reason on_load_done
pid &lt;0.7.0&gt; reason normal
sender &lt;0.7.0&gt; -&gt; pid &lt;0.6.0&gt; reason normal
pid &lt;0.28.0&gt; mfa application_controller:init_starter/4
pid &lt;0.28.0&gt; reason normal
sender &lt;0.28.0&gt; -&gt; pid &lt;0.6.0&gt; reason normal
pid &lt;0.29.0&gt; mfa erlang:apply/2
pid &lt;0.29.0&gt; reason enoent
sender &lt;0.29.0&gt; -&gt; pid &lt;0.17.0&gt; reason enoent
pid &lt;0.30.0&gt; mfa erlang:apply/2
pid &lt;0.30.0&gt; reason enoent
sender &lt;0.30.0&gt; -&gt; pid &lt;0.17.0&gt; reason enoent
pid &lt;0.2.0&gt; reason normal
sender &lt;0.2.0&gt; -&gt; pid &lt;0.0.0&gt; reason normal
pid &lt;0.31.0&gt; mfa erlang:apply/2
pid &lt;0.32.0&gt; mfa erlang:apply/2
</pre>
<p>在另外一个shell里面运行我们的erlang虚拟机，模拟我们的应用系统，我们就可以看到上面的输出。</p>
<pre class="brush: bash; title: ; notranslate">
$ bin/erl -smp disable
Erlang R16B (erts-5.10) 1 [64-bit] [async-threads:0] [hipe] [kernel-poll:false] [systemtap]

Eshell V5.10  (abort with ^G)
1&gt; os:getpid().
&quot;7149&quot;
</pre>
<p>这里要注意的是我们使用的-smp disable参数，使用的是beam的plain版本，它的进程名是beam<br />
$ pstree -p |grep 7149<br />
        |-sshd(1847)-+-sshd(7081)&#8212;sshd(7101)&#8212;bash(7102)-+-beam(7149)</p>
<p>如果使用多处理器版本，那么进程名是beam.smp,需要修改相应的systemtap脚本里面的进程名。</p>
<p>小结：systemtap无敌，erlang与时俱进！</p>
<p>祝玩得开心！</p>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2198/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>了解IO设备</title>
		<link>http://blog.yufeng.info/archives/2195</link>
		<comments>http://blog.yufeng.info/archives/2195#comments</comments>
		<pubDate>Tue, 10 Apr 2012 06:41:17 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[体系结构]]></category>
		<category><![CDATA[杂七杂八]]></category>
		<category><![CDATA[了解IO设备]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2195</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: 了解IO设备 了解IO设备 View more PowerPoint from Feng Yu Post Footer automatically generated by wp-posturl plugin for wordpress.]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2195">了解IO设备</a></p>
</div>
<div style="width:425px" id="__ss_12278621"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mryufeng/io-12278621" title="了解IO设备" target="_blank">了解IO设备</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12278621" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/thecroaker/death-by-powerpoint" target="_blank">PowerPoint</a> from <a href="http://www.slideshare.net/mryufeng" target="_blank">Feng Yu</a> </div>
</p></div>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2195/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>了解IO协议栈</title>
		<link>http://blog.yufeng.info/archives/2194</link>
		<comments>http://blog.yufeng.info/archives/2194#comments</comments>
		<pubDate>Tue, 10 Apr 2012 06:41:02 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[体系结构]]></category>
		<category><![CDATA[杂七杂八]]></category>
		<category><![CDATA[IO协议栈]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2194</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: 了解IO协议栈 了解IO协议栈 View more PowerPoint from Feng Yu Post Footer automatically generated by wp-posturl plugin for wordpress.]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2194">了解IO协议栈</a></p>
</div>
<div style="width:425px" id="__ss_12278640"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/mryufeng/io-12278640" title="了解IO协议栈" target="_blank">了解IO协议栈</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/12278640" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/thecroaker/death-by-powerpoint" target="_blank">PowerPoint</a> from <a href="http://www.slideshare.net/mryufeng" target="_blank">Feng Yu</a> </div>
</p></div>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2194/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang节点互联失败原因分析以及解决方案</title>
		<link>http://blog.yufeng.info/archives/2169</link>
		<comments>http://blog.yufeng.info/archives/2169#comments</comments>
		<pubDate>Wed, 28 Mar 2012 06:00:51 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[Erlang探索]]></category>
		<category><![CDATA[disallowed node]]></category>
		<category><![CDATA[dist_util]]></category>
		<category><![CDATA[net_adm:ping]]></category>
		<category><![CDATA[net_kernel:allow]]></category>
		<category><![CDATA[setcookie]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2169</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Erlang节点互联失败原因分析以及解决方案 今天和项仲在部署新系统的时候发现节点间ping不成功的情况，类似 1> net_adm:ping(&#8216;xx@ip1&#8242;). pang 由于这个问题比较普遍，我就记录下一步步的排除步骤. 首先从原理上分析下!由于erlang节点间通讯是透过tcp来进行的，所以我们确保以下几点： 1. 确保网络连接是通的，可以透过ping来查看。 2. 确保网络连接上tcp是可以通的，可以透过netcat在二个节点所在的机器上分别开个服务器端和客户端进行验证。 3. 确保端口是防火墙友好的。erlang的节点是登记在epmd服务上的，所以4369端口要能访问，其次节点的动态端口是可以访问的。 epmd -names epmd: up and running on port 4369 with data: name xx at port 46627 &#8230; 同样可以用netcat来验证。 4. erlang节点的cookie是一样的，可以透过setcookie来解决。 这几点确认无误后，就可以开始排查问题了。 首先交代下环境，二台机器IP分别是10.1.150.12,10.232.31.89, 上面分别运行Erlang版本R16B和R14B04，cookie统一设置为456789。 接着我们来演习下，首先我们10.1.150.12在节点A上起个节点&#8217;xx@10.1.150.12&#8242;，如下： 同时我们在10.232.31.89上运行另外一个节点&#8217;yy@10.232.31.89&#8242;进行节点间连接，如下: 我们看到节点无法互通，出错的原因是&#8221;** Connection attempt from disallowed node &#8216;yy@10.232.31.89&#8242; ** &#8220;. 有提示消息就好办, 在otp源码目录下简单的运行： 我们可以看到有4个函数有可能打印这个语句，分别是： 1. is_allowed [...]]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2169">Erlang节点互联失败原因分析以及解决方案</a></p>
</div>
<p>今天和项仲在部署新系统的时候发现节点间ping不成功的情况，类似</p>
<blockquote><p>1> net_adm:ping(&#8216;xx@ip1&#8242;).<br />
pang
</p></blockquote>
<p>由于这个问题比较普遍，我就记录下一步步的排除步骤.</p>
<p>首先从原理上分析下!由于erlang节点间通讯是透过tcp来进行的，所以我们确保以下几点：<br />
1. 确保网络连接是通的，可以透过ping来查看。<br />
2. 确保网络连接上tcp是可以通的，可以透过netcat在二个节点所在的机器上分别开个服务器端和客户端进行验证。<br />
3. 确保端口是防火墙友好的。erlang的节点是登记在epmd服务上的，所以4369端口要能访问，其次节点的动态端口是可以访问的。</p>
<blockquote><p>epmd -names<br />
epmd: up and running on port 4369 with data:<br />
name xx at port 46627<br />
&#8230;</p>
</blockquote>
<p>同样可以用netcat来验证。<br />
4. erlang节点的cookie是一样的，可以透过setcookie来解决。</p>
<p>这几点确认无误后，就可以开始排查问题了。<br />
首先交代下环境，二台机器IP分别是10.1.150.12,10.232.31.89, 上面分别运行Erlang版本R16B和R14B04，cookie统一设置为456789。<br />
接着我们来演习下，首先我们10.1.150.12在节点A上起个节点&#8217;xx@10.1.150.12&#8242;，如下：</p>
<p><span id="more-2169"></span></p>
<pre class="brush: bash; title: ; notranslate">
# erl -name xx@`hostname -i` --setcookie 456789
Erlang R16B (erts-5.10) 1 [64-bit] [smp:24:24] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.10  (abort with ^G)
(xx@10.1.150.12)1&gt;
=ERROR REPORT==== 28-Mar-2012::13:25:42 ===
** Connection attempt from disallowed node 'yy@10.232.31.89' ** 
</pre>
<p>同时我们在10.232.31.89上运行另外一个节点&#8217;yy@10.232.31.89&#8242;进行节点间连接，如下:</p>
<pre class="brush: bash; title: ; notranslate">
$erl -name yy@`hostname -i` --setcookie 456789
Erlang R14B04 (erts-5.8.5) 1 [64-bit] [smp:16:16] [rq:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
(yy@10.232.31.89)1&gt;  net_adm:ping('xx@10.1.150.12').
pang
</pre>
<p>我们看到节点无法互通，出错的原因是&#8221;** Connection attempt from disallowed node &#8216;yy@10.232.31.89&#8242; ** &#8220;.<br />
有提示消息就好办, 在otp源码目录下简单的运行：</p>
<pre class="brush: bash; title: ; notranslate">
# grep -rin &quot;disallowed node&quot; .
./lib/kernel/src/dist_util.erl:154:                   &quot;disallowed node ~w ** ~n&quot;, [Node]),
./lib/kernel/src/dist_util.erl:603:                           &quot;disallowed node ~w ** ~n&quot;, [NodeB]),
./lib/kernel/src/dist_util.erl:623:                           &quot;disallowed node ~w ** ~n&quot;, [NodeB]),
./lib/kernel/src/net_kernel.erl:1149:                 &quot;disallowed node ~w ** ~n&quot;, [Node]),
</pre>
<p>我们可以看到有4个函数有可能打印这个语句，分别是：<br />
1. is_allowed %% check if connecting node is allowed to connect with allow-node-scheme<br />
2 .recv_challenge_reply  %% wait for challenge response after send_challenge<br />
3. recv_challenge_ack<br />
4. setup %% Set up connection to a new node.</p>
<p>其中和被动连接相关的俄只有1,2,3这几种情况.</p>
<p>情况1: 节点间allow相关的东西可以参考这篇文章：<a href="http://blog.yufeng.info/archives/1752">Erlang如何限制节点对集群的访问之net_kernel:allow</a><br />
我们来排除下allow导致问题的原因,把allow设成[],允许任意节点访问：</p>
<blockquote><p>2> net_kernel:allow([]).<br />
ok<br />
(xx@10.1.150.12)2><br />
=ERROR REPORT==== 28-Mar-2012::13:36:09 ===<br />
** Connection attempt from disallowed node &#8216;yy@10.232.31.89&#8242; ** </p></blockquote>
<p>很清楚,这样并没有解决问题。</p>
<p>那就可以肯定是第2，3个原因了，回头来看下我们的版本号：<br />
R14B04 和 R16B， 差了二个大版本， 这个是核心原因。<br />
换成同样的版本的erlang问题应该解决！如下：</p>
<pre class="brush: bash; title: ; notranslate">
$erl -name yy@`hostname -i` --setcookie 456789
Erlang R16B (erts-5.10) 1 [64-bit] [smp:24:24] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.10  (abort with ^G)
(yy@10.232.31.89)1&gt;  net_adm:ping('xx@10.1.150.12').
pong
</pre>
<p>看来确实解决了!</p>
<p>小结： Erlang版本不混用，即使混用最好不超过2个版本。<br />
祝玩得开心！</p>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2169/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Linux TASK_IO_ACCOUNTING功能以及如何使用</title>
		<link>http://blog.yufeng.info/archives/2138</link>
		<comments>http://blog.yufeng.info/archives/2138#comments</comments>
		<pubDate>Sun, 11 Mar 2012 07:02:50 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[工具介绍]]></category>
		<category><![CDATA[源码分析]]></category>
		<category><![CDATA[iotop]]></category>
		<category><![CDATA[pidstat]]></category>
		<category><![CDATA[TASK_IO_ACCOUNTING]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2138</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Linux TASK_IO_ACCOUNTING功能以及如何使用 在过去我们了解系统IO的情况大多数是通过iostat来获取的，这个粒度只能精确到每个设备。通常我们会想了解每个进程,线程层面发起了多少IO，在Linux 2.6.20之前除了用systemtap这样的工具来实现是没有其他方法的，因为系统没有暴露这方面的统计。 disktop per设备per应用层面的IO读写统计，可以参考我之前写的，见这里. 透过lxr的代码确认，在Linux 2.6.20以后引入了TASK_IO_ACCOUNTING功能，通过把每个线程和进程的io活动通过/proc/pid/io导出大大方便了用户，这里需要注意的是RHEL 5U4基于2.6.18内核但是他们backport了这个功能，并由此催生了相应的了解per进程Io活动的工具如pidstat和iotop, 这两个软件工作的时候截图如下： pidstat可以看到带层次线程IO活动 iotop能看到扁平线程IO活动 通过strace来了解到这二个软件关于IO活动部分输入源都是/proc/pid/io， 让我们来了解下这个文件： 这个文件后三个参数是IO记账功能新添加的，我们来了解下他们的意义,摘抄从man pidstat: kB_rd/s Number of kilobytes the task has caused to be read from disk per second. kB_wr/s Number of kilobytes the task has caused, or shall cause to be written to disk per second. kB_ccwr/s Number of [...]]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2138">Linux TASK_IO_ACCOUNTING功能以及如何使用</a></p>
</div>
<p>在过去我们了解系统IO的情况大多数是通过iostat来获取的，这个粒度只能精确到每个设备。通常我们会想了解每个进程,线程层面发起了多少IO，在Linux 2.6.20之前除了用systemtap这样的工具来实现是没有其他方法的，因为系统没有暴露这方面的统计。 disktop per设备per应用层面的IO读写统计，可以参考我之前写的，见<a href="http://blog.yufeng.info/archives/1314">这里</a>. </p>
<p>透过lxr的代码确认，在Linux  2.6.20以后引入了TASK_IO_ACCOUNTING功能，通过把每个线程和进程的io活动通过/proc/pid/io导出大大方便了用户，这里需要注意的是RHEL 5U4基于2.6.18内核但是他们backport了这个功能，并由此催生了相应的了解per进程Io活动的工具如pidstat和iotop, 这两个软件工作的时候截图如下：<br />
<a href="http://blog.yufeng.info/wp-content/uploads/2012/03/pidstat.jpg"><img src="http://blog.yufeng.info/wp-content/uploads/2012/03/pidstat.jpg" alt="" title="pidstat" width="574" height="168" class="alignnone size-full wp-image-2139" /></a><br />
pidstat可以看到带层次线程IO活动</p>
<p><a href="http://blog.yufeng.info/wp-content/uploads/2012/03/iotop.jpg"><img src="http://blog.yufeng.info/wp-content/uploads/2012/03/iotop.jpg" alt="" title="iotop" width="601" height="241" class="alignnone size-full wp-image-2140" /></a><br />
iotop能看到扁平线程IO活动</p>
<p>通过strace来了解到这二个软件关于IO活动部分输入源都是/proc/pid/io， 让我们来了解下这个文件：<br />
<span id="more-2138"></span></p>
<pre class="brush: bash; title: ; notranslate">
# cat /proc/self/io
rchar: 1956
wchar: 0
syscr: 7
syscw: 0
read_bytes: 0
write_bytes: 0
cancelled_write_bytes: 0
</pre>
<p>这个文件后三个参数是IO记账功能新添加的，我们来了解下他们的意义,摘抄从man pidstat:</p>
<blockquote><p>        kB_rd/s<br />
                     Number of kilobytes the task has caused to be read from disk per second.</p>
<p>              kB_wr/s<br />
                     Number of kilobytes the task has caused, or shall cause to be written to disk per second.</p>
<p>              kB_ccwr/s<br />
                     Number  of kilobytes whose writing to disk has been cancelled by the task. This may occur when the task truncates some dirty page-<br />
                     cache. In this case, some IO which another task has been accounted for will not be happening.</p></blockquote>
<p>接着我们再来看下内核如何统计这三个值的，在RHEL 5U4源码数下简单的grep下：</p>
<pre class="brush: bash; title: ; notranslate">
[linux-2.6.18.x86_64]$ grep -rin task_io_account_ .
./block/ll_rw_blk.c:3286:               task_io_account_read(bio-&gt;bi_size);
./include/linux/task_io_accounting_ops.h:8:static inline void task_io_account_read(size_t bytes)
./include/linux/task_io_accounting_ops.h:13:static inline void task_io_account_write(size_t bytes)
./include/linux/task_io_accounting_ops.h:18:static inline void task_io_account_cancelled_write(size_t bytes)
./include/linux/task_io_accounting_ops.h:30:static inline void task_io_account_read(size_t bytes)
./include/linux/task_io_accounting_ops.h:34:static inline void task_io_account_write(size_t bytes)
./include/linux/task_io_accounting_ops.h:38:static inline void task_io_account_cancelled_write(size_t bytes)
./fs/direct-io.c:671:           task_io_account_write(len);
./fs/cifs/file.c:2221:                  task_io_account_read(bytes_read);
./fs/buffer.c:965:                              task_io_account_write(PAGE_CACHE_SIZE);
./fs/buffer.c:3400:                     task_io_account_cancelled_write(PAGE_CACHE_SIZE);
./mm/truncate.c:47:             task_io_account_cancelled_write(PAGE_CACHE_SIZE);
./mm/page-writeback.c:649:                                      task_io_account_write(PAGE_CACHE_SIZE);
./mm/readahead.c:180:           task_io_account_read(PAGE_CACHE_SIZE);
</pre>
<p>可以看出统计力度还是比较粗的。</p>
<p>同时Io记账相关的proc导出位于 fs/proc/base.c:</p>
<pre class="brush: cpp; title: ; notranslate">
#ifdef CONFIG_TASK_IO_ACCOUNTING
static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
{
 ...
        return sprintf(buffer,
                        &quot;rchar: %llu\n&quot;
                        &quot;wchar: %llu\n&quot;
                        &quot;syscr: %llu\n&quot;
                        &quot;syscw: %llu\n&quot;
                        &quot;read_bytes: %llu\n&quot;
                        &quot;write_bytes: %llu\n&quot;
                        &quot;cancelled_write_bytes: %llu\n&quot;,
                        rchar, wchar, syscr, syscw,
                        ioac.read_bytes, ioac.write_bytes,
                        ioac.cancelled_write_bytes);
}
</pre>
<p>简单的分析了下TASK_IO_ACCOUNTING运作方式，对了解每个进程的IO活动还是很有帮助的。另外再罗嗦下在RHEL 5U4是可以用这个功能的。</p>
<p>祝玩得开心！</p>
<p>后记： taskstats.c还支持netlink导出任务的pid,tgid已经注册和反注册cpumask. Iotop用到了这个特性。</p>
<blockquote><p>sendto(3, &#8220;\34\0\0\0\26\0\1\0\216\1\0\0\30\357\377\377\1\0\0\0\10\0\1\0\324\5\0\0&#8243;, 28, 0, NULL, 0) = 28<br />
recvfrom(3, &#8220;l\1\0\0\26\0\0\0\216\1\0\0\30\357\377\377\2\1\0\0X\1\4\0\10\0\1\0\324\5\0\0&#8243;&#8230;, 16384, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 364
</p></blockquote>
<p>谢谢 kinwin同学指出！</p>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2138/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Iostat看不到设备统计信息的原因分析</title>
		<link>http://blog.yufeng.info/archives/2129</link>
		<comments>http://blog.yufeng.info/archives/2129#comments</comments>
		<pubDate>Sat, 10 Mar 2012 09:50:48 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[工具介绍]]></category>
		<category><![CDATA[调优]]></category>
		<category><![CDATA[diskstats]]></category>
		<category><![CDATA[iostat]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2129</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Iostat看不到设备统计信息的原因分析 最近在把玩些高速的SSD和nvram设备的时候，发现iostat无法统计到这些设备的信息，很是奇怪，于是分析和总结了一把，挺有意思的。 现象描述如下： # uname -a Linux dr4000 2.6.32-131.17.1.el6.x86_64 #1 SMP Wed Oct 5 17:19:54 CDT 2011 x86_64 x86_64 x86_64 GNU/Linux # ls -al /dev/nvdisk0 brw-rw-r&#8211; 1 root root 252, 0 Mar 10 16:18 /dev/nvdisk0 # iostat -d Linux 2.6.32-131.17.1.el6.x86_64 (dr4000) 03/10/2012 _x86_64_ (24 CPU) Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda [...]]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2129">Iostat看不到设备统计信息的原因分析</a></p>
</div>
<p>最近在把玩些高速的SSD和nvram设备的时候，发现iostat无法统计到这些设备的信息，很是奇怪，于是分析和总结了一把，挺有意思的。</p>
<p>现象描述如下：</p>
<blockquote><p>
# uname -a<br />
Linux dr4000 2.6.32-131.17.1.el6.x86_64 #1 SMP Wed Oct 5 17:19:54 CDT 2011 x86_64 x86_64 x86_64 GNU/Linux<br />
# ls -al /dev/nvdisk0<br />
brw-rw-r&#8211; 1 root root 252, 0 Mar 10 16:18 /dev/nvdisk0<br />
# iostat -d<br />
Linux 2.6.32-131.17.1.el6.x86_64 (dr4000)       03/10/2012      _x86_64_        (24 CPU)</p>
<p>Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn<br />
sda              60.74       200.21        95.44   55171731   26299534
</p></blockquote>
<p>iostat很奇怪的看不到nvdisk0的IO统计信息. </p>
<p>开始我们的分析之旅，先简单的用strace看下iostat从那里读取这些统计信息的：<br />
<span id="more-2129"></span></p>
<pre class="brush: bash; title: ; notranslate">
# strace iostat -d
execve(&quot;/usr/bin/iostat&quot;, [&quot;iostat&quot;, &quot;-d&quot;], [/* 25 vars */]) = 0
...
open(&quot;/sys/devices/system/cpu&quot;, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
getdents(3, /* 35 entries */, 32768)    = 1056
stat(&quot;/sys/devices/system/cpu/cpu0&quot;, {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
...
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
open(&quot;/proc/diskstats&quot;, O_RDONLY)       = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
read(3, &quot;   1       0 ram0 0 0 0 0 0 0 0 &quot;..., 1024) = 1024
read(3, &quot;881869 2312902 26299638 3731982 &quot;..., 1024) = 464
read(3, &quot;&quot;, 1024)                       = 0
close(3)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
open(&quot;/etc/localtime&quot;, O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
read(3, &quot;TZif2&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;\3&#92;&#48;&#92;&#48;&#92;&#48;\3&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&quot;..., 4096) = 405
lseek(3, -240, SEEK_CUR)                = 165
read(3, &quot;TZif2&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;\3&#92;&#48;&#92;&#48;&#92;&#48;\3&#92;&#48;&#92;&#48;&#92;&#48;&#92;&#48;&quot;..., 4096) = 240
close(3)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
uname({sys=&quot;Linux&quot;, node=&quot;dr4000&quot;, ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 23), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
write(1, &quot;Linux 2.6.32-131.17.1.el6.x86_64&quot;..., 73Linux 2.6.32-131.17.1.el6.x86_64 (dr4000)     03/10/2012      _x86_64_        (24 CPU)
) = 73
write(1, &quot;\n&quot;, 1
)                       = 1
rt_sigaction(SIGALRM, {0x404230, [ALRM], SA_RESTORER|SA_RESTART, 0x3ff7c32ac0}, {SIG_DFL, [], 0}, <img src='http://blog.yufeng.info/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> = 0
alarm(0)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
open(&quot;/proc/uptime&quot;, O_RDONLY)          = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
read(3, &quot;275660.93 6524235.15\n&quot;, 1024) = 21
close(3)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
open(&quot;/proc/stat&quot;, O_RDONLY)            = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
read(3, &quot;cpu  1702243 167 1971793 6524235&quot;..., 1024) = 1024
read(3, &quot;0\ncpu20 26162 0 16915 27374407 1&quot;..., 1024) = 1024
read(3, &quot; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&quot;..., 1024) = 1024
read(3, &quot; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&quot;..., 1024) = 797
read(3, &quot;&quot;, 1024)                       = 0
close(3)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
open(&quot;/proc/diskstats&quot;, O_RDONLY)       = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea55000
read(3, &quot;   1       0 ram0 0 0 0 0 0 0 0 &quot;..., 1024) = 1024
access(&quot;/sys/block/ram0&quot;, F_OK)         = 0
open(&quot;/etc/sysconfig/sysstat.ioconf&quot;, O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=6253, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa8ea54000
read(4, &quot;#\n# sysstat.ioconf\n#\n#  Copyrigh&quot;..., 4096) = 4096
read(4, &quot;8:7:\n136:48:8:\n137:48:9:\n138:48:&quot;..., 4096) = 2157
read(4, &quot;&quot;, 4096)                       = 0
close(4)                                = 0
munmap(0x7ffa8ea54000, 4096)            = 0
access(&quot;/sys/block/ram1&quot;, F_OK)         = 0
..
access(&quot;/sys/block/loop7&quot;, F_OK)        = 0
read(3, &quot;881869 2312902 26299638 3731982 &quot;..., 1024) = 464
access(&quot;/sys/block/sda&quot;, F_OK)          = 0
...
access(&quot;/sys/block/nvdisk0&quot;, F_OK)      = 0
read(3, &quot;&quot;, 1024)                       = 0
close(3)                                = 0
munmap(0x7ffa8ea55000, 4096)            = 0
stat(&quot;/etc/localtime&quot;, {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
write(1, &quot;&quot;, 0)                         = 0
write(1, &quot;Device:            tps&quot;, 22Device:            tps)  = 22
write(1, &quot;   Blk_read/s   Blk_wrtn/s   Blk&quot;..., 49   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
) = 49
write(1, &quot;sda          &quot;, 13sda          )           = 13
write(1, &quot;    60.72       200.14        95&quot;..., 58    60.72       200.14        95.41   55171731   26299638
) = 58
write(1, &quot;\n&quot;, 1
)                       = 1
exit_group(0)                           = ?
</pre>
<p>很容易看出，主要IO相关信息是从/proc/diskstats读取的。 我们再来看下这个文件的内容：</p>
<pre class="brush: bash; title: ; notranslate">
# cat /proc/diskstats
   1       0 ram0 0 0 0 0 0 0 0 0 0 0 0
..
   1      15 ram15 0 0 0 0 0 0 0 0 0 0 0
   7       0 loop0 0 0 0 0 0 0 0 0 0 0 0
..
   7       7 loop7 0 0 0 0 0 0 0 0 0 0 0
   8       0 sda 11856307 92646 55171731 7784368 4881904 2312902 26299918 3731991 0 397111 11495597
...
   8       5 sda5 11832182 79153 54227969 7705146 4618019 600324 10473322 1854282 0 314124 9538788
 252       0 nvdisk0 0 0 0 0 0 0 0 0 0 0 0
</pre>
<p>顺手打开内核代码block/genhd.c可以看到和diskstats统计相关的代码：</p>
<pre class="brush: cpp; title: ; notranslate">
        seq_printf(s, &quot;%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n&quot;,
                gp-&gt;major, n + gp-&gt;first_minor, disk_name(gp, n, buf),
                disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
                (unsigned long long)disk_stat_read(gp, sectors[0]),
                jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
                disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
                (unsigned long long)disk_stat_read(gp, sectors[1]),
                jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
                gp-&gt;in_flight,
                jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
                jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
</pre>
<p>这些字段的意义如下：<br />
Field 1 &#8212; # of reads issued<br />
Field 2 &#8212; # of reads merged, field 6 &#8212; # of writes merged<br />
Field 3 &#8212; # of sectors read<br />
Field 4 &#8212; # of milliseconds spent reading<br />
Field 5 &#8212; # of writes completed<br />
Field 7 &#8212; # of sectors written<br />
Field 8 &#8212; # of milliseconds spent writing<br />
Field 9 &#8212; # of I/Os currently in progress<br />
Field 10 &#8212; # of milliseconds spent doing I/Os<br />
Field 11 &#8212; weighted # of milliseconds spent doing I/Os<br />
更具体的参看 <a href="http://www.linuxquestions.org/questions/suse-novell-60/interpreting-proc-diskstats-360350/">这里</a>。</p>
<p>上面的现象的直接原因是由于我们的设备nvdisk0统计值全0引起的。 </p>
<p>那为什么这些值全部是空的呢，显然是设备没有把这些信息暴露出来。 我们看下内核更新这些统计值的部分。<br />
注意：为了简单我就抄了2.6.18相关代码，因为他的代码集中在 ll_rw_blk.c 文件中，而2.6.32分散到其他文件，不好交代事情。</p>
<pre class="brush: bash; title: ; notranslate">
$ grep -rin _stat_add .
./ll_rw_blk.c:2744:             __disk_stat_add(disk, time_in_queue,
./ll_rw_blk.c:2746:             __disk_stat_add(disk, io_ticks, (now - disk-&gt;stamp));
./ll_rw_blk.c:2762:             part_stat_add(part, time_in_queue,
./ll_rw_blk.c:2764:             part_stat_add(part, io_ticks, (now - ps-&gt;stamp));
./ll_rw_blk.c:3379:             all_stat_add(req-&gt;rq_disk, sectors[rw],
./ll_rw_blk.c:3402:             __all_stat_add(disk, ticks[rw], duration, req-&gt;sector);
</pre>
<p>调用点主要是blk_account_io_done和blk_account_io_completion，而最终的源头是void end_request(struct request *req, int uptodate)； 也就是说如果设备驱动程序不调用 end_request之类的函数更新统计的话，那我们就得不到。</p>
<p>我们的nvdisk0是marvell造的nvram卡，目前不单卖，幸运的随机厂家附送了驱动程序代码(谢谢老栋同学指出困惑)，我们来看下：<br />
mvwam-1.6.2/driver/lokidrv.c</p>
<pre class="brush: cpp; title: ; notranslate">
#define NV_BDEV_SECTOR_SZ       512  

static int
nv_bdev_create(nvram_hba_t *nvhba)
{
...
        /*
         * Initialize block device queue
         */
        gd-&gt;queue = blk_alloc_queue(GFP_KERNEL);
...
        blk_queue_make_request(gd-&gt;queue, nvram_make_request);
...
        blk_queue_hardsect_size(gd-&gt;queue, NV_BDEV_SECTOR_SZ);
...
}
*
 * Entry of block I/O
 *
 * This function will construct prepare and submit block I/O to the queue
 *
 * @q           - request queue from bio layer
 * @bio         - block io request
 *
 * @return 0 any way, extra info will be returned in nvram_endio
 */
static int
nvram_make_request(struct request_queue *q, struct bio *bio)
{
...

        dma_req = kmem_cache_alloc(nv_dma_req_cache, GFP_KERNEL);
        if (dma_req == NULL)
                return -ENOMEM;

        memset(dma_req, 0, sizeof(*dma_req));
        dma_req-&gt;dma_next = NULL;
...
        dma_req-&gt;dma_done = nv_blk_req_done;
...
 bio_for_each_segment(bvec, bio, segno) {
                paddr = (page_to_pfn(bvec-&gt;bv_page) &lt;&lt; PAGE_SHIFT)
                                            + bvec-&gt;bv_offset;
                valid_bytes = bvec-&gt;bv_len;

                ret = host_prd_try_merge(&amp;cntxt, paddr, valid_bytes);
                if (ret != 0) {
                        /* max prd limit reached. need to split io */
                        ret = nv_split_io(nvhba, &amp;dma_req, rw,
                                        &amp;offset, &amp;cntxt);
                        if (ret != 0) {
                                goto prep_err;
                        }
                        nr_splits++;
                        host_prd_try_merge(&amp;cntxt, paddr, valid_bytes);
                }
        }

...
}
</pre>
<p>该驱动直接在nvram_make_request中DMA的干活了，为了性能就不走标准的IO请求队列，所以也就不会调用和队列功能相关的end_request函数。</p>
<p>深层次的原因找到了！</p>
<p>其实还有其他的硬件厂商做的设备为了性能，在这块对用户不是太友好，不知道能不能改进下，尊重用户的使用习惯！</p>
<p>小结：有源码，一切了然！</p>
<p>祝大家玩得开心！</p>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2129/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Linux下试验大页面映射（MAP_HUGETLB）</title>
		<link>http://blog.yufeng.info/archives/2118</link>
		<comments>http://blog.yufeng.info/archives/2118#comments</comments>
		<pubDate>Fri, 09 Mar 2012 14:58:05 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[MAP_HUGETLB]]></category>
		<category><![CDATA[mmap]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2118</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Linux下试验大页面映射（MAP_HUGETLB） Linux对大页面内存的引入对减少TLB的失效效果不错，特别是内存大而密集型的程序，比如说在数据库中的使用。innodb引擎就支持大页面内存，具体使用可参见 这里。 大页面更详细的资料可以参考： Documentation/vm/hugetlbpage.txt 过去使用大页面内存主要透过hugetlbfs需要mount文件系统到某个点去，部署起来很不方便,我们只想要点匿名页面，要搞的那么麻烦吗？ 新的2.6.32内核通过支持MAP_HUGETLB方式来使用内存,避免了烦琐的mount操作，对用户更友好。 参见man mmap： MAP_HUGETLB (since Linux 2.6.32) Allocate the mapping using &#8220;huge pages.&#8221; See the kernel source file Documentation/vm/hugetlbpage.txt for further information. 这样明显会方便些，但是大内存页面预留的操作还是要做的，我们来演示下，先来准备环境： 从上面输出可以看到我们的内核是2.6.32, 我用的是RHEL 6U2发行版本，同时保留了192*2M页面。 再来看演示代码如下： 我们成功用大页面申请了8M内存，4个大页面，同时进行清零操作成功，再munmap之前，我们需要确认内存确实是被我们使用了。 好，切换到另外一个窗口来看下： 是不是不费吹灰之力就成功了，这也说明内核天天在进步。 祝玩得开心！ Post Footer automatically generated by wp-posturl plugin for wordpress.]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2118">Linux下试验大页面映射（MAP_HUGETLB）</a></p>
</div>
<p>Linux对大页面内存的引入对减少TLB的失效效果不错，特别是内存大而密集型的程序，比如说在数据库中的使用。innodb引擎就支持大页面内存，具体使用可参见 <a href="http://www.cyberciti.biz/tips/linux-hugetlbfs-and-mysql-performance.html">这里</a>。</p>
<p>大页面更详细的资料可以参考： Documentation/vm/hugetlbpage.txt</p>
<p>过去使用大页面内存主要透过hugetlbfs需要mount文件系统到某个点去，部署起来很不方便,我们只想要点匿名页面，要搞的那么麻烦吗？<br />
新的2.6.32内核通过支持MAP_HUGETLB方式来使用内存,避免了烦琐的mount操作，对用户更友好。</p>
<p>参见man mmap：</p>
<blockquote><p> MAP_HUGETLB (since Linux 2.6.32)<br />
              Allocate the mapping using &#8220;huge pages.&#8221;  See the kernel source file Documentation/vm/hugetlbpage.txt for further information.
</p></blockquote>
<p>这样明显会方便些，但是大内存页面预留的操作还是要做的，我们来演示下，先来准备环境：<br />
<span id="more-2118"></span></p>
<pre class="brush: bash; title: ; notranslate">
# uname -a
Linux dr4000 2.6.32-131.17.1.el6.x86_64 #1 SMP Wed Oct 5 17:19:54 CDT 2011 x86_64 x86_64 x86_64 GNU/Linux

# cat /proc/meminfo |grep -i huge
AnonHugePages:      2048 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

# sysctl vm.nr_hugepages=192
vm.nr_hugepages = 192

# cat /proc/meminfo |grep -i huge
AnonHugePages:      2048 kB
HugePages_Total:     192
HugePages_Free:      192
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
</pre>
<p>从上面输出可以看到我们的内核是2.6.32, 我用的是RHEL 6U2发行版本，同时保留了192*2M页面。</p>
<p>再来看演示代码如下：</p>
<pre class="brush: bash; title: ; notranslate">
# cat huge.c
#include &lt;sys/mman.h&gt;
#include &lt;stdio.h&gt;
#include &lt;memory.h&gt;

int main(int argc, char *argv[]) {
  char *m;
  size_t s = (8UL * 1024 * 1024);

  m = mmap(NULL, s, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /*MAP_HUGETLB*/, -1, 0);
  if (m == MAP_FAILED) {
    perror(&quot;map mem&quot;);
    m = NULL;
    return 1;
  }

  memset(m, 0, s);

  printf(&quot;map_hugetlb ok, press ENTER to quit!\n&quot;);
  getchar();

  munmap(m, s);
  return 0;
}
# gcc huge.c
# ./a.out
map_hugetlb ok, press ENTER to quit!
</pre>
<p>我们成功用大页面申请了8M内存，4个大页面，同时进行清零操作成功，再munmap之前，我们需要确认内存确实是被我们使用了。</p>
<p>好，切换到另外一个窗口来看下：</p>
<pre class="brush: bash; title: ; notranslate">
# cat /proc/meminfo |grep -i huge
AnonHugePages:      2048 kB
HugePages_Total:     192
HugePages_Free:      188
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
</pre>
<p>是不是不费吹灰之力就成功了，这也说明内核天天在进步。</p>
<p>祝玩得开心！
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2118/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Fio压测工具和io队列深度理解和误区</title>
		<link>http://blog.yufeng.info/archives/2104</link>
		<comments>http://blog.yufeng.info/archives/2104#comments</comments>
		<pubDate>Fri, 09 Mar 2012 12:42:57 +0000</pubDate>
		<dc:creator>Yu Feng</dc:creator>
				<category><![CDATA[工具介绍]]></category>
		<category><![CDATA[fio]]></category>
		<category><![CDATA[iodepth]]></category>
		<category><![CDATA[libaio]]></category>

		<guid isPermaLink="false">http://blog.yufeng.info/?p=2104</guid>
		<description><![CDATA[原创文章，转载请注明： 转载自Erlang非业余研究 本文链接地址: Fio压测工具和io队列深度理解和误区 Fio 是个强大的IO压力测试工具，我之前写过不少fio的使用和实践，参见 这里。 随着块设备的发展，特别是SSD盘的出现，设备的并行度越来越高。利用好这些设备，有个诀窍就是提高设备的iodepth, 一把喂给设备更多的IO请求，让电梯算法和设备有机会来安排合并以及内部并行处理，提高总体效率。 应用使用IO通常有二种方式：同步和异步。 同步的IO一次只能发出一个IO请求，等待内核完成才返回，这样对于单个线程iodepth总是小于1，但是可以透过多个线程并发执行来解决，通常我们会用16-32根线程同时工作把iodepth塞满。 异步的话就是用类似libaio这样的linux native aio一次提交一批，然后等待一批的完成，减少交互的次数，会更有效率。 io队列深度通常对不同的设备很敏感，那么如何用fio来探测出合理的值呢？ 让我们先来看下和iodepth相关的参数： iodepth=int Number of I/O units to keep in flight against the file. Note that increasing iodepth beyond 1 will not affect synchronous ioengines (except for small degress when verify_async is in use). Even async engines my impose OS restrictions [...]]]></description>
			<content:encoded><![CDATA[<div style="margin-top: 15px; font-style: italic">
<p><strong>原创文章，转载请注明：</strong> 转载自<a href="http://blog.yufeng.info/">Erlang非业余研究</a></p>
<p><strong>本文链接地址:</strong> <a href="http://blog.yufeng.info/archives/2104">Fio压测工具和io队列深度理解和误区</a></p>
</div>
<p>Fio 是个强大的IO压力测试工具，我之前写过不少fio的使用和实践，参见 <a href="http://blog.yufeng.info/archives/tag/fio">这里</a>。 </p>
<p>随着块设备的发展，特别是SSD盘的出现，设备的并行度越来越高。利用好这些设备，有个诀窍就是提高设备的iodepth, 一把喂给设备更多的IO请求，让电梯算法和设备有机会来安排合并以及内部并行处理，提高总体效率。</p>
<p>应用使用IO通常有二种方式：同步和异步。 同步的IO一次只能发出一个IO请求，等待内核完成才返回，这样对于单个线程iodepth总是小于1，但是可以透过多个线程并发执行来解决，通常我们会用16-32根线程同时工作把iodepth塞满。 异步的话就是用类似libaio这样的linux native aio一次提交一批，然后等待一批的完成，减少交互的次数，会更有效率。</p>
<p>io队列深度通常对不同的设备很敏感，那么如何用fio来探测出合理的值呢？</p>
<p>让我们先来看下和iodepth相关的参数：</p>
<blockquote><p>       iodepth=int<br />
              Number of I/O units to keep in flight against the file. Note that increasing iodepth beyond  1  will  not  affect  synchronous  ioengines<br />
              (except  for small degress when verify_async is in use). Even async engines my impose OS restrictions causing the desired depth not to be<br />
              achieved.  This may happen on Linux when using libaio and not setting direct=1, since buffered IO is not async on that OS. Keep an eye on<br />
              the IO depth distribution in the fio output to verify that the achieved depth is as expected. Default:<br />
1.</p>
<p>       iodepth_batch=int<br />
              Number of I/Os to submit at once.  Default: iodepth.</p>
<p>       iodepth_batch_complete=int<br />
              This defines how many pieces of IO to retrieve at once. It defaults to 1 which<br />
               means  that we’ll ask for a minimum of 1 IO in the retrieval process from the kernel. The IO retrieval will go on until we hit the limit<br />
              set by iodepth_low. If this variable is set to 0, then fio will always check for completed events before  queuing  more  IO.  This  helps<br />
              reduce IO latency, at the cost of more retrieval system calls.</p>
<p>       iodepth_low=int<br />
              Low watermark indicating when to start filling the queue again.  Default: iodepth.</p>
<p>       direct=bool<br />
              If true, use non-buffered I/O (usually O_DIRECT).  Default: false.</p>
<p>       fsync=int<br />
              How many I/Os to perform before issuing an fsync(2) of dirty data.  If 0, don’t sync.  Default: 0.
</p></blockquote>
<p>这几个参数在libaio的引擎下的作用，文档写的挺明白，但容我再罗嗦下IO请求的流程：</p>
<p>libaio引擎会用这个iodepth值来调用io_setup准备个可以一次提交iodepth个IO的上下文，同时申请个io请求队列用于保持IO。 在压测进行的时候，系统会生成特定的IO请求，往io请求队列里面扔，当队列里面的IO个数达到iodepth_batch值的时候，就调用io_submit批次提交请求，然后开始调用io_getevents开始收割已经完成的IO。 每次收割多少呢？由于收割的时候，超时时间设置为0，所以有多少已完成就算多少，最多可以收割iodepth_batch_complete值个。随着收割，IO队列里面的IO数就少了，那么需要补充新的IO。 什么时候补充呢？当IO数目降到iodepth_low值的时候，就重新填充，保证OS可以看到至少iodepth_low数目的io在电梯口排队着。 </p>
<p>注意：这些参数在文档里面描述的有点小问题，比如说默认值什么的是不太对的，所以我的建议是这些参数要去显示的写。</p>
<p>如何确认fio安装我们的配置在工作呢？ fio提供了诊断办法 <code>--debug=io</code> ，我们来演示下：</p>
<p><span id="more-2104"></span></p>
<pre class="brush: bash; title: ; notranslate">
# cat nvdisk-test
[global]
bs=512
ioengine=libaio
userspace_reap
rw=randrw
rwmixwrite=20
time_based
runtime=180
direct=1
group_reporting
randrepeat=0
norandommap
ramp_time=6
iodepth=16
iodepth_batch=8
iodepth_low=8
iodepth_batch_complete=8
exitall
[test]
filename=/dev/nvdisk0
numjobs=1
</pre>
<p>fio任务配置里面有几个点需要非常注意：<br />
1. libaio工作的时候需要文件direct方式打开。<br />
2. 块大小必须是扇区(512字节)的倍数。<br />
3. userspace_reap提高异步IO收割的速度。<br />
4. ramp_time的作用是减少日志对高速IO的影响。<br />
5. 只要开了direct,fsync就不会发生。</p>
<pre class="brush: bash; title: ; notranslate">
# fio nvdisk-test --debug=io
fio: set debug option io
io       22441 load ioengine libaio
io       22441 load ioengine libaio
test: (g=0): rw=randrw, bs=512-512/512-512, ioengine=libaio, iodepth=16
fio 2.0.5
Starting 1 process
io       22444 invalidate cache /dev/nvdisk0: 0/8589926400
io       22444 fill_io_u: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d3210)=0
io       22444 queue: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d2f80)=0
io       22444 queue: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d2cb0)=0
io       22444 queue: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d29a0)=0
io       22444 queue: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d2710)=0
io       22444 queue: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d2400)=0
io       22444 queue: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d2130)=0
io       22444 queue: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d1ea0)=0
io       22444 queue: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0
io       22444 calling -&gt;commit(), depth 8
io       22444 fill_io_u: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0
io       22444 prep: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0
io       22444 -&gt;prep(0x6d1b90)=0
io       22444 queue: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0
io       22444 fill_io_u: io_u 0x6cdfa0: off=6449852928/len=512/ddir=0//dev/nvdisk0
...
</pre>
<p>我们可以看到详细的IO工作过程，这个方法不需要对OS非常的熟悉，比较实用。</p>
<p>还有个方法就是透过strace来跟踪系统调用的情况, 更直观点。</p>
<pre class="brush: bash; title: ; notranslate">
# pstree -p
init(1)─┬─agent_eagleye(22296)
        ├─screen(13490)─┬─bash(18324)─┬─emacs(19429)
        │               │             ├─emacs(20365)
        │               │             ├─emacs(21268)
        │               │             ├─fio(22452)─┬─fio(22454)
        │               │             │            └─{fio}(22453)
        │               │             └─man(20385)───sh(20386)───sh(20387)───less(20391)
        ├─sshd(1834)───sshd(13115)───bash(13117)───screen(13662)
        └─udevd(705)─┬─udevd(1438)
                     └─udevd(1745
# strace -p 22454
...
io_submit(140534061244416, 8, {{(nil), 0, 1, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 1, 0, 3}, {(nil), 0, 1, 0, 3}, {(nil), 0, 0, 0, 3}}) = 8
io_getevents(140534061244416, 8, 8, {{(nil), 0x6d3210, 512, 0}, {(nil), 0x6d2f80, 512, 0}, {(nil), 0x6d2cb0, 512, 0}, {(nil), 0x6d29a0, 512, 0}, {(nil), 0x6d2710, 512, 0}, {(nil), 0x6d2400, 512, 0}, {(nil), 0x6d2130, 512, 0}, {(nil), 0x6d1ea0, 512, 0}}, NULL) = 8
...
</pre>
<p>最后有效的一招就是用iostat -dx 1来确认你的iodepth是符合设备特性的。<br />
<a href="http://blog.yufeng.info/wp-content/uploads/2012/03/iostat.jpg"><img src="http://blog.yufeng.info/wp-content/uploads/2012/03/iostat.jpg" alt="" title="iostat" width="837" height="230" class="alignnone size-full wp-image-2111" /></a><br />
(由于我用的是nvram卡，这个卡的设备驱动没有队列，iostat看不到队列深度，就用了其他的设备的图代替，表明可以用看iostat看IO队列深度,谢谢网友Uranus指出)<br />
通过这些方法确认你的配置是对的，之后分析出来的数据才会有意义。</p>
<p>祝玩得开心！</p>
<div style="margin-top: 0; margin-bottom: 15px; color: #888888; font-size: 80%; font-style: italic">
<p>Post Footer automatically generated by <a href="http://easwy.com/blog/wordpress/wp-posturl/" style="color: #8888FF; text-decoration: underline;">wp-posturl plugin</a> for wordpress.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.yufeng.info/archives/2104/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

