<?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>idea&#039;s blog &#187; 高性能Web架构</title>
	<atom:link href="http://www.ideawu.net/blog/category/high-performance/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ideawu.net/blog</link>
	<description>网络服务器架构, Linux C/C++服务器端开发, TCP/IP网络协议, PHP Web后端和Web前端开发, 网站架构.</description>
	<lastBuildDate>Wed, 08 Feb 2012 10:02:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MySQL&#8221;海量数据&#8221;查询性能分析</title>
		<link>http://www.ideawu.net/blog/archives/590.html</link>
		<comments>http://www.ideawu.net/blog/archives/590.html#comments</comments>
		<pubDate>Sat, 21 May 2011 02:18:05 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[高性能Web架构]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=590</guid>
		<description><![CDATA[<p>最近做了一次<a href="http://www.ideawu.net/blog/tag/mysql">MySQL</a>所谓的&#8221;海量数据&#8221;查询性能分析.</p>
<h3>表结构</h3>
<table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0"	width="98%" style="font-family: arial; font-size: 13px; border-collapse: collapse;">
<tr style="background: #bbb">
<td><b>dt</b></td>
<td><b>dt2</b></td>
<td><b>dt3</b></td>
<td><b>it</b></td>
<td><b>it2</b></td>
<td><b>it3</b></td>
<td><b></b></td>
</tr>
<tr>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>int PK</td>
</tr>
<tr>
<td></td>
<td></td>
<td><b>ext1</b></td>
<td></td>
<td></td>
<td><b>ext1</b></td>
<td>varchar(256)</td>
</tr>
<tr>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>int/datetime KEY</td>
</tr>
<tr>
<td></td>
<td><b>ext2</b></td>
<td><b>ext2</b></td>
<td></td>
<td><b>ext2</b></td>
<td><b>ext2</b></td>
<td>varchar(128)</td>
</tr>
</table>
<p>说明, MyISAM引擎, dt表示时间字段使用datetime类型, it表示时间字段使用int类型. </p>
<h3>初始数据</h3>
<p>首先生成100K个UNIX时间戳(int), 然后随机选取10M次, 每一次往6个表里插入一条记录(当time字段是datetime类型时, 做类型转换). 所以每一个表都有10M条记录. ext1和ext2字段会用随机的字符串填充.</p>
<p><span id="more-590"></span></p>
<h3>SQL查询</h3>
<p>使用的查询SQL语句如: </p>
<pre>
select SQL_NO_CACHE count(*) from it where time&gt;10000;
select SQL_NO_CACHE count(*) from dt where time&gt;from_unixtime(10000);
select SQL_NO_CACHE * from it where time&gt;10000 order by time limit 1;
select SQL_NO_CACHE * from it use key(PRIMARY) where time&gt;10000 order by id limit 1;
</pre>
<p>SQL_NO_CACHE用于消除查询结果缓存的影响. use key用于指定查询时使用的索引. 统计每一条SQL的执行时间(单位s)和满足WHERE条件的记录总数(total), it-tm表示在dt表上执行SQL的耗时, 并explain得到key和extra, 结果如下.</p>
<table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="98%" style="font-family: arial; font-size: 13px; border-collapse: collapse;">
<tr style="background: #bbb">
<td><b>where</b></td>
<td><b>total</b></td>
<td><b>select</b></td>
<td><b>orderby</b></td>
<td><b>key</b></td>
<td><b>it-tm</b></td>
<td><b>dt-tm</b></td>
<td><b>it2-tm</b></td>
<td><b>dt2-tm</b></td>
<td><b>it3-tm</b></td>
<td><b>dt3-tm</b></td>
<td><b>extra</b></td>
</tr>
<tr>
<td>time&gt;10000</td>
<td>8999050</td>
<td>count(*)</td>
<td></td>
<td>time</td>
<td>3.52</td>
<td>4.28</td>
<td>3.74</td>
<td>4.49</td>
<td>3.53</td>
<td>4.47</td>
<td>where; index</td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td>time</td>
<td>3.44</td>
<td>4.00</td>
<td>3.69</td>
<td>4.36</td>
<td>3.56</td>
<td>4.26</td>
<td>where; index</td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td>NULL</td>
<td><b>1.44</b></td>
<td><b>1.92</b></td>
<td>4.30</td>
<td>4.60</td>
<td>4.79</td>
<td>4.98</td>
<td>where</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td>time</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>where</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td>time</td>
<td><b>14.81</b></td>
<td><b>15.38</b></td>
<td><b>19.37</b></td>
<td><b>20.30</b></td>
<td><b>20.94</b></td>
<td><b>21.42</b></td>
<td>where; filesort</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td>PK</td>
<td>0.00</td>
<td>0.03</td>
<td>0.00</td>
<td>0.02</td>
<td>0.00</td>
<td>0.04</td>
<td>where</td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;50000</td>
<td>4987990</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>1.90</td>
<td>2.36</td>
<td>2.02</td>
<td>2.41</td>
<td>1.99</td>
<td>2.42</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>1.90</td>
<td>2.23</td>
<td>2.01</td>
<td>2.32</td>
<td>1.96</td>
<td>2.29</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td>1.48</td>
<td>1.91</td>
<td>4.25</td>
<td>4.61</td>
<td>4.80</td>
<td>5.12</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>8.15</td>
<td>8.77</td>
<td>10.74</td>
<td>11.36</td>
<td>11.59</td>
<td>11.79</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;80000</td>
<td>1991982</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>0.76</td>
<td>0.95</td>
<td>0.83</td>
<td>0.98</td>
<td>0.80</td>
<td>1.00</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>0.77</td>
<td>0.91</td>
<td>0.81</td>
<td>0.91</td>
<td>0.83</td>
<td>0.92</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td><b>1.38</b></td>
<td><b>1.86</b></td>
<td>4.17</td>
<td>4.49</td>
<td>4.71</td>
<td>5.02</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>3.26</td>
<td>3.44</td>
<td>4.26</td>
<td>4.51</td>
<td>4.56</td>
<td>4.76</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;99900</td>
<td>10871</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.01</td>
<td>0.01</td>
<td>0.00</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>0.01</td>
<td>0.01</td>
<td>0.01</td>
<td>0.00</td>
<td>0.01</td>
<td>0.01</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td>0.01</td>
<td>0.01</td>
<td>0.02</td>
<td>0.03</td>
<td>0.02</td>
<td>0.02</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.02</td>
<td>0.02</td>
<td>0.03</td>
<td>0.03</td>
<td>0.03</td>
<td>0.03</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
</table>
<h3>分析和结论</h3>
<p>count(*), count(time)和count(id)的对比. 结果有较大变化. 当表的字段只有2个且查询条件较宽松(即符合条件的记录数较多)时, count(id)比count(*)快很多, 但是, 当表中还有其它的字段时, count(id)反而更慢了. 虽然id是主键, time是索引列, 但是select count(id) where time并没有用到索引, 而是进行<b>全表扫描</b>. 当对count(*)进行ignore key(time)时, 查询时间和count(id)相同. <b>证明当结果集较大时索引导致查询变慢, </b>应该是全表扫描进行的是连续的磁盘IO和内存操作, 而使用索引是进行随机的磁盘IO和内存操作, 并且MyISAM存储索引的BTree结构占用更多的空间. 当WHERE条件约束更严格, total的值小到一定程度时, 全表扫描比使用索引慢, 因为索引极大减少了磁盘IO和内存操作.</p>
<p>排序字段和索引的使用. 当有排序且LIMIT(偏移为0)时, <b>如果查询时使用的索引不是排序字段的索引, 那么速度非常慢</b>. 当偏移不为0时, 如果使用排序列的索引, 要考虑偏移可能导致扫描的记录数, 所以应该根据情况选取合适的索引.</p>
<p><b>判断符合条件的记录是否存在, 使用select * limit 1速度要比select count(*)计数快得多</b>.</p>
<p>时间字段类型的选择. int比datetime快, 但差距不是很明显. </p>
<p>无论如何, 条件限制得越严格, 查询就会越快.</p>
<p>另外, 根据随机id更新时, 大约能达到5K行/s.</p>
<p><strong>列的先后顺序对查询性能的影响也非常大.</strong></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/133.html' rel='bookmark' title='Permanent Link: 写一个对搜索引擎友好的文章SEO分页类'>写一个对搜索引擎友好的文章SEO分页类</a></li>
<li><a href='http://www.ideawu.net/blog/archives/417.html' rel='bookmark' title='Permanent Link: MySQL 建立外键约束'>MySQL 建立外键约束</a></li>
<li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/590.html" title="MySQL&#8221;海量数据&#8221;查询性能分析">MySQL&#8221;海量数据&#8221;查询性能分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>最近做了一次<a href="http://www.ideawu.net/blog/tag/mysql">MySQL</a>所谓的&#8221;海量数据&#8221;查询性能分析.</p>
<h3>表结构</h3>
<table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0"	width="98%" style="font-family: arial; font-size: 13px; border-collapse: collapse;">
<tr style="background: #bbb">
<td><b>dt</b></td>
<td><b>dt2</b></td>
<td><b>dt3</b></td>
<td><b>it</b></td>
<td><b>it2</b></td>
<td><b>it3</b></td>
<td><b></b></td>
</tr>
<tr>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>id</td>
<td>int PK</td>
</tr>
<tr>
<td></td>
<td></td>
<td><b>ext1</b></td>
<td></td>
<td></td>
<td><b>ext1</b></td>
<td>varchar(256)</td>
</tr>
<tr>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>time</td>
<td>int/datetime KEY</td>
</tr>
<tr>
<td></td>
<td><b>ext2</b></td>
<td><b>ext2</b></td>
<td></td>
<td><b>ext2</b></td>
<td><b>ext2</b></td>
<td>varchar(128)</td>
</tr>
</table>
<p>说明, MyISAM引擎, dt表示时间字段使用datetime类型, it表示时间字段使用int类型. </p>
<h3>初始数据</h3>
<p>首先生成100K个UNIX时间戳(int), 然后随机选取10M次, 每一次往6个表里插入一条记录(当time字段是datetime类型时, 做类型转换). 所以每一个表都有10M条记录. ext1和ext2字段会用随机的字符串填充.</p>
<p><span id="more-590"></span></p>
<h3>SQL查询</h3>
<p>使用的查询SQL语句如: </p>
<pre>
select SQL_NO_CACHE count(*) from it where time&gt;10000;
select SQL_NO_CACHE count(*) from dt where time&gt;from_unixtime(10000);
select SQL_NO_CACHE * from it where time&gt;10000 order by time limit 1;
select SQL_NO_CACHE * from it use key(PRIMARY) where time&gt;10000 order by id limit 1;
</pre>
<p>SQL_NO_CACHE用于消除查询结果缓存的影响. use key用于指定查询时使用的索引. 统计每一条SQL的执行时间(单位s)和满足WHERE条件的记录总数(total), it-tm表示在dt表上执行SQL的耗时, 并explain得到key和extra, 结果如下.</p>
<table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" width="98%" style="font-family: arial; font-size: 13px; border-collapse: collapse;">
<tr style="background: #bbb">
<td><b>where</b></td>
<td><b>total</b></td>
<td><b>select</b></td>
<td><b>orderby</b></td>
<td><b>key</b></td>
<td><b>it-tm</b></td>
<td><b>dt-tm</b></td>
<td><b>it2-tm</b></td>
<td><b>dt2-tm</b></td>
<td><b>it3-tm</b></td>
<td><b>dt3-tm</b></td>
<td><b>extra</b></td>
</tr>
<tr>
<td>time&gt;10000</td>
<td>8999050</td>
<td>count(*)</td>
<td></td>
<td>time</td>
<td>3.52</td>
<td>4.28</td>
<td>3.74</td>
<td>4.49</td>
<td>3.53</td>
<td>4.47</td>
<td>where; index</td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td>time</td>
<td>3.44</td>
<td>4.00</td>
<td>3.69</td>
<td>4.36</td>
<td>3.56</td>
<td>4.26</td>
<td>where; index</td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td>NULL</td>
<td><b>1.44</b></td>
<td><b>1.92</b></td>
<td>4.30</td>
<td>4.60</td>
<td>4.79</td>
<td>4.98</td>
<td>where</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td>time</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>where</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td>time</td>
<td><b>14.81</b></td>
<td><b>15.38</b></td>
<td><b>19.37</b></td>
<td><b>20.30</b></td>
<td><b>20.94</b></td>
<td><b>21.42</b></td>
<td>where; filesort</td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td>PK</td>
<td>0.00</td>
<td>0.03</td>
<td>0.00</td>
<td>0.02</td>
<td>0.00</td>
<td>0.04</td>
<td>where</td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;50000</td>
<td>4987990</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>1.90</td>
<td>2.36</td>
<td>2.02</td>
<td>2.41</td>
<td>1.99</td>
<td>2.42</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>1.90</td>
<td>2.23</td>
<td>2.01</td>
<td>2.32</td>
<td>1.96</td>
<td>2.29</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td>1.48</td>
<td>1.91</td>
<td>4.25</td>
<td>4.61</td>
<td>4.80</td>
<td>5.12</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>8.15</td>
<td>8.77</td>
<td>10.74</td>
<td>11.36</td>
<td>11.59</td>
<td>11.79</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;80000</td>
<td>1991982</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>0.76</td>
<td>0.95</td>
<td>0.83</td>
<td>0.98</td>
<td>0.80</td>
<td>1.00</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>0.77</td>
<td>0.91</td>
<td>0.81</td>
<td>0.91</td>
<td>0.83</td>
<td>0.92</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td><b>1.38</b></td>
<td><b>1.86</b></td>
<td>4.17</td>
<td>4.49</td>
<td>4.71</td>
<td>5.02</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>3.26</td>
<td>3.44</td>
<td>4.26</td>
<td>4.51</td>
<td>4.56</td>
<td>4.76</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #eee">
<td>&nbsp;</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>time&gt;99900</td>
<td>10871</td>
<td>count(*)</td>
<td></td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.01</td>
<td>0.01</td>
<td>0.00</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(time)</td>
<td></td>
<td></td>
<td>0.01</td>
<td>0.01</td>
<td>0.01</td>
<td>0.00</td>
<td>0.01</td>
<td>0.01</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>count(id)</td>
<td></td>
<td></td>
<td>0.01</td>
<td>0.01</td>
<td>0.02</td>
<td>0.03</td>
<td>0.02</td>
<td>0.02</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>time</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.02</td>
<td>0.02</td>
<td>0.03</td>
<td>0.03</td>
<td>0.03</td>
<td>0.03</td>
<td></td>
</tr>
<tr style="background: #ff9">
<td></td>
<td></td>
<td>*</td>
<td>id</td>
<td></td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td>0.00</td>
<td></td>
</tr>
</table>
<h3>分析和结论</h3>
<p>count(*), count(time)和count(id)的对比. 结果有较大变化. 当表的字段只有2个且查询条件较宽松(即符合条件的记录数较多)时, count(id)比count(*)快很多, 但是, 当表中还有其它的字段时, count(id)反而更慢了. 虽然id是主键, time是索引列, 但是select count(id) where time并没有用到索引, 而是进行<b>全表扫描</b>. 当对count(*)进行ignore key(time)时, 查询时间和count(id)相同. <b>证明当结果集较大时索引导致查询变慢, </b>应该是全表扫描进行的是连续的磁盘IO和内存操作, 而使用索引是进行随机的磁盘IO和内存操作, 并且MyISAM存储索引的BTree结构占用更多的空间. 当WHERE条件约束更严格, total的值小到一定程度时, 全表扫描比使用索引慢, 因为索引极大减少了磁盘IO和内存操作.</p>
<p>排序字段和索引的使用. 当有排序且LIMIT(偏移为0)时, <b>如果查询时使用的索引不是排序字段的索引, 那么速度非常慢</b>. 当偏移不为0时, 如果使用排序列的索引, 要考虑偏移可能导致扫描的记录数, 所以应该根据情况选取合适的索引.</p>
<p><b>判断符合条件的记录是否存在, 使用select * limit 1速度要比select count(*)计数快得多</b>.</p>
<p>时间字段类型的选择. int比datetime快, 但差距不是很明显. </p>
<p>无论如何, 条件限制得越严格, 查询就会越快.</p>
<p>另外, 根据随机id更新时, 大约能达到5K行/s.</p>
<p><strong>列的先后顺序对查询性能的影响也非常大.</strong></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/133.html' rel='bookmark' title='Permanent Link: 写一个对搜索引擎友好的文章SEO分页类'>写一个对搜索引擎友好的文章SEO分页类</a></li>
<li><a href='http://www.ideawu.net/blog/archives/417.html' rel='bookmark' title='Permanent Link: MySQL 建立外键约束'>MySQL 建立外键约束</a></li>
<li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/590.html" title="MySQL&#8221;海量数据&#8221;查询性能分析">MySQL&#8221;海量数据&#8221;查询性能分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/590.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>高性能并发Web服务器实现核心内幕</title>
		<link>http://www.ideawu.net/blog/archives/589.html</link>
		<comments>http://www.ideawu.net/blog/archives/589.html#comments</comments>
		<pubDate>Fri, 29 Apr 2011 10:06:54 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/589.html</guid>
		<description><![CDATA[<p>今天, 和部门的同事一起分享了Web服务器的核心内幕, 把PPT奉上, 大家喜欢可以下载. 本PPT的出发点和许多所谓的XX源码分析非常不同.</p>
<div style="width:425px" id="__ss_7775049"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ideawu/web-7775049" title="高性能并发Web服务器实现核心内幕">高性能并发Web服务器实现核心内幕</a></strong> <object id="__sse7775049" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=web-110429050116-phpapp02&#038;rel=0&#038;stripped_title=web-7775049&#038;userName=ideawu" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse7775049" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=web-110429050116-phpapp02&#038;rel=0&#038;stripped_title=web-7775049&#038;userName=ideawu" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ideawu">ideawu</a> </div>
</p></div>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/364.html' rel='bookmark' title='Permanent Link: [不会停止]idea&#8217;s blog 即将停止了&#8230;'>[不会停止]idea&#8217;s blog 即将停止了&#8230;</a></li>
<li><a href='http://www.ideawu.net/blog/archives/355.html' rel='bookmark' title='Permanent Link: 朋友在中关村买华硕笔记本被骗'>朋友在中关村买华硕笔记本被骗</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/589.html" title="高性能并发Web服务器实现核心内幕">高性能并发Web服务器实现核心内幕</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>今天, 和部门的同事一起分享了Web服务器的核心内幕, 把PPT奉上, 大家喜欢可以下载. 本PPT的出发点和许多所谓的XX源码分析非常不同.</p>
<div style="width:425px" id="__ss_7775049"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ideawu/web-7775049" title="高性能并发Web服务器实现核心内幕">高性能并发Web服务器实现核心内幕</a></strong> <object id="__sse7775049" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=web-110429050116-phpapp02&#038;rel=0&#038;stripped_title=web-7775049&#038;userName=ideawu" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse7775049" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=web-110429050116-phpapp02&#038;rel=0&#038;stripped_title=web-7775049&#038;userName=ideawu" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ideawu">ideawu</a> </div>
</p></div>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/364.html' rel='bookmark' title='Permanent Link: [不会停止]idea&#8217;s blog 即将停止了&#8230;'>[不会停止]idea&#8217;s blog 即将停止了&#8230;</a></li>
<li><a href='http://www.ideawu.net/blog/archives/355.html' rel='bookmark' title='Permanent Link: 朋友在中关村买华硕笔记本被骗'>朋友在中关村买华硕笔记本被骗</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/589.html" title="高性能并发Web服务器实现核心内幕">高性能并发Web服务器实现核心内幕</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/589.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Lighttpd mod_fastcgi源码分析</title>
		<link>http://www.ideawu.net/blog/archives/537.html</link>
		<comments>http://www.ideawu.net/blog/archives/537.html#comments</comments>
		<pubDate>Sun, 29 Aug 2010 10:00:51 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/537.html</guid>
		<description><![CDATA[<p>最近在设计一种网络服务器架构, 最重要的一点是把耗时操作委托给工作进程(或者线程)来做, 所以考察一下 <a href="http://www.fastcgi.com/">fastcgi</a>. 大概看了下 <a href="http://www.lighttpd.net/">lighttpd</a> 的 mod_fastcgi 的源码, 没想到立即被卡住了. 根据我的想法, PHP 等 fastcgi 程序(php-cgi 进程)监听网络, 然后 mod_fastcgi 只需要 connect 这些进程即可, 奇怪的是, 我竟然看到了 listen! -</p>
<pre>
fcgi_spawn_connection() 函数:

fcgi_fd = socket(socket_type, SOCK_STREAM, 0);

if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
    close(fcgi_fd);
    fcgi_fd = socket(socket_type, SOCK_STREAM, 0);
    /* create socket */
    bind(fcgi_fd, fcgi_addr, servlen);
    <b>listen(fcgi_fd, 1024);</b>

    switch ((child = fork())) {
    case 0: {
        // child process
        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
            close(FCGI_LISTENSOCK_FILENO);
            <b>dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);</b>
            close(fcgi_fd);
        }
        /* exec the cgi */
        <b>execve</b>(arg.ptr[0], arg.ptr, env.ptr);
        exit(errno);
    }
}
</pre>
<p>我很奇怪, mod_fastcgi 为什么要监听网络连接? 谁会连接它? 问了同事, 同事说可能是 fastcgi 进程要连接它, 可问题是 fastcgi 进程怎么知道连接什么地方, 更不用说, fastcgi 协议里没有提到要 fastcgi 进程主动连接 Web Server 一说.</p>
<p><span id="more-537"></span>再看一遍代码, 我注意到了 <a href="http://linux.die.net/man/2/dup2">dup2</a>() 调用, 会不会是 lighttpd 为 php-cgi 进程创建了一个监听 socket? 于是看了下 PHP fastcgi 的代码, 如下解析命令行参数的一段:</p>
<pre>
"  -b &lt;address:port&gt;|&lt;port&gt; Bind Path for external FASTCGI Server mode\n"
/* if we're started on command line, check to see if
   we are being started as an 'external' fastcgi
   server by accepting a bindpath parameter. */
case 'b':
...
if (bindpath) {
    fcgi_fd = fcgi_listen(bindpath, 128);
}
</pre>
<p>也就是说, 如果指定了 -b 选项, php-cgi 就会创建监听进程, 如果没有的话, fcgi_fd 就是默认的 0(标准输入的文件描述符), 也就是 FCGI_LISTENSOCK_FILENO.</p>
<p>所以, lighttpd mod_fastcgi 的逻辑是这样, 如果需要 spawn php-cgi 进程, 它会创建一个监听的 socket, 然后把该 socket dup2 到 标准输入的 fd, 接着 fork 并用 <a href="http://linux.die.net/man/2/execve">execve</a>() 函数执行 php-cgi 程序, 这样, php-cgi 程序就可以使用该监听 socket 来接受 mod_fastcgi 的网络连接了.</p>
<p>只要知道了这个逻辑, 细节问题不必深究.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/537.html" title="Lighttpd mod_fastcgi源码分析">Lighttpd mod_fastcgi源码分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>最近在设计一种网络服务器架构, 最重要的一点是把耗时操作委托给工作进程(或者线程)来做, 所以考察一下 <a href="http://www.fastcgi.com/">fastcgi</a>. 大概看了下 <a href="http://www.lighttpd.net/">lighttpd</a> 的 mod_fastcgi 的源码, 没想到立即被卡住了. 根据我的想法, PHP 等 fastcgi 程序(php-cgi 进程)监听网络, 然后 mod_fastcgi 只需要 connect 这些进程即可, 奇怪的是, 我竟然看到了 listen! -</p>
<pre>
fcgi_spawn_connection() 函数:

fcgi_fd = socket(socket_type, SOCK_STREAM, 0);

if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
    close(fcgi_fd);
    fcgi_fd = socket(socket_type, SOCK_STREAM, 0);
    /* create socket */
    bind(fcgi_fd, fcgi_addr, servlen);
    <b>listen(fcgi_fd, 1024);</b>

    switch ((child = fork())) {
    case 0: {
        // child process
        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
            close(FCGI_LISTENSOCK_FILENO);
            <b>dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);</b>
            close(fcgi_fd);
        }
        /* exec the cgi */
        <b>execve</b>(arg.ptr[0], arg.ptr, env.ptr);
        exit(errno);
    }
}
</pre>
<p>我很奇怪, mod_fastcgi 为什么要监听网络连接? 谁会连接它? 问了同事, 同事说可能是 fastcgi 进程要连接它, 可问题是 fastcgi 进程怎么知道连接什么地方, 更不用说, fastcgi 协议里没有提到要 fastcgi 进程主动连接 Web Server 一说.</p>
<p><span id="more-537"></span>再看一遍代码, 我注意到了 <a href="http://linux.die.net/man/2/dup2">dup2</a>() 调用, 会不会是 lighttpd 为 php-cgi 进程创建了一个监听 socket? 于是看了下 PHP fastcgi 的代码, 如下解析命令行参数的一段:</p>
<pre>
"  -b &lt;address:port&gt;|&lt;port&gt; Bind Path for external FASTCGI Server mode\n"
/* if we're started on command line, check to see if
   we are being started as an 'external' fastcgi
   server by accepting a bindpath parameter. */
case 'b':
...
if (bindpath) {
    fcgi_fd = fcgi_listen(bindpath, 128);
}
</pre>
<p>也就是说, 如果指定了 -b 选项, php-cgi 就会创建监听进程, 如果没有的话, fcgi_fd 就是默认的 0(标准输入的文件描述符), 也就是 FCGI_LISTENSOCK_FILENO.</p>
<p>所以, lighttpd mod_fastcgi 的逻辑是这样, 如果需要 spawn php-cgi 进程, 它会创建一个监听的 socket, 然后把该 socket dup2 到 标准输入的 fd, 接着 fork 并用 <a href="http://linux.die.net/man/2/execve">execve</a>() 函数执行 php-cgi 程序, 这样, php-cgi 程序就可以使用该监听 socket 来接受 mod_fastcgi 的网络连接了.</p>
<p>只要知道了这个逻辑, 细节问题不必深究.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/537.html" title="Lighttpd mod_fastcgi源码分析">Lighttpd mod_fastcgi源码分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/537.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>最大文件描述符限制对高性能Web架构的影响</title>
		<link>http://www.ideawu.net/blog/archives/463.html</link>
		<comments>http://www.ideawu.net/blog/archives/463.html#comments</comments>
		<pubDate>Sun, 14 Mar 2010 02:59:04 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=463</guid>
		<description><![CDATA[<p>不同于Windows平台的高效的线程机制, Linux/Unix系统早期通过多进程来解决Web大规模并发访问量的问题. 而随着Linux内核的改进, 单纯增加进程数量的方式也慢慢被弃用, 转而使用单进程异步IO接口, 比如epoll(Linux), kqueue(BSD).</p>
<p>单进程异步IO接口可以简单理解为, 进程把大量的socket连接交给内核管理, 一旦连接中有数据需要处理, 则激活进程进行处理. 这样, 一个进程同时打开的socket(也即文件描述符)就有成千上万个.</p>
<p>Linux系统默认的单个进程所能打开的最大文件描述符一般是1024(可通过ulimit -n命令查询), 这就导致了文件描述符被用完的情况出现. 所以, 要开发能处理高并发请求的Web系统, 必须修改操作系统的最大文件描述符.</p>
<p>即使使用的是Apache这样的多进程Web服务器, 也有可能被最大文件描述符限制给绊倒, 因为后端可能使用的是fastcgi, memcached这些应用. 比如memcached, 一般使用的就是单进程异步IO接口, fastcgi的PHP脚本与其连接时, 将保持TCP长连接, 也是会消耗大量的文件描述符.</p>
<p>所以, 运行在Linux之上的高性能Web系统, 一定要扩大进程的最大文件描述符限制, 这是有很惨痛经验教训的.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/141.html' rel='bookmark' title='Permanent Link: Linux发行版的选择'>Linux发行版的选择</a></li>
<li><a href='http://www.ideawu.net/blog/archives/432.html' rel='bookmark' title='Permanent Link: 如何为Linux生成和打上patch'>如何为Linux生成和打上patch</a></li>
<li><a href='http://www.ideawu.net/blog/archives/230.html' rel='bookmark' title='Permanent Link: 我要转到 Windows 平台了'>我要转到 Windows 平台了</a></li>
<li><a href='http://www.ideawu.net/blog/archives/174.html' rel='bookmark' title='Permanent Link: 安装和使用Skype for Linux'>安装和使用Skype for Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/148.html' rel='bookmark' title='Permanent Link: 安装和使用Google Earth &#8211; Linux'>安装和使用Google Earth &#8211; Linux</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/463.html" title="最大文件描述符限制对高性能Web架构的影响">最大文件描述符限制对高性能Web架构的影响</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>不同于Windows平台的高效的线程机制, Linux/Unix系统早期通过多进程来解决Web大规模并发访问量的问题. 而随着Linux内核的改进, 单纯增加进程数量的方式也慢慢被弃用, 转而使用单进程异步IO接口, 比如epoll(Linux), kqueue(BSD).</p>
<p>单进程异步IO接口可以简单理解为, 进程把大量的socket连接交给内核管理, 一旦连接中有数据需要处理, 则激活进程进行处理. 这样, 一个进程同时打开的socket(也即文件描述符)就有成千上万个.</p>
<p>Linux系统默认的单个进程所能打开的最大文件描述符一般是1024(可通过ulimit -n命令查询), 这就导致了文件描述符被用完的情况出现. 所以, 要开发能处理高并发请求的Web系统, 必须修改操作系统的最大文件描述符.</p>
<p>即使使用的是Apache这样的多进程Web服务器, 也有可能被最大文件描述符限制给绊倒, 因为后端可能使用的是fastcgi, memcached这些应用. 比如memcached, 一般使用的就是单进程异步IO接口, fastcgi的PHP脚本与其连接时, 将保持TCP长连接, 也是会消耗大量的文件描述符.</p>
<p>所以, 运行在Linux之上的高性能Web系统, 一定要扩大进程的最大文件描述符限制, 这是有很惨痛经验教训的.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/141.html' rel='bookmark' title='Permanent Link: Linux发行版的选择'>Linux发行版的选择</a></li>
<li><a href='http://www.ideawu.net/blog/archives/432.html' rel='bookmark' title='Permanent Link: 如何为Linux生成和打上patch'>如何为Linux生成和打上patch</a></li>
<li><a href='http://www.ideawu.net/blog/archives/230.html' rel='bookmark' title='Permanent Link: 我要转到 Windows 平台了'>我要转到 Windows 平台了</a></li>
<li><a href='http://www.ideawu.net/blog/archives/174.html' rel='bookmark' title='Permanent Link: 安装和使用Skype for Linux'>安装和使用Skype for Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/148.html' rel='bookmark' title='Permanent Link: 安装和使用Google Earth &#8211; Linux'>安装和使用Google Earth &#8211; Linux</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/463.html" title="最大文件描述符限制对高性能Web架构的影响">最大文件描述符限制对高性能Web架构的影响</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/463.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用dbproxy来处理高并发数据库请求</title>
		<link>http://www.ideawu.net/blog/archives/462.html</link>
		<comments>http://www.ideawu.net/blog/archives/462.html#comments</comments>
		<pubDate>Wed, 10 Mar 2010 15:51:47 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=462</guid>
		<description><![CDATA[<p>大规模Web应用系统, 几乎都会遇到数据库瓶颈问题. 在早期, 通过数据库配置优化, 表优化, 索引优化等软件方法, 可以解决一些问题. 马上, 数据库瓶颈迫使不得不把MySQL和Apache单独部署到不同的机器, 形成Web服务器(Web Server)和数据库服务器(DB Server)的物理分离, 这样就能解决大部分的问题. 但是, 在继续发展时, 一台Web服务器和一台数据库服务器也不能满足高并发的访问量了.</p>
<p>这时, 问题首先是计算能力的问题, 也就是硬件不够用的问题. 所以, 需要上多台Web服务器和多台数据库服务器.</p>
<p>有时候, 网站可以纵向切分, 这样, 任何两台服务器(一台Web Server + 一台DB Server)单独配置, 便能运行一个应用. 比如某两台运行着论坛程序, 某两台运行着新闻程序.</p>
<p>很多情况下, 并不能纵向切分, 每一台的Web Server的角色和功能都是一样的, 没有差别, DB Server也是一样. 理想的情况下, 同种压力的SQL语句平均分布到每一台DB Server, 那就能解决高并发数据库请求问题了</p>
<p>dbproxy的作用便是如此: 合理地分配数据库请求给所有的DB Server, 使得在请求的数量等于或者小于所有DB Server的计算能力总和时, 服务能够正常运行.<br />
<span id="more-462"></span><br />
第一种方式的dbproxy: Web Server上的数据库客户端(如PHP脚本)拥有选择DB Server的智能.</p>
<p>这种方式实现简单, 完全用Web脚本实现, 脚本自己判断应该连接其中的一台或者几台DB Server, 请决定把SQL请求发给谁. 这种方式因为性能问题, 所以应用不是很广.</p>
<p>第二种方式的dbproxy: SQL代理进程</p>
<p>类似HTTP代理服务器, 这种方式的dbproxy独立运行, 所以客户端请求将不再直接和DB Server连接, 而是通过它中转. 这样的dbproxy, 首先要拥有解析协议(也即SQL)的能力, 这也带来一个特点, dbproxy可以与后端的MySQL连接, 但却接收前端(如PHP脚本)发来的Oracle数据库的SQL请求.</p>
<p>当然, dbproxy的主要功能还是在SQL分发方面. 另外, 还可以在dbproxy上面做与业务更接近的缓存, 相比数据库的底层缓存很多时候更有效.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
<li><a href='http://www.ideawu.net/blog/archives/248.html' rel='bookmark' title='Permanent Link: PHP LDAP连接微软活动目录进行身份验证'>PHP LDAP连接微软活动目录进行身份验证</a></li>
<li><a href='http://www.ideawu.net/blog/archives/537.html' rel='bookmark' title='Permanent Link: Lighttpd mod_fastcgi源码分析'>Lighttpd mod_fastcgi源码分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/398.html' rel='bookmark' title='Permanent Link: Linux+Keepalived双机互备'>Linux+Keepalived双机互备</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/462.html" title="使用dbproxy来处理高并发数据库请求">使用dbproxy来处理高并发数据库请求</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>大规模Web应用系统, 几乎都会遇到数据库瓶颈问题. 在早期, 通过数据库配置优化, 表优化, 索引优化等软件方法, 可以解决一些问题. 马上, 数据库瓶颈迫使不得不把MySQL和Apache单独部署到不同的机器, 形成Web服务器(Web Server)和数据库服务器(DB Server)的物理分离, 这样就能解决大部分的问题. 但是, 在继续发展时, 一台Web服务器和一台数据库服务器也不能满足高并发的访问量了.</p>
<p>这时, 问题首先是计算能力的问题, 也就是硬件不够用的问题. 所以, 需要上多台Web服务器和多台数据库服务器.</p>
<p>有时候, 网站可以纵向切分, 这样, 任何两台服务器(一台Web Server + 一台DB Server)单独配置, 便能运行一个应用. 比如某两台运行着论坛程序, 某两台运行着新闻程序.</p>
<p>很多情况下, 并不能纵向切分, 每一台的Web Server的角色和功能都是一样的, 没有差别, DB Server也是一样. 理想的情况下, 同种压力的SQL语句平均分布到每一台DB Server, 那就能解决高并发数据库请求问题了</p>
<p>dbproxy的作用便是如此: 合理地分配数据库请求给所有的DB Server, 使得在请求的数量等于或者小于所有DB Server的计算能力总和时, 服务能够正常运行.<br />
<span id="more-462"></span><br />
第一种方式的dbproxy: Web Server上的数据库客户端(如PHP脚本)拥有选择DB Server的智能.</p>
<p>这种方式实现简单, 完全用Web脚本实现, 脚本自己判断应该连接其中的一台或者几台DB Server, 请决定把SQL请求发给谁. 这种方式因为性能问题, 所以应用不是很广.</p>
<p>第二种方式的dbproxy: SQL代理进程</p>
<p>类似HTTP代理服务器, 这种方式的dbproxy独立运行, 所以客户端请求将不再直接和DB Server连接, 而是通过它中转. 这样的dbproxy, 首先要拥有解析协议(也即SQL)的能力, 这也带来一个特点, dbproxy可以与后端的MySQL连接, 但却接收前端(如PHP脚本)发来的Oracle数据库的SQL请求.</p>
<p>当然, dbproxy的主要功能还是在SQL分发方面. 另外, 还可以在dbproxy上面做与业务更接近的缓存, 相比数据库的底层缓存很多时候更有效.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
<li><a href='http://www.ideawu.net/blog/archives/248.html' rel='bookmark' title='Permanent Link: PHP LDAP连接微软活动目录进行身份验证'>PHP LDAP连接微软活动目录进行身份验证</a></li>
<li><a href='http://www.ideawu.net/blog/archives/537.html' rel='bookmark' title='Permanent Link: Lighttpd mod_fastcgi源码分析'>Lighttpd mod_fastcgi源码分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/398.html' rel='bookmark' title='Permanent Link: Linux+Keepalived双机互备'>Linux+Keepalived双机互备</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/462.html" title="使用dbproxy来处理高并发数据库请求">使用dbproxy来处理高并发数据库请求</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/462.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Linux+Keepalived双机互备</title>
		<link>http://www.ideawu.net/blog/archives/398.html</link>
		<comments>http://www.ideawu.net/blog/archives/398.html#comments</comments>
		<pubDate>Thu, 16 Jul 2009 15:09:45 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=398</guid>
		<description><![CDATA[<p>大规模Web应用有两个要解决的问题: 高可用性和负载均衡. Keepalived可以提供IP层的高可用性, 一旦某一台机器的网络出现问题, 另一台服务器会立即(几秒或者更少的时间)使用出故障的服务器的IP进行工作. 具体的工作原理会在我学习之后, 发布在后期的文章中.</p>
<p>现在有两台虚拟机ServerA和ServerB. 两个对外提供Web服务器的虚IP(VIP)192.168.200.100和192.168.200.200, 虚IP用在keepalived的配置中, 网卡接口配置有内网IP.</p>
<pre>
ServerA:
eth0: 192.168.200.128
VIP: 192.168.200.100

ServerB:
eth0: 192.168.200.129
VIP: 192.168.200.200
</pre>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2009/07/keepalived.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2009/07/keepalived.jpg" alt="" title="keepalived双机双IP互备" class="alignnone size-full wp-image-402" /></a></p>
<p>如果两台服务器都正常地提供网络服务, 那么, 发往192.168.200.100的服务请求会被ServerA处理, 发往192.168.200.200的服务请求会被ServerB处理. 假设只有ServerB出现故障, 那么, 所有的请求都由ServerA进行处理. 当只有ServerA出现故障时, 也是同理.</p>
<h3>安装Ubuntu Linux Server</h3>
<p>本文使用的Linux为Ubuntu 9.04 服务器版, 请到<a href="http://www.ubuntu.com.cn/getubuntu/download-server/">http://www.ubuntu.com.cn/getubuntu/download-server/</a>下载. 需要安装gcc, make开发环境.</p>
<p><span id="more-398"></span></p>
<h3>安装Keepalived</h3>
<p>然后到keepalived网站下载源码, <a href="http://www.keepalived.org/download.html">http://www.keepalived.org/download.html</a>, 本文使用1.1.16版本.</p>
<pre>
tar zxf keepalived-1.1.16.tar.gz
cd keepalived-1.1.16
./configure --prefix=/usr --sysconf=/etc
make
make intall
</pre>
<p>安装后的keepalived的启动脚本在/etc/rc.d/init.d/keepalived, 配置文件在/etc/keepalived/keepalived.conf, 还有一个配置文件/etc/sysconfig/keepalived, 一般不用到.</p>
<p>如果你希望keepalived开机自动启动,</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ln -s /etc/rc.d/init.d/keepalived /etc/rc2.d/S99keepalived
</pre>
<p>启动脚本可能有问题, 编辑/etc/rc.d/init.d/keepalived, 将/var/lock/subsys/$prog修改为/var/lock/$prog.</p>
<h3>配置Keepalived</h3>
<p>接下来, 是最重要的修改配置文件/etc/keepalived/keepalived.conf.</p>
<pre>
!This is keepalived config file, <a href="http://www.ideawu.net">ideawu.net</a>
global_defs {
   notification_email {
        me@ideawu.net
   }
   notification_email_from me@ideawu.net
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   lvs_id LVS_DEVEL_1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    smtp_alert

    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.100
    }
}

vrrp_instance VI_2 {
    state BACKUP
    interface eth0
    virtual_router_id 52
    priority 10
    advert_int 1
    smtp_alert

    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.200
    }
}
</pre>
<p>执行 /etc/rc.d/init.d/keepalived start 启动keepalived后, 执行ip a, 你将看到类似的信息:</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet 192.168.200.200/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>可以看到, ServerA的网卡绑定了两个虚IP 192.168.200.100和192.168.200.200, 这时在第3台机器上ping这两个IP, 是可以通的.</p>
<p>然后, 按上面的方法安装ServerB. ServerB的keepalived.conf配置和ServerA基本相同, 但是, 把state MASTER和state BACKUP调换, priority 100和priority 10调换. 启动ServerB后, 再到ServerA上运行ip a, 你将看到</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>192.168.200.200已经不见了, 因为被ServerB使用了, ServerB是这个IP的MASTER, 它有优先使用权. 这样, 两个IP的网络数据分别被两台服务器处理. 如果设置好DNS, 就可以进行负载均衡了. 现在验证ServerB出在故障的情况, 请ServerB的网线拔掉, 然后在ServerA上执行ip a, 你将看到</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet 192.168.200.200/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>192.168.200.200又被ServerA使用了. 如果你安装了lighttpd, 各放两个内容不同的网页, 你将能更直观的看到这种效果.</p>
<h3>总结</h3>
<p>Keepalived安装和配置都非常方便, IP切换也很快速. 由于我是在虚拟机上测试, 发现keepalived有时出现日志中提示正常启动, 但无法绑定虚IP的情况, 不知道是配置出了问题还是虚拟机有问题.</p>
<p>另外, 我也是刚接触keepalived, 很多地方都不明白, 还需要进一步学习. 有一项称为vertual_server的内容, 似乎可以进行HTTP级别的故障判断, 不知道是不是可以应用到IP切换中.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/87.html' rel='bookmark' title='Permanent Link: Debian Linux 系统提速'>Debian Linux 系统提速</a></li>
<li><a href='http://www.ideawu.net/blog/archives/336.html' rel='bookmark' title='Permanent Link: C# P2P 传输模块'>C# P2P 传输模块</a></li>
<li><a href='http://www.ideawu.net/blog/archives/287.html' rel='bookmark' title='Permanent Link: 使用 Ideawu.P2P.Core.UdpLink 进行 NAT 穿透'>使用 Ideawu.P2P.Core.UdpLink 进行 NAT 穿透</a></li>
<li><a href='http://www.ideawu.net/blog/archives/174.html' rel='bookmark' title='Permanent Link: 安装和使用Skype for Linux'>安装和使用Skype for Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/289.html' rel='bookmark' title='Permanent Link: 使用 Channel 进行可靠传输'>使用 Channel 进行可靠传输</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/398.html" title="Linux+Keepalived双机互备">Linux+Keepalived双机互备</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>大规模Web应用有两个要解决的问题: 高可用性和负载均衡. Keepalived可以提供IP层的高可用性, 一旦某一台机器的网络出现问题, 另一台服务器会立即(几秒或者更少的时间)使用出故障的服务器的IP进行工作. 具体的工作原理会在我学习之后, 发布在后期的文章中.</p>
<p>现在有两台虚拟机ServerA和ServerB. 两个对外提供Web服务器的虚IP(VIP)192.168.200.100和192.168.200.200, 虚IP用在keepalived的配置中, 网卡接口配置有内网IP.</p>
<pre>
ServerA:
eth0: 192.168.200.128
VIP: 192.168.200.100

ServerB:
eth0: 192.168.200.129
VIP: 192.168.200.200
</pre>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2009/07/keepalived.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2009/07/keepalived.jpg" alt="" title="keepalived双机双IP互备" class="alignnone size-full wp-image-402" /></a></p>
<p>如果两台服务器都正常地提供网络服务, 那么, 发往192.168.200.100的服务请求会被ServerA处理, 发往192.168.200.200的服务请求会被ServerB处理. 假设只有ServerB出现故障, 那么, 所有的请求都由ServerA进行处理. 当只有ServerA出现故障时, 也是同理.</p>
<h3>安装Ubuntu Linux Server</h3>
<p>本文使用的Linux为Ubuntu 9.04 服务器版, 请到<a href="http://www.ubuntu.com.cn/getubuntu/download-server/">http://www.ubuntu.com.cn/getubuntu/download-server/</a>下载. 需要安装gcc, make开发环境.</p>
<p><span id="more-398"></span></p>
<h3>安装Keepalived</h3>
<p>然后到keepalived网站下载源码, <a href="http://www.keepalived.org/download.html">http://www.keepalived.org/download.html</a>, 本文使用1.1.16版本.</p>
<pre>
tar zxf keepalived-1.1.16.tar.gz
cd keepalived-1.1.16
./configure --prefix=/usr --sysconf=/etc
make
make intall
</pre>
<p>安装后的keepalived的启动脚本在/etc/rc.d/init.d/keepalived, 配置文件在/etc/keepalived/keepalived.conf, 还有一个配置文件/etc/sysconfig/keepalived, 一般不用到.</p>
<p>如果你希望keepalived开机自动启动,</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ln -s /etc/rc.d/init.d/keepalived /etc/rc2.d/S99keepalived
</pre>
<p>启动脚本可能有问题, 编辑/etc/rc.d/init.d/keepalived, 将/var/lock/subsys/$prog修改为/var/lock/$prog.</p>
<h3>配置Keepalived</h3>
<p>接下来, 是最重要的修改配置文件/etc/keepalived/keepalived.conf.</p>
<pre>
!This is keepalived config file, <a href="http://www.ideawu.net">ideawu.net</a>
global_defs {
   notification_email {
        me@ideawu.net
   }
   notification_email_from me@ideawu.net
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   lvs_id LVS_DEVEL_1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    smtp_alert

    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.100
    }
}

vrrp_instance VI_2 {
    state BACKUP
    interface eth0
    virtual_router_id 52
    priority 10
    advert_int 1
    smtp_alert

    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.200
    }
}
</pre>
<p>执行 /etc/rc.d/init.d/keepalived start 启动keepalived后, 执行ip a, 你将看到类似的信息:</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet 192.168.200.200/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>可以看到, ServerA的网卡绑定了两个虚IP 192.168.200.100和192.168.200.200, 这时在第3台机器上ping这两个IP, 是可以通的.</p>
<p>然后, 按上面的方法安装ServerB. ServerB的keepalived.conf配置和ServerA基本相同, 但是, 把state MASTER和state BACKUP调换, priority 100和priority 10调换. 启动ServerB后, 再到ServerA上运行ip a, 你将看到</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>192.168.200.200已经不见了, 因为被ServerB使用了, ServerB是这个IP的MASTER, 它有优先使用权. 这样, 两个IP的网络数据分别被两台服务器处理. 如果设置好DNS, 就可以进行负载均衡了. 现在验证ServerB出在故障的情况, 请ServerB的网线拔掉, 然后在ServerA上执行ip a, 你将看到</p>
<pre>
root@<a href="http://www.ideawu.net">ideawu.net</a>:~# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:01:11:2a brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.128/24 brd 192.168.200.255 scope global eth0
    inet 192.168.200.100/32 scope global eth0
    inet 192.168.200.200/32 scope global eth0
    inet6 fe80::20c:29ff:fe01:112a/64 scope link
</pre>
<p>192.168.200.200又被ServerA使用了. 如果你安装了lighttpd, 各放两个内容不同的网页, 你将能更直观的看到这种效果.</p>
<h3>总结</h3>
<p>Keepalived安装和配置都非常方便, IP切换也很快速. 由于我是在虚拟机上测试, 发现keepalived有时出现日志中提示正常启动, 但无法绑定虚IP的情况, 不知道是配置出了问题还是虚拟机有问题.</p>
<p>另外, 我也是刚接触keepalived, 很多地方都不明白, 还需要进一步学习. 有一项称为vertual_server的内容, 似乎可以进行HTTP级别的故障判断, 不知道是不是可以应用到IP切换中.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/87.html' rel='bookmark' title='Permanent Link: Debian Linux 系统提速'>Debian Linux 系统提速</a></li>
<li><a href='http://www.ideawu.net/blog/archives/336.html' rel='bookmark' title='Permanent Link: C# P2P 传输模块'>C# P2P 传输模块</a></li>
<li><a href='http://www.ideawu.net/blog/archives/287.html' rel='bookmark' title='Permanent Link: 使用 Ideawu.P2P.Core.UdpLink 进行 NAT 穿透'>使用 Ideawu.P2P.Core.UdpLink 进行 NAT 穿透</a></li>
<li><a href='http://www.ideawu.net/blog/archives/174.html' rel='bookmark' title='Permanent Link: 安装和使用Skype for Linux'>安装和使用Skype for Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/289.html' rel='bookmark' title='Permanent Link: 使用 Channel 进行可靠传输'>使用 Channel 进行可靠传输</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/398.html" title="Linux+Keepalived双机互备">Linux+Keepalived双机互备</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/398.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

