<?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>big bug ban</title>
	<atom:link href="http://3haku.net/feed" rel="self" type="application/rss+xml" />
	<link>http://3haku.net</link>
	<description>兴趣 创新 践行</description>
	<lastBuildDate>Sat, 21 Jan 2012 03:53:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>swfupload的session问题</title>
		<link>http://3haku.net/2012/01/19/swfupload%e7%9a%84session%e9%97%ae%e9%a2%98.html</link>
		<comments>http://3haku.net/2012/01/19/swfupload%e7%9a%84session%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Thu, 19 Jan 2012 05:46:40 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[swfupload]]></category>

		<guid isPermaLink="false">http://3haku.net/?p=2401</guid>
		<description><![CDATA[<p><font color="#333333">swupload是个一个客户端文件上传工具</font></p>  <p><font color="#333333">让这个上传flash嵌入在网页里面可以使用一些非常棒的特性</font></p>  <p><font color="#333333">官网在这里</font><a href="http://code.google.com/p/swfupload/"><font color="#333333">http://code.google.com/p/swfupload/</font></a></p>  <p><font color="#333333">最近使用的时候发生一个问题</font></p>  <p><font color="#333333">文件上传的session和页面session不同步</font></p>  <p><font color="#333333">demo里面有提到设置post_params</font></p>  <p><a href="http://3haku.net/wp-content/uploads/2012/01/image.png"><font color="#333333"><a href="http://3haku.net/wp-content/uploads/2012/01/image1.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://3haku.net/wp-content/uploads/2012/01/image_thumb.png" width="433" height="147" /></a></font></a></p>  <p><font color="#333333">让swfupload吧页面的session_id作为参数传递</font></p>  <p><font color="#333333">但是实际使用的时候依然有问题</font></p>  <p><font color="#333333"><font color="#333333">具体表现就是在文件上传处理页面设置的session</font>无法在当前页面得到</font></p>  <p><font color="#333333">使用fidder抓包后发现原因是swfupload里面的cookie上也带有一个sessid</font></p>  <p><a href="http://3haku.net/wp-content/uploads/2012/01/image2.png"><font color="#333333"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://3haku.net/wp-content/uploads/2012/01/image_thumb1.png" width="572" height="215" /></font></a></p>  <p><font color="#333333">POST字段里面才是实际需要的sessid</font></p>  <p><font color="#333333">因为swfupload使用的是socket方式 所以和我们的浏览器不是共享cookie的</font></p>  <p><font color="#333333">但是php的session一般是通过cookie上的PHPSESSID进行会话</font></p>  <p><font color="#333333">而这里的cookie上是错误的，于是造成了PHPSESSID不一致</font></p>  <p><font color="#333333">我们需要使用POST字段上的，</font></p>  <p><font color="#333333">解决方案有很多</font></p>  <p><font color="#333333">其中之一是直接强制用post里面的设置为sessid</font></p>  <p><font color="#333333">php可以使用函数session_id($_POST[&#34;PHPSESSID&#34;]);强制更改</font></p>  <p><font color="#333333">当然.也可以把cookie重设，不过得刷新页面了</font></p>  <p><font color="#333333"></font></p>  <p><a href="http://3haku.net/wp-content/uploads/2012/01/image2.png"><font color="#333333">&#160;</font></a></p>  <p><font color="#333333"></font></p>  <p><font color="#333333"></font></p>  <p><font color="#333333"></font></p><p><br/>点击阅读: <a href="http://3haku.net/2012/01/19/swfupload%e7%9a%84session%e9%97%ae%e9%a2%98.html">swfupload的session问题</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p><font color="#333333">swupload是个一个客户端文件上传工具</font></p>
<p><font color="#333333">让这个上传flash嵌入在网页里面可以使用一些非常棒的特性</font></p>
<p><font color="#333333">官网在这里</font><a href="http://code.google.com/p/swfupload/"><font color="#333333">http://code.google.com/p/<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/swfupload" title="查看 swfupload 中的全部文章" target="_blank">swfupload</a></span>/</font></a></p>
<p><font color="#333333">最近使用的时候发生一个问题</font></p>
<p><font color="#333333">文件上传的session和页面session不同步</font></p>
<p><font color="#333333">demo里面有提到设置post_params</font></p>
<p><a href="http://3haku.net/wp-content/uploads/2012/01/image.png" rel="lightbox[2401]"><font color="#333333"><a href="http://3haku.net/wp-content/uploads/2012/01/image1.png" rel="lightbox[2401]"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://3haku.net/wp-content/uploads/2012/01/image_thumb.png" width="433" height="147" /></a></font></a></p>
<p><font color="#333333">让<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/swfupload" title="查看 swfupload 中的全部文章" target="_blank">swfupload</a></span>吧页面的session_id作为参数传递</font></p>
<p><font color="#333333">但是实际使用的时候依然有问题</font></p>
<p><font color="#333333"><font color="#333333">具体表现就是在文件上传处理页面设置的session</font>无法在当前页面得到</font></p>
<p><font color="#333333">使用fidder抓包后发现原因是<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/swfupload" title="查看 swfupload 中的全部文章" target="_blank">swfupload</a></span>里面的cookie上也带有一个sessid</font></p>
<p><a href="http://3haku.net/wp-content/uploads/2012/01/image2.png" rel="lightbox[2401]"><font color="#333333"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://3haku.net/wp-content/uploads/2012/01/image_thumb1.png" width="572" height="215" /></font></a></p>
<p><font color="#333333">POST字段里面才是实际需要的sessid</font></p>
<p><font color="#333333">因为<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/swfupload" title="查看 swfupload 中的全部文章" target="_blank">swfupload</a></span>使用的是socket方式 所以和我们的浏览器不是共享cookie的</font></p>
<p><font color="#333333">但是php的session一般是通过cookie上的PHPSESSID进行会话</font></p>
<p><font color="#333333">而这里的cookie上是错误的，于是造成了PHPSESSID不一致</font></p>
<p><font color="#333333">我们需要使用POST字段上的，</font></p>
<p><font color="#333333">解决方案有很多</font></p>
<p><font color="#333333">其中之一是直接强制用post里面的设置为sessid</font></p>
<p><font color="#333333">php可以使用函数session_id($_POST[&quot;PHPSESSID&quot;]);强制更改</font></p>
<p><font color="#333333">当然.也可以把cookie重设，不过得刷新页面了</font></p>
<p><font color="#333333"></font></p>
<p><a href="http://3haku.net/wp-content/uploads/2012/01/image2.png" rel="lightbox[2401]"><font color="#333333">&#160;</font></a></p>
<p><font color="#333333"></font></p>
<p><font color="#333333"></font></p>
<p><font color="#333333"></font></p>
<p><br/>点击阅读: <a href="http://3haku.net/2012/01/19/swfupload%e7%9a%84session%e9%97%ae%e9%a2%98.html">swfupload的session问题</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2012/01/19/swfupload%e7%9a%84session%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pafetion1.4版本发布</title>
		<link>http://3haku.net/2011/12/06/pafetion1-4%e7%89%88%e6%9c%ac%e5%8f%91%e5%b8%83.html</link>
		<comments>http://3haku.net/2011/12/06/pafetion1-4%e7%89%88%e6%9c%ac%e5%8f%91%e5%b8%83.html#comments</comments>
		<pubDate>Tue, 06 Dec 2011 02:34:45 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[pafetion]]></category>
		<category><![CDATA[飞信API]]></category>

		<guid isPermaLink="false">http://3haku.net/?p=2378</guid>
		<description><![CDATA[<span style="color: #333333;">近期很多同学反映接口不能使用.</span>

<span style="color: #333333;">然后改动了下接口</span>

<span style="color: #333333;">并把以前不规范的cookie获取方式修改了</span>

<span style="color: #333333;">直接使用</span>

<a href="http://lab.3haku.net/f/" target="_blank">http://lab.3haku.net/f/</a>

<span style="color: #333333;">下载地址</span>

<span style="color: #333333;">[download id="35"]</span>

<span style="color: #333333;">调用例子</span>

<span style="color: #333333;">1.发送消息</span>
<blockquote><span style="color: #333333;">http://lab.3haku.net/f/do?phone=xxxxxx&#38;pwd=xxx&#38;to=xxxx,xxxx,xxxx&#38;msg=xxxx</span></blockquote>
<span style="color: #333333;">2.添加好友</span>
<blockquote><span style="color: #333333;">http://lab.3haku.net/f/do?phone=xxxxxx&#38;pwd=xxx&#38;add=xxxx,xxxx,xxxx</span></blockquote>
<span style="color: #333333;">说明:</span>

<span style="color: #333333;">phone 发送者手机号码 (-v1)</span>

<span style="color: #333333;">pwd  发送者飞信密码 (-v1)</span>

<span style="color: #333333;">———————————————-</span>

<span style="color: #333333;">to 接收者的标志 (可以是手机号 也可以是昵称 ,昵称如果有重复的默认发第一个的)</span>

<span style="color: #333333;">msg 消息的正文(默认gbk 编码) </span>

<span style="color: #333333;">(可选) u 是否使用utf8编码(默认的编码是gbk , 此参数用于一些需要对中文特殊处理的地方 比如, 如果您需要做一个在线发什么东西的)</span>

<span style="color: #333333;">———————————————-</span>

<span style="color: #333333;">add 需要添加成好友的手机号码</span>

<span style="color: #333333;">name 好友请求验证时看到的姓名</span><p><br/>点击阅读: <a href="http://3haku.net/2011/12/06/pafetion1-4%e7%89%88%e6%9c%ac%e5%8f%91%e5%b8%83.html">pafetion1.4版本发布</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p><span style="color: #333333;">近期很多同学反映接口不能使用.</span></p>
<p><span style="color: #333333;">然后改动了下接口</span></p>
<p><span style="color: #333333;">并把以前不规范的cookie获取方式修改了</span></p>
<p><span style="color: #333333;">直接使用</span></p>
<p><a href="http://lab.3haku.net/f/" target="_blank">http://lab.3haku.net/f/</a></p>
<p><span style="color: #333333;">下载地址</span></p>
<p><span style="color: #333333;"><a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=35" title=" downloaded 165 times" >pafetion1.4 (165)</a></span></p>
<p><span style="color: #333333;">调用例子</span></p>
<p><span style="color: #333333;">1.发送消息</span></p>
<blockquote><p><span style="color: #333333;">http://lab.3haku.net/f/do?phone=xxxxxx&amp;pwd=xxx&amp;to=xxxx,xxxx,xxxx&amp;msg=xxxx</span></p></blockquote>
<p><span style="color: #333333;">2.添加好友</span></p>
<blockquote><p><span style="color: #333333;">http://lab.3haku.net/f/do?phone=xxxxxx&amp;pwd=xxx&amp;add=xxxx,xxxx,xxxx</span></p></blockquote>
<p><span style="color: #333333;">说明:</span></p>
<p><span style="color: #333333;">phone 发送者手机号码 (-v1)</span></p>
<p><span style="color: #333333;">pwd  发送者飞信密码 (-v1)</span></p>
<p><span style="color: #333333;">———————————————-</span></p>
<p><span style="color: #333333;">to 接收者的标志 (可以是手机号 也可以是昵称 ,昵称如果有重复的默认发第一个的)</span></p>
<p><span style="color: #333333;">msg 消息的正文(默认gbk 编码) </span></p>
<p><span style="color: #333333;">(可选) u 是否使用utf8编码(默认的编码是gbk , 此参数用于一些需要对中文特殊处理的地方 比如, 如果您需要做一个在线发什么东西的)</span></p>
<p><span style="color: #333333;">———————————————-</span></p>
<p><span style="color: #333333;">add 需要添加成好友的手机号码</span></p>
<p><span style="color: #333333;">name 好友请求验证时看到的姓名</span></p>
<p><br/>点击阅读: <a href="http://3haku.net/2011/12/06/pafetion1-4%e7%89%88%e6%9c%ac%e5%8f%91%e5%b8%83.html">pafetion1.4版本发布</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/12/06/pafetion1-4%e7%89%88%e6%9c%ac%e5%8f%91%e5%b8%83.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>关于一致性哈希</title>
		<link>http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html</link>
		<comments>http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html#comments</comments>
		<pubDate>Tue, 15 Nov 2011 13:12:14 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[hash]]></category>

		<guid isPermaLink="false">http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html</guid>
		<description><![CDATA[<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt; mso-char-indent-count: 0; mso-outline-level: 1; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;"><strong>1.</strong> <strong>一致性哈希</strong></p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.1</strong> <strong>基本场景</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">比如你有 N 个 cache 服务器（后面简称 cache ），那么如何将一个对象 object 映射到 N 个 cache 上呢，你很可能会采用类似下面的通用方法计算 object 的 hash 值，然后均匀的映射到到 N 个 cache ；</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(object)%N</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">一切都运行正常，再考虑如下的两种情况；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">1 一个 cache 服务器 m down 掉了（在实际应用中必须要考虑这种情况），这样所有映射到 cache m 的对象都会失效，怎么办，需要把 cache m 从 cache 中移除，这时候 cache 是 N-1 台，映射公式变成了 hash(object)%(N-1) ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">2 由于访问加重，需要添加 cache ，这时候 cache 是 N+1 台，映射公式变成了 hash(object)%(N+1) ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">1 和 2 意味着什么？这意味着突然之间几乎所有的 cache 都失效了。对于服务器而言，这是一场灾难，洪水般的访问都会直接冲向后台服务器；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">再来考虑第三个问题，由于硬件能力越来越强，你可能想让后面添加的节点多做点活，显然上面的 hash 算法也做不到。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">有什么方法可以改变这个状况呢，这就是 consistent hashing...</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.2</strong> <strong>hash</strong> <strong>算法和单调性</strong></p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">　　 Hash 算法的一个衡量指标是单调性（ Monotonicity ），定义如下：</p>
<p style="text-align: left; text-indent: 19.5pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中，又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去，而不会被映射到旧的缓冲集合中的其他缓冲区。</p>
<p style="text-align: left; text-indent: 19.5pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_001n3deac82d.png" alt="" width="435" height="312" /></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">容易看到，上面的简单 hash 算法 hash(object)%N 难以满足单调性要求。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">如果我们的node2节点挂掉了..</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">新的hash()%3</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">node1 应存放1 2 3 4 node3 应放 5 6 7 8 node4 应放 9 10 11 12</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">需要迁移的节点 node1 1个 node3 3个 node4 1个</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">总共需迁移5个 比例数5/12 差不多到50%了..</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">如果value更多呢..后果不堪设想..</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.3</strong> <strong>consistent hashing</strong> <strong>算法的原理</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_003p37496d02.png" alt="" width="499" height="418" /></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">consistent hashing 是一种 hash 算法，简单的说，在移除 / 添加一个 cache 时，它能够尽可能小的改变已存在 key 映射关系，尽可能的满足单调性的要求。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">下面就来按照 5 个步骤简单讲讲 consistent hashing 算法的基本原理。</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.1</strong><strong>环形hash</strong> 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考虑通常的 hash 算法都是将 value 映射到一个 32 为的 key 值，也即是 0~2^32-1 次方的数值空间；我们可以将这个空间想象成一个首（ 0 ）尾（ 2^32-1 ）相接的圆环，如下面图 1 所示的那样。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_004n2baf70a9.png" alt="" width="95" height="108" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 1 环形 hash 空间</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.2</strong> <strong>把对象映射到hash</strong> 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">接下来考虑 4 个对象 object1~object4 ，通过 hash 函数计算出的 hash 值 key 在环上的分布如图 2 所示。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(object1) = key1;</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">… …</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(object4) = key4;</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_005p426e5290.png" alt="" width="238" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 2 4 个对象的 key 值分布</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.3</strong> <strong>把cache</strong> 映射到hash 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Consistent hashing 的基本思想就是将对象和 cache 都映射到同一个 hash 数值空间中，并且使用相同的hash 算法。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">假设当前有 A,B 和 C 共 3 台 cache ，那么其映射结果将如图 3 所示，他们在 hash 空间中，以对应的 hash值排列。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(cache A) = key A;</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">… …</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(cache C) = key C;</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_006n3e9af41f.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 3 cache 和对象的 key 值分布</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">说到这里，顺便提一下 cache 的 hash 计算，一般的方法可以使用 cache 机器的 IP 地址或者机器名作为hash 输入。</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.4</strong> <strong>把对象映射到cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">现在 cache 和对象都已经通过同一个 hash 算法映射到 hash 数值空间中了，接下来要考虑的就是如何将对象映射到 cache 上面了。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">在这个环形空间中，如果沿着顺时针方向从对象的 key 值出发，直到遇见一个 cache ，那么就将该对象存储在这个 cache 上，因为对象和 cache 的 hash 值是固定的，因此这个 cache 必然是唯一和确定的。这样不就找到了对象和 cache 的映射方法了吗？！</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">依然继续上面的例子（参见图 3 ），那么根据上面的方法，对象 object1 将被存储到 cache A 上； object2和 object3 对应到 cache C ； object4 对应到 cache B ；</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.5</strong> <strong>考察cache</strong> 的变动</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">前面讲过，通过 hash 然后求余的方法带来的最大问题就在于不能满足单调性，当 cache 有所变动时，cache 会失效，进而对后台服务器造成巨大的冲击，现在就来分析分析 consistent hashing 算法。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><strong>a)</strong> <strong>移除 cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考虑假设 cache B 挂掉了，根据上面讲到的映射方法，这时受影响的将仅是那些沿 cache B 逆时针遍历直到下一个 cache （ cache C ）之间的对象，也即是本来映射到 cache B 上的那些对象。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此这里仅需要变动对象 object4 ，将其重新映射到 cache C 上即可；参见图 4 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_007n77df2844.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 4 Cache B 被移除后的 cache 映射</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><strong>b)</strong> <strong>添加 cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">再考虑添加一台新的 cache D 的情况，假设在这个环形 hash 空间中， cache D 被映射在对象 object2 和object3 之间。这时受影响的将仅是那些沿 cache D 逆时针遍历直到下一个 cache （ cache B ）之间的对象（它们是也本来映射到 cache C 上对象的一部分），将这些对象重新映射到 cache D 上即可。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此这里仅需要变动对象 object2 ，将其重新映射到 cache D 上；参见图 5 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_008n69674042.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 5 添加 cache D 后的映射关系</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.4</strong> <strong>虚拟节点</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考量 Hash 算法的另一个指标是平衡性 (Balance) ，定义如下：</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">平衡性</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">　　平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去，这样可以使得所有的缓冲空间都得到利用。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash 算法并不是保证绝对的平衡，如果 cache 较少的话，对象并不能被均匀的映射到 cache 上，比如在上面的例子中，仅部署 cache A 和 cache C 的情况下，在 4 个对象中， cache A 仅存储了 object1 ，而 cache C 则存储了 object2 、 object3 和 object4 ；分布是很不均衡的。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">为了解决这种情况， consistent hashing 引入了"虚拟节点"的概念，它可以如下定义：</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">"虚拟节点"（ virtual node ）是实际节点在 hash 空间的复制品（ replica ），一实际个节点对应了若干个"虚拟节点"，这个对应个数也成为"复制个数"，"虚拟节点"在 hash 空间中以 hash 值排列。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">仍以仅部署 cache A 和 cache C 的情况为例，在图 4 中我们已经看到， cache 分布并不均匀。现在我们引入虚拟节点，并设置"复制个数"为 2 ，这就意味着一共会存在 4 个"虚拟节点"， cache A1, cache A2 代表了 cache A ； cache C1, cache C2 代表了 cache C ；假设一种比较理想的情况，参见图 6 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_009n58b972cf.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 6 引入"虚拟节点"后的映射关系</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">此时，对象到"虚拟节点"的映射关系为：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">objec1-&#62;cache A2 ； objec2-&#62;cache A1 ； objec3-&#62;cache C1 ； objec4-&#62;cache C2 ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此对象 object1 和 object2 都被映射到了 cache A 上，而 object3 和 object4 映射到了 cache C 上；平衡性有了很大提高。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"后，映射关系就从 { 对象 -&#62; 节点 } 转换到了 { 对象 -&#62; 虚拟节点 } 。查询物体所在 cache时的映射关系如图 7 所示。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_010p69809704.png" alt="" width="533" height="236" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 7 查询对象所在 cache</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">"虚拟节点"的 hash 计算可以采用对应节点的 IP 地址加数字后缀的方式。例如假设 cache A 的 IP 地址为202.168.14.241 。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"前，计算 cache A 的 hash 值：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241");</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"后，计算"虚拟节"点 cache A1 和 cache A2 的 hash 值：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241#1"); // cache A1</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241#2"); // cache A2</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.5</strong> <strong>参考</strong></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">a) <a href="http://www.codeproject.com/KB/recipes/lib-conhash.aspx">http://www.codeproject.com/KB/recipes/lib-conhash.aspx</a></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">b) <a href="http://www.jiacheo.org/blog/174">http://www.jiacheo.org/blog/174</a></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">另外附上我用php实现的crc32版本的一致性hash</p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">没有做节点迁移</p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">[download id="34"]</p><p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html">关于一致性哈希</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt; mso-char-indent-count: 0; mso-outline-level: 1; mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;"><strong>1.</strong> <strong>一致性哈希</strong></p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.1</strong> <strong>基本场景</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">比如你有 N 个 cache 服务器（后面简称 cache ），那么如何将一个对象 object 映射到 N 个 cache 上呢，你很可能会采用类似下面的通用方法计算 object 的 <span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/hash" title="查看 hash 中的全部文章" target="_blank">hash</a></span> 值，然后均匀的映射到到 N 个 cache ；</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/hash" title="查看 hash 中的全部文章" target="_blank">hash</a></span>(object)%N</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">一切都运行正常，再考虑如下的两种情况；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">1 一个 cache 服务器 m down 掉了（在实际应用中必须要考虑这种情况），这样所有映射到 cache m 的对象都会失效，怎么办，需要把 cache m 从 cache 中移除，这时候 cache 是 N-1 台，映射公式变成了 <span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/hash" title="查看 hash 中的全部文章" target="_blank">hash</a></span>(object)%(N-1) ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">2 由于访问加重，需要添加 cache ，这时候 cache 是 N+1 台，映射公式变成了 <span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/hash" title="查看 hash 中的全部文章" target="_blank">hash</a></span>(object)%(N+1) ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">1 和 2 意味着什么？这意味着突然之间几乎所有的 cache 都失效了。对于服务器而言，这是一场灾难，洪水般的访问都会直接冲向后台服务器；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">再来考虑第三个问题，由于硬件能力越来越强，你可能想让后面添加的节点多做点活，显然上面的 hash 算法也做不到。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">有什么方法可以改变这个状况呢，这就是 consistent hashing...</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.2</strong> <strong>hash</strong> <strong>算法和单调性</strong></p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">　　 Hash 算法的一个衡量指标是单调性（ Monotonicity ），定义如下：</p>
<p style="text-align: left; text-indent: 19.5pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中，又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去，而不会被映射到旧的缓冲集合中的其他缓冲区。</p>
<p style="text-align: left; text-indent: 19.5pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_001n3deac82d.png" alt="" width="435" height="312" /></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">容易看到，上面的简单 hash 算法 hash(object)%N 难以满足单调性要求。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">如果我们的node2节点挂掉了..</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">新的hash()%3</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">node1 应存放1 2 3 4 node3 应放 5 6 7 8 node4 应放 9 10 11 12</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">需要迁移的节点 node1 1个 node3 3个 node4 1个</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">总共需迁移5个 比例数5/12 差不多到50%了..</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">如果value更多呢..后果不堪设想..</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.3</strong> <strong>consistent hashing</strong> <strong>算法的原理</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_003p37496d02.png" alt="" width="499" height="418" /></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">consistent hashing 是一种 hash 算法，简单的说，在移除 / 添加一个 cache 时，它能够尽可能小的改变已存在 key 映射关系，尽可能的满足单调性的要求。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">下面就来按照 5 个步骤简单讲讲 consistent hashing 算法的基本原理。</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.1</strong><strong>环形hash</strong> 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考虑通常的 hash 算法都是将 value 映射到一个 32 为的 key 值，也即是 0~2^32-1 次方的数值空间；我们可以将这个空间想象成一个首（ 0 ）尾（ 2^32-1 ）相接的圆环，如下面图 1 所示的那样。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_004n2baf70a9.png" alt="" width="95" height="108" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 1 环形 hash 空间</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.2</strong> <strong>把对象映射到hash</strong> 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">接下来考虑 4 个对象 object1~object4 ，通过 hash 函数计算出的 hash 值 key 在环上的分布如图 2 所示。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(object1) = key1;</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">… …</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(object4) = key4;</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_005p426e5290.png" alt="" width="238" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 2 4 个对象的 key 值分布</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.3</strong> <strong>把cache</strong> 映射到hash 空间</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Consistent hashing 的基本思想就是将对象和 cache 都映射到同一个 hash 数值空间中，并且使用相同的hash 算法。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">假设当前有 A,B 和 C 共 3 台 cache ，那么其映射结果将如图 3 所示，他们在 hash 空间中，以对应的 hash值排列。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(cache A) = key A;</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">… …</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash(cache C) = key C;</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_006n3e9af41f.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 3 cache 和对象的 key 值分布</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">说到这里，顺便提一下 cache 的 hash 计算，一般的方法可以使用 cache 机器的 IP 地址或者机器名作为hash 输入。</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.4</strong> <strong>把对象映射到cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">现在 cache 和对象都已经通过同一个 hash 算法映射到 hash 数值空间中了，接下来要考虑的就是如何将对象映射到 cache 上面了。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">在这个环形空间中，如果沿着顺时针方向从对象的 key 值出发，直到遇见一个 cache ，那么就将该对象存储在这个 cache 上，因为对象和 cache 的 hash 值是固定的，因此这个 cache 必然是唯一和确定的。这样不就找到了对象和 cache 的映射方法了吗？！</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">依然继续上面的例子（参见图 3 ），那么根据上面的方法，对象 object1 将被存储到 cache A 上； object2和 object3 对应到 cache C ； object4 对应到 cache B ；</p>
<p style="text-align: left; text-indent: 0.1pt; margin: 0cm 0cm 0pt 21.2pt; background: white; mso-char-indent-count: .01; mso-outline-level: 3; mso-pagination: widow-orphan; mso-para-margin-left: 2.02gd;"><strong>2.3.5</strong> <strong>考察cache</strong> 的变动</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">前面讲过，通过 hash 然后求余的方法带来的最大问题就在于不能满足单调性，当 cache 有所变动时，cache 会失效，进而对后台服务器造成巨大的冲击，现在就来分析分析 consistent hashing 算法。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><strong>a)</strong> <strong>移除 cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考虑假设 cache B 挂掉了，根据上面讲到的映射方法，这时受影响的将仅是那些沿 cache B 逆时针遍历直到下一个 cache （ cache C ）之间的对象，也即是本来映射到 cache B 上的那些对象。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此这里仅需要变动对象 object4 ，将其重新映射到 cache C 上即可；参见图 4 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_007n77df2844.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 4 Cache B 被移除后的 cache 映射</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><strong>b)</strong> <strong>添加 cache</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">再考虑添加一台新的 cache D 的情况，假设在这个环形 hash 空间中， cache D 被映射在对象 object2 和object3 之间。这时受影响的将仅是那些沿 cache D 逆时针遍历直到下一个 cache （ cache B ）之间的对象（它们是也本来映射到 cache C 上对象的一部分），将这些对象重新映射到 cache D 上即可。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此这里仅需要变动对象 object2 ，将其重新映射到 cache D 上；参见图 5 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_008n69674042.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 5 添加 cache D 后的映射关系</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.4</strong> <strong>虚拟节点</strong></p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">考量 Hash 算法的另一个指标是平衡性 (Balance) ，定义如下：</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">平衡性</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">　　平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去，这样可以使得所有的缓冲空间都得到利用。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">hash 算法并不是保证绝对的平衡，如果 cache 较少的话，对象并不能被均匀的映射到 cache 上，比如在上面的例子中，仅部署 cache A 和 cache C 的情况下，在 4 个对象中， cache A 仅存储了 object1 ，而 cache C 则存储了 object2 、 object3 和 object4 ；分布是很不均衡的。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">为了解决这种情况， consistent hashing 引入了"虚拟节点"的概念，它可以如下定义：</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">"虚拟节点"（ virtual node ）是实际节点在 hash 空间的复制品（ replica ），一实际个节点对应了若干个"虚拟节点"，这个对应个数也成为"复制个数"，"虚拟节点"在 hash 空间中以 hash 值排列。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">仍以仅部署 cache A 和 cache C 的情况为例，在图 4 中我们已经看到， cache 分布并不均匀。现在我们引入虚拟节点，并设置"复制个数"为 2 ，这就意味着一共会存在 4 个"虚拟节点"， cache A1, cache A2 代表了 cache A ； cache C1, cache C2 代表了 cache C ；假设一种比较理想的情况，参见图 6 。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_009n58b972cf.png" alt="" width="287" height="257" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 6 引入"虚拟节点"后的映射关系</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">此时，对象到"虚拟节点"的映射关系为：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">objec1-&gt;cache A2 ； objec2-&gt;cache A1 ； objec3-&gt;cache C1 ； objec4-&gt;cache C2 ；</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">因此对象 object1 和 object2 都被映射到了 cache A 上，而 object3 和 object4 映射到了 cache C 上；平衡性有了很大提高。</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"后，映射关系就从 { 对象 -&gt; 节点 } 转换到了 { 对象 -&gt; 虚拟节点 } 。查询物体所在 cache时的映射关系如图 7 所示。</p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;"><img src="http://3haku.net/wp-content/uploads/2011/11/zrclip_010p69809704.png" alt="" width="533" height="236" /></p>
<p style="text-align: center; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">图 7 查询对象所在 cache</p>
<p style="text-align: left; text-indent: 21pt; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">"虚拟节点"的 hash 计算可以采用对应节点的 IP 地址加数字后缀的方式。例如假设 cache A 的 IP 地址为202.168.14.241 。</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"前，计算 cache A 的 hash 值：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241");</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">引入"虚拟节点"后，计算"虚拟节"点 cache A1 和 cache A2 的 hash 值：</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241#1"); // cache A1</p>
<p style="text-align: left; margin: 0cm 0cm 0pt; background: white; mso-pagination: widow-orphan;">Hash("202.168.14.241#2"); // cache A2</p>
<p style="text-align: left; text-indent: -50.7pt; margin: 0cm 0cm 0pt 72pt; background: white; mso-char-indent-count: 0; mso-outline-level: 2; mso-list: l1 level2 lfo1; tab-stops: list 42.55pt; mso-pagination: widow-orphan;"><strong>2.5</strong> <strong>参考</strong></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">a) <a href="http://www.codeproject.com/KB/recipes/lib-conhash.aspx">http://www.codeproject.com/KB/recipes/lib-conhash.aspx</a></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">b) <a href="http://www.jiacheo.org/blog/174">http://www.jiacheo.org/blog/174</a></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">另外附上我用php实现的crc32版本的一致性hash</p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;">没有做节点迁移</p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt; mso-char-indent-count: 0; mso-list: l0 level1 lfo2;"><a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=34" title=" downloaded 14 times" >ConsistentHash_php (14)</a></p>
<p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html">关于一致性哈希</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/11/15/%e5%85%b3%e4%ba%8e%e4%b8%80%e8%87%b4%e6%80%a7%e5%93%88%e5%b8%8c.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>phpcurl模块</title>
		<link>http://3haku.net/2011/11/15/phpcurl%e6%a8%a1%e5%9d%97.html</link>
		<comments>http://3haku.net/2011/11/15/phpcurl%e6%a8%a1%e5%9d%97.html#comments</comments>
		<pubDate>Tue, 15 Nov 2011 11:48:43 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://3haku.net/?p=2351</guid>
		<description><![CDATA[<strong>1  </strong><strong>概述</strong>

PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。

目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。

为什么不用socket?

curl，是client url的简写，用来模拟浏览器的功能,浏览器能做的它基本都能实现,登陆，上传文件，下载...
socket可以理解为通信链的句柄，比CURL更底层一点

某些时候我们可能更需要简单模拟下浏览器功能即可，所以用CURL

到底能干什么??

<em>sample : </em><a href="http://3haku.net/?p=2177"><em>http://3haku.net/?p=2177</em></a><em>   </em>飞信API

<strong>2  </strong><strong>安装</strong><strong></strong>

1. 编译方式安装

./configure  --prefix=%PHP_DIR% --with-curl

make

make install
<ol>
	<li>模块安装</li>
</ol>
复制mod_curl.so到module目录

修改php.ini

加入module=mod_curl.so

然后重启apache服务器

用phpinfo如果能看到就说明安装成功

<a href="http://3haku.net/wp-content/uploads/2011/11/info.png"><img class="alignnone size-full wp-image-2352" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info.png" alt="" width="644" height="96" /></a>

<strong>3  </strong><strong>使用例子</strong><strong></strong>

$curl= curl_init();

curl_setopt($curl, CURLOPT_URL, “http://baidu.com”);

// 设置header

curl_setopt($curl, CURLOPT_HEADER, 1);

// 设置cURL 参数，要求结果保存到字符串中还是输出到屏幕上。

curl_setopt($this-&#62;curl, CURLOPT_RETURNTRANSFER, 1);

// 运行cURL，请求网页

$data = curl_exec($curl);

&#160;

在执行curl_exec的时候会阻塞线程，直到返回结果

cookie的使用可以用

curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);

或者从响应头拆分set-cookie出来

<strong>7.4 </strong><strong>关于CURL_MULTI</strong><strong></strong>

考虑如下情形，你需要从google.com.hk和baidu.com拿到他们的首页资料

前面已经说过执行curl_exec(的时候会阻塞线程。如果使用它，相当于分两次请求，每次1个网站。

平均执行时间如下

<a href="http://3haku.net/wp-content/uploads/2011/11/info2.png"><img class="alignnone size-full wp-image-2354" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info2.png" alt="" width="260" height="28" /></a>

用wiresharp抓包可以发现系统的两个请求，第二个等待第一个返回后才发出的

<a href="http://3haku.net/wp-content/uploads/2011/11/info1.png"><img class="alignnone size-full wp-image-2353" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info1.png" alt="" width="646" height="67" /></a>

<a href="http://www.php.net/manual/zh/function.curl-multi-exec.php">curl_ multi</a>的功能是并发地执行几个请求

curl_multi_exec($mh,$running);

这个函数是非阻塞的，返回的$running是表示当前是否还有正在处理的curl进程

之前的代码改用multi_exec实现

<a href="http://3haku.net/wp-content/uploads/2011/11/info3.png"><img class="alignnone size-full wp-image-2355" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info3.png" alt="" width="346" height="239" /></a>

平均结果为

<a href="http://3haku.net/wp-content/uploads/2011/11/info4.png"><img class="alignnone size-full wp-image-2356" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info4.png" alt="" width="286" height="33" /></a>

用wiresharp抓包可以看到系统同时发出了两个请求

<a href="http://3haku.net/wp-content/uploads/2011/11/info5.png"><img class="alignnone size-full wp-image-2357" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info5.png" alt="" width="637" height="62" /></a>

<strong>5  </strong><strong>附录:TIPS</strong><strong></strong>
<ol>
	<li>命令行版的CURL的使用参考</li>
</ol>
a)        <a href="http://www.ruanyifeng.com/blog/2011/09/curl.html">http://www.ruanyifeng.com/blog/2011/09/curl.html</a>

b)        <a href="http://curl.haxx.se/docs/httpscripting.html">http://curl.haxx.se/docs/httpscripting.html</a>
<ol>
	<li>超时设置</li>
</ol>
<a href="http://3haku.net/wp-content/uploads/2011/11/info6.png"><img class="alignnone size-full wp-image-2358" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info6.png" alt="" width="642" height="96" /></a>

CURLOPT_CONNCETTIMEOUT_MS支持毫秒级别的超时

不过只有在CURL7.16.2和5.2.3同时满足的情况下才可用

<strong>
</strong><p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/phpcurl%e6%a8%a1%e5%9d%97.html">phpcurl模块</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p><strong>1  </strong><strong>概述</strong></p>
<p>PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。</p>
<p>目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。</p>
<p>为什么不用socket?</p>
<p>curl，是client url的简写，用来模拟浏览器的功能,浏览器能做的它基本都能实现,登陆，上传文件，下载...<br />
socket可以理解为通信链的句柄，比CURL更底层一点</p>
<p>某些时候我们可能更需要简单模拟下浏览器功能即可，所以用CURL</p>
<p>到底能干什么??</p>
<p><em>sample : </em><a href="http://3haku.net/?p=2177"><em>http://3haku.net/?p=2177</em></a><em>   </em>飞信API</p>
<p><strong>2  </strong><strong>安装</strong><strong></strong></p>
<p>1. 编译方式安装</p>
<p>./configure  --prefix=%PHP_DIR% --with-curl</p>
<p>make</p>
<p>make install</p>
<ol>
<li>模块安装</li>
</ol>
<p>复制mod_curl.so到module目录</p>
<p>修改php.ini</p>
<p>加入module=mod_curl.so</p>
<p>然后重启apache服务器</p>
<p>用phpinfo如果能看到就说明安装成功</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2352" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info.png" alt="" width="644" height="96" /></a></p>
<p><strong>3  </strong><strong>使用例子</strong><strong></strong></p>
<p>$curl= curl_init();</p>
<p>curl_setopt($curl, CURLOPT_URL, “http://baidu.com”);</p>
<p>// 设置header</p>
<p>curl_setopt($curl, CURLOPT_HEADER, 1);</p>
<p>// 设置cURL 参数，要求结果保存到字符串中还是输出到屏幕上。</p>
<p>curl_setopt($this-&gt;curl, CURLOPT_RETURNTRANSFER, 1);</p>
<p>// 运行cURL，请求网页</p>
<p>$data = curl_exec($curl);</p>
<p>&nbsp;</p>
<p>在执行curl_exec的时候会阻塞线程，直到返回结果</p>
<p>cookie的使用可以用</p>
<p>curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);</p>
<p>或者从响应头拆分set-cookie出来</p>
<p><strong>7.4 </strong><strong>关于CURL_MULTI</strong><strong></strong></p>
<p>考虑如下情形，你需要从google.com.hk和baidu.com拿到他们的首页资料</p>
<p>前面已经说过执行curl_exec(的时候会阻塞线程。如果使用它，相当于分两次请求，每次1个网站。</p>
<p>平均执行时间如下</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info2.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2354" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info2.png" alt="" width="260" height="28" /></a></p>
<p>用wiresharp抓包可以发现系统的两个请求，第二个等待第一个返回后才发出的</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info1.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2353" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info1.png" alt="" width="646" height="67" /></a></p>
<p><a href="http://www.php.net/manual/zh/function.curl-multi-exec.php">curl_ multi</a>的功能是并发地执行几个请求</p>
<p>curl_multi_exec($mh,$running);</p>
<p>这个函数是非阻塞的，返回的$running是表示当前是否还有正在处理的curl进程</p>
<p>之前的代码改用multi_exec实现</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info3.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2355" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info3.png" alt="" width="346" height="239" /></a></p>
<p>平均结果为</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info4.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2356" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info4.png" alt="" width="286" height="33" /></a></p>
<p>用wiresharp抓包可以看到系统同时发出了两个请求</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info5.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2357" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info5.png" alt="" width="637" height="62" /></a></p>
<p><strong>5  </strong><strong>附录:TIPS</strong><strong></strong></p>
<ol>
<li>命令行版的CURL的使用参考</li>
</ol>
<p>a)        <a href="http://www.ruanyifeng.com/blog/2011/09/curl.html">http://www.ruanyifeng.com/blog/2011/09/curl.html</a></p>
<p>b)        <a href="http://curl.haxx.se/docs/httpscripting.html">http://curl.haxx.se/docs/httpscripting.html</a></p>
<ol>
<li>超时设置</li>
</ol>
<p><a href="http://3haku.net/wp-content/uploads/2011/11/info6.png" rel="lightbox[2351]"><img class="alignnone size-full wp-image-2358" title="info" src="http://3haku.net/wp-content/uploads/2011/11/info6.png" alt="" width="642" height="96" /></a></p>
<p>CURLOPT_CONNCETTIMEOUT_MS支持毫秒级别的超时</p>
<p>不过只有在CURL7.16.2和5.2.3同时满足的情况下才可用</p>
<p><strong><br />
</strong></p>
<p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/phpcurl%e6%a8%a1%e5%9d%97.html">phpcurl模块</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/11/15/phpcurl%e6%a8%a1%e5%9d%97.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>apache日志分离组件cronolog</title>
		<link>http://3haku.net/2011/11/15/apache%e6%97%a5%e5%bf%97%e5%88%86%e7%a6%bb%e7%bb%84%e4%bb%b6cronolog.html</link>
		<comments>http://3haku.net/2011/11/15/apache%e6%97%a5%e5%bf%97%e5%88%86%e7%a6%bb%e7%bb%84%e4%bb%b6cronolog.html#comments</comments>
		<pubDate>Tue, 15 Nov 2011 11:36:23 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[webbuild]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[日志分离]]></category>

		<guid isPermaLink="false">http://3haku.net/?p=2347</guid>
		<description><![CDATA[<strong>1.1   </strong><strong>概述</strong><strong></strong>

apache默认的日志都会记录到一个文件内

如果访问量过多，时间过长，将导致日志堆积，文件变大，影响apache的性能

cronolog是一个用于日志切分的软件,使用管道把输入定位到其他路径保存

<strong>1.2   </strong><strong>安装</strong><strong></strong>

<em>wget http://cronolog.org/download/cronolog-1.6.2.tar.gz</em>

<em>tar xcvf cronolog-1.6.2.tar.gz</em>

<em>cd cronolog-1.6.2</em>

<em>sudo ./configure -–prefix=%INSTALL_DIR%</em>

<em>sudo make install</em>

<strong>1.3   </strong><strong>使用</strong><strong></strong>

修改apache的日志记录

<em>CustomLog "&#124;%INSTALL_DIR%/cronolog %APACHE_HOME%/apache/logs/cronolog/%Y/%m/%d/%H_access_log" combined</em>

<em>ErrorLog "&#124;%INSTALL_DIR%/cronolog %APACHE_HOME%/logs/cronolog/%Y/%m/%d/error_log"</em>

<em> </em>

然后需要reload下apache

<em>sudo service apache restart</em>

接下来可以在对应的logs/cronolog里面找到分离开的日志

<strong>1.4   </strong><strong>Cronolog</strong><strong>的参书规则</strong><strong></strong>
<table width="93%" border="1" cellpadding="0">
<tbody>
<tr>
<td width="10%">
<p align="center"><strong>Specifier</strong><strong></strong></p>
</td>
<td width="88%">
<p align="center"><strong>Description</strong><strong></strong></p>
</td>
</tr>
<tr>
<td width="10%"><tt>%%</tt></td>
<td width="88%">a literal <tt>%</tt> character</td>
</tr>
<tr>
<td width="10%"><tt>%n</tt></td>
<td width="88%">a new-line character</td>
</tr>
<tr>
<td width="10%"><tt>%t</tt></td>
<td width="88%">a horizontal tab character</td>
</tr>
<tr>
<td colspan="2" width="99%"><strong>Time fields</strong></td>
</tr>
<tr>
<td width="10%"><tt>%H</tt></td>
<td width="88%">hour (00..23)</td>
</tr>
<tr>
<td width="10%"><tt>%I</tt></td>
<td width="88%">hour (01..12)</td>
</tr>
<tr>
<td width="10%"><tt>%p</tt></td>
<td width="88%">the locale's AM or PM indicator</td>
</tr>
<tr>
<td width="10%"><tt>%M</tt></td>
<td width="88%">minute (00..59)</td>
</tr>
<tr>
<td width="10%"><tt>%S</tt></td>
<td width="88%">second (00..61, which allows for leap seconds)</td>
</tr>
<tr>
<td width="10%"><tt>%X</tt></td>
<td width="88%">the locale's time representation (e.g.: "15:12:47")</td>
</tr>
<tr>
<td width="10%"><tt>%Z</tt></td>
<td width="88%">time zone (e.g. GMT), or nothing if the time zone cannot be determined</td>
</tr>
<tr>
<td colspan="2" width="99%"><strong>Date fields</strong></td>
</tr>
<tr>
<td width="10%"><tt>%a</tt></td>
<td width="88%">the locale's abbreviated weekday name (e.g.: Sun..Sat)</td>
</tr>
<tr>
<td width="10%"><tt>%A</tt></td>
<td width="88%">the locale's full weekday name (e.g.: Sunday .. Saturday)</td>
</tr>
<tr>
<td width="10%"><tt>%b</tt></td>
<td width="88%">the locale's abbreviated month name (e.g.: Jan .. Dec)</td>
</tr>
<tr>
<td width="10%"><tt>%B</tt></td>
<td width="88%">the locale's full month name, (e.g.: January .. December)</td>
</tr>
<tr>
<td width="10%"><tt>%c</tt></td>
<td width="88%">the locale's date and time (e.g.: <tt>"Sun Dec 15 14:12:47 GMT 1996")</tt></td>
</tr>
<tr>
<td width="10%"><tt>%d</tt></td>
<td width="88%">day of month (01 .. 31)</td>
</tr>
<tr>
<td width="10%"><tt>%j</tt></td>
<td width="88%">day of year (001 .. 366)</td>
</tr>
<tr>
<td width="10%"><tt>%m</tt></td>
<td width="88%">month (01 .. 12)</td>
</tr>
<tr>
<td width="10%"><tt>%U</tt></td>
<td width="88%">week of the year with Sunday as first day of week (00..53, where week 1 is the week containing the first Sunday of the year)</td>
</tr>
<tr>
<td width="10%"><tt>%W</tt></td>
<td width="88%">week of the year with Monday as first day of week (00..53, where week 1 is the week containing the first Monday of the year)</td>
</tr>
<tr>
<td width="10%"><tt>%w</tt></td>
<td width="88%">day of week (0 .. 6, where 0 corresponds to Sunday)</td>
</tr>
<tr>
<td width="10%"><tt>%x</tt></td>
<td width="88%">locale's date representation (e.g. today in Britain: "15/12/96")</td>
</tr>
<tr>
<td width="10%"><tt>%y</tt></td>
<td width="88%">year without the century (00 .. 99)</td>
</tr>
<tr>
<td width="10%"><tt>%Y</tt></td>
<td width="88%">year with the century (1970 .. 2038)</td>
</tr>
</tbody>
</table><p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/apache%e6%97%a5%e5%bf%97%e5%88%86%e7%a6%bb%e7%bb%84%e4%bb%b6cronolog.html">apache日志分离组件cronolog</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p><strong>1.1   </strong><strong>概述</strong><strong></strong></p>
<p><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/apache" title="查看 apache 中的全部文章" target="_blank">apache</a></span>默认的日志都会记录到一个文件内</p>
<p>如果访问量过多，时间过长，将导致日志堆积，文件变大，影响<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/apache" title="查看 apache 中的全部文章" target="_blank">apache</a></span>的性能</p>
<p>cronolog是一个用于日志切分的软件,使用管道把输入定位到其他路径保存</p>
<p><strong>1.2   </strong><strong>安装</strong><strong></strong></p>
<p><em>wget http://cronolog.org/download/cronolog-1.6.2.tar.gz</em></p>
<p><em>tar xcvf cronolog-1.6.2.tar.gz</em></p>
<p><em>cd cronolog-1.6.2</em></p>
<p><em>sudo ./configure -–prefix=%INSTALL_DIR%</em></p>
<p><em>sudo make install</em></p>
<p><strong>1.3   </strong><strong>使用</strong><strong></strong></p>
<p>修改<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/apache" title="查看 apache 中的全部文章" target="_blank">apache</a></span>的日志记录</p>
<p><em>CustomLog "|%INSTALL_DIR%/cronolog %APACHE_HOME%/<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/apache" title="查看 apache 中的全部文章" target="_blank">apache</a></span>/logs/cronolog/%Y/%m/%d/%H_access_log" combined</em></p>
<p><em>ErrorLog "|%INSTALL_DIR%/cronolog %APACHE_HOME%/logs/cronolog/%Y/%m/%d/error_log"</em></p>
<p><em> </em></p>
<p>然后需要reload下<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/apache" title="查看 apache 中的全部文章" target="_blank">apache</a></span></p>
<p><em>sudo service apache restart</em></p>
<p>接下来可以在对应的logs/cronolog里面找到分离开的日志</p>
<p><strong>1.4   </strong><strong>Cronolog</strong><strong>的参书规则</strong><strong></strong></p>
<table width="93%" border="1" cellpadding="0">
<tbody>
<tr>
<td width="10%">
<p align="center"><strong>Specifier</strong><strong></strong></p>
</td>
<td width="88%">
<p align="center"><strong>Description</strong><strong></strong></p>
</td>
</tr>
<tr>
<td width="10%"><tt>%%</tt></td>
<td width="88%">a literal <tt>%</tt> character</td>
</tr>
<tr>
<td width="10%"><tt>%n</tt></td>
<td width="88%">a new-line character</td>
</tr>
<tr>
<td width="10%"><tt>%t</tt></td>
<td width="88%">a horizontal tab character</td>
</tr>
<tr>
<td colspan="2" width="99%"><strong>Time fields</strong></td>
</tr>
<tr>
<td width="10%"><tt>%H</tt></td>
<td width="88%">hour (00..23)</td>
</tr>
<tr>
<td width="10%"><tt>%I</tt></td>
<td width="88%">hour (01..12)</td>
</tr>
<tr>
<td width="10%"><tt>%p</tt></td>
<td width="88%">the locale's AM or PM indicator</td>
</tr>
<tr>
<td width="10%"><tt>%M</tt></td>
<td width="88%">minute (00..59)</td>
</tr>
<tr>
<td width="10%"><tt>%S</tt></td>
<td width="88%">second (00..61, which allows for leap seconds)</td>
</tr>
<tr>
<td width="10%"><tt>%X</tt></td>
<td width="88%">the locale's time representation (e.g.: "15:12:47")</td>
</tr>
<tr>
<td width="10%"><tt>%Z</tt></td>
<td width="88%">time zone (e.g. GMT), or nothing if the time zone cannot be determined</td>
</tr>
<tr>
<td colspan="2" width="99%"><strong>Date fields</strong></td>
</tr>
<tr>
<td width="10%"><tt>%a</tt></td>
<td width="88%">the locale's abbreviated weekday name (e.g.: Sun..Sat)</td>
</tr>
<tr>
<td width="10%"><tt>%A</tt></td>
<td width="88%">the locale's full weekday name (e.g.: Sunday .. Saturday)</td>
</tr>
<tr>
<td width="10%"><tt>%b</tt></td>
<td width="88%">the locale's abbreviated month name (e.g.: Jan .. Dec)</td>
</tr>
<tr>
<td width="10%"><tt>%B</tt></td>
<td width="88%">the locale's full month name, (e.g.: January .. December)</td>
</tr>
<tr>
<td width="10%"><tt>%c</tt></td>
<td width="88%">the locale's date and time (e.g.: <tt>"Sun Dec 15 14:12:47 GMT 1996")</tt></td>
</tr>
<tr>
<td width="10%"><tt>%d</tt></td>
<td width="88%">day of month (01 .. 31)</td>
</tr>
<tr>
<td width="10%"><tt>%j</tt></td>
<td width="88%">day of year (001 .. 366)</td>
</tr>
<tr>
<td width="10%"><tt>%m</tt></td>
<td width="88%">month (01 .. 12)</td>
</tr>
<tr>
<td width="10%"><tt>%U</tt></td>
<td width="88%">week of the year with Sunday as first day of week (00..53, where week 1 is the week containing the first Sunday of the year)</td>
</tr>
<tr>
<td width="10%"><tt>%W</tt></td>
<td width="88%">week of the year with Monday as first day of week (00..53, where week 1 is the week containing the first Monday of the year)</td>
</tr>
<tr>
<td width="10%"><tt>%w</tt></td>
<td width="88%">day of week (0 .. 6, where 0 corresponds to Sunday)</td>
</tr>
<tr>
<td width="10%"><tt>%x</tt></td>
<td width="88%">locale's date representation (e.g. today in Britain: "15/12/96")</td>
</tr>
<tr>
<td width="10%"><tt>%y</tt></td>
<td width="88%">year without the century (00 .. 99)</td>
</tr>
<tr>
<td width="10%"><tt>%Y</tt></td>
<td width="88%">year with the century (1970 .. 2038)</td>
</tr>
</tbody>
</table>
<p><br/>点击阅读: <a href="http://3haku.net/2011/11/15/apache%e6%97%a5%e5%bf%97%e5%88%86%e7%a6%bb%e7%bb%84%e4%bb%b6cronolog.html">apache日志分离组件cronolog</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/11/15/apache%e6%97%a5%e5%bf%97%e5%88%86%e7%a6%bb%e7%bb%84%e4%bb%b6cronolog.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一段代码说优化[php]</title>
		<link>http://3haku.net/2011/10/29/%e4%b8%80%e6%ae%b5%e4%bb%a3%e7%a0%81%e8%af%b4%e4%bc%98%e5%8c%96php.html</link>
		<comments>http://3haku.net/2011/10/29/%e4%b8%80%e6%ae%b5%e4%bb%a3%e7%a0%81%e8%af%b4%e4%bc%98%e5%8c%96php.html#comments</comments>
		<pubDate>Sat, 29 Oct 2011 08:50:56 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://3haku.net/?p=2333</guid>
		<description><![CDATA[<span style="color: #000080;">这是原始代码</span>
<ol class="linenums">
	<li class="L0"><span class="pun">&#60;?</span></li>
	<li class="L1"><span class="pln">       echo </span><span class="str">"Hello "</span><span class="pun">.</span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">].</span><span class="str">"!"</span><span class="pun">;</span></li>
	<li class="L2"><span class="pun">?&#62; </span></li>
</ol>
<span style="color: #000080;">这段代码是大体没有问题的，但是存在一些细节</span>

<span style="color: #888888;">1.<span class="Apple-style-span">       开头使用&#60;?    没有使用&#60;?php  不规范如果php.ini里面没有开启的话  此段代码将无法执行</span></span>

<span style="color: #888888;">2.       $_GET['name']没有做前置判断是否存在。如果url里面没有这个参数。用户进来很有可能看到报警信息，不友好</span>

<span style="color: #888888;">3.       "(双引号)和'(单引号)的区别是单引号不会对里面的内容进行匹配转义。</span>

<span style="color: #000080;">比如</span>
<ol class="linenums">
	<li class="L0"><span class="pln">$a</span><span class="pun">=</span><span class="str">'123'</span><span class="pun">;</span></li>
	<li class="L1"><span class="pln">echo </span><span class="str">'a$a'</span><span class="pun">;</span></li>
</ol>
<span style="color: #000080;">会输出a$a而非a123。</span>

<span style="color: #000080;">在上面的代码中不需要进行这种操作，所以用'(单引号)更好，解释器不再检测变量替换，速度更快</span>

<span style="color: #888888;">4.        这段代码的目的是打印出字符串。字符串中间的连接符可以改为,(逗号)   让echo顺序打印，不再执行字符串的连接操作</span>

<span style="color: #808080;">5.        输出没有转义，存在跨站漏洞，忘了，呵呵。 感谢老大指正~（<a href="http://weibo.com/taobaojiansu">@见素</a>）</span>

<span style="color: #000080;">最后的代码如下</span>
<ol class="linenums">
	<li class="L0"><span class="pun">&#60;?</span><span class="pln" style="color: #ff0000;">php</span></li>
	<li class="L1"><span style="color: #ff0000;"><span class="pln">     </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span></span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">])) </span><span class="pln">echo </span><span class="str"><span style="color: #ff0000;">'</span>Hello <span style="color: #ff0000;">'</span></span><span class="pun" style="color: #ff0000;">,htmlspecialchars(</span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]<span style="color: #ff0000;">)</span><span style="color: #ff0000;">,</span></span><span class="str"><span style="color: #ff0000;">'</span>!<span style="color: #ff0000;">'</span></span><span class="pun">;</span></li>
	<li class="L2"><span class="pun">?&#62;</span><span class="pln"> </span></li>
</ol><p><br/>点击阅读: <a href="http://3haku.net/2011/10/29/%e4%b8%80%e6%ae%b5%e4%bb%a3%e7%a0%81%e8%af%b4%e4%bc%98%e5%8c%96php.html">一段代码说优化[php]</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000080;">这是原始代码</span></p>
<ol class="linenums">
<li class="L0"><span class="pun">&lt;?</span></li>
<li class="L1"><span class="pln">       echo </span><span class="str">"Hello "</span><span class="pun">.</span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">].</span><span class="str">"!"</span><span class="pun">;</span></li>
<li class="L2"><span class="pun">?&gt; </span></li>
</ol>
<p><span style="color: #000080;">这段代码是大体没有问题的，但是存在一些细节</span></p>
<p><span style="color: #888888;">1.<span class="Apple-style-span">       开头使用&lt;?    没有使用&lt;?<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/php" title="查看 php 中的全部文章" target="_blank">php</a></span>  不规范如果<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/php" title="查看 php 中的全部文章" target="_blank">php</a></span>.ini里面没有开启的话  此段代码将无法执行</span></span></p>
<p><span style="color: #888888;">2.       $_GET['name']没有做前置判断是否存在。如果url里面没有这个参数。用户进来很有可能看到报警信息，不友好</span></p>
<p><span style="color: #888888;">3.       "(双引号)和'(单引号)的区别是单引号不会对里面的内容进行匹配转义。</span></p>
<p><span style="color: #000080;">比如</span></p>
<ol class="linenums">
<li class="L0"><span class="pln">$a</span><span class="pun">=</span><span class="str">'123'</span><span class="pun">;</span></li>
<li class="L1"><span class="pln">echo </span><span class="str">'a$a'</span><span class="pun">;</span></li>
</ol>
<p><span style="color: #000080;">会输出a$a而非a123。</span></p>
<p><span style="color: #000080;">在上面的代码中不需要进行这种操作，所以用'(单引号)更好，解释器不再检测变量替换，速度更快</span></p>
<p><span style="color: #888888;">4.        这段代码的目的是打印出字符串。字符串中间的连接符可以改为,(逗号)   让echo顺序打印，不再执行字符串的连接操作</span></p>
<p><span style="color: #808080;">5.        输出没有转义，存在跨站漏洞，忘了，呵呵。 感谢老大指正~（<a href="http://weibo.com/taobaojiansu">@见素</a>）</span></p>
<p><span style="color: #000080;">最后的代码如下</span></p>
<ol class="linenums">
<li class="L0"><span class="pun">&lt;?</span><span class="pln" style="color: #ff0000;"><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/php" title="查看 php 中的全部文章" target="_blank">php</a></span></span></li>
<li class="L1"><span style="color: #ff0000;"><span class="pln">     </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">isset</span><span class="pun">(</span></span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">])) </span><span class="pln">echo </span><span class="str"><span style="color: #ff0000;">'</span>Hello <span style="color: #ff0000;">'</span></span><span class="pun" style="color: #ff0000;">,htmlspecialchars(</span><span class="pln">$_GET</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]<span style="color: #ff0000;">)</span><span style="color: #ff0000;">,</span></span><span class="str"><span style="color: #ff0000;">'</span>!<span style="color: #ff0000;">'</span></span><span class="pun">;</span></li>
<li class="L2"><span class="pun">?&gt;</span><span class="pln"> </span></li>
</ol>
<p><br/>点击阅读: <a href="http://3haku.net/2011/10/29/%e4%b8%80%e6%ae%b5%e4%bb%a3%e7%a0%81%e8%af%b4%e4%bc%98%e5%8c%96php.html">一段代码说优化[php]</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/10/29/%e4%b8%80%e6%ae%b5%e4%bb%a3%e7%a0%81%e8%af%b4%e4%bc%98%e5%8c%96php.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ARP攻击和防御</title>
		<link>http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html</link>
		<comments>http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html#comments</comments>
		<pubDate>Thu, 13 Oct 2011 03:04:26 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[arp]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html</guid>
		<description><![CDATA[去实习前还是得找点事情做.于是决定写下这篇文章.

一.ARP概述

1) IP数据包常通过以太网发送。但是以太网设备并不识别32位IP地址：它们是以48位以太网地址(就是所谓的MAC)传输

以太网数据包的。因此，必须把IP目的地址转换成以太网网目的地址。在这两种地址之间存在着某种静态的或算法的映

射，常常需要查看一张表。地址解析协议(Address Resolution Protocol，ARP)就是用来确定这些映象的协议

2) ARP工作时,会向整个子网广播信息,ARP发送分两步。第一步request，第二步reply。第一步的时候，需要查询的主

机会询问整个子网，谁有我需要的ip？如果有主机拥有这个ip，目的主机就发送一个回应消息，并包含自己的MAC地址。

查询主机收到后便会更新自己的ARP表

下面用抓包工具给大家说明下，抓包工具我使用的是Wireshark，过滤只显示arp包

<a href="http://3haku.net/wp-content/uploads/2011/10/image.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb.png" alt="image" width="671" height="85" border="0" /></a>

根据上图 可以很明显的看到  首先QuantaCo_e3:77:0a (00:1e:68:e3:77:0a)这台电脑广播信息谁有192.168.0.3。请求包的最后含有请求主机的ip和mac，还有询问的ip

<a href="http://3haku.net/wp-content/uploads/2011/10/image1.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb1.png" alt="image" width="478" height="73" border="0" /></a>

接着主机AsustekC_94:5e:76 (00:26:18:94:5e:76)  回应给我们的QuantaCo_e3:77:0a (00:1e:68:e3:77:0a) 并带上了自己的mac地址00:26:18:94:5e:76告诉我们它有192.168.0.3

<a href="http://3haku.net/wp-content/uploads/2011/10/image2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb2.png" alt="image" width="475" height="69" border="0" /></a>

然后看看我们电脑的ARP表,已经出现他了

<a href="http://3haku.net/wp-content/uploads/2011/10/image3.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb3.png" alt="image" width="422" height="107" border="0" /></a>

之后如果我想和192.168.0.3通信就会使用00-26-18-94-5e-76这个MAC地址和目标主机进行通信

二.ARP欺骗

刚才说到了请求主机是向整个内网发送的请求,然后目标主机回应。这样就出现一个问题。如果我其实并不是目标主机

呢？于是我发送发布虚假的ARP报文，然后我就可以扮演某些机器，或者顺便对数据流进行简单的修改。

1) 典型的路由欺骗

一个正常的局域网内应该像这样  ABC如果想和外网通信 都需通过路由器出去

<a href="http://3haku.net/wp-content/uploads/2011/10/image4.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb4.png" alt="image" width="252" height="197" border="0" /></a>

但是如果A不停向BC发送ARP报文 包里面封装上路由的IP和自己的MAC.把自己伪装成路由

这样BC都会认为A是路由器,于是傻傻得把数据都交给A了..与此同时路由也会发送自己正确的ARP..

如果A不把包再转发出去..结果就是BC端端徐徐不能上网,或者很难才能联上外网

<a href="http://3haku.net/wp-content/uploads/2011/10/image5.png"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb5.png" alt="image" width="244" height="189" border="0" /></a>

就变成这样了  A拦截到所有的通信包,并可以进行分析

1.1) 代码实现

我用java实现了一个很简单的ARP攻击例子,java不能操作底层网络包.所以我们需要一个

其他的辅助工具jpcap [download id="32"] 这个东西因为是使用jni调用的,以下的以win为例子..linux需要改下包

安装的时候注意2点:

1. 请先安装winpcap或者ubuntu

2.使用32位的jdk或者jre   否则它都不会工作
<div class="cnblogs_code">
<pre><span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">核心是这些</span></pre>
</div>
arp.sender_hardaddr=device.mac_address;

arp.sender_protoaddr=gateway.getAddress();

改变报文ip为路由的ip  改变mac为我自己的mac

伪装路由器向整个局域网发送谁有<span style="color: #8b0000;">192.168.0.5<span style="color: #000000;">请告诉<span style="color: #8b0000;">192.168.0.1</span></span></span>

<span style="color: #8b0000;"><span style="color: #000000;"><span style="color: #8b0000;"><span style="color: #1f1f1f;">目标主机收到后.便会改变他自己电脑上的arp表.把192.168.0.1的mac对应成我的电脑的</span></span></span></span>

<span style="color: #8b0000;"><span style="color: #8b0000;"><span style="color: #1f1f1f;">结果就是之后的请求他都认为我是路由器从而我可以得到他发送的报文</span></span></span>

示例代码里面拦截所有80端口,,可以看到被攻击主机发送的http请求..cookie信息当然也在啦..

然后我们可以..

源码:  [download id="33"]

2) 针对服务器的ARP攻击

这类攻击常见于服务器群, vps群..内网上的主机被同网段的攻击主机攻陷..结果是您的网站不

定期被跳转到其他网站或者出现其他很奇怪的页面

原理和刚才一样.但是这类软件同时还有构造伪装的http包的功能.会把服务器正常的包给拦截下

转而发送自己的包给客户端.于是造成刚才说的现象..这类攻击比较隐蔽..而且在国内主机里面都比较普片

<a href="http://3haku.net/wp-content/uploads/2011/10/image6.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb6.png" alt="image" width="244" height="189" border="0" /></a>

三.ARP防御

1) 手动绑定网关

ARP表分为两种    动态的和静态的   用ARP协议进行更新的都是动态的

但是我们通过可以手动绑定ARP表的方式  静态的arp不会受影响

2) 使用软件

其实原理和上面的差不多  最好的解决办法就是绑定静态arp..

3) 有带保护功能的路由

但是如果是路由arp欺骗也基本无效..因为被欺骗的是其他内网用户 不是路由

综上  最简单方便的办法就是用arp –s 绑定静态路由

文中资料下载:

库:  [download id="32"]
源码:  [download id="33"]<p><br/>点击阅读: <a href="http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html">ARP攻击和防御</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p>去实习前还是得找点事情做.于是决定写下这篇文章.</p>
<p>一.ARP概述</p>
<p>1) IP数据包常通过以太网发送。但是以太网设备并不识别32位IP地址：它们是以48位以太网地址(就是所谓的MAC)传输</p>
<p>以太网数据包的。因此，必须把IP目的地址转换成以太网网目的地址。在这两种地址之间存在着某种静态的或算法的映</p>
<p>射，常常需要查看一张表。地址解析协议(Address Resolution Protocol，ARP)就是用来确定这些映象的协议</p>
<p>2) ARP工作时,会向整个子网广播信息,ARP发送分两步。第一步request，第二步reply。第一步的时候，需要查询的主</p>
<p>机会询问整个子网，谁有我需要的ip？如果有主机拥有这个ip，目的主机就发送一个回应消息，并包含自己的MAC地址。</p>
<p>查询主机收到后便会更新自己的ARP表</p>
<p>下面用抓包工具给大家说明下，抓包工具我使用的是Wireshark，过滤只显示<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/arp" title="查看 arp 中的全部文章" target="_blank">arp</a></span>包</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb.png" alt="image" width="671" height="85" border="0" /></a></p>
<p>根据上图 可以很明显的看到  首先QuantaCo_e3:77:0a (00:1e:68:e3:77:0a)这台电脑广播信息谁有192.168.0.3。请求包的最后含有请求主机的ip和mac，还有询问的ip</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image1.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb1.png" alt="image" width="478" height="73" border="0" /></a></p>
<p>接着主机AsustekC_94:5e:76 (00:26:18:94:5e:76)  回应给我们的QuantaCo_e3:77:0a (00:1e:68:e3:77:0a) 并带上了自己的mac地址00:26:18:94:5e:76告诉我们它有192.168.0.3</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image2.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb2.png" alt="image" width="475" height="69" border="0" /></a></p>
<p>然后看看我们电脑的ARP表,已经出现他了</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image3.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb3.png" alt="image" width="422" height="107" border="0" /></a></p>
<p>之后如果我想和192.168.0.3通信就会使用00-26-18-94-5e-76这个MAC地址和目标主机进行通信</p>
<p>二.ARP欺骗</p>
<p>刚才说到了请求主机是向整个内网发送的请求,然后目标主机回应。这样就出现一个问题。如果我其实并不是目标主机</p>
<p>呢？于是我发送发布虚假的ARP报文，然后我就可以扮演某些机器，或者顺便对数据流进行简单的修改。</p>
<p>1) 典型的路由欺骗</p>
<p>一个正常的局域网内应该像这样  ABC如果想和外网通信 都需通过路由器出去</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image4.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb4.png" alt="image" width="252" height="197" border="0" /></a></p>
<p>但是如果A不停向BC发送ARP报文 包里面封装上路由的IP和自己的MAC.把自己伪装成路由</p>
<p>这样BC都会认为A是路由器,于是傻傻得把数据都交给A了..与此同时路由也会发送自己正确的ARP..</p>
<p>如果A不把包再转发出去..结果就是BC端端徐徐不能上网,或者很难才能联上外网</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image5.png" rel="lightbox[2329]"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb5.png" alt="image" width="244" height="189" border="0" /></a></p>
<p>就变成这样了  A拦截到所有的通信包,并可以进行分析</p>
<p>1.1) 代码实现</p>
<p>我用<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/java" title="查看 java 中的全部文章" target="_blank">java</a></span>实现了一个很简单的ARP攻击例子,<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/java" title="查看 java 中的全部文章" target="_blank">java</a></span>不能操作底层网络包.所以我们需要一个</p>
<p>其他的辅助工具jpcap <a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=32" title=" downloaded 30 times" >jpcap-0.1.6 (30)</a> 这个东西因为是使用jni调用的,以下的以win为例子..linux需要改下包</p>
<p>安装的时候注意2点:</p>
<p>1. 请先安装winpcap或者ubuntu</p>
<p>2.使用32位的jdk或者jre   否则它都不会工作</p>
<div class="cnblogs_code">
<pre><span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">核心是这些</span></pre>
</div>
<p><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/arp" title="查看 arp 中的全部文章" target="_blank">arp</a></span>.sender_hardaddr=device.mac_address;</p>
<p><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/arp" title="查看 arp 中的全部文章" target="_blank">arp</a></span>.sender_protoaddr=gateway.getAddress();</p>
<p>改变报文ip为路由的ip  改变mac为我自己的mac</p>
<p>伪装路由器向整个局域网发送谁有<span style="color: #8b0000;">192.168.0.5<span style="color: #000000;">请告诉<span style="color: #8b0000;">192.168.0.1</span></span></span></p>
<p><span style="color: #8b0000;"><span style="color: #000000;"><span style="color: #8b0000;"><span style="color: #1f1f1f;">目标主机收到后.便会改变他自己电脑上的<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/arp" title="查看 arp 中的全部文章" target="_blank">arp</a></span>表.把192.168.0.1的mac对应成我的电脑的</span></span></span></span></p>
<p><span style="color: #8b0000;"><span style="color: #8b0000;"><span style="color: #1f1f1f;">结果就是之后的请求他都认为我是路由器从而我可以得到他发送的报文</span></span></span></p>
<p>示例代码里面拦截所有80端口,,可以看到被攻击主机发送的http请求..cookie信息当然也在啦..</p>
<p>然后我们可以..</p>
<p>源码:  <a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=33" title=" downloaded 39 times" >ArpAttract (39)</a></p>
<p>2) 针对服务器的ARP攻击</p>
<p>这类攻击常见于服务器群, vps群..内网上的主机被同网段的攻击主机攻陷..结果是您的网站不</p>
<p>定期被跳转到其他网站或者出现其他很奇怪的页面</p>
<p>原理和刚才一样.但是这类软件同时还有构造伪装的http包的功能.会把服务器正常的包给拦截下</p>
<p>转而发送自己的包给客户端.于是造成刚才说的现象..这类攻击比较隐蔽..而且在国内主机里面都比较普片</p>
<p><a href="http://3haku.net/wp-content/uploads/2011/10/image6.png" rel="lightbox[2329]"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://3haku.net/wp-content/uploads/2011/10/image_thumb6.png" alt="image" width="244" height="189" border="0" /></a></p>
<p>三.ARP防御</p>
<p>1) 手动绑定网关</p>
<p>ARP表分为两种    动态的和静态的   用ARP协议进行更新的都是动态的</p>
<p>但是我们通过可以手动绑定ARP表的方式  静态的<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/arp" title="查看 arp 中的全部文章" target="_blank">arp</a></span>不会受影响</p>
<p>2) 使用软件</p>
<p>其实原理和上面的差不多  最好的解决办法就是绑定静态arp..</p>
<p>3) 有带保护功能的路由</p>
<p>但是如果是路由arp欺骗也基本无效..因为被欺骗的是其他内网用户 不是路由</p>
<p>综上  最简单方便的办法就是用arp –s 绑定静态路由</p>
<p>文中资料下载:</p>
<p>库:  <a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=32" title=" downloaded 30 times" >jpcap-0.1.6 (30)</a><br />
源码:  <a class="downloadlink" href="http://3haku.net/wp-content/plugins/download-monitor/download.php?id=33" title=" downloaded 39 times" >ArpAttract (39)</a></p>
<p><br/>点击阅读: <a href="http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html">ARP攻击和防御</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/10/13/arp%e6%94%bb%e5%87%bb%e5%92%8c%e9%98%b2%e5%be%a1.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>可以去实习了!</title>
		<link>http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html</link>
		<comments>http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html#comments</comments>
		<pubDate>Fri, 30 Sep 2011 02:13:38 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[things goes by]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[淘宝]]></category>
		<category><![CDATA[面试]]></category>

		<guid isPermaLink="false">http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html</guid>
		<description><![CDATA[经过四天的面试后,终于可以去实习了!

面试的最大感觉就是..

得专一..哎.  很多基础性的东西答不上来..

基础需重视!   就如之前某说的   基础决定了你能走多远

感谢所有朋友,同学,面试官.

中途还得回来一下.

一直努力吧~

去之前还得先把学校这个选题系统写完..还差一点.

写完之后还是开源..<p><br/>点击阅读: <a href="http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html">可以去实习了!</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p>经过四天的<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/%e9%9d%a2%e8%af%95" title="查看 面试 中的全部文章" target="_blank">面试</a></span>后,终于可以去实习了!</p>
<p><span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/%e9%9d%a2%e8%af%95" title="查看 面试 中的全部文章" target="_blank">面试</a></span>的最大感觉就是..</p>
<p>得专一..哎.  很多基础性的东西答不上来..</p>
<p>基础需重视!   就如之前某说的   基础决定了你能走多远</p>
<p>感谢所有朋友,同学,<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/%e9%9d%a2%e8%af%95" title="查看 面试 中的全部文章" target="_blank">面试</a></span>官.</p>
<p>中途还得回来一下.</p>
<p>一直努力吧~</p>
<p>去之前还得先把学校这个选题系统写完..还差一点.</p>
<p>写完之后还是开源..</p>
<p><br/>点击阅读: <a href="http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html">可以去实习了!</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/09/30/%e5%8f%af%e4%bb%a5%e5%8e%bb%e5%ae%9e%e4%b9%a0%e4%ba%86.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>线程安全和一条sql语句引起的思考(二)</title>
		<link>http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html</link>
		<comments>http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html#comments</comments>
		<pubDate>Sat, 17 Sep 2011 14:08:30 +0000</pubDate>
		<dc:creator>princehaku</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[线程]]></category>

		<guid isPermaLink="false">http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html</guid>
		<description><![CDATA[接着上次的文章讨论php线程安全

当然不仅仅针对php

范大牛和我争了一下..不过说来问题是确实存在的

那怎么解决呢

其实解决方式有很多种

1. 把运算放在php里面
代码如下:
<div>
<pre><span style="color: #008000;">//如果大于0 就减100</span>
if($money&#62;0){
    $money -=100;
    $res=mysql_query("<span style="color: #8b0000;">UPDATE `test` SET `k` = $money where id=1</span>");
    echo "<span style="color: #8b0000;">减了!</span>";
}else{
    echo "<span style="color: #8b0000;">没做操作</span>";
}
结果:这样虽然会做重复的sql更新操作 但是结果都是正确的值</pre>
<pre>2.加上限定where</pre>
<pre>3.使用事务来控制这个地方我想到其实就是传说中的事务控制但是使用的时候又发现了问题</pre>
<pre>首先必须把mysql的存储方式改成innodb,5.5默认已经是这个了</pre>
<pre>只有这个才支持事务的控制来看看第一次写的版本</pre>
<pre><span style="color: #0000ff;">&#60;?</span>
$host="<span style="color: #8b0000;">127.0.0.1</span>";
$user="<span style="color: #8b0000;">root</span>";
$passwd="<span style="color: #8b0000;">123</span>";

mysql_connect($host,$user,$passwd);
mysql_select_db("<span style="color: #8b0000;">test</span>");
mysql_query("<span style="color: #8b0000;">set names utf8</span>");

mysql_query("<span style="color: #8b0000;">BEGIN</span>");
<span style="color: #008000;">//查询是否是大于0的</span>
$res=mysql_query("<span style="color: #8b0000;">select * from test where id=1 and k=100</span>");
$res=mysql_fetch_array($res);
$money=$res['<span style="color: #8b0000;">k</span>'];

<span style="color: #008000;">//如果大于0 就减100</span>
if($money&#62;0){
    $res=mysql_query("<span style="color: #8b0000;">UPDATE `test` SET `k` = `k`-100 where id=1</span>");
    $err_msg = mysql_error();
    if($err_msg!=""){
	echo "<span style="color: #8b0000;">回滚了</span>";
	mysql_query("<span style="color: #8b0000;">ROLLBACK</span>");
	}
     else{
	echo "<span style="color: #8b0000;">提交了</span>";
	mysql_query("<span style="color: #8b0000;">COMMIT</span>");
      }
}else{
    echo "<span style="color: #8b0000;">没做操作</span>";
}

<span style="color: #0000ff;">?&#62;</span></pre>
<pre><span style="color: #0000ff;">结果是错误的!</span></pre>
<pre><span style="color: #0000ff;">和之前的运行效果一样,事务并没有进行处理</span></pre>
<pre>为什么呢,一直没搞懂了.难道事务是不管脏数据的?</pre>
<pre>第二个线程读到的数据已经被第一个改掉了.按理说应该会抛错啊?</pre>
<pre>直到今天!  终于找到原因了</pre>
<pre>原来在数据库里面,事务的隔离是分级别的</pre>
<pre>默认的是支持脏数据读取</pre>
要加上这一句..
mysql_query("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;");
加在mysql_query("<span style="color: #8b0000;">BEGIN</span>"); 后面就可以了
事务的控制是人为触发.抛错只会在sql执行中
所以其实那个rollback是多余的

不过这样的结果是效率降低
其他的数据库操作需要等待前一个commit之后才能进行
然后还有其他的办法,就是锁行

$res=mysql_query("<span style="color: #8b0000;">select * from test where id=1 and k=100 for update</span>");

这样改动后其他的必须在执行了update之后才能进行读取,就保证了读取的不是脏数据

参考资料:

<a href="http://man.ddvip.com/database/innodbzh/8.htm">http://man.ddvip.com/database/innodbzh/8.htm</a>

</div><p><br/>点击阅读: <a href="http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html">线程安全和一条sql语句引起的思考(二)</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></description>
			<content:encoded><![CDATA[<p>接着上次的文章讨论php<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/%e7%ba%bf%e7%a8%8b" title="查看 线程 中的全部文章" target="_blank">线程</a></span>安全</p>
<p>当然不仅仅针对php</p>
<p>范大牛和我争了一下..不过说来问题是确实存在的</p>
<p>那怎么解决呢</p>
<p>其实解决方式有很多种</p>
<p>1. 把运算放在php里面<br />
代码如下:</p>
<div>
<pre><span style="color: #008000;">//如果大于0 就减100</span>
if($money&gt;0){
    $money -=100;
    $res=mysql_query("<span style="color: #8b0000;">UPDATE `test` SET `k` = $money where id=1</span>");
    echo "<span style="color: #8b0000;">减了!</span>";
}else{
    echo "<span style="color: #8b0000;">没做操作</span>";
}
结果:这样虽然会做重复的sql更新操作 但是结果都是正确的值</pre>
<pre>2.加上限定where</pre>
<pre>3.使用事务来控制这个地方我想到其实就是传说中的事务控制但是使用的时候又发现了问题</pre>
<pre>首先必须把mysql的存储方式改成innodb,5.5默认已经是这个了</pre>
<pre>只有这个才支持事务的控制来看看第一次写的版本</pre>
<pre><span style="color: #0000ff;">&lt;?</span>
$host="<span style="color: #8b0000;">127.0.0.1</span>";
$user="<span style="color: #8b0000;">root</span>";
$passwd="<span style="color: #8b0000;">123</span>";

mysql_connect($host,$user,$passwd);
mysql_select_db("<span style="color: #8b0000;">test</span>");
mysql_query("<span style="color: #8b0000;">set names utf8</span>");

mysql_query("<span style="color: #8b0000;">BEGIN</span>");
<span style="color: #008000;">//查询是否是大于0的</span>
$res=mysql_query("<span style="color: #8b0000;">select * from test where id=1 and k=100</span>");
$res=mysql_fetch_array($res);
$money=$res['<span style="color: #8b0000;">k</span>'];

<span style="color: #008000;">//如果大于0 就减100</span>
if($money&gt;0){
    $res=mysql_query("<span style="color: #8b0000;">UPDATE `test` SET `k` = `k`-100 where id=1</span>");
    $err_msg = mysql_error();
    if($err_msg!=""){
	echo "<span style="color: #8b0000;">回滚了</span>";
	mysql_query("<span style="color: #8b0000;">ROLLBACK</span>");
	}
     else{
	echo "<span style="color: #8b0000;">提交了</span>";
	mysql_query("<span style="color: #8b0000;">COMMIT</span>");
      }
}else{
    echo "<span style="color: #8b0000;">没做操作</span>";
}

<span style="color: #0000ff;">?&gt;</span></pre>
<pre><span style="color: #0000ff;">结果是错误的!</span></pre>
<pre><span style="color: #0000ff;">和之前的运行效果一样,事务并没有进行处理</span></pre>
<pre>为什么呢,一直没搞懂了.难道事务是不管脏数据的?</pre>
<pre>第二个<span class='wp_keywordlink_affiliate'><a href="http://3haku.net/tag/%e7%ba%bf%e7%a8%8b" title="查看 线程 中的全部文章" target="_blank">线程</a></span>读到的数据已经被第一个改掉了.按理说应该会抛错啊?</pre>
<pre>直到今天!  终于找到原因了</pre>
<pre>原来在数据库里面,事务的隔离是分级别的</pre>
<pre>默认的是支持脏数据读取</pre>
<p>要加上这一句..<br />
mysql_query("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;");<br />
加在mysql_query("<span style="color: #8b0000;">BEGIN</span>"); 后面就可以了<br />
事务的控制是人为触发.抛错只会在sql执行中<br />
所以其实那个rollback是多余的</p>
<p>不过这样的结果是效率降低<br />
其他的数据库操作需要等待前一个commit之后才能进行<br />
然后还有其他的办法,就是锁行</p>
<p>$res=mysql_query("<span style="color: #8b0000;">select * from test where id=1 and k=100 for update</span>");</p>
<p>这样改动后其他的必须在执行了update之后才能进行读取,就保证了读取的不是脏数据</p>
<p>参考资料:</p>
<p><a href="http://man.ddvip.com/database/innodbzh/8.htm">http://man.ddvip.com/database/innodbzh/8.htm</a></p>
</div>
<p><br/>点击阅读: <a href="http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html">线程安全和一条sql语句引起的思考(二)</a> <br /><br />我的博客:  <a href="http://3haku.net">big bug ban</a></p>
]]></content:encoded>
			<wfw:commentRss>http://3haku.net/2011/09/17/%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%e5%92%8c%e4%b8%80%e6%9d%a1sql%e8%af%ad%e5%8f%a5%e5%bc%95%e8%b5%b7%e7%9a%84%e6%80%9d%e8%80%83%e4%ba%8c.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

