over 5 years ago

用 Python 來寫 Hadoop 的 MapReduce 程式

  • 安裝:pip install mrjob

  • 一個官網最簡單的 word_count.py 範例:

from mrjob.job import MRJob

class MRWordFrequencyCount(MRJob):
    def mapper(self, _, line):
        yield "chars", len(line)
        yield "words", len(line.split())
        yield "lines", 1

    def reducer(self, key, values):
        yield key, sum(values)


if __name__ == '__main__':
    MRWordFrequencyCount.run()
  • 執行:python word_count.py input.txt
no configs found; falling back on auto-configuration
no configs found; falling back on auto-configuration
creating tmp directory /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769
writing to /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/step-0-mapper_part-00000
Counters from step 1:
  (no counters found)
writing to /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/step-0-mapper-sorted
> sort /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/step-0-mapper_part-00000
writing to /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/step-0-reducer_part-00000
Counters from step 1:
  (no counters found)
Moving /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/step-0-reducer_part-00000 -> /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/output/part-00000
Streaming final output from /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769/output
"chars" 21
"lines" 1
"words" 5
removing tmp directory /var/folders/bz/z8d70ds17y59ggw906xdqrvw0000gn/T/mrjob1.veck.20140804.113920.115769

其中統計結果:

"chars" 21
"lines" 1
"words" 5

程式碼中有個 MRJob,這個物件的 class 定義了你建立的 jobsteps 中會用到的方法:mapper, combiner, reducer,不一定全部都要有,但每個 step 至少要有三者其中之一,也就是說,你的 job 可以只有一個 mapper、一個 combiner 或一個 reducer

mapper(): 吃一個 key 和一個 value 參數,並且產生許多 key-value pair,就跟原本 Java 的 Mapper 一樣
reducer(): 吃一個 key 和一個 iterable value,也會產生許多 key-value pair,同原本 Java 的 Reducer

而最後的兩行程式碼,用來驅動我們的 job:

if __name__ == '__main__':
    MRWordCounter.run()  # where MRWordCounter is your job class

mrjob 預設是將 job 跑在 single python process,這樣比較方便 debug,但這樣不是分散式運算,要切換成其他的執行模式,可以加上 -r,共有三種不同模式:-r local, -r hadoop, -r emr

  1. -r local: 執行在多個子行程上 (虛擬分散式)
  2. -r hadoop: 執行在 hadoop 叢集上 (完全分散式)
  3. -r emr: 執行在 Elastic MapReduce 上

假如你的 input 檔案存放在 HDFS 或 S3 上(with EMR):

$ python my_job.py -r emr s3://my-inputs/input.txt
$ python my_job.py -r hadoop hdfs://my_home/input.txt

假如你有多個 step (通常)在一個 job 中,你可以透過覆寫 steps() 方法來定義 steps,建立 mrjob.step.MRStepstep list,例如以下範例:

from mrjob.job import MRJob
from mrjob.step import MRStep
import re

WORD_RE = re.compile(r"[\w']+")

class MRMostUsedWord(MRJob):

    # 覆寫 steps()
    def steps(self):
        return [
          # 定義 MRStep 1
          MRStep(mapper=self.mapper_get_words,  # 指定此 step 的 mapper 為 mapper_get_words
                 combiner=self.combiner_count_words,# 指定此 step 的 combiner 為 combiner_count_words
                 reducer=self.reducer_count_words), # 指定此 step 的 reducer 為 reducer_count_words
          # 定義 MRStep 2
          MRStep(reducer=self.reducer_find_max_word)
        ]

    def mapper_get_words(self, _, line):
        # yield each word in the line
        for word in WORD_RE.findall(line):
            yield (word.lower(), 1)

    def combiner_count_words(self, word, counts):
        # optimization: sum the words we've seen so far
        yield (word, sum(counts))

    def reducer_count_words(self, word, counts):
        # send all (num_occurrences, word) pairs to the same reducer.
        # num_occurrences is so we can easily use Python's max() function.
        yield None, (sum(counts), word)

    # discard the key; it is just None
    def reducer_find_max_word(self, _, word_count_pairs):
        # each item of word_count_pairs is (count, word),
        # so yielding one results in key=counts, value=word
        yield max(word_count_pairs)


if __name__ == '__main__':
    MRMostUsedWord.run()
 
over 5 years ago

generator function 是在一個 function 中使用了 yield 這個關鍵字來回傳函數結果
但與一般 function 不同的在於,yield 回傳以後,不會就結束 function,而是暫停函數的處理狀態
直到你呼叫 .next() 這個 function,就會再次執行 function

yield = return + pause

例如我們可以這樣用:

def foo(n):
    for i in range(1, n):
        yield i

我們可以這樣用這個 function:

y = foo(10)
y.next()

此時,會回傳 1,接著我們可以再 y.next() 一次,會得到 2,一直到 y.next() 回傳 10 以後,function 才算結束執行

這種用法可以用來優化 iterable function
以下方程式碼來說,要取得小於 n 的所有數列
我們建立了一個 list 來存放結果,並且逐一將符合小於 n 的數加入到 list 中
最後才一次回傳這個 list

# Build and return a list
def firstn(n):
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

def mysum(iterable_object):
        sum = 0
        for i in iterable_object:
        sum += i
    return sum

sum_of_first_n = mysum(firstn(1000000))

這樣的運作方式需要把一整個 list 存在記憶體中
如果項目太多,會導致記憶體浪費(太多被佔用的空間無法釋放給其他行程使用)或是所需記憶體不足的情況

generator 讓我們可以的 function 可以不用一次取得所有的 list 來累加
而可以取得一個就加一次

# a generator that yields items instead of returning a list
def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

def mysum(iterable_object):
    sum = 0
    for i in iterable_object:           # 每次執行至此,就會 yield 一個新值
        sum += i
    return sum

sum_of_first_n = mysum(firstn(1000000))
 
over 5 years ago

我是下載 ADT Bundle 版本的 Eclipse
我想要安裝 Maven Plugin
於是我找到了 m2e (maven to eclipse) 的安裝網址:http://download.eclipse.org/technology/m2e/releases/
到了 Eclipse 的 Help/Install New Software 的地方,將網址填入 Work with 後按下 Enter
就可以找到 m2e 的安裝套件

但是就在 next 之後,Eclipse 去檢查 dependency 發現有個沒有安裝:

Missing requirement: Maven Integration for Eclipse 1.5.0.20140606-0033 (org.eclipse.m2e.core 1.5.0.20140606-0033) requires 'bundle com.google.guava [14.0.1,16.0.0)' but it could not be found

解決方法,先在 Install New Software 的 Work with 輸入:http://download.eclipse.org/releases/luna/
按確定後將把 luna 加入 Available Sites
找到套件就好,不需要安裝,接著就可以直接在 Work with 那邊輸入 m2e 找到剛剛加入 Available Sites 的 m2e 網址
就可以安裝了!

 
almost 6 years ago
  1. 準備兩個檔案,分別是 node.csv 和 edge.csv,其中 node.csv 長這樣


    請在第一行加上 label,id,label 可以視為 user name,id 則是 user id
    然後edge.csv長這樣

    一樣在第一行加上 source,target,type,這是為了符合 Gephi 載入格式
    其中 source 與 target 對應到 node.csv 的 id
    type 有兩種,分別是 Directed (預設) 和 Undirected

  2. 以 New Project 開啟 Gephi

  3. 切換到 『Data Laboratory』,選擇『Import Spreadsheet』

  4. 先選擇要 node.csv,並以『Node table』載入
    (編碼自己注意,中國大陸簡體編碼可能為GBK,台灣繁體編碼可能為Big5)


    可以看到下方 Preview 將 label 和 id 作為 title

  5. 下一步以後


    直接按下『完成』

  6. 載入 node.csv 的 Nodes 結果

  7. 在接著載入 edge.csv,注意要切換成載入為『Edge table』

  8. 下一步


    這裡可以看到有說 Source 和 Target 都需要是 id of node,所以你要是填寫成 label 的話,就會因為 missing node,所以會自動 create 在 node table 中

  9. 沒問題就按下完成


    注意到最右邊那一欄的 Weight,第二個是 2,是因為我們在 edge.csv 中,有兩個 1,5,Undirected,所以 Gephi 自動幫我們加成 weight 為 2,這個可以用在兩個人共同對多少個不同的第三對象有關係,例如以下關係:
    A 和 B 都喜歡吃 apple
    A 和 C 都喜歡吃 apple
    A 和 C 都喜歡吃 banana
    則在編制 edge.csv 時,就會寫成:
    A,B,Undirected
    A,C,Undirected
    A,C,Undirected

  10. 接著就可以切換到 Overview 來看關係圖,可以看到 a (id=1) 和 i (id=5) 的線比較粗,就是因為們的權重是 2

(Thanks for advise from Mr. Shiug-Feng Shih @ IM Lab NCCU-CS, Taiwan)

 
almost 6 years ago

因為台灣中研院的中文斷詞工具CKIP好像從 2012 年以後就沒再更新,而我申請介接的帳號一直收不到信,所以嘗試使用了之前偶然得知中國大陸中科院的漢語分詞工具 ICTCLAS,不過這個網址的版本最後更新也只到2011年,而且在線演示一直沒辦法呈現結果,最後進一步搜尋到 张华平 博士于 2014 年的版本(好像從2013年開始維護):ICTCLAS NLPIR

2014/06/09 更新:就在我發完以後,過了兩天就突然無法啟動,看了 error log,寫說是『Not valid license or your license expired! Please feel free to contact pipy_zhang@msn.com!』,上網查了論壇討論,似乎這個新版本有三個月的使用期限,而六月出正式這個時候....

  1. http://www.bigdatabbs.com/forum.php?mod=viewthread&tid=5309
  2. http://www.bigdatabbs.com/forum.php?mod=viewthread&tid=5226

可以直接按首頁動畫其中一個的『点击下载』获得一整个文件包,大小大約是 50.7 MB,在邊等待下載的同時,就先來玩一下『在线演示』(基于对该系统开发者的尊重....还有我懒得切换繁简中文输入-微软怎么没有快速切换呢?-所以以下直接以简体介绍,如有错误字词,还请包容与来信更正!)


这个展示画面上部份是输入文本的地方,右边提供了两组示范文字

因为最近刚听闻『屌丝』这神奇的词汇,所以就选了它的一段来试试

按下『普通分词』或『自适应分词』后,就可以得到相对应的分词结果
(我不太清楚普通分词与自适应分词的差异,因为按下两个按钮得到的结果好像差不多,有待后续研究...)


可以看到,除了是以空白键 (space) 去断开词汇以外,这个实作所采用的词性标记方式是在字词的後方加上 "/x",其中 x 是这套系统定义的一系列词汇对应的词性,中研院的斷詞系統其實有類似的標記方式,不過這些詞性就要進一步去研究了

中研院線上展示結果中『包含未知詞的斷詞標記結果』的畫面

进一步看結果,我研判中研院系統的『未知詞列表』與中科院的『新词列表』应该是指一样的事物,有趣的是,针对同一份样本,中研院的结果有几笔未知词,中科院则没有未知词,可能的原因我想有二:所收纳的字典词汇不同、我丢进中研院系统的是中科院范本的内容(即简体字内容)

中研院『未知詞列表』


中科院『新词列表』

再来我试试看汇入挡案,所以我编辑了一个挡案如下:

然后在网页中点选『选择文件』,找到对应的这个挡案名后开启:

Oops!我输入的挡案竟然是乱码,我调整了挡案的编码,从 ANSI、UTF-8、UTF-16 LE、UTF-16 BE、Unicode,都是一样的结果,但是用 Word 开启时是可以自动转换的,我观察了一下 Word 开启时的编码,后来在我所用的编辑器 Notepad++ 中找到相似的编码选项,就可以正常显示我的内容了

做法是这样的:『編碼/編碼字符集/中文/GB2312(Simplified)』,
接着才开始输入你要的内容,繁简皆可
存挡的时后会自动以此编码来存挡,如此就可以成功载入了

GB 2312 (GB0)好像就跟 Big5 一樣,是中國地區自行編篡的一套文字編碼系統,很多可以將 GB 轉 Big5 的網站,例如:http://www.j4.com.tw/big-gb/ (请原谅我对字元编码没有足够深的了解 T^T),不过我猜想语系是设定为简体中文的操作系统应该是没这个问题

载入挡案的分词结果

好了,至此,我们的文件包已经下载完了,我们可以解压缩,里面的挡案很多,有一些是给开发人员客制化自己程式需求时可以介接的函数库(类别库),ICTCLAS 这个专案目前以 C/C++/Java 为主要实作语言,但是根据文件说明,也有提供 C# 和 Python 的介接端口(API),详细的说明可以参考解压缩后的资料夹中 Readme 这个挡案

我们可以开起 Readme 来看看


很好,又是乱码,这个问题跟前面的问题是一样的,不再赘述,请自行切换成人类语言~

我这边要介绍的用法主要是在 bin 这个资料夹中的 ICTCLAS2014,进入之后,挡案列表如下:

我们点选『NLPIR_WinDemo』这个执行挡案来启动程式


恩,又是乱码,这次不是文字挡,没法儿直接修改编码,需要改系统语系,但是整个改掉很麻烦滴,使用 Windows 的捧油上网搜一下就知道解决方案是:AppLocale,详细怎么设定开启可以参考 这里

解决的语系问题,就可以知道有哪些功能选项了


(嘿嘿! 张华平 博士 的名字现身了~广告被压缩了...XD)

首先我们使用『分词』,点选以后的画面如刚启动时的上图,在不调整『分词粒度』與『词性标注集』的情况下,试着在上方栏输入字串,接着与在线演示一样,点选普通分词,即可得到分词结果,与在线演示的结果如出一轍

玩玩看打开文件,我们开启方才为了在线演示建立的测试文本

最后我们尝试『用户词典』

一样可以输入文字后做分词,但是这里的重点是在使用者自定词汇,所以我们先来看看字典在哪,事实上,字典是随意的,你可以自行建立,但是需要符合这套系统的『词汇 词性』规范,回顾资料夹中会看到有个挡案叫做 userdic,就是它了,开起来看内容:


很明显的至少『周鸿祎』为人名,不会收录在普通字典中,因此是属于用户自定义的词汇

好,让我们输入一段有这两个词汇的语句,并分词


可以看到我标红的地方,就成功地将那两个自定义词汇分出来了,词性也符合我们定义的

如果你在自己定义的字典中漏掉某些词汇,也可以直接在程式中新增,但是注意噢!这个新增的词汇并无法写回到你自定义的字典挡案中

我在下方的『用户词』中添加了『韦克』与『溫拿』,然後輸入『韦克是个研究计算机科学与语言学的研究生,他求学路成顺遂,是个温拿』,得到结果如下图


哈哈!『韦克』被成功断出来了,但是...『温拿』怎么被拆开了呢?请自行观察吧! 这可不是 Bug~
Hint: 『人』 vs 『一』

对于这套系统的研究目前至此,有些可以改进的地方:在用户新增的词汇那边不知道怎么删除词汇

最后较重要待研究的议题:词性类目有哪些?内建字典在哪?普通分词与自适应分词的差异?

 
almost 6 years ago

TaffyDB 是一個輕量級及 Open Source 的 JavaScript Database

它的專案內容很小,主要的 library 只有一個 taffy.js,所以它的操作應該都是在瀏覽器執行的程式記憶體中,沒有寫入到檔案系統

Taffy 是 ORM 實作的一種,它也有提供 extension 讓網頁程式可以介接 MySQL 等資料庫,像 mongoDB 那樣

在 HTML 中使用 TaffyDB,首先要引入 taffy.js:

<script src="https://github.com/typicaljoe/taffydb/raw/master/taffy.js"></script> 

接著我們要建立一個 TAFFY 物件來操作 taffy 資料庫:

var students = TAFFY();     

這樣就算是建立了 students 這個資料表了

接著我們就可以利用這個物件來對資料庫 CRUD,taffy 採用的是 json 的表示方式 (啊就是 JavaScript 物件啊!)

students.insert([
    { name: "Veck", gender:"male" },
  { name: "Candice", gender:"female" }
]);

這裡我們新增了兩個 entry 到 students 這個資料表物件中

最後,我們就可以呼叫一些資料庫函式來查詢:

students({name:"Candice"}).count();                # => 1

試著查詢第一筆資料:

students().first();

* student.first() is wrong usage.
會得到這樣的結果:

{ name: 'Veck',
  gender: 'male',
  ___id: 'T000002R000002',
  ___s: true }

其中 __id 和 __s 是 taffy 加入的欄位

在 node.js 中只要引入 taffy 物件就可以使用了:

var TAFFY = require("./taffydb/taffy").taffy;      // import taffy library

var students = TAFFY();     //create a TAFFY Object
 
almost 6 years ago

Reference: Scrapy Documentation

Installation: pip install scrapy

Create Project: scrapy startproject [project name]

Project Directory Tree:

tutorial/
    scrapy.cfg
    tutorial/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py

進入專案以後,我們首先要設定哪些項目是我們要抓的,因此要編輯 /tutorial/items.py:

from scrapy.item import Item, Field
    class TutorialItem(Item):
      title = Field()
      link = Field()
      desc = Field()

*這些 Field() 是在 scrapy.item 中定義的類別,在此我們宣告了三個 scrapy.item 的 Field 物件

接著就是要編寫我們的第一個 Crawler,在 /tutorial/spiders 中建立一個檔案 dmoz_spider.py(你的crawler檔):

from scrapy.spider import Spider

class DmozSpider(Spider):
  name = "dmoz"                     // 設定 crawler  的名稱
  allowed_domains = ["dmoz.org"]    // ???
  start_urls = [                    //  設定要爬的網頁 URL 列表
    "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
    "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
  ]
  
  /* 定義抓回來物件的處理函式 */
  def parse(self, response):
    filename = response.url.split("/")[-2]  // 從最後面開始擷取字元為 filename,並在遇到 '/' 時結束擷取
    with open(filename, "wb") as f:         // 建立或開啟名為 filename 的檔案,並指定為 f 
        f.write(response.body)              // 將物件 response 的 body 內容寫入檔案中

然後就可以執行這隻爬蟲程式,將上面兩個 URL 的網頁抓下來了,回到專案的根目錄,輸入:
scrapy crawl [spider_name]

然後就得到下面的執行畫面,並且在根目錄下得到 Books 和 Resources 這兩個 URL 的網頁檔案

在 tutorial/spiders 中,我們可以編寫多個 spider,但是各個 spider 的名稱 (name 屬性) 必須唯一

Note:
本文參考的 Document 版本是 0.22.2,這個版本的專案預設 import 方式與 0.23.0 有點不一樣
在 0.22.2 的 from scrapy.xxx import .... 到了 0.23.0 中是 import scrapy
所以像是:

from scrapy.item import Item

class DmozItem(Item):

都要改成:

import scrapy

class DmozItem(scrapy.Item):

另外要注意的是,from 那邊是 item,import 是 Item,大小寫不一樣!

 
almost 6 years ago

Installation:

  1. Install Python
  2. pip install ipython[notebook]
    Successfully installed ipython gnureadline jinja2 pyzmq tornado markupsafe backports.ssl-match-hostname
    Cleaning up...
    

Start Server:
ipython notebook

If there exists a *.ipynb file, it'll be listed in the directory.

Then you can click it and get it launched.

More official reference: IP[y]: Notebook

 
almost 6 years ago

今天第一次參加 Maker Faire 在台灣的活動,因為是擔任『循跡自走車』的競賽工作人員,所以將整場的比賽給看完了,看到一半,三十幾個隊伍中,因為車子未依照路線正確移動而導致失格的非常多,這也讓我對於曾經認為專利保護或商業化會讓技術研發的進步緩慢這個想法有了些新的觀點

這個比賽主要是,參賽者們必須利用自己編寫程式和接線的自走車,沿著地面上的地圖軌跡行走,一個隊伍可以跑三次,取時間最短的一次作為比賽成績,一旦脫離軌道那次就算失格

總共有 67 隊報名,但是只有 64 隊完成檢錄報到,而且比賽開始前就有兩隊棄權,比賽中也有幾對才跑了一次就棄權,所以整場下來實際上應該只有60隊左右完成比賽,平均時間在 25~40秒間,進到前八強的幾乎都是 25 秒以內的,其中最後得到冠軍的隊伍,是初賽的 2 號,才一開始就給後面隊伍壓力,跑出 18.08 的驚人成績,後面只有一個隊伍以 18.xy (x, y > 0) 的進入 18 領域,而轉彎是透過車上的感應器,感測地面上的白色標記(我覺得是光敏電阻),

令我詫異的是,很多隊伍都無法順利完成比賽,不是脫離軌道,就是跑過頭(場地是一圈的,從起點離開後只能停在終點與起點間的區域,不能再衝過起點,否則亦算失格),甚至我看到有個參賽者,三次都在跑道某個彎道的時候,又搖搖頭,表現出『唉...還是不行』的模樣,結果真的跑到終點的時候就又超過停止範圍,衝過了起點

看到這裡,我在想,如果這是一場由汽車廠商舉辦,希望找到能夠開發智慧型汽車或是無人駕駛車的徵才比賽,要能夠做到讓人工智慧或是內建程式與硬體搭配的接近完美無縫,實在是非常大的工程,但是實際運作的各種機械,是會牽涉到人生安全的,不能不作嚴格的技術與品質把關,如果只是『能夠達到目的』,就跟網站的設計不使用框架、軟體不規範設計方法等等一樣,不只是會讓後人難以接手維護,更重要的是可能讓程式存在著潛在的致命風險。

再者,前幾天剛跟一個朋友觀看 AppWork 的育成計畫發表會,有許多新創公司的商品在那兒發表,我跟朋友邊看,有時就邊討論這個商品的商業價值或市場狀況,老實說,很多項目都是我們質疑的,從工程的角度來看,很多都是很棒的作品,使用的技術或應用都不錯,但是從商業的角度來看,只會覺得那是一個小玩具,很難量產、收費或是商品化。

我一直覺得,參加那些創新競賽的參賽者,不應該在自己的作品被評審否決,或是沒有得到最後的補助或投資後,就不再繼續認同自己的理念,而放棄繼續實踐他們創新作品,這很可惜。

還有這幾年打得超火熱的專利戰,我總覺得,大公司自己的技術研發,為了公司本身的商業利益,理所當然會有營業秘密的保護措施與專利保護,但是這樣似乎違反了 DRY 的精神,許多技術都是很傑出的作品,都是人類科學發展的結晶,但是在專利保護之下,導致各家廠商或是學術界無法輕易學習,而重複投入研發或研究,如此從頭做起,就讓技術研發的進程延宕了。

然而,技術研發與做到完善品質的要求,是非常嚴苛,而且難以達到的,而要讓市場接受,又是另一個關卡,不只是品牌的問題,而是需求的問題,從這次的比賽過程,我開始認同許多智慧結晶會希望商品化或是受到專利保護的理念了,就跟學生寫程式作業,在有競爭的環境下,開放的議題就會被挑戰,那些擁護開放精神的人,在面對自己利益受到威脅的可能性這個前提下,是否真能夠沒有一點私心或心虛的大談開放呢?

 
almost 6 years ago

* 以下將 VMware、Virtual Box、Virtual PC 歸類為 Traditional Vitual Machine,簡稱 TVM

TVM 和 其他虛擬化技術 的最主要差異是主系統的資源共享
  • TVM 這是完整一個系統,這裡的系統包含了所有軟體模擬出來的硬體設備,因此他的執行效能最差,但是能夠完整模擬出一個不同於主系統的環境

  • Xen 是在 Linux 環境下最早出來的虛擬化技術,這是在硬體與 Linux 核心之間插入一個 Xen 程序,讓開機時的 bootloader 原本是要載入 Linux Kernel Code,改成 loading Xen code,而 Linux Kernel 和其他 VM 則是由 Xen 來管理

  • LXC 是緊接著出來的技術,由 IBM 創立,後來才納入 Linux Kernel),這個作法是在主系統的 Processes 中,將虛擬機的 process"es" 偽裝成主系統的 process,讓主系統的 OS 將之加入 Process Scheduling 中

會說是偽裝,是因為主系統中本身會有一套屬於作業系統的 Process,這些 Process 也會在虛擬機的系統中存在,例如 Linux 的 init (PID = 1),如果直接將虛擬機的 Process 插入主系統的排成,可能造成系統錯亂,因此 container 會將虛擬機的 process 偽裝成其他號碼的 process 後才加入排程

container 要求的虛擬機環境要跟主系統一樣,例如你在 Ubuntu 上安裝並建立一個 container,則 container 的環境就只能是 Ubuntu (因此 -t ubuntu 只是將一個已經包裝好的 ubuntu template (image) 下載下來),適合 hadoop 那樣需要相同平台的

  • KVM 是最新的虛擬化技術,這跟 TVM 的架構有點像,不同的在於,這個技術的虛擬機器上所有的 Process 都是由主系統的 Linux Kernel 管理,而 TVM 則是由虛擬系統自己管理,而且 TVM 需要用軟體模擬硬體(增加 Process),所以效能較差,KVM 則因為是跟主系統共享資源,因此不會增加硬體模擬的負擔,效能較好

從效能上來看,TVM 架構下的主系統(host)需要切割實體資源給 Virtual Machine,這些資源就被 Virtaul Machine 佔用了;而 KVM 和 LXC 因為是共享 host 的實體資源,資源的共享就跟 process 或 thread 的佔用與釋放一樣,不會有永久持有,所以硬體資源可以更充分利用,當一個機器(host 或 vm)需要較多資源時,主系統就可以協調另一機器的資源來使用

另一方面,KVM 和 LXC 因為共享主系統資源,所以不需要將檔案從主系統複製或移動到虛擬機器上,即可在虛擬機上存取或運行,如此一來對於要做快速測試的開發專案而言,可以達到快速測試或佈署的目的

在進一步拿目前效能最好的 KVM 跟 LXC 做比較,KVM 的效能略遜於 LXC,因為它是完整的一個作業系統,有自己完整同主系統的 Process,但是 LXC 是一個 container 自己就是一個 process,因此使用的資源較少,但是 LXC 相較上來說彈性較差,因為它要求與主系統相同的環境

額外補充資料:

  • KVM:Kernel-bases Virtual Machine
  • LXC:LinuX Container
  • Xen