<?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>程式設計 遇上 小提琴 &#187; 分享</title>
	<atom:link href="http://blog.ez2learn.com/category/%e5%88%86%e4%ba%ab/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ez2learn.com</link>
	<description>Victor&#039;s個人部落格，關於程式設計與小提琴</description>
	<lastBuildDate>Tue, 07 Feb 2012 03:26:25 +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>新世紀通訊函式庫 &#8211; ZeroMQ</title>
		<link>http://blog.ez2learn.com/2011/12/31/transport-lib-of-new-era-zeromq/</link>
		<comments>http://blog.ez2learn.com/2011/12/31/transport-lib-of-new-era-zeromq/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 09:53:30 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[分散式系統]]></category>
		<category><![CDATA[分散式運算]]></category>
		<category><![CDATA[單點失效]]></category>
		<category><![CDATA[Distributed system]]></category>
		<category><![CDATA[高可得性]]></category>
		<category><![CDATA[負載平衡]]></category>
		<category><![CDATA[雲端]]></category>
		<category><![CDATA[通訊]]></category>
		<category><![CDATA[High availability]]></category>
		<category><![CDATA[Mongrel]]></category>
		<category><![CDATA[Mongrel2]]></category>
		<category><![CDATA[single point failure]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[ZeroMQ]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1678</guid>
		<description><![CDATA[2012年就快到了，離2015年第三次衝擊也快到了，聽不懂我在說什麼就算了，跟主題沒什麼關聯，在介紹主角之前，我總喜歡描述一下主角的背景 欲上雲端，必先分散 這幾年，雲端炒得正熱門，愛跟風的台灣人當然也不能錯過，不管是賣主機的聲稱他們是做雲端的，連賣房子的也稱他們的是雲端，哪天就連在路邊看見雲端雞排都請不要大驚小怪，因為那簡直和奈米光觸媒雞排一樣有異曲同工之妙，然而口口聲聲說雲端，但前陣子iPhone4S預購就給了各家電信商一個大巴掌，他們的網頁伺服器都在一瞬間被大量擁入的使用者塞暴了，更別說其中還有不乏自家推出雲端服務的電信商，說真的，連分散運算的基本功都做不到，跟人家雲什麼端? 你說是吧? 但今天的主角不在於雲端是什麼，或是什麼才算真正的雲端之類的無聊話題，今天的主軸是分散式運算，因為要達到規模的運算和高可得性就一定要扯到分散式的運算，而分散式運算一直以來都不是什麼簡單的議題，最麻煩的就要算是溝通上的問題了，如果你有 三個節點之間想要進行溝通，該怎麼做? 你說簡單，直接串在一起不就好了? 好吧，或許你只有固定的三個節點，這好辦，但是要是你有更多的節點呢? 考慮一下十個節點、一百個節點，光想像就能知道，隨著節點的增加，他們之間的連線數量呈指數在成長，不光是連線本身的問題，連這些節點要如何知道對方的存在以及管理都是相當麻煩的問題 中央集權 光想就令人頭皮發麻，為了解決這樣的問題，一個經典的模式被設計且大量使用，那就是所謂的 Broker (掮客)，也有稱Message Queue、Message bus等，簡單的概念，就是所有節點都連向中間的訊息交換伺服器，而溝通都透過這個中央的交換中心來進行，節點與節點之間無需去在意到底誰在和我溝通，只需要在意訊息的種類和內容即可 &#160; 雖然這樣的模式解決了一些問題，但同時也引入了新的問題，分散式系統的頭號公敵 &#8211; 單點失效，正因為所有節點都依賴著這個中間的掮客幫忙轉送訊息，這也意味著當掮客網路斷線、當機等等意外的發生，都會讓整個系統陷入停擺的狀態，除此之外還有另一個嚴重的問題，就是當節點數量增加，掮客的工作量也會一直往上升，在無法擴增的情況下會造成整個系統的擴展性受到限制，效能也會因為掮客受限制 各自為政 正因為中央集權造成了問題，所以有人提出了各自為政來解決問題，可以想見的，在分散式的系統裡，並不是所有的節點都需要和所有人進行溝通，他們通常只需要和特定的節點溝通，舉個例子，假設你設計的是一個多媒體檔案的處理系統，在第一個節點可能做的是Hash，用來產生該檔案的唯一識別編號，節點二做的是轉檔，節點三做的是儲存，節點四做的是歸檔，那麼你需要的就只是這樣的結構，如果以物件導向的設計模式來看，我們稱這樣的結構為責任鏈 &#160; 再看另一個例子，如果我們是氣象局，想發佈各種天氣的消息，那麼你需要的是一個伺服器，讓大家去訂閱他們有興趣的主題，這樣的結構以物件導向的觀點來看就叫做觀察者模式，與我們先前見到的Broker做的是一樣的事情，然而在這裡的重點在於該伺服器只負責發佈天氣消息，並不參與訊息的交換 整體的概念就是各自有不同的子系統，我們透過通訊的方式將它們串在一起，這樣做有個好處就是效能好，再來就是設計得當的話，某子系統雖然停擺，但不會影響到所有的系統 各自為政的代價 雖然各自為政的做法有其好處，但相對的也有它的代價，光是通訊的協定就是很腦人的問題，考慮一下各種不同的子系統間該用什麼協定來溝通，連線中斷了怎麼處理，負載平衡? 這些問題都要花相當大的心力來解決 而在不同的環境下，使用不同的通訊方式都各有好處，使用TCP/IP的話，不管你的節點在同一台機器或是遠端，都可以連線，缺點是在同一台機器會有一定的效能耗損，而且遇到廣播的訊息，同樣的訊息被傳送N次，就沒有UDP廣播來得划算，如果節點是在同一台機器上溝通，使用IPC的方式效率好，如果是在同一個thread裡，那麼分享記憶體的方式最快，IPC反而會拖慢速度，正因為有各種不同的考量，使得想要達成高效率的分散式系統是一件困難的事情 是主角登場的時候了 &#8211; ZeroMQ 講了半天，ZeroMQ到底是做什麼用的? 簡單的來說，它是一套網路通訊函式庫，用來解決上面所提到的問題，考慮一下上面所提到的物件導向設計模式，你想，即然那樣的模式一再出現，為什麼我們不能將這些常見的通訊方式變成可以輕易重覆使用的形式? ZeroMQ所做到的即是如此，它將常見的通訊方式定義成不同行為的socket，讓你可以輕易地重覆使用這些樣式去組出強健的分散式系統 老樣子 Hello world.. 不! 是Hello baby &#8230; <a href="http://blog.ez2learn.com/2011/12/31/transport-lib-of-new-era-zeromq/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>2012年就快到了，離2015年第三次衝擊也快到了，聽不懂我在說什麼就算了，跟主題沒什麼關聯，在介紹主角之前，我總喜歡描述一下主角的背景</p>
<h2>欲上雲端，必先分散</h2>
<p>這幾年，雲端炒得正熱門，愛跟風的台灣人當然也不能錯過，不管是賣主機的聲稱他們是做雲端的，連賣房子的也稱他們的是雲端，哪天就連在路邊看見雲端雞排都請不要大驚小怪，因為那簡直和奈米光觸媒雞排一樣有異曲同工之妙，然而口口聲聲說雲端，但前陣子iPhone4S預購就給了各家電信商一個大巴掌，他們的網頁伺服器都在一瞬間被大量擁入的使用者塞暴了，更別說其中還有不乏自家推出雲端服務的電信商，說真的，連分散運算的基本功都做不到，跟人家雲什麼端? 你說是吧?</p>
<p>但今天的主角不在於雲端是什麼，或是什麼才算真正的雲端之類的無聊話題，今天的主軸是分散式運算，因為要達到規模的運算和高可得性就一定要扯到分散式的運算，而分散式運算一直以來都不是什麼簡單的議題，最麻煩的就要算是溝通上的問題了，如果你有 三個節點之間想要進行溝通，該怎麼做? 你說簡單，直接串在一起不就好了?</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/Eva-Magi.jpg"><img class="aligncenter size-full wp-image-1680" title="Eva-Magi" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/Eva-Magi.jpg" alt="" width="296" height="202" /></a></p>
<p>好吧，或許你只有固定的三個節點，這好辦，但是要是你有更多的節點呢? 考慮一下十個節點、一百個節點，光想像就能知道，隨著節點的增加，他們之間的連線數量呈指數在成長，不光是連線本身的問題，連這些節點要如何知道對方的存在以及管理都是相當麻煩的問題</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/mitinanime_eva.jpg"><img class="aligncenter size-full wp-image-1681" title="mitinanime_eva" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/mitinanime_eva.jpg" alt="" width="522" height="291" /></a></p>
<h2>中央集權</h2>
<p>光想就令人頭皮發麻，為了解決這樣的問題，一個經典的模式被設計且大量使用，那就是所謂的 Broker (掮客)，也有稱Message Queue、Message bus等，簡單的概念，就是所有節點都連向中間的訊息交換伺服器，而溝通都透過這個中央的交換中心來進行，節點與節點之間無需去在意到底誰在和我溝通，只需要在意訊息的種類和內容即可</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/broker1.png"><img class="aligncenter size-full wp-image-1686" title="broker" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/broker1.png" alt="" width="387" height="394" /></a></p>
<p>&nbsp;</p>
<p>雖然這樣的模式解決了一些問題，但同時也引入了新的問題，分散式系統的頭號公敵 &#8211; 單點失效，正因為所有節點都依賴著這個中間的掮客幫忙轉送訊息，這也意味著當掮客網路斷線、當機等等意外的發生，都會讓整個系統陷入停擺的狀態，除此之外還有另一個嚴重的問題，就是當節點數量增加，掮客的工作量也會一直往上升，在無法擴增的情況下會造成整個系統的擴展性受到限制，效能也會因為掮客受限制</p>
<h2>各自為政</h2>
<p>正因為中央集權造成了問題，所以有人提出了各自為政來解決問題，可以想見的，在分散式的系統裡，並不是所有的節點都需要和所有人進行溝通，他們通常只需要和特定的節點溝通，舉個例子，假設你設計的是一個多媒體檔案的處理系統，在第一個節點可能做的是Hash，用來產生該檔案的唯一識別編號，節點二做的是轉檔，節點三做的是儲存，節點四做的是歸檔，那麼你需要的就只是這樣的結構，如果以物件導向的設計模式來看，我們稱這樣的結構為責任鏈</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/flow-chain1.png"><img class="aligncenter size-full wp-image-1693" title="flow chain" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/flow-chain1.png" alt="" width="394" height="88" /></a></p>
<p>&nbsp;</p>
<p>再看另一個例子，如果我們是氣象局，想發佈各種天氣的消息，那麼你需要的是一個伺服器，讓大家去訂閱他們有興趣的主題，這樣的結構以物件導向的觀點來看就叫做觀察者模式，與我們先前見到的Broker做的是一樣的事情，然而在這裡的重點在於該伺服器只負責發佈天氣消息，並不參與訊息的交換</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/weather-center.png"><img class="aligncenter size-full wp-image-1697" title="weather center" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/weather-center.png" alt="" width="387" height="394" /></a></p>
<p>整體的概念就是各自有不同的子系統，我們透過通訊的方式將它們串在一起，這樣做有個好處就是效能好，再來就是設計得當的話，某子系統雖然停擺，但不會影響到所有的系統</p>
<h2>各自為政的代價</h2>
<p>雖然各自為政的做法有其好處，但相對的也有它的代價，光是通訊的協定就是很腦人的問題，考慮一下各種不同的子系統間該用什麼協定來溝通，連線中斷了怎麼處理，負載平衡? 這些問題都要花相當大的心力來解決</p>
<p>而在不同的環境下，使用不同的通訊方式都各有好處，使用TCP/IP的話，不管你的節點在同一台機器或是遠端，都可以連線，缺點是在同一台機器會有一定的效能耗損，而且遇到廣播的訊息，同樣的訊息被傳送N次，就沒有UDP廣播來得划算，如果節點是在同一台機器上溝通，使用IPC的方式效率好，如果是在同一個thread裡，那麼分享記憶體的方式最快，IPC反而會拖慢速度，正因為有各種不同的考量，使得想要達成高效率的分散式系統是一件困難的事情</p>
<h2>是主角登場的時候了 &#8211; ZeroMQ</h2>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/logo.gif"><img class="aligncenter size-full wp-image-1701" title="logo" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/logo.gif" alt="" width="381" height="119" /></a></p>
<p>講了半天，<a href="http://www.zeromq.org/">ZeroMQ</a>到底是做什麼用的? 簡單的來說，它是一套網路通訊函式庫，用來解決上面所提到的問題，考慮一下上面所提到的物件導向設計模式，你想，即然那樣的模式一再出現，為什麼我們不能將這些常見的通訊方式變成可以輕易重覆使用的形式? ZeroMQ所做到的即是如此，它將常見的通訊方式定義成不同行為的socket，讓你可以輕易地重覆使用這些樣式去組出強健的分散式系統</p>
<h2>老樣子 Hello world.. 不! 是Hello baby</h2>
<p>雖然大部份程式範例都喜歡用Hello world，但我不喜歡和他們一樣，我喜歡Hello baby，我們來看一下簡單的Hello baby範例</p>
<p>Client端</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> zmq
&nbsp;
context = zmq.<span style="color: black;">Context</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">socket</span> = context.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span>zmq.<span style="color: black;">REQ</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">socket</span>.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;tcp://127.0.0.1:7788&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">socket</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'hello'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #dc143c;">socket</span>.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Server端</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> zmq
&nbsp;
context = zmq.<span style="color: black;">Context</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">socket</span> = context.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span>zmq.<span style="color: black;">REP</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">socket</span>.<span style="color: black;">bind</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;tcp://*:7788&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #dc143c;">socket</span>.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">socket</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'baby'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>有了這兩隻Python程式，你可以在本機執行，不管Client或Server端先執行都可，你可能覺得我在說笑，哪有Client先執行的道理，接著會解釋，他們輸出的結果會像這樣</p>
<p>Client端:</p>
<blockquote><p>baby</p></blockquote>
<p>Server端:</p>
<blockquote><p>hello</p></blockquote>
<p>所以這之間到底發生了什麼事? 很簡單的在Client方，以TCP的方式連接了本機端的7788 port，接著送了一個request，然後接收response然後印出來，而Server方以TCP的方式綁定了本地端的7788 port，然後讀了一個request後送了一個response回去，這有什麼特別? 目前為止 &#8230; 沒有，但是，讓我們看下去</p>
<h2>ZeroMQ的特異功能</h2>
<p>上面的兩隻程式整體看起來和一般的socket沒兩樣，而行為也沒太大差別，所以它的特異功能到底在哪裡? 難不成它可以用手指讀封包嗎? 事實上它的特別之處可多了，這兩個程式並沒有表現出太特別的地方，我們改寫上面的程式讓它變成更能突顯ZeroMQ特色的程式</p>
<p>req.py</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> zmq
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">random</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
&nbsp;
context = zmq.<span style="color: black;">Context</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">socket</span> = context.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span>zmq.<span style="color: black;">REQ</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">socket</span>.<span style="color: black;">bind</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;tcp://*:7788&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># wait all worker connected</span>
<span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">9</span><span style="color: black;">&#41;</span>:
    a = <span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
    b = <span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Compute %s + %s ...'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># send request to peer</span>
    <span style="color: #dc143c;">socket</span>.<span style="color: black;">send_multipart</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</span>, <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>b<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># receive response from peer</span>
    rep = <span style="color: #dc143c;">socket</span>.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">' ='</span>, rep</pre></div></div>

<p>rep.py</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> zmq
&nbsp;
context = zmq.<span style="color: black;">Context</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">socket</span> = context.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span>zmq.<span style="color: black;">REP</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">socket</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;tcp://localhost:7788&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Worker %s is running ...'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
    <span style="color: #808080; font-style: italic;"># receive request</span>
    a, b = <span style="color: #dc143c;">socket</span>.<span style="color: black;">recv_multipart</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    a = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</span>
    b = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>b<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Compute %s + %s and send response'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">socket</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>a + b<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>接著我們先執行三個rep.py，然後再執行一個req.py，看發生了什麼事</p>
<p>req.py</p>
<pre>Compute 43 + 91 ...
 = 134
Compute 21 + 63 ...
 = 84
Compute 17 + 93 ...
 = 110
Compute 29 + 98 ...
 = 127
Compute 90 + 55 ...
 = 145
Compute 14 + 74 ...
 = 88
Compute 3 + 85 ...
 = 88
Compute 12 + 73 ...
 = 85
Compute 73 + 21 ...
 = 94</pre>
<p>rep.py 1</p>
<pre>Worker 7296 is running ...
Compute 43 + 91 and send response
Compute 29 + 98 and send response
Compute 3 + 85 and send response</pre>
<p>rep.py 2</p>
<pre>Worker 6532 is running ...
Compute 21 + 63 and send response
Compute 90 + 55 and send response
Compute 12 + 73 and send response</pre>
<p>rep.py 3</p>
<pre>Worker 5928 is running ...
Compute 17 + 93 and send response
Compute 14 + 74 and send response
Compute 73 + 21 and send response</pre>
<p>這兩個程式做的事情很簡單，req.py負責產生兩個亂數，將其當作request送給socket的另一端，而rep.py則是接收兩個亂數request，算出結果來送回給發出者，但是這好像哪裡不太對勁是嗎? 三個socket連到一個socket? 為什麼送request的一方居然變成bind而不是connect了? 為什麼connect的一方先執行居然也能連線? 我已經聽見你在電腦前的吼叫，讓我們來說明一下這到底是怎麼回事</p>
<h3>連線先後順序無關、自動重連機制</h3>
<p>ZeroMQ的socket有個特色就是對於誰先bind誰後connect之類的完全都不在乎，如果是connect先行，發線連線無法建立，ZeroMQ會自動重試，當bind也確立了，連線就會自動接上了，有了這樣的特性，只要管怎樣連接和對方的位址是什麼即可</p>
<p>通常bind那端都是位址為大家所熟知的那端，connect都是位址不為人知的，以我們這樣的例子，因為worker可能有很多個，所以我們將REQ端換成bind，而REP端換成connect，方便多個rep.py連接req.py</p>
<p>除此之外，REQ和REP兩種角色不管哪方bind哪方connect運算的方式都是一樣的</p>
<h3>多個Socket連線、多位址綁定</h3>
<p>ZeroMQ的socket之間可以多個互相連線，所以一個socket的另一端可能有N個節點連接，除此之外，同一個socket也可以綁在不同的位址上</p>
<h3>自動負載平衡</h3>
<p>如果你仔細觀察上面程式的輸出，就會發現request是依序分配給三個rep.py，這也是ZeroMQ的特色之一，REQ端會將send的message用Round-robin的方式分給所有的遠端連線，而你有多少個連線，他都會照一樣的規則分配</p>
<p>但因為先前有提到自動連線，因此會有個問題，當第一個連線接上時，其它連線還來不及連上，此時request可能已經大量分配給第一個連上的，為了解決這問題，我們安排了time.sleep(1)來等所有worker連上線，以避免早起的鳥兒吃光了蟲子</p>
<h3>訊息傳輸</h3>
<p>你可以發現我們送資料和處理的都是訊息，ZeroMQ可以提供你傳送多段資料在一筆訊息裡，因此我們在這看到的send_multipart和recv_multipart作用即為如此，有了這樣的特性，你可以不用擔心通訊協定的問題，只管專心處理訊息即可</p>
<h3>支援不同的通訊方式</h3>
<p>看見了我們在程式中所寫的 "tcp://*:7788&#8243; 和 "tcp://localhost:7788&#8243; 嗎? 它們暗示了TCP只不過只是支援的其中一種通訊方式而已，ZeroMQ還支援IPC，但目前只支援Linux下的domain socket，例如 "ipc:///tmp/req.socket"，甚至它還支援thread之間的通訊方式，因此如果你的兩個節點放在同一個process裡，為了效能考量，你可以用這種協定讓通訊效率最佳化</p>
<p>為了節省傳輸的封包，ZeroMQ甚至提供了基於UDP的廣播通訊方式，因此當你將節點放在同一個網路下，廣播的功能就能節省大量的重覆封包傳送</p>
<h3><span style="color: #000000;">支援N種語言</span></h3>
<p>雖然我們的範例都是用Python寫的，但ZeroMQ目前已經支援了幾乎所有你能在臺面上看到的主流語言，你喜歡用Lua寫子系統A? OK! 你喜歡用Perl寫系統B? 可以! C語言? 當然沒問題，你喜歡PHP? 厄&#8230; 也可以啦，總之，ZeroMQ讓你從不同語言的通訊中解藕開來，只要專注在於訊息的處理上即可</p>
<h2>更多的樣式</h2>
<p>我們做為範例的REQ/REP只不過是ZeroMQ所提供的樣式中的一種，它的特性就是一個request一個response，而REQ端會對所有的連線做fairly queue，也就是會公平地把request塞給REP端，借用官網的圖</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig18.png"><img class="aligncenter size-full wp-image-1719" title="fig18" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig18.png" alt="" width="386" height="358" /></a></p>
<p>另一種常見的樣式是PUB/SUB，也就是我們先前提到的觀察者模式，它的特色是所有PUB發送的消息會廣播給所有SUB的連線，而且SUB可以設定只要某段字串開頭的訊息</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig4.png"><img class="aligncenter size-full wp-image-1720" title="fig4" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig4.png" alt="" width="456" height="400" /></a></p>
<p>還有很常見的需求就是我們想將資料往某個方向負載平衡地推送，這時PUSH/PULL樣式就派上用場了，PUSH會將負載分散給PULL端，而且只能由PUSH推往PULL</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig5.png"><img class="aligncenter size-full wp-image-1721" title="fig5" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig5.png" alt="" width="456" height="582" /></a></p>
<p>還有另一種樣式是跟一般socket沒兩樣的一對一連線，叫做PAIR</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig22.png"><img class="aligncenter size-full wp-image-1722" title="fig22" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig22.png" alt="" width="244" height="484" /></a></p>
<h2>參在一起做撒尿牛丸</h2>
<p>事實上ZeroMQ還有更高級的樣式，但在本文就不介紹了，接著要大略介紹的是官網的一個例子，將這些樣式組合在一起，官網的例子是說當你需要分散式的Key/Value形式的伺服器，利用ZeroMQ來達成其組合方式就像這樣</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig69.png"><img class="aligncenter size-full wp-image-1723" title="fig69" src="http://blog.ez2learn.com/wp-content/uploads/2011/12/fig69.png" alt="" width="466" height="372" /></a></p>
<p>伺服器端負責儲存一份快取，且會透過PUB/SUB讓client保持更新，而Client端被更動時，透過PUSH丟給伺服器，如果新的Client上線了，就透過REQ向server要最新的一份快取</p>
<p>這樣就是用ZeroMQ實作分散式系統的一個簡易的實例，事實上它能做遠比這個還要更複雜的東西</p>
<h2>自從用了ZeroMQ，我人也高了，頭也壯了，考試都得一百分呢</h2>
<p>有了ZeroMQ，分散式系統從又難又腦人變成很難而已，因為通訊的部份由ZeroMQ來完成了，剩下的你只要專心來考慮節點之間的拓撲與連接方式、通訊方式，以及訊息的處理，不同語言的支持也讓你不再擔心要用什麼語言來實作，或是你的同事懂不懂某種語言，真正的心力被花費在設計上，分散式系統因此也能更輕易地設計與實作，而ZeroMQ的本意是用於即時地處理大量的金融資料，效率更是ZeroMQ的金字招牌之一，如果你需要複雜且高效的分散式系統，ZeroMQ絕對是你的好朋友</p>
<p>最後，值得一提的是有人基於ZeroMQ的特性設計了與程式語言無關的網頁框架，或著更精確的來說是與伺服器溝通的協定，類似CGI或WSGI那樣，但是透過ZeroMQ因此和語言無關，叫<a href="http://mongrel2.org/">Mongrel</a>，目前出到第二版，有興趣可以研究看看，或許哪天也會寫篇文章來介紹</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/12/31/transport-lib-of-new-era-zeromq/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>那些台灣軟體產業所缺少的 &#8211; 自動化測試</title>
		<link>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-auto-testing/</link>
		<comments>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-auto-testing/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 13:15:23 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[嘴砲]]></category>
		<category><![CDATA[資訊安全]]></category>
		<category><![CDATA[單元測試]]></category>
		<category><![CDATA[軟體工程]]></category>
		<category><![CDATA[軟體品質]]></category>
		<category><![CDATA[軟體測試]]></category>
		<category><![CDATA[自動化測試]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[整合測試]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1619</guid>
		<description><![CDATA[你是否有計算過，你在寫專案的過程中，測試過了多少次的程式? 我想是沒有，我也沒有，但是你是否有曾想過，或是感覺過，隨著專案的膨漲，你要測試的項目也跟著變多了? 這是理所當然的事情，當專案小，測試還算很輕鬆，因為程式的功能不外乎就那幾樣，一轉眼就測完了，常見的寫程式流程會像這樣 撰寫新功能 測試新功能 當然，也有修正bug的情況 修正bug 測試bug 如此一直循環，當你寫了新功能，理所當然地會去測試新功能，看是否如你預期地執行，那舊功能呢? 或許你記憶力不錯，在寫新功能的同時，想到先前某個舊功能是依賴現在改的東西，這麼一改可能會造成舊的功能出問題，於是你也順便測了一下舊的功能，當程式還小 撰寫新功能 測試新功能 測試舊功能 嘿，不怎麼樣吧? 只佔了開發時間的三分之一，好吧那如果有更多的舊功能要測呢? 撰寫新功能 測試新功能 測試舊功能 測試舊功能 測試舊功能 &#8230;. 發現了沒有? 隨著你的專案越來越大，如果要確保整個系統所有的功能都是正常運作的，無可避免地，在你修改程式之後要測試的項目會越來越多 這表示你每寫一行新程式的成本增加了，身為以減低成本為傲的島國 國民: 台灣人&#8230;，你說，簡單! 不要測舊功能不就好了? 是的，我想這可能就是最常見的情況，不要測試舊功能理所當然地，每寫一行的程式成本都保持一樣很低，但這代表著舊程式可能出錯的風險也跟著增加了，當你喜滋滋地覺得你幫公司省了成本，結果在一個月後因為舊程式缺乏測試，因改動了核心的部份造成舊的功能將所有資料外洩，公司損失慘重，這就是不重視軟體品質的後果 舉真實生活上發生過的例子，PTT曾經有過改程式未經好好地測試，造成每個人都能以管理員的權限登入的事情，知名的檔案同步平台Dropbox，也曾經發生過因為認證的程式改版有bug，造成任何人都可以登入別人帳號的事，我也有曾聽聞一些網站因為工程師為了測試方便，把認證的函數暫時改成 function authenticate&#40;user_id, password&#41; &#123; return true; // do authentication here // &#8230; <a href="http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-auto-testing/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>你是否有計算過，你在寫專案的過程中，測試過了多少次的程式? 我想是沒有，我也沒有，但是你是否有曾想過，或是感覺過，隨著專案的膨漲，你要測試的項目也跟著變多了? 這是理所當然的事情，當專案小，測試還算很輕鬆，因為程式的功能不外乎就那幾樣，一轉眼就測完了，常見的寫程式流程會像這樣</p>
<blockquote><p>撰寫新功能</p>
<p>測試新功能</p></blockquote>
<p>當然，也有修正bug的情況</p>
<blockquote><p>修正bug</p>
<p>測試bug</p></blockquote>
<p>如此一直循環，當你寫了新功能，理所當然地會去測試新功能，看是否如你預期地執行，那舊功能呢? 或許你記憶力不錯，在寫新功能的同時，想到先前某個舊功能是依賴現在改的東西，這麼一改可能會造成舊的功能出問題，於是你也順便測了一下舊的功能，當程式還小</p>
<blockquote><p>撰寫新功能</p>
<p>測試新功能</p>
<p>測試舊功能</p></blockquote>
<p>嘿，不怎麼樣吧? 只佔了開發時間的三分之一，好吧那如果有更多的舊功能要測呢?</p>
<blockquote><p>撰寫新功能</p>
<p>測試新功能</p>
<p>測試舊功能</p>
<p>測試舊功能</p>
<p>測試舊功能</p>
<p>&#8230;.</p></blockquote>
<p>發現了沒有? 隨著你的專案越來越大，如果要確保整個系統所有的功能都是正常運作的，無可避免地，在你修改程式之後要測試的項目會越來越多</p>
<p>這表示你每寫一行新程式的成本增加了，身為以減低成本為傲的島國 國民: 台灣人&#8230;，你說，簡單! 不要測舊功能不就好了? 是的，我想這可能就是最常見的情況，不要測試舊功能理所當然地，每寫一行的程式成本都保持一樣很低，但這代表著舊程式可能出錯的風險也跟著增加了，當你喜滋滋地覺得你幫公司省了成本，結果在一個月後因為舊程式缺乏測試，因改動了核心的部份造成舊的功能將所有資料外洩，公司損失慘重，這就是不重視軟體品質的後果</p>
<p>舉真實生活上發生過的例子，PTT曾經有過改程式未經好好地測試，造成每個人都能以管理員的權限登入的事情，知名的檔案同步平台Dropbox，也曾經<a href="http://blog.dropbox.com/?p=821">發生過因為認證的程式改版有bug，造成任何人都可以登入別人帳號的事</a>，我也有曾聽聞一些網站因為工程師為了測試方便，把認證的函數暫時改成</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">function authenticate<span style="color: black;">&#40;</span>user_id, password<span style="color: black;">&#41;</span> <span style="color: black;">&#123;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> true<span style="color: #66cc66;">;</span>
        // do authentication here
        // ....
<span style="color: black;">&#125;</span></pre></div></div>

<p>然後又不小心commit，因此讓任何人都通過認證的事情，但這些都不能只怪工程師本身，誰能無過? 人總會犯錯的，問題出問於工程本身的制度、專案的管理、和工具的使用上</p>
<p>在未來，網路的應用越來越多，而軟體的品質重要程度只會越來越高，所以，要如何維持軟體的品質又同時能不讓測試的成本隨著專案的擴張而跟著無限制地成長呢? 答案就是 &#8211; 自動化測試</p>
<h2>自動化測試</h2>
<p>自動化測試聽起來好像很美妙，讓電腦自動幫你測試程式? 有這麼好的事情嗎? 事實上不是那樣，自動化測試，是透過寫好的規則，自動對於程式進行測試，所以終究還是得需要人力的介入，那你或許會問，結果倒頭來還不是得用人力? 那到底有什麼好處? 答案就跟我們先前提到的一樣，如果你的專案很小，用人力測試其實可能就已足夠，但當你的專案夠大，如果沒有自動化測試，那麼光是在測舊的程式就是相當龐大的成本上</p>
<p>引入了自動化測試不代表程式就不會出錯，它不是萬能的，但是它至少保證了程式一定的品質，只要使用得當，就能降低測試的成本，也能讓大部份有經過自動測試的程式都不會出現太離譜的錯誤，至於要怎麼做，讓我們看下去</p>
<h2>單元測試</h2>
<p>最常見的測試，就是單元測試(Unit test)，通常是針對單一個或是少數類別，確保這些類別單獨運作是正確的，舉個例子，你寫了一個類別，是用來找輸入的地圖的最短路徑，那麼你就得替這類別，寫一個單元測試，餵入你準備好的資料，然後取得輸出的結果，看是否和你準備的預期答案是一樣的，舉一個最簡單的例子，一個用Python來將輸入文字拆解成一行一行的解析器</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> LineParser<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newline=<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>, remain=<span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">newline</span> = newline
        <span style="color: #008000;">self</span>._buffer = <span style="color: black;">&#91;</span>remain<span style="color: black;">&#93;</span>
        <span style="color: #008000;">self</span>._size = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>remain<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> feed<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, data<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._buffer.<span style="color: black;">append</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>._size += <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> getLine<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        data = <span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._buffer<span style="color: black;">&#41;</span>
        index = data.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">newline</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> index <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span>:
            line = data<span style="color: black;">&#91;</span>:index<span style="color: black;">&#93;</span>
            <span style="color: #008000;">self</span>._buffer = <span style="color: black;">&#91;</span>data<span style="color: black;">&#91;</span>index + <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">newline</span><span style="color: black;">&#41;</span>:<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">length</span> = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._buffer<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> line
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> iterLines<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        line = <span style="color: #008000;">self</span>.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> line <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> line
            line = <span style="color: #008000;">self</span>.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>它的單元測試就長這樣</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">unittest</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TestLineParser<span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestCase</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> makeOne<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> LineParser<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> testParser<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        p = <span style="color: #008000;">self</span>.<span style="color: black;">makeOne</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'abc'</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #483d8b;">'abc'</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># write lots line</span>
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'111<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>222<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>3333'</span><span style="color: black;">&#41;</span>
        lines = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>p.<span style="color: black;">iterLines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'111'</span>, <span style="color: #483d8b;">'222'</span><span style="color: black;">&#93;</span>, lines<span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>text'</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #483d8b;">'3333'</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># write nothing</span>
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>
        line = p.<span style="color: black;">getLine</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
        p.<span style="color: black;">feed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
        lines = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>p.<span style="color: black;">iterLines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span>lines, <span style="color: black;">&#91;</span><span style="color: #483d8b;">'text'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">assertEqual</span><span style="color: black;">&#40;</span><span style="color: #008000;">list</span><span style="color: black;">&#40;</span>p.<span style="color: black;">iterLines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> suite<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    suite = <span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestSuite</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    suite.<span style="color: black;">addTest</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">makeSuite</span><span style="color: black;">&#40;</span>TestLineParser<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> suite
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">unittest</span>.<span style="color: black;">main</span><span style="color: black;">&#40;</span>defaultTest=<span style="color: #483d8b;">'suite'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>很簡單的想法就是列出幾種常見的case，還有你能想到的特例代進去，好的測試資料要能夠測到每一行程式，但是要做到那樣需要花不少心力，其實能夠做到大部份常見的情況和常見的特例，就已經相當足夠</p>
<h2>整合測試</h2>
<p>有些程式，無可避免地會依賴其它程式，如果我們針對這兩個程式同時測試，會無法分出出錯到底是誰的錯，再者，很多依賴的部份可能會牽扯到IO或是其它系統資源，讓測試變得更複雜，例如有個類別是負責輸出文件到印表機的，那你要如何確認印表機印出來的東西是正確的? 答案就是做一個假的 (Mocking)印表機丟給那個類別去做列印的動作，再去讀取裡面的資料，確認跟你預期的一樣</p>
<p>雖然單元測試在相當單純的模擬環境下測過了我們的程式，然而世界並不是那樣的美好，總有些事情沒有經過真槍實彈操演過可能會有差錯，因此有時我們會引入部份受控制的真實環境來測試，例如你想測試網路連線，或許你可以寫一段script在Amazon EC2上建起幾個instance，並上傳程式到那些機器中，自動讓他們連線來確保這些功能是正常的，然而越真實的環境變因就越多，因此測試也就相對困難</p>
<h2>每日建構的好幫手 &#8211; Jenkins</h2>
<p>Joel有說過 <a href="http://chinese.joelonsoftware.com/Articles/DailyBuildsAreYourFriend.html">每日建構是你的朋友</a> (<a href="http://www.joelonsoftware.com/articles/fog0000000023.html">Daily build is your friend</a>)，也有提過 <a href="http://chinese.joelonsoftware.com/Articles/TheJoelTest.html">軟體開發成功的12個法則</a> (<a href="http://www.joelonsoftware.com/articles/fog0000000043.html">The Joel Test: 12 Steps to Better Code</a>)，裡面的daily build是指利用工具每天自動建構整個專案，通常對於編譯式的語言，如C語言寫的大型專案會較需要這類的工具，但是這樣的工具還有一個目的，在於確保程式是可以正常編譯的，並且讓測試員容易拿到最新的程式進行測試，然而自動化測試，同樣的也需要類似的工具，因為通常你在改完程式就會進行測試，那每次一改完程式就得跑一次測試指令，這不是一件很煩的事情嗎?</p>
<p>記得，工具是為我們服務的，不是我們為工具服務，這樣重複的瑣事理所當然也是由工具來幫忙，謝天謝地現今有好用又免費的工具，可以幫你做到這點，那就是<a href="http://jenkins-ci.org/">Jenkins</a>，它是一套基於網頁的自動化測試管理工具，它可以做到什麼呢? 它可以做到幫你定時去版本控制系統取程式回來，用預先設定好的流程進行測試，並且記錄測試的結果，如果有某個測試出錯了，當然也可以發Email通知你，以Now.in的開發為例，因為專案為數眾多，其中又有依賴關係，有了Jenkins的幫忙，程式只要一改送到BitBucket，它就會自動進行測試</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/jenkins.png"><img class="aligncenter size-full wp-image-1634" title="jenkins" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/jenkins.png" alt="" width="746" height="470" /></a>如此一來就省下了大量的時間，同時，也可以專心在於開發上</p>
<p>Jenkins除了功能強大以外，他還有一項特色令我驚訝，就是非常簡單易用，從安裝到設定完所有的測試，除了clone hg檔案庫和設置測試環境以外，我從沒因為Jenkins打過一行指令，全部都可以透過它友善的網頁介面完成，同時它也有內建資料庫，也沒因此設定MySQL，在Windows下安裝更是容易，一個安裝檔執行完就是安裝完成，如果你希望有工具幫你自動定時測試或是建構，請不要懷疑，Jenkins是你最佳選擇</p>
<h2>部署前的自動化測試</h2>
<p>執行自動化測試的時機，除了剛改完程式，還有一個重要的時機，那就是在你把程式部署到伺服器以前，讓你的自動化部署的script先跑過一次自動測試，確認測試通過了再進行部署，為什麼要這樣做呢? 還記得先前提到的PTT和Dropbox以及一些網站對於authentication的return true慘劇嗎? 為了不讓那種事情發生，或著至少讓機會降低，在deploy前讓自動化測試跑過一次，確保測試的範圍內都是正確的，可以大大降低那種情況發生的機會，除此之外，也比較不會因為改出bug，自己沒發現，等到使用者來抱怨了才知道問題在哪</p>
<h2>測試的幾項重點</h2>
<p>自動化測試雖然是一項利器，但是得經過正確的使用才會有好的效果，自動化測試有所謂的覆蓋率，也就是你的程式裡以行為單位，有多少行是在跑測試時有執行過的? 這些工具都可以幫你統計出來，但是切記</p>
<blockquote><p><strong>不要為了追求高測試覆蓋率，替foo bar寫測試</strong></p></blockquote>
<p>這只是在浪費時間，如果某段程式已經簡單到沒測試的必要，你寫了也是多餘</p>
<p>除此之外，寫測試事實上也是成本，因此如果時間有限，請</p>
<blockquote><p><strong>優先針對重要的核心、資料模型、商業邏輯測試</strong></p></blockquote>
<p>因為就算你測再多無關緊要的程式，最重要的核心出錯了，可能整個系統就完蛋了，所以盡量以重要的程式做為測試的優先考量</p>
<blockquote><p><strong>優先針對安全性相關、存取權限、身份認證、常見攻擊手法測試</strong></p></blockquote>
<p>雖然身份認證這種事情算不上是核心，但這關係到你的系統會不會被輕易地攻擊，除此之外，如果你的程式是網站應用程式，SQL Injection、XSS、buffer overflow這類攻擊也會很常發生，因此，你也需要優先自行設計一些攻擊，針對這些常見的問題餵一些資料，雖然這無法保證一定不會犯錯，至少確保不會發生太低等級的錯誤，因為常見的case都已經有自動測試過了，搭配先前所提到的，deploy前跑過一次測試，如此一來就能將犯錯的機會降低許多</p>
<p>雖然你的程式可能大多都已經有自動化測試在幫你測試，但即使如此，你還是會發現新的bug，如果說，你直接改了bug，就這樣了事，很有可能在下幾次改版bug又回來了，因此</p>
<blockquote><p><strong>每當你發現你先前沒想到的bug，請加到你的測試中</strong></p></blockquote>
<p>如此一來，隨著你針對的bug測試case越多，你的程式品質就越高，未發現的bug也會越少，在未來確保這些bug不會再出現</p>
<h2>最後</h2>
<p>再一次，自動化測試不是萬能的，除此之外也需要正確的運用，如果台灣軟體業界能夠好好運用自動化測試，軟體的品質可以有所提升，開發者也不會因為除錯除到死加班到天亮，雖然寫測試是額外的負擔，但是對於大形專案長期看來是非常值得的投資</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-auto-testing/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>那些台灣軟體產業所缺少的 &#8211; 版本控制系統</title>
		<link>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-vcs/</link>
		<comments>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-vcs/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 04:02:15 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[嘴砲]]></category>
		<category><![CDATA[版本控制]]></category>
		<category><![CDATA[軟體工程]]></category>
		<category><![CDATA[軟體產業]]></category>
		<category><![CDATA[VCS]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1587</guid>
		<description><![CDATA[這幾年來，多多少少接觸了不少業界的人，雖然我自己還不算有真正待過業界太久，但是這期間看到不少業界的現象都令我挺驚訝的，例如在聊天時提到你們公司用的版本控制系統是什麼，有很多人都會回答 「那是什麼?」，一直以來這些在國外的主流開發環境都基本常識或是標準配備的東西台灣業界居然很多都連有那樣的工具存在都不知道，或著是對於某些東西有錯誤的認知，所以我想大略提一下常見的幾個問題 版本控制系統 我想這是最常見的毛病，很常發現很多公司在開發軟體時從來都不使用版本控制系統，最誇張的狀況就是管它三七二十一直接修改 &#160; 除此之外，常見的土法鍊鋼有聽說過資料夾複製，然後將資料夾名稱命名為版本1之類的方法，高級一點還有搭配Excel來記錄改過了什麼之類的 更進階的還有多人共同開發，還架了FTP來放這些檔案 但這些都有很大的問題，而且其會遇到的問題都正好是版本控制系統所要解決的，所以到底是什麼樣的問題非用版本控制系統不可? 首先，用資料夾copy有個很大的問題，一來是copy的過程很容易出錯，而且更糟的是出的錯很難發現，你怎麼從資料夾的內容來判斷這到底是哪個版本? 最常見的做法就是回想你到底在哪個版本改了什麼，然後去看對應的位置，是否有那些改動，但你有可能記得嗎? 要是程式不是你改的呢? 因此依賴資料夾名稱來得知檔案的版本是極度不可靠的做法，再者，如果你不幸改到錯誤的版本，辛辛苦苦改了半天，才發現改到舊版本了，那你要如何把你改的和正確的版本合在一起? 如果你只改了三行，這還好辦，但如果你改了三百行，那該怎麼辦? 用Excel來記錄改動的事項和版本一樣不會有幫助 那多人開發使用FTP來分享檔案呢? 老天，事情更慘了，原先只是你自己的開發，自己改錯了就算了，如今變成多人開發，有時出問題還不是你改的，這樣想好了，FTP上有個檔案 hello.py 今天張三載回去改了，變成 hello.py (張三版) 不幸的是，王五在張三上傳回FTP之前，也載回來改，變成 hello.py (王五版) 接著，張三把它的檔案上傳了，所以FTP上的檔案變成了 hello.py (張三版) 然後好戲發生了，王五也把它改的東西上傳了，所以FTP上的檔案被蓋掉，變成 hello.py (王五版) 發生了什麼事? 張三改的版本被蓋掉了，你可以想見張三在demo給老闆看時發現改的地方被蓋掉了，翻過辦公桌衝過去揍王五的情景了嗎? 像這樣還只是最簡單的情境，以這類土法鍊鋼的方式，還有太多太多預料不到的複雜情況會發生，什麼? 那你說，如果我們規定每人都得把資料夾以自己的名稱命名，加上版號，再上傳，這樣就不會錯了吧? hello_project-王五-rev123/ 拜託，何苦呢 ? 版本控制系統就是用來解決這些問題而開發出來的，學一套新工具有這麼難嗎? 常見的理由可能會有什麼沒時間學、不信任工具等等，事實上那些都不是理由，只要是程式碼的開發，都得使用版本控制系統，現在已經是2011年，如果你的軟體開發沒有使用版本控制系統，我說這不叫落後，這是原始 用了版本控制系統，最重要的好處是 你可以安心地放膽去改程式 &#8230; <a href="http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-vcs/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>這幾年來，多多少少接觸了不少業界的人，雖然我自己還不算有真正待過業界太久，但是這期間看到不少業界的現象都令我挺驚訝的，例如在聊天時提到你們公司用的版本控制系統是什麼，有很多人都會回答 「那是什麼?」，一直以來這些在國外的主流開發環境都基本常識或是標準配備的東西台灣業界居然很多都連有那樣的工具存在都不知道，或著是對於某些東西有錯誤的認知，所以我想大略提一下常見的幾個問題</p>
<h2>版本控制系統</h2>
<p>我想這是最常見的毛病，很常發現很多公司在開發軟體時從來都不使用版本控制系統，最誇張的狀況就是管它三七二十一直接修改</p>
<p>&nbsp;</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/directly_modify2.png"><img class="aligncenter size-large wp-image-1599" title="directly_modify" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/directly_modify2-1024x324.png" alt="" width="640" height="202" /></a></p>
<p>除此之外，常見的土法鍊鋼有聽說過資料夾複製，然後將資料夾名稱命名為版本1之類的方法，高級一點還有搭配Excel來記錄改過了什麼之類的</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/copy_dir.png"><img class="aligncenter size-large wp-image-1600" title="copy_dir" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/copy_dir-1024x269.png" alt="" width="640" height="168" /></a></p>
<p>更進階的還有多人共同開發，還架了FTP來放這些檔案</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/ftp.png"><img class="aligncenter size-large wp-image-1601" title="ftp" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/ftp-1024x533.png" alt="" width="640" height="333" /></a></p>
<p>但這些都有很大的問題，而且其會遇到的問題都正好是版本控制系統所要解決的，所以到底是什麼樣的問題非用版本控制系統不可?</p>
<p>首先，用資料夾copy有個很大的問題，一來是copy的過程很容易出錯，而且更糟的是出的錯很難發現，你怎麼從資料夾的內容來判斷這到底是哪個版本? 最常見的做法就是回想你到底在哪個版本改了什麼，然後去看對應的位置，是否有那些改動，但你有可能記得嗎? 要是程式不是你改的呢? 因此依賴資料夾名稱來得知檔案的版本是極度不可靠的做法，再者，如果你不幸改到錯誤的版本，辛辛苦苦改了半天，才發現改到舊版本了，那你要如何把你改的和正確的版本合在一起? 如果你只改了三行，這還好辦，但如果你改了三百行，那該怎麼辦? 用Excel來記錄改動的事項和版本一樣不會有幫助</p>
<p>那多人開發使用FTP來分享檔案呢? 老天，事情更慘了，原先只是你自己的開發，自己改錯了就算了，如今變成多人開發，有時出問題還不是你改的，這樣想好了，FTP上有個檔案</p>
<blockquote><p>hello.py</p></blockquote>
<p>今天張三載回去改了，變成</p>
<blockquote><p>hello.py (張三版)</p></blockquote>
<p>不幸的是，王五在張三上傳回FTP之前，也載回來改，變成</p>
<blockquote><p>hello.py (王五版)</p></blockquote>
<p>接著，張三把它的檔案上傳了，所以FTP上的檔案變成了</p>
<blockquote><p>hello.py (張三版)</p></blockquote>
<p>然後好戲發生了，王五也把它改的東西上傳了，所以FTP上的檔案被蓋掉，變成</p>
<blockquote><p>hello.py (王五版)</p></blockquote>
<p>發生了什麼事? 張三改的版本被蓋掉了，你可以想見張三在demo給老闆看時發現改的地方被蓋掉了，翻過辦公桌衝過去揍王五的情景了嗎? 像這樣還只是最簡單的情境，以這類土法鍊鋼的方式，還有太多太多預料不到的複雜情況會發生，什麼? 那你說，如果我們規定每人都得把資料夾以自己的名稱命名，加上版號，再上傳，這樣就不會錯了吧?</p>
<blockquote><p>hello_project-王五-rev123/</p></blockquote>
<p>拜託，何苦呢 ? 版本控制系統就是用來解決這些問題而開發出來的，學一套新工具有這麼難嗎? 常見的理由可能會有什麼沒時間學、不信任工具等等，事實上那些都不是理由，只要是程式碼的開發，都得使用版本控制系統，現在已經是2011年，如果你的軟體開發沒有使用版本控制系統，我說這不叫落後，這是原始</p>
<p>用了版本控制系統，最重要的好處是</p>
<blockquote><p><span style="font-size: x-large;"><strong>你可以安心地放膽去改程式</strong></span></p></blockquote>
<h2>什麼是版本控制系統?</h2>
<p>講了那麼多，所以版本控制系統到底是什麼? 這麼來形容好了，如果你有玩過RPG遊戲，像是仙劍奇俠傳、軒轅劍等等，你一定知道遊戲打到一半可以存檔，然後也可以讀檔，接續先前的遊戲進度，如果你發現目前的等級太差了，打不贏魔王，你可以讀前面一點的檔案來重新練，或是前面的寶物忘記拿，也可以讀檔回去拿</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/game_save.png"><img class="aligncenter size-full wp-image-1603" title="game_save" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/game_save.png" alt="" width="327" height="476" /></a></p>
<p>而版本控制系統做的事情，就和RPG裡的遊戲存檔是一樣的概念，你可以將目前程式開發的進度的快照存下來，當你發現改的檔案有問題，可以回朔到以前的版本，除此之外，它還可以幫助你找出兩個版本的差異，你再也不怕不小心改了哪一行結果都不知道，也不怕你的同事幫你偷改了幾行結果你卻不知道，甚至還可以合併兩個不同的分支</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/diff.png"><img class="aligncenter size-full wp-image-1607" title="diff" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/diff.png" alt="" width="732" height="549" /></a></p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/hg_history.png"><img class="aligncenter size-full wp-image-1606" title="hg_history" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/hg_history.png" alt="" width="684" height="376" /></a></p>
<h2>版本控制系統有哪些? 我該用哪一套?</h2>
<p>版本控制系統在幾十年前就已經有現成的工具，然而一直一路演進到今天，現在的版本控制系統已經相當先進且成熟，週邊的工具或是平臺也都相當齊全，從20年前的CVS看起，介紹一些最主流的</p>
<h3><a href="http://zh.wikipedia.org/wiki/%E5%8D%94%E4%BD%9C%E7%89%88%E6%9C%AC%E7%B3%BB%E7%B5%B1">CVS</a></h3>
<p>算是古董級的版本控制系統，主要用於open source的開發，特色是可以多人共同使用，缺點是如果多人要存取同個檔案，要先將檔案鎖起來，很多時候會鎖了忘了開，造成別人無法使用，雖然已經至古董了，但是因為很多大型的開源專案還在使用這系統，所以現在多少還看見有人使用，但不建議一般用途使用</p>
<h3><a href="http://zh.wikipedia.org/wiki/Subversion">Subversion</a></h3>
<p>Subversion簡稱svn，約十年前出現，是CVS的繼承者，主要是改進CVS的缺點，像是最重要的改進，就是檔案鎖定的問題，SVN以試著自動合併檔案的方式來解決同時有兩人修改同一個檔案的問題，現今很多開源專案也還在使用SVN</p>
<p><a href="http://zh.wikipedia.org/wiki/Git">Git</a> &amp; <a href="http://zh.wikipedia.org/wiki/Mercurial">Mercurial</a></p>
<p>接著時間來到了現代，分散式版本控制系統成為了新興專案的主流，在這些新的系統中，檔案庫不在是集中式的，而是分散式的，原本commit都要集中送到中央檔案庫，現在不同的檔案庫之間可以互相傳送對方沒有的commit，如此一來讓開發更加容易，即使沒有網路也可以在本地端commit之後再送給遠端的檔案庫，除此之外，它們引入的新特性也讓合併兩個分支之類的事變得更加容易，個人推薦如果你還沒有用過版本控制系統，可以直接學這些現代的工具，以前的工具大多都已經很少人在使用，可用的資源也在變少中</p>
<h2>Git 的簡介</h2>
<p>Git是Linus Torvalds開發用來管理Linux核心程式碼用的系統，特色是這套系統以效率為設計的考量，並且支援很多較低階的檔案歷史處理，支援的主流免費檔案庫有</p>
<p><a href="http://github.com">Github.com</a></p>
<p><a href="http://bitbucket.org">Bitbucket.org</a></p>
<p>原先Bitbucket只支援Mercurial，這幾天也支援Git了，而Github和Bitbucket的差別在於，Github如果想開私有的檔案庫要錢，而Bitbucket不用，而且是無限個數</p>
<p>如果你想學Git，個人推薦讀</p>
<p><a href="http://progit.org/">Git pro</a></p>
<p>裡面講得非常清楚而且詳細，也有圖說明系統的運作，相對的，如果是讀其它的文件，大多數都很難懂，因為都是寫給geek看的，看不懂是很正常的，整體看起來，Git比Mercurial還難學，除此之外還有一個缺點就是對於Windows的支援較差</p>
<h2>Mercurial的簡介</h2>
<p>Mercurial是基於Python的分散式版本控制系統，特色是以較簡易使用，並且很重視檔案修改的安全性為考量的工具，像是Git有很多指令，一下錯你改的檔案可能因此而遺失，這類情況在Mercurial中較少，大部份指令都會幫你自動備份，如果弄錯指令通常還有救</p>
<p>主流的檔案庫平台是</p>
<p><a href="http://bitbucket.org">Bitbucket.org</a></p>
<p>如果你想學Mercurial，個人推薦看Joel寫的</p>
<p><a href="http://hginit.com/">Hg Init 教學</a></p>
<p>個人較喜歡Mercurial的原因是它的GUI介面工具較為豐富，像是有</p>
<p><a href="http://tortoisehg.bitbucket.org/">TortoiseHg</a></p>
<p><a href="http://jasonfharris.com/machg/">MacHg</a></p>
<p><a href="http://www.sourcetreeapp.com/">SourceTree</a></p>
<p>等好用的GUI工具</p>
<h2>最後</h2>
<p>我在大學教過的<a href="http://www.slideshare.net/stubbornlin/mercurial-9779393">教學用投影片</a>，可以參考看看，未來有空的話或許我可以寫一些這方面的教學，因為畢竟中文資源很少，似乎也沒專門的書在講這些工具的使用</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/10/20/taiwan-software-lacking-of-vcs/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>淺談區域性 (locality)</title>
		<link>http://blog.ez2learn.com/2011/10/14/talk-about-locality/</link>
		<comments>http://blog.ez2learn.com/2011/10/14/talk-about-locality/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 12:10:11 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[區域性]]></category>
		<category><![CDATA[連線延遲]]></category>
		<category><![CDATA[locality]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1569</guid>
		<description><![CDATA[在設計不同的網路服務系統時，為了能夠有擴展性，通常都會設計成分散式的架構，然而除了架構上的設計，如何部署也是很重要的事，其中有個很重要的議題叫做區域性，因為沒有統一或明確的翻譯慣例，所以以英文來說明較為精確，在這裡指的區域性英文為locality，對於這個議題最近有一點心得 所以，回到主題，到底什麼是區域性? 簡單的來說，就是存取資料或資源時，很常存取或是相關的資料放在一起、或很近的地方的特性，舉個實例，例如假設我們有關於某個使用者的資料，但是使用者相關的資料分散在全球不同的資料庫裡，這時我們就會說，這資料庫的區域性不好，以圖來表示，我們假設使用者的資料分散在美西的DB1、美中的DB2和美東的DB3，而使用者在西雅圖要存取這些資料，就得走很遠的距離到三個很遠的地點存取資料 反言之，如果關於這使用者的資料，都存在離使用者很近的點，而且也都在同樣或是很接近的資料庫裡，那麼存取起來就會較快，這樣一來我們就可以說這樣的資料儲存方式它的區域性比較好，我們假設把同一使用者相關的資料都放在相近的地方，以圖為例，都放在加洲，這樣一來同樣是存取使用者的資料，其中所花的傳輸距離成本就遠比上一個例子來得少，反應速度也會因此較快 一般而言，區域性是越強越好，但是也有例外，那就是當考慮到可得性(availability)的時候，這樣的特性是指資料或資源隨時都可取得的機率高低，如果當我們把雞蛋放在同一個籃子裡，也就是資料都放在同樣的Datacenter裡，一但這個Datacenter對外的網路中斷，或是甚至遇到不可預料的災難時，那麼那些資料都會因此而無法取得，所以除了考慮到存取時的區域性，當資料有一定重要程度時，可得性也是很重要的考量，所以某些情況下，資料分散也是必要的 然而，區域性就表面看來，似乎只要將常用的、相關的資料都放在一起好像就能達成，然而經過仔細思考會發現其實並不是只有這樣，還有需要考慮到存取資料的距離，還有存取要求本身的高低階，在這篇文章我想分享的就是主要在於思考關於區域性設計上的一些理論的心得 請求的相依性與粒度 我發現並不是所有的情況下不佳的地區性都一定會嚴重影響到存取的效能，像是請求的相依性其實對於延遲的影響就非常大，如果說所有的情求都不能同時處理，一定得要上一個完成才能完成下一個的話，這樣一來就會造成每個request的請求都要額外花費一次連線的延遲成本，可以參考下圖 很明顯的，左邊的情況，傳輸距離所造成的影響，會是 請求數量 * (運算成本 + 延遲成本) 右邊的情況是 (請求數量 * 運算成本) + 延遲成本 因此光是請求是否能同步處理，並且是否有前後相依，就會造成相當大的差別，如果請求的數量越多，這樣的成本差距就越大，左邊的例子我們以NoSQL或是 SQL的請求為例子，通常下一道請求都是基於上一道請求的資料而決定的，如果說任務被拆散成很零碎的多道請求，像是有些key-value based的NoSQL資料庫，因為沒有高階的查詢指令，必然會有大量的請求，如此一來如果NoSQL資料庫放在很遠的地方，就會造成光是這之間的傳輸成本就會高得嚇人，而以SQL來看，因為可以盡可能地將多道SQL濃縮為少數幾道查詢，因此同樣的傳輸成本對於SQL資料庫來說，傳輸的成本造成的影響會小一點 而右邊的情況，通常是大量的資料傳輸，例如影音串流，因為上一筆資料無關下一筆資料，以這種情況來看，傳輸的距離不會是太大的問題，只有一開始會有的傳輸延遲 心得 一些簡單的心得就是，當請求是相依的，如果數量不大，那麼其實傳輸的延遲是可以被忽視的，又或著是大量連續的資料傳輸，距離的影響是較小的，如果不考慮連線的品質問題的話，但是如果是有相依特性的請求，數量又大的話，最好資料庫的部署要越接近越好，否則光是連線的延遲成本就相當驚人，就算你的NoSQL資料庫再怎麼快，也沒有任何幫助，甚至會比SQL資料庫還要慢]]></description>
			<content:encoded><![CDATA[<p>在設計不同的網路服務系統時，為了能夠有擴展性，通常都會設計成分散式的架構，然而除了架構上的設計，如何部署也是很重要的事，其中有個很重要的議題叫做區域性，因為沒有統一或明確的翻譯慣例，所以以英文來說明較為精確，在這裡指的區域性英文為locality，對於這個議題最近有一點心得</p>
<p>所以，回到主題，到底什麼是區域性? 簡單的來說，就是存取資料或資源時，很常存取或是相關的資料放在一起、或很近的地方的特性，舉個實例，例如假設我們有關於某個使用者的資料，但是使用者相關的資料分散在全球不同的資料庫裡，這時我們就會說，這資料庫的區域性不好，以圖來表示，我們假設使用者的資料分散在美西的DB1、美中的DB2和美東的DB3，而使用者在西雅圖要存取這些資料，就得走很遠的距離到三個很遠的地點存取資料</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/locality01.png"><img class="alignnone size-full wp-image-1574" title="Weak locality" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/locality01.png" alt="" width="506" height="324" /></a></p>
<p>反言之，如果關於這使用者的資料，都存在離使用者很近的點，而且也都在同樣或是很接近的資料庫裡，那麼存取起來就會較快，這樣一來我們就可以說這樣的資料儲存方式它的區域性比較好，我們假設把同一使用者相關的資料都放在相近的地方，以圖為例，都放在加洲，這樣一來同樣是存取使用者的資料，其中所花的傳輸距離成本就遠比上一個例子來得少，反應速度也會因此較快</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/locality02.png"><img class="alignnone size-full wp-image-1576" title="Strong locality" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/locality02.png" alt="" width="506" height="324" /></a></p>
<p>一般而言，區域性是越強越好，但是也有例外，那就是當考慮到可得性(availability)的時候，這樣的特性是指資料或資源隨時都可取得的機率高低，如果當我們把雞蛋放在同一個籃子裡，也就是資料都放在同樣的Datacenter裡，一但這個Datacenter對外的網路中斷，或是甚至遇到不可預料的災難時，那麼那些資料都會因此而無法取得，所以除了考慮到存取時的區域性，當資料有一定重要程度時，可得性也是很重要的考量，所以某些情況下，資料分散也是必要的</p>
<p>然而，區域性就表面看來，似乎只要將常用的、相關的資料都放在一起好像就能達成，然而經過仔細思考會發現其實並不是只有這樣，還有需要考慮到存取資料的距離，還有存取要求本身的高低階，在這篇文章我想分享的就是主要在於思考關於區域性設計上的一些理論的心得</p>
<h2>請求的相依性與粒度</h2>
<p>我發現並不是所有的情況下不佳的地區性都一定會嚴重影響到存取的效能，像是請求的相依性其實對於延遲的影響就非常大，如果說所有的情求都不能同時處理，一定得要上一個完成才能完成下一個的話，這樣一來就會造成每個request的請求都要額外花費一次連線的延遲成本，可以參考下圖</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/10/delay011.png"><img title="Locality delay chart" src="http://blog.ez2learn.com/wp-content/uploads/2011/10/delay011.png" alt="" width="547" height="360" /></a></p>
<p>很明顯的，左邊的情況，傳輸距離所造成的影響，會是</p>
<blockquote><p>請求數量 * (運算成本 + 延遲成本)</p></blockquote>
<p>右邊的情況是</p>
<blockquote><p>(請求數量 * 運算成本) + 延遲成本</p></blockquote>
<p>因此光是請求是否能同步處理，並且是否有前後相依，就會造成相當大的差別，如果請求的數量越多，這樣的成本差距就越大，左邊的例子我們以NoSQL或是 SQL的請求為例子，通常下一道請求都是基於上一道請求的資料而決定的，如果說任務被拆散成很零碎的多道請求，像是有些key-value based的NoSQL資料庫，因為沒有高階的查詢指令，必然會有大量的請求，如此一來如果NoSQL資料庫放在很遠的地方，就會造成光是這之間的傳輸成本就會高得嚇人，而以SQL來看，因為可以盡可能地將多道SQL濃縮為少數幾道查詢，因此同樣的傳輸成本對於SQL資料庫來說，傳輸的成本造成的影響會小一點</p>
<p>而右邊的情況，通常是大量的資料傳輸，例如影音串流，因為上一筆資料無關下一筆資料，以這種情況來看，傳輸的距離不會是太大的問題，只有一開始會有的傳輸延遲</p>
<h2>心得</h2>
<p>一些簡單的心得就是，當請求是相依的，如果數量不大，那麼其實傳輸的延遲是可以被忽視的，又或著是大量連續的資料傳輸，距離的影響是較小的，如果不考慮連線的品質問題的話，但是如果是有相依特性的請求，數量又大的話，最好資料庫的部署要越接近越好，否則光是連線的延遲成本就相當驚人，就算你的NoSQL資料庫再怎麼快，也沒有任何幫助，甚至會比SQL資料庫還要慢</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/10/14/talk-about-locality/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我的open source專案整理列表</title>
		<link>http://blog.ez2learn.com/2011/05/31/my-open-source-projects/</link>
		<comments>http://blog.ez2learn.com/2011/05/31/my-open-source-projects/#comments</comments>
		<pubDate>Tue, 31 May 2011 05:56:52 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[開源]]></category>
		<category><![CDATA[Open source]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1279</guid>
		<description><![CDATA[從很久以前，我就覺得open source是一件很酷的事，覺得能夠免費讓大家用自己心血的結晶真的是件很了不起的事，因此我自己除了使用了不少的open source資源，也一直希望自己也能夠多少有點貢獻，所以在過去多年中確實也有寫了一些open source的專案，雖然都不大，但都很多都是我自己會用到的工具，雖然以前可能有寫過一些介紹，但其實還有不少是沒有介紹過的，會寫open source專案其實多少就是希望有人能使用，而隨著時間久了，我自己會在看到時才想起原來我有寫過這個專案，所以想說弄篇文章來整理一下我所做過的open source專案 Python HGE HGE以前是一款商用的2D遊戲引擎，後來開源，因為我覺得他的引擎挺簡單好用的，重點是有硬體加速，不像SDL純軟體算圖很慢，所以想說把它移植到Python，於是就用Boost.Python寫了一個專案，完成度大約7~8成，裡面有些比較難處理的部份還沒弄好，但主要功能大多都已經可以使用 專案網址: http://code.google.com/p/python-hge/ Gluttony Glottony是一個用來分析Python函式庫在PyPi上的相依情況，主要是有一次我安裝TurboGears時遇到其中一個package的伺服器似乎掛掉了，整個進度就因為那個檔案載不了而無法進行，因此我覺得或許這種相依的情況也是選工具時重要的考量，於是就寫了這樣的工具 專案網址: https://bitbucket.org/victorlin/gluttony Po translator 這是一個用來將.PO檔中的內容透過Google自動翻譯的工具，主要是因為我自己的網站有中文版，想翻成簡體中文，手動一個一個實在太花時間，於是就寫了一個這樣的工具，不過目前有個缺點是當送的量太多，會被Google擋掉一陣子的樣子 專案網址: https://bitbucket.org/victorlin/po_translate Apply firewall iptable幾乎是所有用Linux主機多少都會用到的服務，但是在重設iptable的過程中，難免有時會不小心擋掉自己，如果是遠端登入就麻煩大了，主機在美國也碰不到，只有遠端重開機一條路可走，為了解決這問題，我做這個小工具，可以讓設定iptable像是切換螢幕解析度一樣，會有一段時間讓你確認，沒反應的話會自動取回更動前的設定 專案網址: https://bitbucket.org/victorlin/apply_firewall Correct pycountry 這是一個pycountry的fork，主要是因為pycountry引用ISO裡的國家名稱，但大家都知道台灣的名稱被ISO亂訂，看了心情就不是很爽，所以就fork出一個專案然後改掉裡面的名稱部份 專案網址: https://bitbucket.org/victorlin/correct_pycountry Middleman Middleman是一個基於gevent的簡單網頁proxy，主要是我自己寫來抓論文用的，不過現在已經沒在使用，middleman的名稱主要是取自middleman attack 專案網址: https://bitbucket.org/victorlin/middleman/ Logy 一個簡易的中央日誌記錄用的網頁服務，目前沒有繼續開發的打算 專案網址: https://bitbucket.org/victorlin/logy Loso &#8230; <a href="http://blog.ez2learn.com/2011/05/31/my-open-source-projects/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>從很久以前，我就覺得open source是一件很酷的事，覺得能夠免費讓大家用自己心血的結晶真的是件很了不起的事，因此我自己除了使用了不少的open source資源，也一直希望自己也能夠多少有點貢獻，所以在過去多年中確實也有寫了一些open source的專案，雖然都不大，但都很多都是我自己會用到的工具，雖然以前可能有寫過一些介紹，但其實還有不少是沒有介紹過的，會寫open source專案其實多少就是希望有人能使用，而隨著時間久了，我自己會在看到時才想起原來我有寫過這個專案，所以想說弄篇文章來整理一下我所做過的open source專案</p>
<h2>Python HGE</h2>
<p><a href="http://hge.relishgames.com/">HGE</a>以前是一款商用的2D遊戲引擎，後來開源，因為我覺得他的引擎挺簡單好用的，重點是有硬體加速，不像SDL純軟體算圖很慢，所以想說把它移植到Python，於是就用Boost.Python寫了一個專案，完成度大約7~8成，裡面有些比較難處理的部份還沒弄好，但主要功能大多都已經可以使用</p>
<p>專案網址:</p>
<p><a href="http://code.google.com/p/python-hge/">http://code.google.com/p/python-hge/</a></p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/05/t7.png"><img class="alignnone size-medium wp-image-1280" title="Python - HGE" src="http://blog.ez2learn.com/wp-content/uploads/2011/05/t7-300x235.png" alt="" width="300" height="235" /></a></p>
<h2>Gluttony</h2>
<p>Glottony是一個用來分析Python函式庫在<a href="http://pypi.python.org/pypi">PyPi</a>上的相依情況，主要是有一次我安裝TurboGears時遇到其中一個package的伺服器似乎掛掉了，整個進度就因為那個檔案載不了而無法進行，因此我覺得或許這種相依的情況也是選工具時重要的考量，於是就寫了這樣的工具</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/gluttony">https://bitbucket.org/victorlin/gluttony</a></p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/05/sprox_dot.png"><img class="alignnone size-medium wp-image-1281" title="Gluttony" src="http://blog.ez2learn.com/wp-content/uploads/2011/05/sprox_dot-300x177.png" alt="" width="300" height="177" /></a></p>
<h2>Po translator</h2>
<p>這是一個用來將.PO檔中的內容透過Google自動翻譯的工具，主要是因為我自己的網站有中文版，想翻成簡體中文，手動一個一個實在太花時間，於是就寫了一個這樣的工具，不過目前有個缺點是當送的量太多，會被Google擋掉一陣子的樣子</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/po_translate">https://bitbucket.org/victorlin/po_translate</a></p>
<h2>Apply firewall</h2>
<p>iptable幾乎是所有用Linux主機多少都會用到的服務，但是在重設iptable的過程中，難免有時會不小心擋掉自己，如果是遠端登入就麻煩大了，主機在美國也碰不到，只有遠端重開機一條路可走，為了解決這問題，我做這個小工具，可以讓設定iptable像是切換螢幕解析度一樣，會有一段時間讓你確認，沒反應的話會自動取回更動前的設定</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/apply_firewall">https://bitbucket.org/victorlin/apply_firewall</a></p>
<h2>Correct pycountry</h2>
<p>這是一個pycountry的fork，主要是因為pycountry引用ISO裡的國家名稱，但大家都知道台灣的名稱被ISO亂訂，看了心情就不是很爽，所以就fork出一個專案然後改掉裡面的名稱部份</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/correct_pycountry">https://bitbucket.org/victorlin/correct_pycountry</a></p>
<h2>Middleman</h2>
<p>Middleman是一個基於gevent的簡單網頁proxy，主要是我自己寫來抓論文用的，不過現在已經沒在使用，middleman的名稱主要是取自middleman attack</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/middleman/">https://bitbucket.org/victorlin/middleman</a>/</p>
<h2>Logy</h2>
<p>一個簡易的中央日誌記錄用的網頁服務，目前沒有繼續開發的打算</p>
<p>專案網址:</p>
<p><a href="https://bitbucket.org/victorlin/logy">https://bitbucket.org/victorlin/logy</a></p>
<h2>Loso</h2>
<p>Loso主要是我替Plurk寫的一套中文斷詞系統，稍後有空我會寫篇文章來介紹這套系統</p>
<p>專案網址:</p>
<p><a href="https://github.com/victorlin/loso">https://github.com/victorlin/loso</a></p>
<h2>Avoid Disaster</h2>
<p>Avoid disaster是一套用來備份資料用的工具，這也是我會加入Plurk的原因，當時我替我的Now.in寫了備份資料庫的工具，剛好看見Amir也寫了一套，裡面有個做法我覺得很不錯，於是就把兩套合在一起，做了一個fork，Amir看了就邀請我加入Plurk，這套工具不只可以備份到Amazon S3去，只要新增不同的storage類別，例如FTP storage，就能改將資料備份到FTP去</p>
<p>專案網址:</p>
<p><a href="https://github.com/victorlin/avoid_disaster">https://github.com/victorlin/avoid_disaster</a></p>
<h1>License</h1>
<p>這裡的專案所有的License應該都是MIT，好像只有少數幾個BSD，為什麼選MIT呢? 一來是我覺得GPL那種病毒式的，修改了想散播就得強迫你加入的自由算哪門子的自由，其實這點反而讓它變成很多商業產品喜歡使用的授權，因為你改了要散播也得開放出來，對於競爭對手有所限制，但BSD like就沒這問題，我這些東西都沒有商業考量，我覺得要開放就是要做到你拿去做商業軟體散播也無所謂的地步，就像天元突破裡的一段，他們之所以想開源</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/05/gurren02.jpg"><img class="alignnone size-large wp-image-1282" title="gurren" src="http://blog.ez2learn.com/wp-content/uploads/2011/05/gurren02-1024x576.jpg" alt="" width="580" height="320" /></a></p>
<p>不過如果我也不是什麼聖人，或許哪天我的開源專案有了商業考量，或許我也會使用那病毒GPL來防止別人競爭吧，但是應該是不會，我覺得要開源就不怕別人用，就算用了GPL對方也不一定會照著規則走</p>
<p>第二個用MIT的理由，是因為MIT聽起來很酷!</p>
<p>第三，就是因為 MIT = Made in Taiwan :D</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/05/31/my-open-source-projects/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Zero-downtime service migration</title>
		<link>http://blog.ez2learn.com/2011/02/04/zero-downtime-service-migration/</link>
		<comments>http://blog.ez2learn.com/2011/02/04/zero-downtime-service-migration/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 09:12:20 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[分享]]></category>
		<category><![CDATA[English Articles]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Unix-Like]]></category>
		<category><![CDATA[0-down-time]]></category>
		<category><![CDATA[hot code swap]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[service]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1225</guid>
		<description><![CDATA[When I am running my website, now.in, I did encounter a trouble.  That is, when there is a bug in the production server, then I need to restart them.  Sounds fine, right? Just to restart a server.  Yes, for most &#8230; <a href="http://blog.ez2learn.com/2011/02/04/zero-downtime-service-migration/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When I am running my website, now.in, I did encounter a trouble.  That is, when there is a bug in the production server, then I need to restart them.  Sounds fine, right? Just to restart a server.  Yes, for most of web HTTP servers, they are stateless,  it is fine to restart them whenever you want, but not true for now.in, they are audio streaming servers.  Here s a server stats diagram shows the problem:</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/server_diagram.png"><img class="alignnone size-medium wp-image-1217" title="server_diagram" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/server_diagram-300x196.png" alt="" width="300" height="196" /></a></p>
<p>You can see there are some gaps in the plot, that&#8217;s caused by server restarting.  Of course, for users, that would definitely be bad experience.  Thus, I&#8217;m thinking how to solve this problem recently.  Before we go into the design, let&#8217;s look the reasons for restarting server first.</p>
<ul>
<li>To deploy new version of program</li>
<li>To fix bugs</li>
<li>The process is using to much memory</li>
<li>To reload environment, ulimit -n for example (the limit count of file descriptor under unix-like environment)</li>
<li>To migrate from host A to host B</li>
</ul>
<p>For simply employe new version of program, we can use reload function of Python to reload modules.  But there is some problems, reload function only rerun the module, those created instances are still there, it might work if the change is minor.  On the other hand,  reloading can&#8217;t solve memory usage problem, process environment change problem.  And here comes the final reason, to migrate service from host A to B.  Indeed, it is difficult not to make any down time for such migration, and there is little chance to do such migration, therefore, we&#8217;ll only focus on migration in same host.</p>
<h2>The idea</h2>
<p>The biggest challenge is, how to migrate those working connections?  My idea is simple, create a new process, and transfer those connection to the new process, and shut the old one down.  Following diagrams show my method.</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_011.png"><img class="alignnone size-medium wp-image-1226" title="mig_01" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_011-226x300.png" alt="" width="226" height="300" /></a></p>
<p>The Master is a process which is charge for managing migration and receiving command from other process.  And the process A is for running service.</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_02.png"><img class="alignnone size-medium wp-image-1220" title="mig_02" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_02-300x263.png" alt="" width="300" height="263" /></a></p>
<p>Before we perform the migration, the Manager startup process B, and wait it says it&#8217;s readly.</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_03.png"><img class="alignnone size-medium wp-image-1221" title="mig_03" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_03-300x263.png" alt="" width="300" height="263" /></a></p>
<p>When process B said "Hey! I&#8217;m ready", then manager tell process A to send the connection state descriptor to process B.  Process B receive the state, and take over the service.</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_04.png"><img class="alignnone size-medium wp-image-1222" title="mig_04" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_04-243x300.png" alt="" width="243" height="300" /></a></p>
<p>Finally, process B took over the service, then master tells process A "You are fired." and the process A rolls itself out.</p>
<p>That&#8217;s it, the service was migrated, and there is no down time.</p>
<h2>The problem &#8211; socket transfer</h2>
<p>The idea sounds good, right? But still, we have some technical problem to solve.  It is "How to transfer socket (file descriptor) from one process to another?".  To solve this problem, I have some study, and eventually I know two methods to achieve the goal.</p>
<h3>Child process</h3>
<p>For most of unix-like OS, child processes inherit file descriptors from their parent.  Of course we can use this feature to migrate our service, but however, it got its limitation.  You can only transfer file descriptors to child process.</p>
<h3>Sendmsg</h3>
<p>Another way to achieve same goal is, to use sendmsg through a unix domain socket to send the file descriptors.  With sendmsg, you can transfer file descriptors to almost any processes you like, that&#8217;s much flexible.</p>
<h2>A simple implementation</h2>
<p>To simplify the example, we only implement process A and process B here, it is quite enough for two process to complete the migration.  Before we go into the details, there is another problem to solve, which is sendmsg is not a standard function in Python.  Fortunately, there is a third party library named sendmsg provides this function.  To install sendmsg, it is easy, just type</p>
<p>easy_install sendmsg</p>
<p>And here you are.  Okay, following are the two programs.</p>
<p>a.py</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">import</span> sendmsg
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">struct</span>
&nbsp;
s = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
s.<span style="color: black;">bind</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>, <span style="color: #ff4500;">5566</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
s.<span style="color: black;">listen</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
conn, addr = s.<span style="color: black;">accept</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
conn.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello, process %d is serving<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Accept inet connection'</span>, conn
&nbsp;
us = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_UNIX</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">bind</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mig.sock'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">listen</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
uconn, addr = us.<span style="color: black;">accept</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Accept unix connection'</span>, uconn
&nbsp;
payload = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'i'</span>, conn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
sendmsg.<span style="color: black;">sendmsg</span><span style="color: black;">&#40;</span>
    uconn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">''</span>, <span style="color: #ff4500;">0</span>, <span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">SOL_SOCKET</span>, sendmsg.<span style="color: black;">SCM_RIGHTS</span>, payload<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Sent socket'</span>, conn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Done.'</span></pre></div></div>

<p>b.py</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">import</span> sendmsg
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">struct</span>
&nbsp;
us = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_UNIX</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mig.sock'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Make unix connection'</span>, us
&nbsp;
result = sendmsg.<span style="color: black;">recvmsg</span><span style="color: black;">&#40;</span>us.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
identifier, flags, <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>level, <span style="color: #008000;">type</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> = result
<span style="color: #ff7700;font-weight:bold;">print</span> identifier, flags, <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>level, <span style="color: #008000;">type</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
fd = <span style="color: #dc143c;">struct</span>.<span style="color: black;">unpack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'i'</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Get fd'</span>, fd
&nbsp;
conn = <span style="color: #dc143c;">socket</span>.<span style="color: black;">fromfd</span><span style="color: black;">&#40;</span>fd, <span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span>fd<span style="color: black;">&#41;</span>
conn.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello, process %d is serving<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>The flow is simple, the a.py accept an inet socket and open an unix domain socket, wait b.py to take over the service.  And here we runs b.py, it connects to a.py, receives the fd of socket and takes over providing service.</p>
<h2>The result</h2>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/螢幕快照-2011-02-04-下午4.07.07.png"><img class="alignnone size-full wp-image-1223" title="螢幕快照 2011-02-04 下午4.07.07" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/螢幕快照-2011-02-04-下午4.07.07.png" alt="" width="656" height="440" /></a></p>
<p>As the result shows, there is not down time between the service migration.</p>
<p>It is very useful to employ this technique in server programs.  You can even migrate service from Python server to a C/C++ server, or vice versa.  Also, to keep the memory usage low, you can also migrate the service to same program periodically.  I will try to employ this technique in my servers to achieve zero down time migration.  If you are interesting in this technique, have a try, it is fun and useful :)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/02/04/zero-downtime-service-migration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>無停機服務遷移</title>
		<link>http://blog.ez2learn.com/2011/02/04/zero-down-time-service-migration/</link>
		<comments>http://blog.ez2learn.com/2011/02/04/zero-down-time-service-migration/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 08:15:30 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[0-down-time]]></category>
		<category><![CDATA[伺服器]]></category>
		<category><![CDATA[網路連線]]></category>
		<category><![CDATA[無停機]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[sendmsg]]></category>
		<category><![CDATA[Server]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1214</guid>
		<description><![CDATA[一直以來在營運now.in都有一個令人困擾的問題，就是每當伺服器更新或是出現問題時，就得關掉重開，雖然說大部份的伺服器我在設計上都做成重開也沒有關係，但有少部份一但重啟就會造成使用者斷線，參考下面這張伺服器狀態的圖 圖中被切斷的山峰都是伺服器重啟的時候，無疑的這對使用者來說是不好的體驗，對於一般網頁HTTP這類stateless的伺服器來說重啟是無所謂，但串流伺服器就不一樣，因此最近我在思考如何解決這樣的問題，首先想到的是伺服器重開的原因，不外乎有幾種 部署新版的程式 為了修正BUG 記憶體用量過高 重新讀取執行環境，例如ulimit -n，也就是檔案數量的限制大小 從主機A移到主機B 以Python的伺服器來說，如果只是單單只是為了部署新版的程式，Python有個reload函數可以重讀整個module，因此可以設個管理用的後門用來重載模組，但是這樣做有個問題，就是已經產生的instance還是一樣，其實說穿了等於是重新執行那個module，如果只是簡單的改版還好，但複雜的改版就可能牽扯到太多因素難以透過這樣來更新，而除此之外，很多重開的因素像是記憶體用量過高，或著執行的環境參數改變，這些都無可避免的一定得建新的process，至於從A主機移到B主機，基本上是難以避免的一定得重啟伺服器，除非有某個前端的伺服器保持連線，後端的伺服器進行交移工作才有可能，而主機轉移的狀況其實很少出現，因此這篇文章要探討的是如何辦到同一臺機器內的服務轉移 方法 最大的問題就在於，連線中的socket該如保持住連線，最簡單的想法就是建立新的process，將目前的連線交給新的process，新的process接手完所有的連線開始運作後舊的process就能終止了，當然所謂的連線還包函了服務的狀態，我們在者裡稱之為 CSD (Connection State Descriptor)，大致想法如下面圖片所示 首先Process A是正在運行的process，而Manager是負責控制遷移的process 此時Manager啟動了要負責接手的Process B 接著Manager通知A將連線狀態傳送給Process B，B接手後繼續提供服務，並且告知接收完成 在確定B能夠接手服務並且正確執行後，這時Manager就能將A中止，走到這裡服務就算是完整地移交了，中間沒有任何間斷 技術層面問題 &#8211; Socket的轉移 這樣的做法理論上看起來確實可行沒錯，但是最主要有技術上的問題得解決，就是如何將socket，或著是file descriptor轉移到另一個process，在我找過相關的資料後知道目前有兩個方法 child process 這個方法主要是因為child process在生成後會繼承parent process的file descriptor，但是缺點就是只限於child process，如果我們想將服務移交給另一個完整的獨立process這個方法就會行不通，因此使用上會有很多限制 sendmsg 另一個方法就是unix domain的socket有提供一個函數叫sendmsg，可以將file descriptor轉移到任何process，這樣一來實用性就比child process高很多，於是我決定採用此方法 簡易的實作 &#8230; <a href="http://blog.ez2learn.com/2011/02/04/zero-down-time-service-migration/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>一直以來在營運now.in都有一個令人困擾的問題，就是每當伺服器更新或是出現問題時，就得關掉重開，雖然說大部份的伺服器我在設計上都做成重開也沒有關係，但有少部份一但重啟就會造成使用者斷線，參考下面這張伺服器狀態的圖</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/server_diagram.png"><img class="alignnone size-medium wp-image-1217" title="server_diagram" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/server_diagram-300x196.png" alt="" width="300" height="196" /></a></p>
<p>圖中被切斷的山峰都是伺服器重啟的時候，無疑的這對使用者來說是不好的體驗，對於一般網頁HTTP這類stateless的伺服器來說重啟是無所謂，但串流伺服器就不一樣，因此最近我在思考如何解決這樣的問題，首先想到的是伺服器重開的原因，不外乎有幾種</p>
<ul>
<li>部署新版的程式</li>
<li>為了修正BUG</li>
<li>記憶體用量過高</li>
<li>重新讀取執行環境，例如ulimit -n，也就是檔案數量的限制大小</li>
<li>從主機A移到主機B</li>
</ul>
<p>以Python的伺服器來說，如果只是單單只是為了部署新版的程式，Python有個reload函數可以重讀整個module，因此可以設個管理用的後門用來重載模組，但是這樣做有個問題，就是已經產生的instance還是一樣，其實說穿了等於是重新執行那個module，如果只是簡單的改版還好，但複雜的改版就可能牽扯到太多因素難以透過這樣來更新，而除此之外，很多重開的因素像是記憶體用量過高，或著執行的環境參數改變，這些都無可避免的一定得建新的process，至於從A主機移到B主機，基本上是難以避免的一定得重啟伺服器，除非有某個前端的伺服器保持連線，後端的伺服器進行交移工作才有可能，而主機轉移的狀況其實很少出現，因此這篇文章要探討的是如何辦到同一臺機器內的服務轉移</p>
<h2>方法</h2>
<p>最大的問題就在於，連線中的socket該如保持住連線，最簡單的想法就是建立新的process，將目前的連線交給新的process，新的process接手完所有的連線開始運作後舊的process就能終止了，當然所謂的連線還包函了服務的狀態，我們在者裡稱之為 CSD (Connection State Descriptor)，大致想法如下面圖片所示</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_01.png"><img class="alignnone size-medium wp-image-1219" title="Migration process 01" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_01-226x300.png" alt="" width="226" height="300" /></a></p>
<p>首先Process A是正在運行的process，而Manager是負責控制遷移的process</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_02.png"><img class="alignnone size-medium wp-image-1220" title="mig_02" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_02-300x263.png" alt="" width="300" height="263" /></a></p>
<p>此時Manager啟動了要負責接手的Process B</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_03.png"><img class="alignnone size-medium wp-image-1221" title="mig_03" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_03-300x263.png" alt="" width="300" height="263" /></a></p>
<p>接著Manager通知A將連線狀態傳送給Process B，B接手後繼續提供服務，並且告知接收完成</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_04.png"><img class="alignnone size-medium wp-image-1222" title="mig_04" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/mig_04-243x300.png" alt="" width="243" height="300" /></a></p>
<p>在確定B能夠接手服務並且正確執行後，這時Manager就能將A中止，走到這裡服務就算是完整地移交了，中間沒有任何間斷</p>
<h2>技術層面問題 &#8211; Socket的轉移</h2>
<p>這樣的做法理論上看起來確實可行沒錯，但是最主要有技術上的問題得解決，就是如何將socket，或著是file descriptor轉移到另一個process，在我找過相關的資料後知道目前有兩個方法</p>
<h3>child process</h3>
<p>這個方法主要是因為child process在生成後會繼承parent process的file descriptor，但是缺點就是只限於child process，如果我們想將服務移交給另一個完整的獨立process這個方法就會行不通，因此使用上會有很多限制</p>
<h3>sendmsg</h3>
<p>另一個方法就是unix domain的socket有提供一個函數叫sendmsg，可以將file descriptor轉移到任何process，這樣一來實用性就比child process高很多，於是我決定採用此方法</p>
<h2>簡易的實作</h2>
<p>在這樣的轉移架構設計，Manager主要目的是要能夠對外有個統一個process能溝通，如果不需要的話其實兩個process就能達成服務轉移，為了實作簡單因此這個例子只用了兩個process進行轉移</p>
<p>還有另一個問題是Python標準函式庫裡沒有sendmsg，不過幸好有第三方函式庫已經準備好，就叫做sendmsg，安裝也很簡單，只要打</p>
<p>easy_install sendmsg</p>
<p>就可以了，接下來就是兩個範例程式</p>
<p>a.py:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">import</span> sendmsg
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">struct</span>
&nbsp;
s = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
s.<span style="color: black;">bind</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>, <span style="color: #ff4500;">5566</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
s.<span style="color: black;">listen</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
conn, addr = s.<span style="color: black;">accept</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
conn.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello, process %d is serving<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Accept inet connection'</span>, conn
&nbsp;
us = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_UNIX</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">bind</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mig.sock'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">listen</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
uconn, addr = us.<span style="color: black;">accept</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Accept unix connection'</span>, uconn
&nbsp;
payload = <span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'i'</span>, conn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
sendmsg.<span style="color: black;">sendmsg</span><span style="color: black;">&#40;</span>
    uconn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">''</span>, <span style="color: #ff4500;">0</span>, <span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">SOL_SOCKET</span>, sendmsg.<span style="color: black;">SCM_RIGHTS</span>, payload<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Sent socket'</span>, conn.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Done.'</span></pre></div></div>

<p>b.py</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">import</span> sendmsg
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">struct</span>
&nbsp;
us = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_UNIX</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
us.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mig.sock'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Make unix connection'</span>, us
&nbsp;
result = sendmsg.<span style="color: black;">recvmsg</span><span style="color: black;">&#40;</span>us.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
identifier, flags, <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>level, <span style="color: #008000;">type</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> = result
<span style="color: #ff7700;font-weight:bold;">print</span> identifier, flags, <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>level, <span style="color: #008000;">type</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
fd = <span style="color: #dc143c;">struct</span>.<span style="color: black;">unpack</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'i'</span>, data<span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Get fd'</span>, fd
&nbsp;
conn = <span style="color: #dc143c;">socket</span>.<span style="color: black;">fromfd</span><span style="color: black;">&#40;</span>fd, <span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_STREAM</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span>fd<span style="color: black;">&#41;</span>
conn.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Hello, process %d is serving<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>大致上的流程很簡單，首先a.py接收一個inet的連線，接著就開一個unix socket，等待b.py上線，然後把服務透過sendmsg轉移給b.py</p>
<h2>執行結果</h2>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/02/螢幕快照-2011-02-04-下午4.07.07.png"><img class="alignnone size-full wp-image-1223" title="螢幕快照 2011-02-04 下午4.07.07" src="http://blog.ez2learn.com/wp-content/uploads/2011/02/螢幕快照-2011-02-04-下午4.07.07.png" alt="" width="656" height="440" /></a></p>
<p>由執行結果我們可以看見，原本的連線是由process A提供的，然後轉交給process B，中間沒有任何中斷</p>
<p>有了這樣的技術基礎和想法，接著就剩下的是細節，基本上連線的狀態盡量以抽象的方式提供，如此一來任何程式只要能夠處理連線狀態就能夠接手，甚至可以由Python寫的伺服器轉移到由C/C++寫的伺服器，這些都可以辦到，中間服務都不會有間斷，而且也可以像HTTP伺服器一樣，處理到一定的量自動開新的process轉移給自己，如此一來可以保持低記憶體用量，有相當多的好處，未來我會試著將伺服器以這樣的想法改寫，應該就能做到無停機更新，有興趣的話也可以自己試試看</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/02/04/zero-down-time-service-migration/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Logy &#8211; a central logging system for Python</title>
		<link>http://blog.ez2learn.com/2011/01/01/logy-a-central-logging-system-for-python/</link>
		<comments>http://blog.ez2learn.com/2011/01/01/logy-a-central-logging-system-for-python/#comments</comments>
		<pubDate>Sat, 01 Jan 2011 09:30:46 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[分享]]></category>
		<category><![CDATA[English Articles]]></category>
		<category><![CDATA[Logging]]></category>
		<category><![CDATA[Open source]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1174</guid>
		<description><![CDATA[I&#8217;m glad to announce my new open source project:Logy. Logy is a simple lightweight central logging system for Python. When do you need a central logging system?  Well, when you have many servers online, and they are running different python &#8230; <a href="http://blog.ez2learn.com/2011/01/01/logy-a-central-logging-system-for-python/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m glad to announce my new open source project:Logy.  Logy is a simple lightweight central logging system for Python. When do you need a central logging system?  Well, when you have many servers online, and they are running different python application, you will want to have a central logging system for making sure everything is going fine.  And you might ask, why not just use email for error reports? Well, following screenshot explains:</p>
<p><img class="alignnone size-medium wp-image-1175" title="error_reports" src="http://blog.ez2learn.com/wp-content/uploads/2011/01/error_reports-300x238.png" alt="" width="300" height="238" /></p>
<p>I use email as error logging report, but however, as you can see if there is something wrong with my servers in same time, network outage for instance, there will be so many error report mails come in my mailbox like crazy.  Therefore think a central log might be a good idea, then I decide to develop a simple central logging system for my own servers.  Here is a screenshot of the Logy web page.</p>
<p><a href="http://blog.ez2learn.com/wp-content/uploads/2011/01/logy_screenshot01.png"><img class="alignnone size-full wp-image-1178" title="logy_screenshot01" src="http://blog.ez2learn.com/wp-content/uploads/2011/01/logy_screenshot01.png" alt="" width="732" height="617" /></a></p>
<p>It categorizes your logging records by IP address automatically, and also, you can set a application name for different applications which are running in same box.  And one important feature is, it is base on Flask :)</p>
<p>It is super easy to write records to Logy, here is an example:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> ex_loghandlers
&nbsp;
rootLogger = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>
rootLogger.<span style="color: black;">setLevel</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
&nbsp;
sream_handler = <span style="color: #dc143c;">logging</span>.<span style="color: black;">StreamHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># set up the http handler which writes records to Logy server</span>
http_handler = ex_loghandlers.<span style="color: black;">ExHTTPHandler</span><span style="color: black;">&#40;</span>host=<span style="color: #483d8b;">'localhost:5000'</span>,
                                            url=<span style="color: #483d8b;">'/sink/TEST/myapp'</span>,
                                            method=<span style="color: #483d8b;">'POST'</span><span style="color: black;">&#41;</span>
rootLogger.<span style="color: black;">addHandler</span><span style="color: black;">&#40;</span>sream_handler<span style="color: black;">&#41;</span>
rootLogger.<span style="color: black;">addHandler</span><span style="color: black;">&#40;</span>http_handler<span style="color: black;">&#41;</span>
&nbsp;
logger1 = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'myapp.area1'</span><span style="color: black;">&#41;</span>
logger2 = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'myapp.area2'</span><span style="color: black;">&#41;</span>
&nbsp;
logger1.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Quick zephyrs blow, vexing daft Jim.'</span><span style="color: black;">&#41;</span>
logger1.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'How quickly daft jumping zebras vex.'</span><span style="color: black;">&#41;</span>
logger2.<span style="color: black;">warning</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Jail zesty vixen who grabbed pay from quack.'</span><span style="color: black;">&#41;</span>
logger2.<span style="color: black;">error</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'The five boxing wizards jump quickly.'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">Exception</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Boom&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span>:
    logger1.<span style="color: black;">fatal</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Huston, we've got a problem&quot;</span>, exc_info=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span> 
&nbsp;
logger1.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Everything goes fine, now.'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>You need to install my module named ex_loghandlers before you can run this script, it contains an ExHTTPHandler which provides extra information for Logy.</p>
<p>Here are some more information of Logy:</p>
<p>PyPi page: <a href="http://pypi.python.org/pypi/logy">http://pypi.python.org/pypi/logy</a></p>
<p>Bitbucket: <a href="https://bitbucket.org/victorlin/logy/src">https://bitbucket.org/victorlin/logy/src</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2011/01/01/logy-a-central-logging-system-for-python/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Po translate &#8211; automatic translation tool for .PO files</title>
		<link>http://blog.ez2learn.com/2010/10/18/po-translate-automatic-translation-tool-for-po-files/</link>
		<comments>http://blog.ez2learn.com/2010/10/18/po-translate-automatic-translation-tool-for-po-files/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 13:14:56 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[分享]]></category>
		<category><![CDATA[English Articles]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[gettext]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[po]]></category>
		<category><![CDATA[simplified chinese]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[traditional chinese]]></category>
		<category><![CDATA[translate]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1108</guid>
		<description><![CDATA[It is kinda hateful to translate .PO files from Traditional-Chinese to Simplified-Chinese, most of the meanings are identical but different in simplified word or traditional word.  It is not a very difficult to translate.  But however, it is still an &#8230; <a href="http://blog.ez2learn.com/2010/10/18/po-translate-automatic-translation-tool-for-po-files/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>It is kinda hateful to translate .PO files from <a href="http://en.wikipedia.org/wiki/Traditional_Chinese_characters">Traditional-Chinese</a> to <a href="http://en.wikipedia.org/wiki/Simplified_Chinese_characters">Simplified-Chinese</a>, most of the meanings are identical but different in simplified word or traditional word.  It is not a very difficult to translate.  But however, it is still an hateful job to do that manually.  For this reason, I wrote a tool which uses Google translate API to translate .PO files automatically.  It is quite easy to install</p>
<blockquote><p>easy_install po_translate</p></blockquote>
<p>It is also very easy to use, too.</p>
<blockquote><p>po_translate input.po output.po zh-TW zh-CN</p></blockquote>
<p>Of course, you can replace zh-TW and zh-CN to the source and destination language you like, e.g. English to Chinese, if the result is acceptable to you :)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2010/10/18/po-translate-automatic-translation-tool-for-po-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Po translate 自動化翻譯工具</title>
		<link>http://blog.ez2learn.com/2010/10/18/po-translate/</link>
		<comments>http://blog.ez2learn.com/2010/10/18/po-translate/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 12:59:01 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[工具]]></category>
		<category><![CDATA[國際化]]></category>
		<category><![CDATA[繁簡轉換]]></category>
		<category><![CDATA[自動翻譯]]></category>
		<category><![CDATA[gettext]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[simplified chinese]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tradition chinese]]></category>
		<category><![CDATA[translate]]></category>
		<category><![CDATA[zh-cn]]></category>
		<category><![CDATA[zh-tw]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=1099</guid>
		<description><![CDATA[之前有寫一個 PO檔自動繁簡轉換程式，但是因為沒有把它傳到PyPi上，所以要到處copy貼上很麻煩，為了方便使用，我把它打包並且傳到了PyPi，以MIT License開放源始碼，不過只是一個很簡單的程式而已，我想應該沒有多少人會想改些什麼，但是當然有人有興趣的話，歡迎修改 這個程式主要是用來解決繁體中文的.PO檔和簡體之間的互換問題，因為翻譯完繁體中文，基本上和簡體沒有太大差別，用Google translate轉成簡體就可以，但是手工作起來很煩，這種事情當然是交給程式執行 安裝方法很簡單 easy_install po_translate 使用也很簡單 po_translate input.po output.po zh-TW zh-CN 像這樣就能輕鬆的透過Google translate把繁中的.PO檔轉成簡中的 相關連結 PyPi的連結 Bitbucket的Repo]]></description>
			<content:encoded><![CDATA[<p>之前有寫一個 <a href="http://blog.ez2learn.com/2010/04/28/po-file-zh_tw-to-zh_cn-program/">PO檔自動繁簡轉換程式</a>，但是因為沒有把它傳到PyPi上，所以要到處copy貼上很麻煩，為了方便使用，我把它打包並且傳到了PyPi，以MIT License開放源始碼，不過只是一個很簡單的程式而已，我想應該沒有多少人會想改些什麼，但是當然有人有興趣的話，歡迎修改</p>
<p>這個程式主要是用來解決繁體中文的.PO檔和簡體之間的互換問題，因為翻譯完繁體中文，基本上和簡體沒有太大差別，用Google translate轉成簡體就可以，但是手工作起來很煩，這種事情當然是交給程式執行</p>
<p>安裝方法很簡單</p>
<blockquote><p>easy_install po_translate</p></blockquote>
<p>使用也很簡單</p>
<blockquote><p>po_translate input.po output.po zh-TW zh-CN</p></blockquote>
<p>像這樣就能輕鬆的透過Google translate把繁中的.PO檔轉成簡中的</p>
<p>相關連結</p>
<p><a href="http://pypi.python.org/pypi/po_translate">PyPi的連結</a></p>
<p><a href="http://bitbucket.org/victorlin/po_translate">Bitbucket的Repo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2010/10/18/po-translate/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

