<?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>一个故事@MySQL DBA</title>
	<atom:link href="http://www.orczhou.com/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.orczhou.com</link>
	<description>一个故事@MySQL DBA</description>
	<lastBuildDate>Tue, 20 Dec 2011 15:51:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>MySQL/InnoDB和Group Commit(2)</title>
		<link>http://www.orczhou.com/index.php/2011/12/time-to-group-commit-2/</link>
		<comments>http://www.orczhou.com/index.php/2011/12/time-to-group-commit-2/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 15:51:20 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Group Commit]]></category>
		<category><![CDATA[InnoDB]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3397</guid>
		<description><![CDATA[<p>今天发现Percona Release的<a href="http://www.mysqlperformanceblog.com/2011/12/19/percona-server-5-5-18-23-0-now-with-group-commit/">Percona-Server-5-5-18-23-0</a>已经完成了Group Commit工作，而且是用最优雅的方式（移植了MariaDB的实现，而不是workaround），心里难掩激动。</p>
<p>这篇文章接<a href="http://www.orczhou.com/index.php/2010/08/time-to-group-commit-1/">前篇</a>继续介绍一下问题的背景：什么是Group Commit，现在的官方版本Group Commit做到了什么程度？</p>
<div class="myt1">1. 什么是Group Commit</div>
<p>MySQL/InnoDB在做事务的时候使用的日志先行（<a href="http://en.wikipedia.org/wiki/Write-ahead_logging">Write-ahead logging</a>）的方式保证事务的快速和持久，所以每次事务完成都要求日志必须持久化到磁盘，在Linux上对应的操作就是“<a href="http://www.orczhou.com/index.php/2009/08/innodb_flush_method-file-io/">write and fsync</a>”，write速度是很快的，一般对应的写Page Cache，而fsync则要求文件系统把对应文件的哦Page Cache必须持久化到磁盘上，而对于传统磁盘一次写操作大约需要1~3ms（不说BBU），这意味着对于传统磁盘1秒钟最多最多做333～1000个事务，这是不理想的，对硬件的利用率（吞吐量）也是非常低。</p>
<p>所以，这里就有了Group操作的概念，即当好几个线程都要fsync同一个日志文件时，我们将这些fsync合并到一次来做。简单举例：我们让系统每2ms做一次fsync，这样如果这2ms内有100个线程都需要做fsync，那就赚到了，原本100个fsync都独立来做那耗时会非常多的。</p>
<p>你肯定会说，难道这不是很简单的想法吗？是的，这就是原本是很简单、也很自然的想法。</p>
<p>但对MySQL来说却变成了一种奢求（看看这个<a href="http://bugs.mysql.com/bug.php?id=13669">Bug讨论</a>）。</p>
<div class="myt1">2. 为啥MySQL一直没有实现？</div>
<p>MySQL是不是太弱了，这么简单的事情都搞不定？不是的。</p>
<p>MySQL从开源到现在，成功的一个非常重要的原因，就是MySQL的插件式架构。如果MySQL只是MyISAM估计不会有现在的流行程度，插件式的架构让诸如Heikki Tuuri有了发挥空间，在InnoDB和MySQL一起时，MySQL才能算是一个真正的DBMS。再到后来，有Infobright、 FEDERATED、PBXT等等。</p>
<p>插件式的架构给MySQL带来了活力，做出牺牲便是在上层(MySQL)和下层(存储引擎)交互时带来的额外消耗，有时甚至上层和下层需要做一些重复工作。无法做Group Commit就是这其中的牺牲之一。</p>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/12/time-to-group-commit-2/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>今天发现Percona Release的<a href="http://www.mysqlperformanceblog.com/2011/12/19/percona-server-5-5-18-23-0-now-with-group-commit/">Percona-Server-5-5-18-23-0</a>已经完成了Group Commit工作，而且是用最优雅的方式（移植了MariaDB的实现，而不是workaround），心里难掩激动。</p>
<p>这篇文章接<a href="http://www.orczhou.com/index.php/2010/08/time-to-group-commit-1/">前篇</a>继续介绍一下问题的背景：什么是Group Commit，现在的官方版本Group Commit做到了什么程度？</p>
<div class="myt1">1. 什么是Group Commit</div>
<p>MySQL/InnoDB在做事务的时候使用的日志先行（<a href="http://en.wikipedia.org/wiki/Write-ahead_logging">Write-ahead logging</a>）的方式保证事务的快速和持久，所以每次事务完成都要求日志必须持久化到磁盘，在Linux上对应的操作就是“<a href="http://www.orczhou.com/index.php/2009/08/innodb_flush_method-file-io/">write and fsync</a>”，write速度是很快的，一般对应的写Page Cache，而fsync则要求文件系统把对应文件的哦Page Cache必须持久化到磁盘上，而对于传统磁盘一次写操作大约需要1~3ms（不说BBU），这意味着对于传统磁盘1秒钟最多最多做333～1000个事务，这是不理想的，对硬件的利用率（吞吐量）也是非常低。</p>
<p>所以，这里就有了Group操作的概念，即当好几个线程都要fsync同一个日志文件时，我们将这些fsync合并到一次来做。简单举例：我们让系统每2ms做一次fsync，这样如果这2ms内有100个线程都需要做fsync，那就赚到了，原本100个fsync都独立来做那耗时会非常多的。</p>
<p>你肯定会说，难道这不是很简单的想法吗？是的，这就是原本是很简单、也很自然的想法。</p>
<p>但对MySQL来说却变成了一种奢求（看看这个<a href="http://bugs.mysql.com/bug.php?id=13669">Bug讨论</a>）。</p>
<div class="myt1">2. 为啥MySQL一直没有实现？</div>
<p>MySQL是不是太弱了，这么简单的事情都搞不定？不是的。</p>
<p>MySQL从开源到现在，成功的一个非常重要的原因，就是MySQL的插件式架构。如果MySQL只是MyISAM估计不会有现在的流行程度，插件式的架构让诸如Heikki Tuuri有了发挥空间，在InnoDB和MySQL一起时，MySQL才能算是一个真正的DBMS。再到后来，有Infobright、 FEDERATED、PBXT等等。</p>
<p>插件式的架构给MySQL带来了活力，做出牺牲便是在上层(MySQL)和下层(存储引擎)交互时带来的额外消耗，有时甚至上层和下层需要做一些重复工作。无法做Group Commit就是这其中的牺牲之一。</p>
<p><span id="more-3397"></span></p>
<div class="myt1">3. 现在的官方版本Group Commit做到了什么程度</div>
<p>InnoDB在一次事务中，有两次fsync，分别是prepare阶段和commit阶段，对于这两次操作InnoDB都是<a href="http://www.innodb.com/wp/products/innodb_plugin/plugin-performance/innodb-plugin-1-0-4-group-commit-test-sysbench/">实现了Group操作</a>的。</p>
<p>如果你设置了binlog_sync=1，则又多了一次fsync操作（参考MYSQL_BIN_LOG::flush_and_sync），这次操作在innobase_xa_prepare和innodb_commit之间：</p>
<blockquote><p>binlog_prepare (do nothing)<br />
innodb_prepare<br />
...<br />
binlog_commit<br />
innobase_commit</p></blockquote>
<p><strong>这次fsync，在MySQL中一直都无法做Group</strong>。所以，一直以来当innodb_flush_log_at_trx_commit和binlog_sync都等于1的时候，MySQL的性能就<a href="http://www.mysqlperformanceblog.com/2011/07/13/testing-the-group-commit-fix/">非常、非常糟糕</a>。原因是为了保证InnoDB<strong>内部Commit</strong>的顺序和MySQL日志的顺序一致（<a href="http://www.orczhou.com/index.php/2010/08/time-to-group-commit-1/">参考</a>）。</p>
<div class="myt1">4. 开源社区的努力</div>
<p>难道没人去解决这个问题吗？不是的。有很多人已经做出了努力，直到Kristian Nielsen@MariaDB提出了理论和实际上的最优解决方案。</p>
<p>Mark Callaghan@Facebook关于Group Commit做的工作：<a href="http://www.facebook.com/note.php?note_id=386328905932">FB的基本实现</a> | <a href="http://www.facebook.com/note.php?note_id=438641125932">FB的问题和改进</a> | <a href="http://www.facebook.com/note.php?note_id=10150261692455933">性能</a> | <a href="http://www.facebook.com/note.php?note_id=10150211546215933">对比MariaDB的实现</a>(对比的结果是MariaDB完胜，无论是方案架构还是性能)</p>
<p>Facebooke可以说是通过<a href="http://www.facebook.com/note.php?note_id=386328905932">一个Trick</a>快速实现了Group Commit。而Kristian Nielsen@MariaDB这是从架构上根本的解决了这个问题。</p>
<p>MariaDB关于Group Commit架构和实现： <a href="http://askmonty.org/worklog/Server-Sprint/?tid=116">WL116</a> | <a href="http://askmonty.org/worklog/Server-Sprint/?tid=132">WL132</a> | <a href="http://askmonty.org/worklog/Server-RawIdeaBin/?tid=164">WL164</a></p>
<div class="myt1">5. 未完待续</div>
<p>后面还有很多值得写的，我希望自己能够一直写完这个系列。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/12/time-to-group-commit-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用tbdba-restore-mysqldump.pl切割mysqldump文件</title>
		<link>http://www.orczhou.com/index.php/2011/12/how-to-split-mysqldump-file/</link>
		<comments>http://www.orczhou.com/index.php/2011/12/how-to-split-mysqldump-file/#comments</comments>
		<pubDate>Wed, 14 Dec 2011 14:40:42 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysqldump]]></category>
		<category><![CDATA[备份]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3364</guid>
		<description><![CDATA[<p>这里介绍一个最近用得很多的一个小工具：<a href="https://github.com/orczhou/dba-tool/blob/master/tbdba-restore-mysqldump.pl">tbdba-restore-mysqldump.pl</a>。</p>
<p>主要有两个功能：</p>
<p>(1) 尽可能快的从一个非常大的mysqldump文件的分离出某个单表的备份文件</p>
<p>(2) 可以帮你把一个大的mysqldump文件，切割成非常小的单表备份文件（可继续做并行恢复）</p>
<div class="myt1">1. 什么时候需要这么做</div>
<p>(1) 如果把MySQL中<strong>某一个表</strong>数据弄丢了，需要从很大的mysqldump备份文件中恢复这个表</p>
<p>(2) 如果你想并行恢复整个mysqldump备份文件时，这个脚本可以帮你把大文件切割成多个小的单表备份文件，然后就可以方便并行恢复多个文件了</p>
<div class="myt1">2. 如何使用这个脚本</div>
<p>这里以实例的方式介绍如何使用该脚本：</p>
<p>(1) 从backup.sql文件中获取表process的备份：</p>
<blockquote><div style="color:blue">tbdba-restore-mysqldump.pl -t process -f backup.sql</div>
</blockquote>
<p>(2) 从backup.sql文件中获取数据库monitor中的表process的备份：</p>
<blockquote><div style="color:blue">tbdba-restore-mysqldump.pl -t process -s monitor -f backup.sql</div>
</blockquote>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/12/how-to-split-mysqldump-file/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>这里介绍一个最近用得很多的一个小工具：<a href="https://github.com/orczhou/dba-tool/blob/master/tbdba-restore-mysqldump.pl">tbdba-restore-mysqldump.pl</a>。</p>
<p>主要有两个功能：</p>
<p>(1) 尽可能快的从一个非常大的mysqldump文件的分离出某个单表的备份文件</p>
<p>(2) 可以帮你把一个大的mysqldump文件，切割成非常小的单表备份文件（可继续做并行恢复）</p>
<div class="myt1">1. 什么时候需要这么做</div>
<p>(1) 如果把MySQL中<strong>某一个表</strong>数据弄丢了，需要从很大的mysqldump备份文件中恢复这个表</p>
<p>(2) 如果你想并行恢复整个mysqldump备份文件时，这个脚本可以帮你把大文件切割成多个小的单表备份文件，然后就可以方便并行恢复多个文件了</p>
<div class="myt1">2. 如何使用这个脚本</div>
<p>这里以实例的方式介绍如何使用该脚本：</p>
<p>(1) 从backup.sql文件中获取表process的备份：</p>
<blockquote><div style="color:blue">tbdba-restore-mysqldump.pl -t process -f backup.sql</div>
</blockquote>
<p>(2) 从backup.sql文件中获取数据库monitor中的表process的备份：</p>
<blockquote><div style="color:blue">tbdba-restore-mysqldump.pl -t process -s monitor -f backup.sql</div>
</blockquote>
<p><span id="more-3364"></span></p>
<p>(3) 从backup.sql文件中获取多个表的备份文件（例如表process、users）：</p>
<blockquote><div style="color:blue">tbdba-restore-mysqldump.pl -t process,user -s monitor -f backup.sql</div>
</blockquote>
<p>(4) 直接接收来自管道的输出（如果你的mysqldump备份是压缩后，则可以使用）：</p>
<blockquote><div style="color:blue">gunzip -c backup.sql.gz|tbdba-restore-mysqldump.pl -t process,user -s monitor</div>
</blockquote>
<p>(5) 从backup.sql文件中获取数据库monitor下<strong>所有表</strong>的备份文件：</p>
<blockquote><div style="color:blue">gunzip -c backup.sql.gz|tbdba-restore-mysqldump.pl -s monitor </div>
</blockquote>
<p>(6) 从backup.sql文件中获取<strong>所有数据库下所有表</strong>的备份文件：</p>
<blockquote><div style="color:blue">gunzip -c backup.sql.gz|tbdba-restore-mysqldump.pl --all-tables</div>
</blockquote>
<p>(7) 使用-d参数，则可以看到切割的过程中的更多信息：</p>
<blockquote><div style="color:blue">date &#038;& gunzip -c /backdir/backup.sql.gz|tbdba-restore-mysqldump.pl -d -a &#038;& date</div>
</blockquote>
<div class="myt1">3. tbdba-restore-mysqldump.pl有什么优势</div>
<p>(1) 如果指定了-s（获取<strong>某个</strong>数据库中的备份）参数，则脚本在成功截取需要恢复的<strong>表</strong>后就会立刻退出，所以如果你要恢复的表恰好在备份文件的比较靠前的位置时，该脚本的速度会非常快。</p>
<p>一个实际工作例子：</p>
<blockquote><p>$ls -lh backup.sql.gz<br />
 -rw-r--r-- 1 mysql dba 14G Nov 21 04:49 backup.sql.gz<br />
$date &#038;& gunzip -c backup.sql.gz|./tbdba-restore-mysqldump.pl -s monitor_general -t monitor_host_info &#038;& date<br />
Fri Nov 25 14:35:06 CST 2011<br />
Fri Nov 25 14:46:49 CST 2011<br />
(the unzip of backup.sql.gz is 88G)</p></blockquote>
<p>如果要全量恢复的话，根据经验值：88GB的sql文件完全恢复约需要400分钟（<a href="http://www.orczhou.com/index.php/2009/12/more-about-mysqldump/">经验值</a>）。</p>
<p>(2) 为了让每个独立的单表备份文件能够准确恢复，脚本做了两个额外的处理工作：在每个单表备份前加上'use db'，让该表能够恢复到正确的数据库；为了让单表恢复时字符集不出错误，脚本在某个单表备份前加上了对应的SET NAMES utf8、SET TIME_ZONE等命令。</p>
<div class="myt1">4. 其他人都怎么做</div>
<p><a href="http://blog.tsheets.com/2008/tips-tricks/extract-a-single-table-from-a-mysqldump-file.html">Extract a Single Table from a mysqldump File</a>：这篇文章提到了三个办法，分别是：perl脚本（我这里的做法基本“雷同”），awk解析后切割，先恢复到临时库(对大文件这个不现实...)。对比了我们的Perl脚本，这里做了几个改进：可以同时解析出多个表；完成目标表的切割后，则立刻退出，不再扫描剩余部分；会把mysqldump头部输出放到每一个切割文件中，方便各种字符集的恢复；</p>
<p><a href="http://gtowey.blogspot.com/2009/11/restore-single-table-from-mysqldump.html">Restore a Single Table From mysqldump</a>：这篇文章介绍如何用Sed来完成这个工作。</p>
<p><a href="http://ushastry.blogspot.com/2009/08/mysql-restoring-single-table-from.html">MySQL - Restoring a single table from nightly backup </a>：这位朋友则，想出一个“更损”的招：只给恢复用户赋予需要恢复的表的权限，然后用--force参数恢复整个mysqldump文件。</p>
<p><a href="http://code.openark.org/blog/mysql/on-restoring-a-single-table-from-mysqldump">On restoring a single table from mysqldump</a>：这篇文章则对比了使用grep sed 和“权限控制”三种方法的速度。</p>
<p>最后，如果不喜欢mysqldump这种一股脑的备份方式，可以考虑试用mydumper。</p>
<p>OK，That's all.</p>
<p><embed src="http://www.xiami.com/widget/318706_184466/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/12/how-to-split-mysqldump-file/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>使用mod_proxy_html完善Apache反向代理</title>
		<link>http://www.orczhou.com/index.php/2011/12/apache-reverse-proxy-with-mod-proxy-html/</link>
		<comments>http://www.orczhou.com/index.php/2011/12/apache-reverse-proxy-with-mod-proxy-html/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 14:37:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[技术细节]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[反向代理]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3335</guid>
		<description><![CDATA[<p>在使用和配置过程中，还是遇到了一些波折，这里分享、记录一下。</p>
<div class="myt1">1. 模块mod_proxy_html可以做些什么</div>
<p>使用Apache内置的mod_proxy的<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass">Proxypass</a>可以帮助我们实现基本的<a href="http://httpd.apache.org/docs/2.2/urlmapping.html#proxy">反向代理</a>功能。但是，代理返回的结果页面包含的链接并不会被重写，所以如果被代理的Server返回的是绝对地址，用户则无法正确访问这些链接。例如：</p>
<p>我们有反向代理服务器http://myproxy.taobao.org/，而内网有需要代理的服务器http://internalserver.taobao.org/，通过基本的反向代理指令<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass">Proxypass</a>：</p>
<blockquote><p>ProxyPass  ^/proxy_internal/(.*)$ http://internalserver.taobao.org/$1</p></blockquote>
<p>可以完成基本的反向代理任务，但是如果internalserver.taobao.org返回的HTML代码中有如下链接，则客户端则无法正常链接到目标页面了：</p>
<blockquote><p>&#60;a href="/test/index.html">Sample Link&#60;/a></p></blockquote>
<p>因为，客户端点击该链接时会定向到http://myproxy.taobao.org/test/index.html，而资源实际是在http://internalserver.taobao.org/test/index.html上。</p>
<p>Apache自带的mod_proxy<a href="http://httpd.apache.org/docs/2.2/urlmapping.html#proxy">无法解决这个问题</a>，开源的第三方模块<a href="http://apache.webthing.com/mod_proxy_html/">mod_proxy_html</a>为此而生。经过代理服务器的HTML可以通过该模块做一次替换，从而变成可以正常访问的URL（上例中会把/oninternal/index.html替换成/proxy_internal/test/index.html）。<br />
[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/12/apache-reverse-proxy-with-mod-proxy-html/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>在使用和配置过程中，还是遇到了一些波折，这里分享、记录一下。</p>
<div class="myt1">1. 模块mod_proxy_html可以做些什么</div>
<p>使用Apache内置的mod_proxy的<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass">Proxypass</a>可以帮助我们实现基本的<a href="http://httpd.apache.org/docs/2.2/urlmapping.html#proxy">反向代理</a>功能。但是，代理返回的结果页面包含的链接并不会被重写，所以如果被代理的Server返回的是绝对地址，用户则无法正确访问这些链接。例如：</p>
<p>我们有反向代理服务器http://myproxy.taobao.org/，而内网有需要代理的服务器http://internalserver.taobao.org/，通过基本的反向代理指令<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass">Proxypass</a>：</p>
<blockquote><p>ProxyPass  ^/proxy_internal/(.*)$ http://internalserver.taobao.org/$1</p></blockquote>
<p>可以完成基本的反向代理任务，但是如果internalserver.taobao.org返回的HTML代码中有如下链接，则客户端则无法正常链接到目标页面了：</p>
<blockquote><p>&lt;a href="/test/index.html">Sample Link&lt;/a></p></blockquote>
<p>因为，客户端点击该链接时会定向到http://myproxy.taobao.org/test/index.html，而资源实际是在http://internalserver.taobao.org/test/index.html上。</p>
<p>Apache自带的mod_proxy<a href="http://httpd.apache.org/docs/2.2/urlmapping.html#proxy">无法解决这个问题</a>，开源的第三方模块<a href="http://apache.webthing.com/mod_proxy_html/">mod_proxy_html</a>为此而生。经过代理服务器的HTML可以通过该模块做一次替换，从而变成可以正常访问的URL（上例中会把/oninternal/index.html替换成/proxy_internal/test/index.html）。<br />
<span id="more-3335"></span></p>
<div class="myt1">2. 编译安装mod_proxy_html模块</div>
<p>我是在RHEL5.4上安装的，并不容易。<strong>理想的安装步骤</strong>（为了支持多字符集需要同时安装mod_xml2enc）：</p>
<p>1. 检查是否安装了libxml2。</p>
<p>2. 下载mod_proxy_html源码：<a href="http://apache.webthing.com/mod_proxy_html/">地址</a>；下载mod_xml2enc的源码：地址<a href="http://apache.webthing.com/mod_xml2enc/">mod_xml2enc</a></p>
<p>3. 编译mod_proxy_html和mod_xml2enc：</p>
<blockquote><p>
sudo /usr/sbin/apxs -c -I/usr/include/libxml2 -I. -I /usr/lib -i mod_proxy_html.c<br />
sudo /usr/sbin/apxs -c -I/usr/include/libxml2 -I. -i mod_xml2enc.c<br />
chmod 755 /usr/lib64/httpd/modules/mod_proxy_html.so
</p></blockquote>
<p>如果你这么顺利就编译好了模块，那你很幸运。</p>
<div class="myt2">编译中的问题</div>
<blockquote><p>$ /usr/sbin/apxs -c -I/usr/include/libxml2 -I. -I /usr/lib -i mod_proxy_html.c<br />
"my" variable $libdir masks earlier declaration in same scope at /usr/sbin/apxs line 36.<br />
/apr-1/build/libtool --silent --mode=compile gcc -prefer-pic -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fno-strict-aliasing  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -pthread -I/usr/include/httpd  -I/usr/include/apr-1   -I/usr/include/apr-1  -I/usr/include/libxml2 -I. -I/usr/lib  -c -o mod_proxy_html.lo mod_proxy_html.c &#038;& touch mod_proxy_html.slo<br />
sh: /apr-1/build/libtool: No such file or directory<br />
apxs:Error: Command failed with rc=8323072</p></blockquote>
<p>仔细看是：<strong>/apr-1/build/libtool: No such file or directory</strong>。对libtool和apr-1不很熟悉，看出是因为没有正确找到libtool的路径导致的，所以修改了一下脚本apxs，强制指定libtool的位置，虽然这不是“优雅的”解决办法：</p>
<div class="mycode">
$locate libtool   #找到你的libtool<br />
......<br />
$vi /usr/sbin/apxs<br />
...<br />
my $libtool = `$apr_config --apr-libtool`;<br />
chomp($libtool);<br />
$libtool = "/usr/lib64/apr-1/build/libtool";<br />
...
</div>
<p>It works!  如果有个有更好的办法，或者知道根本原因的，请告诉我，谢过先。</p>
<div class="myt1">3. 配置该模块</div>
<p>强烈建议参考mod_proxy_html源码中的proxy_html.conf，这是一个示例配置文件，非常有指导意义。我这里的配置如下：</p>
<p>1. 加载必要的模块：</p>
<blockquote><p>LoadFile /usr/lib64/libxml2.so<br />
LoadModule xml2enc_module modules/mod_xml2enc.so<br />
LoadModule proxy_html_module modules/mod_proxy_html.so</p></blockquote>
<p>2. 指定需要修改的链接标签：</p>
<blockquote><p>SetOutputFilter proxy-html<br />
ProxyHTMLExtended On<br />
ProxyHTMLLinks  a           href<br />
ProxyHTMLLinks  area        href<br />
ProxyHTMLLinks  link        href<br />
ProxyHTMLLinks  img         src longdesc usemap<br />
ProxyHTMLLinks  object      classid codebase data usemap<br />
ProxyHTMLLinks  q           cite<br />
ProxyHTMLLinks  blockquote  cite<br />
ProxyHTMLLinks  ins         cite<br />
ProxyHTMLLinks  del         cite<br />
ProxyHTMLLinks  form        action<br />
ProxyHTMLLinks  input       src usemap<br />
ProxyHTMLLinks  head        profile<br />
ProxyHTMLLinks  base        href<br />
ProxyHTMLLinks  script      src for<br />
ProxyHTMLEvents onclick ondblclick onmousedown onmouseup \<br />
        onmouseover onmousemove onmouseout onkeypress \<br />
        onkeydown onkeyup onfocus onblur onload \<br />
        onunload onsubmit onreset onselect onchange</p></blockquote>
<p>3. 指定的URL替换规则：</p>
<pre>
<blockquote>
ProxyPassMatch ^/proxy_dir/(.*)$ http://yourdomain/$1
&lt;LocationMatch "/proxy_dir/">
        ProxyPassReverse /
        ProxyHTMLURLMap  / /proxy_dir/
        ProxyHTMLURLMap  http://some_(reg_exp)_url_(is_supported)you_wanna_replace/  /proxy_dir/$1/$2/ R
        RequestHeader    unset  Accept-Encoding
&lt;/LocationMatch></blockquote>
</pre>
<p>OK，That's all.</p>
<p><script type="text/javascript" src="http://www.xiami.com/widget/player-single?uid=318706&#038;sid=1769953757&#038;mode=js"></script></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
<p>参考：</p>
<p>1. <a href="http://apache.webthing.com/mod_proxy_html/">mod_proxy_html主页</a></p>
<p>2. <a href="http://www.apachetutor.org/admin/reverseproxies">Running a Reverse Proxy in Apache</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/12/apache-reverse-proxy-with-mod-proxy-html/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL如何传输二进制日志</title>
		<link>http://www.orczhou.com/index.php/2011/11/how-mysql-send-the-binary-log/</link>
		<comments>http://www.orczhou.com/index.php/2011/11/how-mysql-send-the-binary-log/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 15:53:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Replication]]></category>
		<category><![CDATA[图解]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3279</guid>
		<description><![CDATA[<p>MySQL Replication可以很方便的用来做应用的读扩展，也可以帮MySQL实现一定程度的HA方案。MySQL通过<a href="http://www.orczhou.com/index.php/2009/04/how-mysql-replication-works/">向备库传送二进制日志来实现Replication</a>，本文将通过二进制日志相关源代码的主要接口来解释：“<strong>MySQL如何传输二进制日志，是主库推，还是备库拉？MySQL日志传输的实时性如何？</strong>”。</p>
<p>在MySQL Replication结构中，备库端初次通过<a href="http://dev.mysql.com/doc/refman/5.1/en/change-master-to.html">CHANGE MASTER TO</a>完成Replication配置，再使用start slave命令开始复制。更细致的，备库通过IO Thread向主库发起读取binlog的请求（COM_BINLOG_DUMP命令），主库收到COM_BINLOG_DUMP请求后，使用单独线程（dump thread）不断向备库IO Thread发送Binlog。示意图(<a href="http://farm7.staticflickr.com/6237/6369693149_49d43db964_b.jpg">大图</a>)：<br />
<a href="http://www.orczhou.com/wp-content/uploads/2011/11/how_mysql_send_binary_log.jpg"><img src="http://www.orczhou.com/wp-content/uploads/2011/11/how_mysql_send_binary_log.jpg" alt="" title="how_mysql_send_binary_log" width="686" height="369" class="alignleft size-full wp-image-3292" /></a></p>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/11/how-mysql-send-the-binary-log/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>MySQL Replication可以很方便的用来做应用的读扩展，也可以帮MySQL实现一定程度的HA方案。MySQL通过<a href="http://www.orczhou.com/index.php/2009/04/how-mysql-replication-works/">向备库传送二进制日志来实现Replication</a>，本文将通过二进制日志相关源代码的主要接口来解释：“<strong>MySQL如何传输二进制日志，是主库推，还是备库拉？MySQL日志传输的实时性如何？</strong>”。</p>
<p>在MySQL Replication结构中，备库端初次通过<a href="http://dev.mysql.com/doc/refman/5.1/en/change-master-to.html">CHANGE MASTER TO</a>完成Replication配置，再使用start slave命令开始复制。更细致的，备库通过IO Thread向主库发起读取binlog的请求（COM_BINLOG_DUMP命令），主库收到COM_BINLOG_DUMP请求后，使用单独线程（dump thread）不断向备库IO Thread发送Binlog。示意图(<a href="http://farm7.staticflickr.com/6237/6369693149_49d43db964_b.jpg">大图</a>)：<br />
<a href="http://www.orczhou.com/wp-content/uploads/2011/11/how_mysql_send_binary_log.jpg"><img src="http://www.orczhou.com/wp-content/uploads/2011/11/how_mysql_send_binary_log.jpg" alt="" title="how_mysql_send_binary_log" width="686" height="369" class="alignleft size-full wp-image-3292" /></a></p>
<p><span id="more-3279"></span></p>
<p>在主库端一旦有新的日志产生后，立刻会发送一次广播，dump线程在收到广播后，则会读取二进制日志并通过网络向备库传输日志，所以这是一个主库向备库不断推送的过程；</p>
<p>新日志在产生后，只需一次广播和网络就会立刻（<1ms）向发送到备库，如果主备之间网络较好的话（例如RTT<1ms），备库端的日志也就小于2ms了。所以，一般的（依赖于RTT），备库的实时性都非常好。</p>
<p>参考：</p>
<p>1. <a href="http://dev.mysql.com/doc/refman/5.1/en/replication.html">MySQL Replication Manual</a></p>
<p>2. <a href="http://www.orczhou.com/index.php/2009/04/how-mysql-replication-works/">图解"How MySQL Replication Works" </a></p>
<p>Have fun!</p>
<p><embed src="http://www.xiami.com/widget/0_1025147/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/11/how-mysql-send-the-binary-log/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TCP/IP重传超时--RTO</title>
		<link>http://www.orczhou.com/index.php/2011/10/tcpip-protocol-start-rto/</link>
		<comments>http://www.orczhou.com/index.php/2011/10/tcpip-protocol-start-rto/#comments</comments>
		<pubDate>Thu, 27 Oct 2011 12:19:27 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[技术细节]]></category>
		<category><![CDATA[retransmission timeout]]></category>
		<category><![CDATA[RTO]]></category>
		<category><![CDATA[TCP]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3162</guid>
		<description><![CDATA[<p>概述：本文讨论主机在发送一个TCP数据包后，如果迟迟没有收到ACK，主机多久后会重传这个数据包。主机从发出数据包到第一次TCP重传开始，<a href="http://zh.wikipedia.org/wiki/RFC#RFC.E6.96.87.E4.BB.B6.E7.9A.84.E7.94.A2.E7.94.9F">RFC</a>中这段时间间隔称为retransmission timeout，缩写做RTO。本文会先看看RFC中如何定义RTO，然后看看Linux中如何实现。<strong>本文旨在分享</strong>：当遇到了TCP层问题改如何去查找、阅读文档，该如何去在Linux源码中寻求答案。</p>
<div class="myt1">1. 起源</div>
<p>在分析MySQL Semi-sync故障时，我们用Tcpdump+Wireshark（感谢淘宝雕梁）抓住当时的网络包传送细节，观察到了一次TCP重传最终导致了Semi-sync超时：</p>
<pre>
<div class="mycode">第一次传输
13:55:11.893291 master => slave	Binlog pos:319890197
重传：
13:55:12.094596	master => slave	Binlog pos:319890197
</div>
</pre>
<p>看到两次传送间隔约201毫秒，即第一次传输201毫秒后，还没有收到ACK响应，TCP认为传输超时，开始重传。</p>
<p>疑问：host和host之间的RTT大约是0.5毫秒，为什么第一次重传需要等200毫秒？（我希望是&#60;20ms）socket程序可以配置吗RTO吗？TCP有参数可配置RTO吗？</p>
<div class="myt1">2. Google/书籍/RFC</div>
<p>翻开TCP/IP详解找到关于TCP Retransmission章节，较详细的介绍TCP的超时机制，书中是个概述，于是又找到RFC1122。</p>
<p>RFC1122的4.2.2.15和4.2.3.1都介绍了Retransmission Timeout的处理（说来惭愧，这是第一次阅读TCP相关RFC）。</p>
<p>在<a href="http://www.ietf.org/rfc.html">RFC中搜索</a>Retransmission发现RFC 793 1122 2988 6298都有对重传算法、和初次重传超时的描述。于是开始阅读这个四个RFC，耗时约2小时，了解了大致的重传超时算法。[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/10/tcpip-protocol-start-rto/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>概述：本文讨论主机在发送一个TCP数据包后，如果迟迟没有收到ACK，主机多久后会重传这个数据包。主机从发出数据包到第一次TCP重传开始，<a href="http://zh.wikipedia.org/wiki/RFC#RFC.E6.96.87.E4.BB.B6.E7.9A.84.E7.94.A2.E7.94.9F">RFC</a>中这段时间间隔称为retransmission timeout，缩写做RTO。本文会先看看RFC中如何定义RTO，然后看看Linux中如何实现。<strong>本文旨在分享</strong>：当遇到了TCP层问题改如何去查找、阅读文档，该如何去在Linux源码中寻求答案。</p>
<div class="myt1">1. 起源</div>
<p>在分析MySQL Semi-sync故障时，我们用Tcpdump+Wireshark（感谢淘宝雕梁）抓住当时的网络包传送细节，观察到了一次TCP重传最终导致了Semi-sync超时：</p>
<pre>
<div class="mycode">第一次传输
13:55:11.893291 master => slave	Binlog pos:319890197
重传：
13:55:12.094596	master => slave	Binlog pos:319890197
</div>
</pre>
<p>看到两次传送间隔约201毫秒，即第一次传输201毫秒后，还没有收到ACK响应，TCP认为传输超时，开始重传。</p>
<p>疑问：host和host之间的RTT大约是0.5毫秒，为什么第一次重传需要等200毫秒？（我希望是<20ms）socket程序可以配置吗RTO吗？TCP有参数可配置RTO吗？</p>
<div class="myt1">2. Google/书籍/RFC</div>
<p>翻开TCP/IP详解找到关于TCP Retransmission章节，较详细的介绍TCP的超时机制，书中是个概述，于是又找到RFC1122。</p>
<p>RFC1122的4.2.2.15和4.2.3.1都介绍了Retransmission Timeout的处理（说来惭愧，这是第一次阅读TCP相关RFC）。</p>
<p>在<a href="http://www.ietf.org/rfc.html">RFC中搜索</a>Retransmission发现RFC 793 1122 2988 6298都有对重传算法、和初次重传超时的描述。于是开始阅读这个四个RFC，耗时约2小时，了解了大致的重传超时算法。<span id="more-3162"></span></p>
<div class="myt1">3. RFC中如何计算RTO(Retransmission Timeout)</div>
<div class="myt2">3.1 RFC-793如何计算RTO</div>
<p>概述：先根据该socket的RTT计算出SRTT（Smoothed Round Trip Time），然后根据一个最大、最小超时时间确定当前RTO。说明：srtt可以理解为“平滑化”的RTT，即在保持计算简单的情况尽量考虑历史RTT。</p>
<p>详细计算：SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)</p>
<p>基于SRTT，我们再来计算RTO：RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]</p>
<p>UBOUND是RTO上线，ALPHA是平滑因子（smoothing factor， e.g., .8 to .9），BETA是一个延迟方差因子（BETA is a delay variance factor (e.g., 1.3 to 2.0)）。</p>
<p>仔细看这两个公式大概就能理解了RTO的计算了。</p>
<p>这里对上面两个公式做一个简单的注释：公式1中计算SRTT，ALPHA越接近于0，则表示SRTT越相信这一次的RTT；越接近于1，则表示SRTT越相信上次统计的RTT。公式二给RTO分别设置了一个上限和下限。</p>
<div class="myt2">3.2 RTO重传间隔是指数增加的</div>
<p>上面我们介绍的是初次重传时的RTO，如果重传后还没收到另一端的响应，下一次重传RTO则会指数增加，例如第一次重传RTO是1，之后分别2，4，8，16...。</p>
<div class="myt2">3.3 RFC-2988和RFC-6298中的RTO计算</div>
<p>在RFC-2988和RFC-6298中又重新改进了RTO的计算方法，Linux中的实现即使参考RFC-2988。算法核心公式：</p>
<pre>
<div class="mycode">初始：
SRTT <- R
RTTVAR <- R/2
RTO <- SRTT + max (G, K*RTTVAR)
where K = 4.

根据RTT计算SRTT：
RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'|
SRTT <- (1 - alpha) * SRTT + alpha * R'

最后RTO：
RTO <- SRTT + max (G, K*RTTVAR)
</div>
</pre>
<div class="myt1">4. Linux中的RTO(Retransmission Timeout)</div>
<p>这里说的是RHEL5.4的2.6.18内核，RFC-2988实现参考net/ipv4/tcp_input.c中的tcp_rtt_estimator和tcp_set_rto。可以看到，在Linux中alpha=1/8，RTO最小为TCP_RTO_MIN。因为我们的系统中RTT总是很小，所以RTO取值总是能够取到TCP_RTO_MIN。</p>
<p>在看看TCP_RTO_MIN在Linux中的定义：</p>
<pre>
<div class="mycode">123#define TCP_RTO_MAX     ((unsigned)(120*HZ))
124#define TCP_RTO_MIN     ((unsigned)(HZ/5))
</div>
</pre>
<p>(这里简单的介绍介绍一下HZ，HZ可以理解为1s，所以120*HZ就是120秒，HZ/5就是200ms。详细的：HZ表示CPU一秒种发出多少次时间中断--IRQ-0，Linux中通常用HZ来做时间片的计算，<a href="http://blog.csdn.net/bdc995/article/details/4144031">参考</a>)</p>
<div class="myt1">5. 其他：Linux中可配置重传参数</div>
<p>/proc/sys/net/ipv4/tcp_retries1  (integer; default: 3)</p>
<p>TCP尝试了3次（tcp_retries1默认3）重传后，还没有收到ACK的话，则后续每次重传都需要network layer先更新路由。</p>
<p>/proc/sys/net/ipv4/tcp_retries2  (integer; default: 15)</p>
<p>TCP默认最多做15次重传。根据RTO(retransmission timeout)不同，最后一次重传间隔大概是13到30分钟左右。如果15次重传都做完了，TCP/IP就会告诉应用层说：“搞不定了，包怎么都传不过去！”</p>
<div class="myt1">6. 最后</div>
<p>回答前面的问题：即使RTT很小（0.8ms），但是因为RTO有下限，最小必须是200ms，所以这是RTT再小也白搭；RTO最小值是内核编译是决定的，socket程序中无法修改，Linux TCP也没有任何参数可以改变这个值。</p>
<p>好了，不容易。</p>
<p><script type="text/javascript" src="http://www.xiami.com/widget/player-single?uid=318706&#038;sid=382457&#038;mode=js"></script></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
<p>参考文献</p>
<p>1. RFC 1122 ... (<a href="http://www.ietf.org/rfc.html">在哪儿查找RFC</a>) TCP协议相关的RFC：<br />
RFC 675 - Specification of Internet Transmission Control Program, December 1974 Version<br />
RFC 793 - TCP v4<br />
RFC 1122 - includes some error corrections for TCP<br />
RFC 1323 - TCP-Extensions<br />
RFC 1379 - Extending TCP for Transactions—Concepts<br />
RFC 1948 - Defending Against Sequence Number Attacks<br />
RFC 2018 - TCP Selective Acknowledgment Options<br />
RFC 2988 - Computing TCP's Retransmission Timer<br />
RFC 4614 - A Roadmap for TCP Specification Documents<br />
RFC 5681 - TCP Congestion Control</p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/10/tcpip-protocol-start-rto/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL5.5 Semi-sync备库响应协议分析</title>
		<link>http://www.orczhou.com/index.php/2011/10/semy-sync-slave-protocol-slave-reply/</link>
		<comments>http://www.orczhou.com/index.php/2011/10/semy-sync-slave-protocol-slave-reply/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 14:53:58 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[代码细节]]></category>
		<category><![CDATA[MySQL5.5]]></category>
		<category><![CDATA[semi-sync replication]]></category>
		<category><![CDATA[半同步]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3125</guid>
		<description><![CDATA[<p>这又是一篇介绍Semi-sync的文章。</p>
<p>Semi-sync主库在一定时间内（可配置的超时时间），如果没有收到备库的响应，则会超时从而降级为普通的replication复制。如果超时发生，有时需要查清什么原因导致备库没有及时响应，一方面可以从备库的日志着手，另一方面，如果需要更细致的信息则需要从备库端的网络包查找原因。这里介绍如何分析一个Semi-sync备库响应主库的数据包。</p>
<p>概述：先使用tcpdump抓取正确（主要是src和dst都正确）的数据包；然后借助wireshark玻璃TCP/IP等层的头信息，仅保留发送的MySQL数据包；再分析MySQL Semi-sync Slave响应的协议。</p>
<div class="myt1">1. tcpdump原始数据包</div>
<p>通过如下tcpdump抓取主机的网络包：</p>
<pre>
<div class="mycode">nohup tcpdump -n -nn -tttt -i bond0 -s 65535 'port 3306 and ((dst host master.host and src host slave.host and len &#038;lt 100) or (dst host slave.host and src host master.host))' -w tcpdump.ret -C 50 &#038;
</div>
</pre>
<p>参数简单说明：</p>
<pre>
<div class="mycode">-n  表示ip不要转换为主机名
-nn表示端口号，不要转为为服务名（例如3306会被转换为mysql）
-tttt 打印出完成的格式化的时间戳
-C 50 表示抓取的结果放到文件中，文件大小不超过50MB
</div>
</pre>
<div class="myt1">2. 使用wireshark找到对应的包</div>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/10/semy-sync-slave-protocol-slave-reply/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>这又是一篇介绍Semi-sync的文章。</p>
<p>Semi-sync主库在一定时间内（可配置的超时时间），如果没有收到备库的响应，则会超时从而降级为普通的replication复制。如果超时发生，有时需要查清什么原因导致备库没有及时响应，一方面可以从备库的日志着手，另一方面，如果需要更细致的信息则需要从备库端的网络包查找原因。这里介绍如何分析一个Semi-sync备库响应主库的数据包。</p>
<p>概述：先使用tcpdump抓取正确（主要是src和dst都正确）的数据包；然后借助wireshark玻璃TCP/IP等层的头信息，仅保留发送的MySQL数据包；再分析MySQL Semi-sync Slave响应的协议。</p>
<div class="myt1">1. tcpdump原始数据包</div>
<p>通过如下tcpdump抓取主机的网络包：</p>
<pre>
<div class="mycode">nohup tcpdump -n -nn -tttt -i bond0 -s 65535 'port 3306 and ((dst host master.host and src host slave.host and len &#038;lt 100) or (dst host slave.host and src host master.host))' -w tcpdump.ret -C 50 &#038;
</div>
</pre>
<p>参数简单说明：</p>
<pre>
<div class="mycode">-n  表示ip不要转换为主机名
-nn表示端口号，不要转为为服务名（例如3306会被转换为mysql）
-tttt 打印出完成的格式化的时间戳
-C 50 表示抓取的结果放到文件中，文件大小不超过50MB
</div>
</pre>
<div class="myt1">2. 使用wireshark找到对应的包</div>
<p><span id="more-3125"></span></p>
<p>Semi-sync备库响应主库包，一般大小整个包大小约95字节。找到该网络包如下：</p>
<p><a href="http://www.orczhou.com/wp-content/uploads/2011/10/tmp.jpg"><img src="http://www.orczhou.com/wp-content/uploads/2011/10/tmp.jpg" alt="" title="tmp" width="618" height="156" class="alignleft size-full wp-image-3151" /></a></p>
<p>完整网络包内容：</p>
<pre>
<div class="mycode">0000  00 24 e8 57 76 5e 00 1d  70 82 ca c0 08 00 45 00   .$.Wv^.. p.....E.
0010  00 51 a6 e2 40 00 3e 06  89 34 ac 13 46 44 ac 17   .Q..@.>. .4..FD..
0020  6e 21 b3 35 0c ea b2 2d  26 2a da 46 3c df 80 18   n!.5...- &#038;*.F<...
0030  04 82 35 ef 00 00 01 01  08 0a 5a a2 7f cd 50 43   ..5..... ..Z...PC
0040  c1 5b 19 00 00 00 ef 38  40 01 00 00 00 00 00 6d   .[.....8 @......m
0050  79 73 71 6c 2d 62 69 6e  2e 30 30 31 35 31 36      ysql-bin .001516
</div>
</pre>
<div class="myt1">3. MySQL数据包分析</div>
<p>剥去TCP/IP等层（使用wireshark就可以了），剩下MySQL 包如下：</p>
<pre>
<div class="mycode">0040        19 00 00 00 ef 38  40 01 00 00 00 00 00 6d   .[.....8 @......m
0050  79 73 71 6c 2d 62 69 6e  2e 30 30 31 35 31 36      ysql-bin .001516
</div>
</pre>
<p>更具Semi-sync备库响应源码分析如下：</p>
<pre>
<div class="mycode">+============================+
| packetlength      0 : 4    | 对应的：19 00 00 00 表示包数据长度为0x19=25字节
+----------------------------+
| magic_num         4 : 1    | 对应的：ef 这是一个kPacketMagicNum，表示这是一个Semi-sync slave响应
+----------------------------+
| binlog_pos        5 : 4    | 对应的：38  40 01 00 Binlog Pos:0x14038 = 81976
+----------------------------+
| event_length      9 : 20   | 对应的：00 00 00 00 6d 79 73 71 6c .... 31 36 （mysql-bin.001516）
+----------------------------+
</div>
</pre>
<p>可以看出，改网络包，响应主库端的mysql-bin.001516中的偏移为81976的事务。</p>
<div class="myt1">4. 最后【更新2011-10-19】</div>
<p>通过tcpdump的网络包，我们可以看到毫秒（甚至微秒）级别数据包的传送情况。依据此，通常可以精确分析出Semi-sync在何时、何处出现超时。然后，可以继续分析为何出现超时。</p>
<p>That's all...  这篇枯燥吧，哈哈  </p>
<p><embed src="http://www.xiami.com/widget/0_1769845026/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/10/semy-sync-slave-protocol-slave-reply/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Percona-Server/MySQL响应时间统计</title>
		<link>http://www.orczhou.com/index.php/2011/09/thanks-percona-response-time-distribution/</link>
		<comments>http://www.orczhou.com/index.php/2011/09/thanks-percona-response-time-distribution/#comments</comments>
		<pubDate>Mon, 19 Sep 2011 13:02:57 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona MySQL]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3068</guid>
		<description><![CDATA[<p>在Percona的5.1.53和5.5.8版本，开始将RT的统计内置到MySQL Server端。Thanks, Percona.</p>
<p>Percona在提供了<a href="http://www.mysqlperformanceblog.com/2010/08/31/introducing-tcprstat-a-tcp-response-time-tool/">tcprstat工具</a>统计RT时间之后，很快就在Percona Server中集成了响应时间统计的功能。这里介绍一下该功能，各位看官如果在犹豫选择<a href="http://www.percona.com/software/percona-server/">Percona Server</a>还是<a href="http://dev.mysql.com/downloads/mysql/">MySQL Community Server</a>，这里给Percona Server加一个筹码。</p>
<p>"响应时间"（Response time，后面简称RT）在数据库应用中，特别是OLTP的场景，可以说非常重要，不过，MySQL官方版本中一直没有加上这个统计功能。最早，社区开始尝试tcmdump+perl脚本的方式查看RT，后来告警一点用<a href="http://ronaldbradford.com/blog/take-a-look-at-mk-query-digest-2009-10-08/">tcpdump+mk-query-digest</a>，再后来Ignacio Nin和Baron Schwartz完成了tcprstat。</p>
<p>在Percona的5.1.53和5.5.8版本，开始将RT的统计内置到MySQL Server端。</p>
<div class="myt1">1. 配置该功能</div>
<p>这个是功能默认是关闭的，可以通过设置参数query_response_time_stats=1打开这个功能，这是一个动态参数，所以在服务器上可以很方便的打开或者关闭这个功能。可以通过命令SHOW QUERY_RESPONSE_TIME查看响应时间统计。[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/09/thanks-percona-response-time-distribution/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>在Percona的5.1.53和5.5.8版本，开始将RT的统计内置到MySQL Server端。Thanks, Percona.</p>
<p>Percona在提供了<a href="http://www.mysqlperformanceblog.com/2010/08/31/introducing-tcprstat-a-tcp-response-time-tool/">tcprstat工具</a>统计RT时间之后，很快就在Percona Server中集成了响应时间统计的功能。这里介绍一下该功能，各位看官如果在犹豫选择<a href="http://www.percona.com/software/percona-server/">Percona Server</a>还是<a href="http://dev.mysql.com/downloads/mysql/">MySQL Community Server</a>，这里给Percona Server加一个筹码。</p>
<p>"响应时间"（Response time，后面简称RT）在数据库应用中，特别是OLTP的场景，可以说非常重要，不过，MySQL官方版本中一直没有加上这个统计功能。最早，社区开始尝试tcmdump+perl脚本的方式查看RT，后来告警一点用<a href="http://ronaldbradford.com/blog/take-a-look-at-mk-query-digest-2009-10-08/">tcpdump+mk-query-digest</a>，再后来Ignacio Nin和Baron Schwartz完成了tcprstat。</p>
<p>在Percona的5.1.53和5.5.8版本，开始将RT的统计内置到MySQL Server端。</p>
<div class="myt1">1. 配置该功能</div>
<p>这个是功能默认是关闭的，可以通过设置参数query_response_time_stats=1打开这个功能，这是一个动态参数，所以在服务器上可以很方便的打开或者关闭这个功能。可以通过命令SHOW QUERY_RESPONSE_TIME查看响应时间统计。<span id="more-3068"></span></p>
<div class="myt2">默认关闭状态：</div>
<pre>
<div class="mycode">SHOW QUERY_RESPONSE_TIME;
+----------------+---+----------------+
|                |   |                |
+----------------+---+----------------+
|       0.000001 | 0 |       0.000000 |
|       0.000010 | 0 |       0.000000 |
|       0.000100 | 0 |       0.000000 |
|       0.001000 | 0 |       0.000000 |
......
|  1000000.00000 | 0 |       0.000000 |
| TOO LONG       | 0 | TOO LONG       |
+----------------+---+----------------+</div>
</pre>
<div class="myt2">打开参数后：</div>
<pre>
<div class="mycode">set global query_response_time_stats=1;
Query OK, 0 rows affected (0.00 sec)

08:23:13>SHOW QUERY_RESPONSE_TIME;
+----------------+-------+----------------+
|                |       |                |
+----------------+-------+----------------+
|       0.000001 |  7982 |       0.000000 |
|       0.000010 | 13927 |       0.014511 |
|       0.000100 | 43811 |       1.553811 |
|       0.001000 |    29 |       0.007936 |
|       0.010000 |     1 |       0.001711 |
|       0.100000 |     0 |       0.000000 |
</div>
</pre>
<p>这里可以看到，响应时间小于0.000001<strong>秒</strong>的SQL有7982个，0.000001 &lt; RT &lt;  0.000010有13927个， 0.000010 &lt; RT &lt; 0.000100有43811  ...... 。这样整个系统的响应时间就清晰了。</p>
<div class="myt1">2. INFORMATION_SCHEMA.QUERY_RESPONSE_TIME</div>
<p>除了用命令SHOW QUERY_RESPONSE_TIME，还可以通过INFORMATION_SCHEMA里面的表QUERY_RESPONSE_TIME来查看MySQL的响应时间。</p>
<pre>
<div class="mycode">08:25:16>SELECT * from INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+----------------+--------+----------------+
| time           | count  | total          |
+----------------+--------+----------------+
|       0.000001 |  33824 |       0.000000 |
|       0.000010 |  59222 |       0.060457 |
|       0.000100 | 186003 |       6.659908 |
|       0.001000 |    117 |       0.025163 |
|       0.010000 |      8 |       0.014534 |</div>
</pre>
<p>使用INFORMATION_SCHEMA.QUERY_RESPONSE_TIME，就可以稍微定制一下输出结果了：</p>
<pre>
<div class="mycode">
SELECT time, CONCAT(ROUND(100*count/query_count,2),"%") as percent,count
FROM(
    SELECT
    	c.count,
    	c.time,
    	(
    	    SELECT SUM(a.count)
    	    FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a
    	    WHERE a.count != 0
    	) as query_count
    FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c
    WHERE c.count > 0
) d;
+----------------+---------+--------+
| time           | percent | count  |
+----------------+---------+--------+
|       0.000001 | 12.64%  |  81557 |
|       0.000010 | 20.69%  | 133440 |
|       0.000100 | 66.62%  | 429705 |
|       0.001000 | 0.05%   |    339 |
|       0.010000 | 0.00%   |     10 |
|    1000.000000 | 0.00%   |      1 |
+----------------+---------+--------+
</div>
</pre>
<div class="myt1">3. 高端一点的功能：定制化时间区间</div>
<p>默认的时间区间是：</p>
<p>(0; 10 ^ -6], (10 ^ -6; 10 ^ -5], (10 ^ -5; 10 ^ -4], ..., (10 ^ -1; 10 ^1], (10^1; 10^2]...(10^</p>
<p>你可以通过修改参数query_response_time_range_base来缩小时间区间，默认该参数是10，时间区间如上。</p>
<p>例如我们修个set global query_response_time_range_base=2; 则区间如下：</p>
<p>(0; 2 ^ -19], (2 ^ -19; 2 ^ -18], (2 ^ -18; 2 ^ -17], ..., (2 ^ -1; 2 ^1], (2 ^ 1; 2 ^ 2]...(2 ^</p>
<p>第一个区间总是最接近0.000001区间开始(2^19次方最接近)；最后一个区间是到最接近且小于10000000处结束。</p>
<p>具体的：</p>
<div class="mycode">set global query_response_time_range_base=2;<br />
flush QUERY_RESPONSE_TIME;<br />
SHOW QUERY_RESPONSE_TIME;<br />
|       0.000001 |  711 |       0.000000 |<br />
|       0.000003 | 1456 |       0.001456 |<br />
......<br />
|       0.125000 |    0 |       0.000000 |<br />
|       0.250000 |    0 |       0.000000 |<br />
|       0.500000 |    0 |       0.000000 |<br />
|       1.000000 |    0 |       0.000000 |<br />
|       2.000000 |    0 |       0.000000 |<br />
|       4.000000 |    0 |       0.000000 |<br />
|       8.000000 |    0 |       0.000000 |<br />
|      16.000000 |    0 |       0.000000 |<br />
......<br />
|  8388608.00000 |    0 |       0.000000 |<br />
| TOO LONG       |    0 | TOO LONG       |
</div>
<div class="myt1">一些注意事项</div>
<p>在备库上，只有打开了参数<a href="log_slow_slave_statements">log_slow_slave_statements</a>(这个参数也是Percona Server上特有的)时，slave sql线程的SQL才会被统计。</p>
<p>启动变量have_response_time_distribution，不能配置，该参数只表示该Server是否具有上述的RT统计功能。</p>
<p>设置了query_response_time_range_base，必须flush QUERY_RESPONSE_TIME后才生效。这里flush做两件事情，使得QUERY_RESPONSE_TIME生效，另外清空之前的统计结果。</p>
<p>累了，听首歌，扭扭脖子吧:)</p>
<p><script type="text/javascript" src="http://www.xiami.com/widget/player-single?uid=0&#038;sid=3599116&#038;mode=js"></script></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
<p>参考文献：</p>
<p>1. <a href="http://www.mysqlperformanceblog.com/2010/08/31/introducing-tcprstat-a-tcp-response-time-tool/">Introducing tcprstat, a TCP response time tool</a></p>
<p>2. <a href="http://www.percona.com/docs/wiki/tcprstat:start">The tcprstat User's Manual</a></p>
<p>3. <a href="http://www.megalinux.net/using-tcpdump-for-mysql-query-logging/">Using Tcpdump for MySQL query logging</a></p>
<p>4. <a href="http://www.mysqlperformanceblog.com/2011/04/18/how-to-use-tcpdump-on-very-busy-hosts/">How to use tcpdump on very busy hosts</a></p>
<p>5. <a href="http://ronaldbradford.com/blog/take-a-look-at-mk-query-digest-2009-10-08/">Take a look at mk-query-digest</a></p>
<p>6. <a href="http://www.percona.com/docs/wiki/percona-server:features:implementation_details:details_response_time_distribution">Implementation Details: Response Time Distribution</a></p>
<p>7. <a href="http://www.percona.com/docs/wiki/percona-server:features:response_time_distribution">Percona Software Documentation :Response Time Distribution</a></p>
<p>【附录】</p>
<p>既然上面读取INFORMATION_SCHEMA的SQL已经有些复杂了，那就不怕再复杂一些：</p>
<pre>
<div class="mycode">SELECT
    case TRIM(time)
    	when '0.000001' then '<  1us'
    	when '0.000010' then '< 10us'
    	when '0.000100' then '<100us'
    	when '0.001000' then '<  1ms'
    	when '0.010000' then '< 10ms'
    	when '0.100000' then '<100ms'
    	when '1.000000' then '<   1s'
    	when '10.000000' then '<  10s'
    	when '100.000000' then '<100s'
    	else '>100s'
    END as `RT area`,
    CONCAT(ROUND(100*count/query_count,2),"%") as percent,
    count
FROM(
    SELECT
    	c.count,
    	c.time,
    	(
    	    SELECT SUM(a.count)
    	    FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a
    	    WHERE a.count != 0
    	) as query_count
    FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c
    WHERE c.count > 0
) d;
+---------+---------+--------+
| RT area | percent | count  |
+---------+---------+--------+
| < 10us  | 41.92%  | 404409 |
| <100us  | 21.34%  | 205881 |
| <  1ms  | 35.20%  | 339574 |
| < 10ms  | 1.30%   |  12586 |
| <100ms  | 0.18%   |   1736 |
| <   1s  | 0.02%   |    160 |
| <  10s  | 0.04%   |    340 |
+---------+---------+--------+
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/09/thanks-percona-response-time-distribution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL半同步Semi-sync原理介绍【图说】</title>
		<link>http://www.orczhou.com/index.php/2011/07/why-and-how-mysql-5-5-semi-sync-replication/</link>
		<comments>http://www.orczhou.com/index.php/2011/07/why-and-how-mysql-5-5-semi-sync-replication/#comments</comments>
		<pubDate>Thu, 21 Jul 2011 15:18:11 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL5.5]]></category>
		<category><![CDATA[semi-sync]]></category>
		<category><![CDATA[semi-sync replication]]></category>
		<category><![CDATA[半同步]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3044</guid>
		<description><![CDATA[<p>上图先。</p>
<p><a href="http://www.flickr.com/photos/26825745@N06/5961167474/" title="Semi-sync-why by orczhou, on Flickr"><img src="http://farm7.static.flickr.com/6017/5961167474_cb1099962f.jpg" width="500" height="424" alt="Semi-sync-why"/></a></p>
<p>如果还不了解Semi-sync可以阅读（<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html">Manual</a> &#124; <a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">概述</a>）</p>
<div class="myt1">1. 优点</div>
<p><strong>当事务返回客户端成功后，则日志一定在至少两台主机上存在。</strong></p>
<p>MySQL在<a href="http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/">加载并开启</a>Semi-sync插件后，每一个事务需等待备库接收日志后才返回给客户端。如果做的是小事务，两台主机的延迟又较小，则Semi-sync可以实现在性能很小损失的情况下的零数据丢失。</p>
<div class="myt1">2. 缺点</div>
<p>完成单条事务增加了额外的等待延迟，延迟的大小取决于网络的好坏。</p>
<p>Semi-sync不是分布式事务，主库会在自己<strong>完成事务后</strong>，等待备库接收<strong>事务日志</strong>。</p>
<div class="myt1">3. 主机Crash时的处理</div>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/07/why-and-how-mysql-5-5-semi-sync-replication/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>上图先。</p>
<p><a href="http://www.flickr.com/photos/26825745@N06/5961167474/" title="Semi-sync-why by orczhou, on Flickr"><img src="http://farm7.static.flickr.com/6017/5961167474_cb1099962f.jpg" width="500" height="424" alt="Semi-sync-why"></a></p>
<p>如果还不了解Semi-sync可以阅读（<a href="http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html">Manual</a> | <a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">概述</a>）</p>
<div class="myt1">1. 优点</div>
<p><strong>当事务返回客户端成功后，则日志一定在至少两台主机上存在。</strong></p>
<p>MySQL在<a href="http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/">加载并开启</a>Semi-sync插件后，每一个事务需等待备库接收日志后才返回给客户端。如果做的是小事务，两台主机的延迟又较小，则Semi-sync可以实现在性能很小损失的情况下的零数据丢失。</p>
<div class="myt1">2. 缺点</div>
<p>完成单条事务增加了额外的等待延迟，延迟的大小取决于网络的好坏。</p>
<p>Semi-sync不是分布式事务，主库会在自己<strong>完成事务后</strong>，等待备库接收<strong>事务日志</strong>。</p>
<div class="myt1">3. 主机Crash时的处理</div>
<p><span id="more-3044"></span></p>
<p>备库Crash时，主库会在某次等待超时后，关闭Semi-sync的特性，降级为普通的异步复制，这种情况比较简单。</p>
<p>主库Crash后，那么可能存在一些事务已经在主库Commit，但是还没有传给任何备库，我们姑且称这类事务为"<strong>墙头事务</strong>"。"墙头事务"都是没有返回给客户端的，所以发起事务的客户端并不知道这个事务是否已经完成。</p>
<p>这时，如果客户端不做切换，只是<strong>等Crash的主库恢复后，继续在主库进行操作</strong>，客户端会发现前面的"墙头事务"都已经完成，可以继续进行后续的业务处理；另一种情况，<strong>如果客户端Failover到备库上</strong>，客户端会发现前面的“墙头事务”都没有成功，则需要重新做这些事务，然后继续进行后续的业务处理。</p>
<div class="myt1">4. 其他</div>
<p>可以做多个备库，任何一个备库接收完成日志后，主库就可以返回给客户端了。</p>
<p>网络传输在并发线程较多时，一次可能传输很多日志，事务的<strong>平均</strong>延迟会降低。</p>
<p>"墙头事务"在墙头上的时候，是可以被读取的，但是这些事务在上面Failover的场景下，是被认为没有完成的。</p>
<p>累了，听首歌，伸个懒腰吧:)</p>
<p><embed src="http://www.xiami.com/widget/0_381336/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/07/why-and-how-mysql-5-5-semi-sync-replication/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>攻壳机动队编年史</title>
		<link>http://www.orczhou.com/index.php/2011/07/stand-alone-complex-ghost-in-the-shell/</link>
		<comments>http://www.orczhou.com/index.php/2011/07/stand-alone-complex-ghost-in-the-shell/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 16:43:36 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[简单生活]]></category>
		<category><![CDATA[Ghost in the Shell]]></category>
		<category><![CDATA[Stand Alone Complex]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=3012</guid>
		<description><![CDATA[<p>很早从<a href="http://su27.org/">su27</a>那知道《攻壳机动队》，看了第一部后，就一发不可收拾，开始看第二部，看塔奇科马的日常，然后把几个剧场版和O.V.A也都下载下来看了。</p>
<p>《攻壳》一共有两部TV版，三部剧场版，两部TV特别篇和一部OVA，还有一个小TV系列《塔奇科马的日常》。看到<a href="http://www.douban.com/group/topic/4231949/">豆瓣上有一些朋友</a>不知道合适的观看顺序，这篇博客就是把银幕上《攻壳》的放映顺序都理一下，如果<strong>对科幻、动漫都感兴趣的人</strong>都可以看看。</p>
<p><a href="http://www.flickr.com/photos/26825745@N06/5901054917/" title="historyofgis by orczhou, on Flickr"><img src="http://farm7.static.flickr.com/6043/5901054917_d1e5d28e6a_z.jpg" width="640" height="225" alt="historyofgis"/></a></p>
<p>（<a href="http://www.flickr.com/photos/26825745@N06/5901054917/lightbox/">大图</a>）</p>
<p>下面是整个《攻壳》的编年史：</p>
<p>1989年4月22日，士郎正宗的《攻壳机动队》首次连载于<a href="http://zh.wikipedia.org/wiki/%E8%AC%9B%E8%AB%87%E7%A4%BE">讲谈社</a><a href="http://zh.wikipedia.org/wiki/%E9%9D%92%E5%B9%B4%E6%BC%AB%E7%95%AB">青年漫画月刊</a>《Young Magazine海贼版》；每三个月一话，总共12话（<a href="http://zh.wikipedia.org/wiki/%E6%94%BB%E5%A3%B3%E6%9C%BA%E5%8A%A8%E9%98%9F_(%E6%BC%AB%E7%94%BB)">参考</a>）<br />
[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/07/stand-alone-complex-ghost-in-the-shell/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>很早从<a href="http://su27.org/">su27</a>那知道《攻壳机动队》，看了第一部后，就一发不可收拾，开始看第二部，看塔奇科马的日常，然后把几个剧场版和O.V.A也都下载下来看了。</p>
<p>《攻壳》一共有两部TV版，三部剧场版，两部TV特别篇和一部OVA，还有一个小TV系列《塔奇科马的日常》。看到<a href="http://www.douban.com/group/topic/4231949/">豆瓣上有一些朋友</a>不知道合适的观看顺序，这篇博客就是把银幕上《攻壳》的放映顺序都理一下，如果<strong>对科幻、动漫都感兴趣的人</strong>都可以看看。</p>
<p><a href="http://www.flickr.com/photos/26825745@N06/5901054917/" title="historyofgis by orczhou, on Flickr"><img src="http://farm7.static.flickr.com/6043/5901054917_d1e5d28e6a_z.jpg" width="640" height="225" alt="historyofgis"></a></p>
<p>（<a href="http://www.flickr.com/photos/26825745@N06/5901054917/lightbox/">大图</a>）</p>
<p>下面是整个《攻壳》的编年史：</p>
<p>1989年4月22日，士郎正宗的《攻壳机动队》首次连载于<a href="http://zh.wikipedia.org/wiki/%E8%AC%9B%E8%AB%87%E7%A4%BE">讲谈社</a><a href="http://zh.wikipedia.org/wiki/%E9%9D%92%E5%B9%B4%E6%BC%AB%E7%95%AB">青年漫画月刊</a>《Young Magazine海贼版》；每三个月一话，总共12话（<a href="http://zh.wikipedia.org/wiki/%E6%94%BB%E5%A3%B3%E6%9C%BA%E5%8A%A8%E9%98%9F_(%E6%BC%AB%E7%94%BB)">参考</a>）<br />
<span id="more-3012"></span></p>
<p>1991年10月，第一次发行漫画单行本（<a href="http://zh.wikipedia.org/wiki/%E6%94%BB%E5%A3%B3%E6%9C%BA%E5%8A%A8%E9%98%9F_(%E6%BC%AB%E7%94%BB)">参考</a>）</p>
<p>1991年，还推出了Human-Error Processor系列，共四部，91、92、95、96分四年发表（<a href="http://zh.wikipedia.org/wiki/%E6%94%BB%E5%A3%B3%E6%9C%BA%E5%8A%A8%E9%98%9F1.5%EF%BC%9AHuman_Error_Processor">参考</a>）</p>
<p>1995年11月在日本上映了第一部剧场版《Ghost in the Shell》 （<a href="http://www.productionig.com/contents/works_sp/16_/index.html">参考</a>）</p>
<p>2000年，又推出了漫画《Ghost in the Shell 2: Man-Machine Interface》（<a href="http://section9.seezone.net/">参考</a>）</p>
<p>2002年，第一部TV版《Ghost in the Shell:Stand Alone Complex》开始上映，在日本播放时间从02年10一直到03年10月结束（<a href="http://www.productionig.com/contents/works_sp/03_/index.html">参考</a>）</p>
<p>2004年第二部《Ghost in the Shell: S.A.C. 2nd GIG》，在日本播放时间从04年1月到05年1月结束（<a href="http://www.productionig.com/contents/works_sp/02_/index.html">参考</a>）</p>
<p>2004年3月还上映第二个剧场版《Innocence: Ghost in the Shell 2》</p>
<p>2005年10月在日本上映了第一个<strong>TV特别篇</strong>《Ghost in the Shell: Stand Alone Complex The Laughing Man》</p>
<p>2006年1月上映了第二个<strong>TV特别篇</strong>《Ghost in the Shell: Stand Alone Complex Individual Eleven》</p>
<p>2006年11月上映了第一个<strong>OVA</strong>《Ghost in the Shell:Stand Alone ComplexSolid State Society》</p>
<p>2008年7月，上映了剧场版《Ghost in the Shell 2.0》，这部是翻拍95年的那部《Ghost in the Shell》，剧情都一样，但是时隔13年动画技术有了很大的变化，所以《Ghost in the Shell 2.0》相比来说，非常精致</p>
<p>2011年3月26日，3D版的《Ghost in the Shell:Stand Alone Complex Solid State Society 3D》这也是一个翻拍，这次买点是3D，国内目前只能下载到一个高清预告片</p>
<p>还有一个短片系列《塔奇科马的日常》，是附随两个TV版的DVD发行的。目的是显而易见的...</p>
<p>........................目前就这些了........................</p>
<p>最后，听首歌吧：</p>
<p><embed src="http://www.xiami.com/widget/0_3339679/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent"></embed></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/07/stand-alone-complex-ghost-in-the-shell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL 5.5 Semi-sync Replication安装配置、参数说明</title>
		<link>http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/</link>
		<comments>http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 05:30:52 +0000</pubDate>
		<dc:creator>orczhou</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL5.5]]></category>
		<category><![CDATA[semi-sync]]></category>
		<category><![CDATA[semi-sync replication]]></category>
		<category><![CDATA[半同步]]></category>

		<guid isPermaLink="false">http://www.orczhou.com/?p=2950</guid>
		<description><![CDATA[<p>从09年12月份MySQL5.5的<a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">第一个Release</a>，再到去年<a href="http://blogs.oracle.com/MySQL/entry/mysql_55_is_ga">12月的第一个GA</a>，MySQL5.5平均<a href="http://dev.mysql.com/doc/refman/5.5/en/news-5-5-x.html">一月一个小版本号的速度</a>在默默更新。该版本最重要的特性目前仍是Semi-sync Replication，之前做了一个<a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">概述</a>，这里将继续介绍如何安装、配置Semi-sync，后续还将继续介绍其性能和一些基本的代码实现。</p>
<div class="myt1">1. Semi-sync Repication的历史</div>
<p>Semi-sync最早是由Google实现的一个补丁，代码主要由<a href="http://forge.mysql.com/wiki/ReplicationFeatures/SemiSyncReplication">Mark Callaghan、Wei Li</a>（@Google）等人贡献。Google原本是将<a href="http://code.google.com/p/google-mysql-tools/wiki/SemiSyncReplication">需求提给Hekki</a>的，但是后来等不及就自己实现了......。(现在Mark Callaghan已跳到Facebook，除了Google，<a href="http://www.linkedin.com/pub/mark-callaghan/2/249/894">他曾经还在Informix、Oracle工作过</a>)</p>
<p>在5.5之后由<a href="http://forge.mysql.com/wiki/ReplicationTeam">MySQL Replication Team</a>按照Plugin的方式将代码移植过来，并将Semi-sync独立成MySQL的一个插件，主要代码移植者是Zhenxing He（<a href="http://forge.mysql.com/wiki/ReplicationTeam">参考</a>）。</p>
<div class="myt1">2. 安装、配置Semi-sync Replication</div>
<p>在两台主机上<a href="http://www.orczhou.com/index.php/2011/06/compile-and-install-mysql-5-5-from-source/">安装好</a>MySQL5.5，编译好的插件在目录CMAKE_INSTALL_PREFIX/lib/plugin下（默认是/usr/local/mysql/lib/plugin）。例如这里编译是指定CMAKE_INSTALL_PREFIX为/home/mysql/mysql，则有：</p>
<div class="mycode">$pwd<br />
/home/mysql/mysql/lib/plugin<br />
$ls -a semisync_*<br />
semisync_master.so  semisync_slave.so</div>
<p>在主库初次启动时，执行如下语句加载semisync_master插件：</p>
<div class="mycode">mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';</div>
<p>备库上则加载semisync_slave插件：</p>
<div class="mycode">mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';</div>
<p>[......]</p><p class='read-more'><a href='http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/'>继续阅读</a></p>]]></description>
			<content:encoded><![CDATA[<p>从09年12月份MySQL5.5的<a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">第一个Release</a>，再到去年<a href="http://blogs.oracle.com/MySQL/entry/mysql_55_is_ga">12月的第一个GA</a>，MySQL5.5平均<a href="http://dev.mysql.com/doc/refman/5.5/en/news-5-5-x.html">一月一个小版本号的速度</a>在默默更新。该版本最重要的特性目前仍是Semi-sync Replication，之前做了一个<a href="http://www.orczhou.com/index.php/2009/12/mysql-55-semi-sync-replication/">概述</a>，这里将继续介绍如何安装、配置Semi-sync，后续还将继续介绍其性能和一些基本的代码实现。</p>
<div class="myt1">1. Semi-sync Repication的历史</div>
<p>Semi-sync最早是由Google实现的一个补丁，代码主要由<a href="http://forge.mysql.com/wiki/ReplicationFeatures/SemiSyncReplication">Mark Callaghan、Wei Li</a>（@Google）等人贡献。Google原本是将<a href="http://code.google.com/p/google-mysql-tools/wiki/SemiSyncReplication">需求提给Hekki</a>的，但是后来等不及就自己实现了......。(现在Mark Callaghan已跳到Facebook，除了Google，<a href="http://www.linkedin.com/pub/mark-callaghan/2/249/894">他曾经还在Informix、Oracle工作过</a>)</p>
<p>在5.5之后由<a href="http://forge.mysql.com/wiki/ReplicationTeam">MySQL Replication Team</a>按照Plugin的方式将代码移植过来，并将Semi-sync独立成MySQL的一个插件，主要代码移植者是Zhenxing He（<a href="http://forge.mysql.com/wiki/ReplicationTeam">参考</a>）。</p>
<div class="myt1">2. 安装、配置Semi-sync Replication</div>
<p>在两台主机上<a href="http://www.orczhou.com/index.php/2011/06/compile-and-install-mysql-5-5-from-source/">安装好</a>MySQL5.5，编译好的插件在目录CMAKE_INSTALL_PREFIX/lib/plugin下（默认是/usr/local/mysql/lib/plugin）。例如这里编译是指定CMAKE_INSTALL_PREFIX为/home/mysql/mysql，则有：</p>
<div class="mycode">$pwd<br />
/home/mysql/mysql/lib/plugin<br />
$ls -a semisync_*<br />
semisync_master.so  semisync_slave.so</div>
<p>在主库初次启动时，执行如下语句加载semisync_master插件：</p>
<div class="mycode">mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';</div>
<p>备库上则加载semisync_slave插件：</p>
<div class="mycode">mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';</div>
<p><span id="more-2950"></span></p>
<p>在初次加载插件后，MySQL会将该插件记录到系统表mysql.plugin中，下次启动时系统则会自动加载该插件了，无需再次执行上面的命令。</p>
<p>另外，主备库的配置文件my.cnf还需要新增如下记录来打开semi-sync。主库上，新增如下参数：</p>
<div class="mycode">$vi my.cnf<br />
...<br />
rpl_semi_sync_master_enabled=1<br />
rpl_semi_sync_master_timeout=1000<br />
...</div>
<p>备库上新增：</p>
<div class="mycode">$vi my.cnf<br />
...<br />
rpl_semi_sync_slave_enabled=1<br />
...</div>
<p>那么主备在启动后，且slave线程开始dump主库的日志后，Semi-sync Replication就会开启，上面的配置(rpl_semi_sync_master_timeout=1000)表示主库在某次事务中，如果等待时间超过1000毫秒，那么则降级为普通模式，不再等待备库。如果主库再次探测到，备库恢复了，则会自动再次回到Semi-sync状态。</p>
<div class="myt1">3. 其他参数</div>
<p>Semi-sync的<a href="http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_rpl_semi_sync_master_timeout">配置参数不多</a>，按照上面配置就可以了，其他少数几个参数默认即可。</p>
<p>主库上的其他参数：</p>
<pre>
<div class="mycode">mysql> show variables like "%rpl_semi%";
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled       | ON    |
| rpl_semi_sync_master_timeout       | 1000  |
| rpl_semi_sync_master_trace_level   | 32    |
| rpl_semi_sync_master_wait_no_slave | ON    |
+------------------------------------+-------+
</div>
</pre>
<p>备库上有：</p>
<pre>
<div class="mycode">mysql> show variables like "%rpl_semi%";
+------------------------------------+-------+
| Variable_name                      | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_wait_no_slave | ON    |
| rpl_semi_sync_slave_enabled        | ON    |
| rpl_semi_sync_slave_trace_level    | 32    |
+------------------------------------+-------+
</div>
</pre>
<p>rpl_semi_sync_master_trace_level和rpl_semi_sync_slave_trace_level是可以组合（求或）的参数，可以是下面值的组合：</p>
<blockquote><p>1 = general level (for example, time function failures)<br />
16 = detail level (more verbose information)<br />
32 = net wait level (more information about network waits)<br />
64 = function level (information about function entry and exit)</p></blockquote>
<div class="myt1">4. 运行状态查看</div>
<p>备库上很简单，只有一个状态值，查看备库是否开启了Semi-sync功能：</p>
<pre>
<div class="mycode">show status like "%rpl_semi%";
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+</div>
</pre>
<p>主库需要关注的状态值则比较多</p>
<pre>
<div class="mycode">mysql> show status like "%rpl_semi%";
+--------------------------------------------+---------------+
| Variable_name                              | Value         |
+--------------------------------------------+---------------+
| Rpl_semi_sync_master_clients               | 1             |# 有多少个Semi-sync的备库
| Rpl_semi_sync_master_net_avg_wait_time     | 732           |# 事务提交后，等待备库响应的平均时间
| Rpl_semi_sync_master_net_wait_time         | 1042785285    |# 等待网络响应的总次数
| Rpl_semi_sync_master_net_waits             | 1423323       |# 总的网络等待时间
| Rpl_semi_sync_master_no_times              | 0             |# 一共有几次从Semi-sync跌回普通状态
| Rpl_semi_sync_master_no_tx                 | 0             |# 备库未及时响应的事务数
| Rpl_semi_sync_master_status                | ON            |# 主库上Semi-sync是否正常开启
| Rpl_semi_sync_master_timefunc_failures     | 0             |# 时间函数未正常工作的次数
| Rpl_semi_sync_master_tx_avg_wait_time      | 29059         |# 开启Semi-sync，事务返回需要等待的平均时间
| Rpl_semi_sync_master_tx_wait_time          | 8164966680929 |# 事务等待备库响应的总时间
| Rpl_semi_sync_master_tx_waits              | 280974820     |# 事务等待备库响应的总次数
| Rpl_semi_sync_master_wait_pos_backtraverse | 5499398       |# 改变当前等待最小二进制日志的次数
| Rpl_semi_sync_master_wait_sessions         | 230           |# 当前有几个线程在等备库响应
| Rpl_semi_sync_master_yes_tx                | 16801244      |# Semi-sync模式下，成功的事务数
+--------------------------------------------+---------------+</div>
</pre>
<p>上面比较重要的状态值有：</p>
<p>Rpl_semi_sync_master_tx_avg_wait_time：事务因开启Semi_sync，<strong>平均</strong>需要额外等待的时间</p>
<p>Rpl_semi_sync_master_net_avg_wait_time：事务进入等待队列后，到网络平均等待时间</p>
<p>依据上面两个状态值可以知道，Semi-sync的网络消耗有多大，给某个事务带来的额外的消耗有多大。</p>
<p>Rpl_semi_sync_master_status 则表示当前Semi-sync是否正常工作。</p>
<p>从Rpl_semi_sync_master_no_times变量，可以知道一段时间内，Semi-sync是否有超时失败过，该计数器则记录了这样的失败次数。</p>
<p>比较难理解参数有：</p>
<p><a href="http://dev.mysql.com/doc/refman/5.5/en/server-status-variables.html#statvar_Rpl_semi_sync_master_wait_pos_backtraverse">Rpl_semi_sync_master_wait_pos_backtraverse</a>：这个稍微难理解一点，不过该参数并不重要。</p>
<div class="myt1">5. 关于Rpl_semi_sync_master_wait_pos_backtraverse</div>
<p>花了一些时间弄明白这个变量，继续证实了这个变量确实不重要。</p>
<p>在semisync_master中，维护了这样的两个变量wait_file_name_和wait_file_pos_，当主库上多个事务都在等待备库的响应时，这两个变量记录了所有等待中，最小的那一个Binlog位置。如果这时，一个新的事务加入等待，并且该事务需要等待的Binlog比wait_file_name_和wait_file_pos_还小的话，则更新这两个值，并将Rpl_semi_sync_master_wait_pos_backtraverse值自增一次。</p>
<p>上面的解释参考如下代码段（semisync_master.cc）：</p>
<pre>
<div class="mycode">int cmp = ActiveTranx::compare(trx_wait_binlog_name, trx_wait_binlog_pos,
                               wait_file_name_, wait_file_pos_);
if (cmp <= 0)
{
  /* This thd has a lower position, let's update the minimum info. */
  strcpy(wait_file_name_, trx_wait_binlog_name);
  wait_file_pos_ = trx_wait_binlog_pos;

  rpl_semi_sync_master_wait_pos_backtraverse++;
  if (trace_level_ &#038; kTraceDetail)
    sql_print_information("%s: move back wait position (%s, %lu),",
                          kWho, wait_file_name_, (unsigned long)wait_file_pos_);
}</div>
</pre>
<p>累了，听首歌，伸个懒腰吧:)</p>
<p><script type="text/javascript" src="http://www.xiami.com/widget/player-single?uid=318706&#038;sid=128281&#038;mode=js"></script></p>
<p>广告：<a href="http://www.orczhou.com/index.php/projects/we-are-hunting-mysql-hacker/">我们寻找靠谱的人</a> | <a href="http://www.orczhou.com/index.php/wish-list/">感谢作者</a></p>
<p>参考文献：</p>
<p>1. <a href="http://forge.mysql.com/wiki/ReplicationFeatures/SemiSyncReplication">ReplicationFeatures/SemiSyncReplication</a></p>
<p>2. <a href="http://code.google.com/p/google-mysql-tools/wiki/SemiSyncReplication">SemiSync Replication of Google-mysql-tool</a></p>
<p>3. <a href="http://code.google.com/p/google-mysql-tools/wiki/SemiSyncReplicationDesign">SemiSyncReplicationDesign</a></p>
<p>4. <a href="http://forge.mysql.com/wiki/ReplicationTeam">ReplicationTeam</a></p>
<p>5. <a href="http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html">MySQL Manual Semisynchronous Replication</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.orczhou.com/index.php/2011/06/mysql-5-5-semi-sync-replication-setup-config/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

