2013年1月27日 星期日

[windows]程式更新機制自動化的考量(2)-流程概念

Omaha 流程說明

Omaha 主要由三個部份組成:

  • 一個client run time(client-side),
  • 一個 meta-installer,
  • 一個 server。

client 及 server 之間,使用 http 或 https 溝通。

當使用者希望安裝新的 google應用程式,實際上,使用者只是下載了一個 meta-installer。該檔包裝了一個client run time 安裝檔,以及使用者所選的應用程式安裝檔。

這個 meta-installer 會依情況做事:

  • 如果使用者的環境裡沒有 client run time,meta-installer 會安裝一個 client run time。(一台電腦只裝一個),
  • 如果使用者環境有一個 client run time,但不是最新的,meta-installer 會更新 client run time。

之後,meta-installer 會要求 client run time,安裝使用者要的 google應用程式。如果,google應用程式不曾被安裝過,client run time 會使用 meta-installer 裡所附帶的 google應用程式安裝檔來安裝,或依 meta-installer 所指示的位置,下載安裝檔來裝裝google應用程式。client run time 會定時跟 server 要資料,檢查安裝在電腦上的 google應用程式,如果有新版本,就會更新google應用程式。

Omaha 也提供了提升權限的功能,讓系統中權限較低的使用者也能安裝google應用程式,不需系統管理員登入來安裝。

新安裝(omaha 沒安裝在系統中)

使用者從 google 網站,下載 meta-install。當使用者啟動 meta-installer 時,它就會安裝並執行 omaha client。在 windows 平台上,像 Vista 的版本,會啟用 UAC 防護,若為所有使用者安裝應用程式(applications per-machine),執行時需要提高至系統管理員權限。接下來 omaha client 會下載應用程式並執行其安裝檔。

二次安裝(omaha 已安裝在系統中)

當 google 網站偵測到,使用者的電腦已經有安裝 omaha client,瀏覽器會利用 ActiveX 或類似物件,開始執行安裝程序,不用下載 meta-installer 的 EXE 或 MSI。

移除 omaha

當系統中,沒有應用程式需要 Omaha 時做為更新機制時,Omaha 會將自己移除。

 

以下是安裝的流程圖:

  1. 使用者下載安裝程式,AppNameSetup.exe,裡面包含了 Omaha 的安裝程式及 tag 資料
  2. 執行 AppNameSetup.exe 的過程,會安裝 Omaha client。Omaha client 讀取 tag 資料,與 Update Server 溝通,得到最新版本的 AppName 安裝檔位置。Omaha client 下載且執行其安裝檔,它本身不參與安裝過程。
  3. Omaha client 定時(預設 5 小時) 會檢查 Update Server,每一個應用程式是否有更新版的安裝檔,若有就下載並執行它。

參考:http://omaha.googlecode.com/svn/wiki/OmahaOverview.html

2013年1月21日 星期一

[hadoop]用純 python 寫 hadoop 的 map reduce 程式

好繞口的標題:)。hadoop 是 java 寫成的,但是並不是只能用 java 才能在 hadoop 裡面執行程式。但是第一個的觀念要有的是,程式的執行環境,就是在 java VM 裡面。所以,在 hadoop 文件裡介紹的 python 程式,要執行的時候,是用 jython 轉成 java jar,然後交由 hadoop framework 來執行。所以,以此類推,任何語言有能力轉成 java jar 的,應該都可以寫出程式讓 hadoop framework 執行。

回頭講 python。用慣 python 的人,應該是不太習慣 jython 的(我就是)。這兩個的確有些差別,讓我無法適應(ironpython 也是)。所以,Noll 先生就介紹了如何用純 python 在 hadoop framework 執行

他所利用的是,hadoop 的一個 Streaming API 收發串流資料的能力,且 hadoop 可存取 stdin 及 stdout 。因此把它們當做通道,把 hadoop framework 與 python 執行期結合起來。所以,接下來要注意的是,mapper.py、reducer.py 是放在本機環境,而資料是放在 hadoop 環境裡。稍不注意放錯位置就會無法執行。

準備環境:

  • hadoop 環境,照之前的文章,準備一個單機環境
  • 準備以下的程式:
    • mapper.py 放在 /home/hduser/mapper.py (記得 chmod +x)

#!/usr/bin/env python

import sys

# input comes from STDIN (standard input)
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()
    # split the line into words
    words = line.split()
    # increase counters
    for word in words:
        # write the results to STDOUT (standard output);
        # what we output here will be the input for the
        # Reduce step, i.e. the input for reducer.py
        #
        # tab-delimited; the trivial word count is 1
        print '%s\t%s' % (word, 1)

    • reducer.py 放在 /home/hduser/reducer.py (記得 chmod +x)

#!/usr/bin/env python

from operator import itemgetter
import sys

current_word = None
current_count = 0
word = None

# input comes from STDIN
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()

    # parse the input we got from mapper.py
    word, count = line.split('\t', 1)

    # convert count (currently a string) to int
    try:
        count = int(count)
    except ValueError:
        # count was not a number, so silently
        # ignore/discard this line
        continue

    # this IF-switch only works because Hadoop sorts map output
    # by key (here: word) before it is passed to the reducer
    if current_word == word:
        current_count += count
    else:
        if current_word:
            # write result to STDOUT
            print '%s\t%s' % (current_word, current_count)
        current_count = count
        current_word = word

# do not forget to output the last word if needed!
if current_word == word:
    print '%s\t%s' % (current_word, current_count)

 

Noll 先生還很好心地建議,利用一點小手法測試一下 mapper.py 及 reducer.py,免得執行完不如預期,牽拖別人。

# very basic test
hduser@ubuntu:~$ echo "foo foo quux labs foo bar quux" | /home/hduser/mapper.py
foo     1
foo     1
quux    1
labs    1
foo     1
bar     1
quux    1

hduser@ubuntu:~$ echo "foo foo quux labs foo bar quux" | /home/hduser/mapper.py | sort -k1,1 | /home/hduser/reducer.py
bar     1
foo     3
labs    1
quux    2

# using one of the ebooks as example input
# (see below on where to get the ebooks)
hduser@ubuntu:~$ cat /tmp/gutenberg/20417-8.txt | /home/hduser/mapper.py
The     1
Project 1
Gutenberg       1
EBook   1
of      1
[...]
(you get the idea)

好了,程式就這麼簡單。接下來要試著讓它跑。要準備材料。跟之前測試的一樣,到 Project Gutenberg 下載三本書,要下載文字版,UTF-8 編碼的檔案。(Plain Text UTF-8)

把文字檔放到 /tmp/gutenberg 目錄去。

然後,要把這三個檔案,放到 HDFS 去(也就是 Hadoop 環境的檔案區)

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -copyFromLocal /tmp/gutenberg /user/hduser/gutenberg
hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -ls
Found 1 items
drwxr-xr-x   - hduser supergroup          0 2010-05-08 17:40 /user/hduser/gutenberg
hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -ls /user/hduser/gutenberg
Found 3 items
-rw-r--r--   3 hduser supergroup     674566 2011-03-10 11:38 /user/hduser/gutenberg/pg20417.txt
-rw-r--r--   3 hduser supergroup    1573112 2011-03-10 11:38 /user/hduser/gutenberg/pg4300.txt
-rw-r--r--   3 hduser supergroup    1423801 2011-03-10 11:38 /user/hduser/gutenberg/pg5000.txt
hduser@ubuntu:/usr/local/hadoop$

然後,就是執行 mapreduce job 的時候,只有一行指令,當然參數很多,不要換行!

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop jar contrib/streaming/hadoop-*streaming*.jar -file /home/hduser/mapper.py    -mapper /home/hduser/mapper.py
-file /home/hduser/reducer.py   -reducer /home/hduser/reducer.py -input /user/hduser/gutenberg/* -output /user/hduser/gutenberg-output

執行完的結果會放在,執行範例如下:

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop jar contrib/streaming/hadoop-*streaming*.jar -mapper /home/hduser/mapper.py -reducer /home/hduser/reducer.py -input /user/hduser/gutenberg/* -output /user/hduser/gutenberg-output
additionalConfSpec_:null
null=@@@userJobConfProps_.get(stream.shipped.hadoopstreaming
packageJobJar: [/app/hadoop/tmp/hadoop-unjar54543/]
[] /tmp/streamjob54544.jar tmpDir=null
[...] INFO mapred.FileInputFormat: Total input paths to process : 7
[...] INFO streaming.StreamJob: getLocalDirs(): [/app/hadoop/tmp/mapred/local]
[...] INFO streaming.StreamJob: Running job: job_200803031615_0021
[...]
[...] INFO streaming.StreamJob:  map 0%  reduce 0%
[...] INFO streaming.StreamJob:  map 43%  reduce 0%
[...] INFO streaming.StreamJob:  map 86%  reduce 0%
[...] INFO streaming.StreamJob:  map 100%  reduce 0%
[...] INFO streaming.StreamJob:  map 100%  reduce 33%
[...] INFO streaming.StreamJob:  map 100%  reduce 70%
[...] INFO streaming.StreamJob:  map 100%  reduce 77%
[...] INFO streaming.StreamJob:  map 100%  reduce 100%
[...] INFO streaming.StreamJob: Job complete: job_200803031615_0021
[...] INFO streaming.StreamJob: Output: /user/hduser/gutenberg-output
hduser@ubuntu:/usr/local/hadoop$

執行完的結果在 HDFS 的 /user/hduser/gutenberg-output,用指令看一下結果的內容

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -ls /user/hduser/gutenberg-output
Found 1 items
/user/hduser/gutenberg-output/part-00000     <r 1>   903193  2007-09-21 13:00
hduser@ubuntu:/usr/local/hadoop$
hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -cat /user/hduser/gutenberg-output/part-00000
"(Lo)cra"       1
"1490   1
"1498," 1
"35"    1
"40,"   1
"A      2
"AS-IS".        2
"A_     1
"Absoluti       1
[...]
hduser@ubuntu:/usr/local/hadoop$

[windows]程式更新機制自動化的考量

現在的使用者,應該已經非常習慣程式一打開,就跳出自動更新的視窗。也有一大部份的程式,是在背景自動更新完畢,完全不打擾使用者。在一個自動化的工廠裡,當然是需要在背景自動更新完畢的流程,因為這個環境裡,沒有使用者。

google 在更新 chrome 的時候,為了要在 windows 上完成自動更新,設計了一套更新的機制,它把這個機制變成了一個開源專案,叫做 omaha。目前,在 windows 上,除了 chrome 之外,google earth 也是採用這個機制。當初,google 許多的專案在 windows 上都有自動更新的需要,然而,每個專案都自己寫了自動更新,許多程式碼都重覆寫,以致於有人就跳出來開了這個專案,讓大家都有方便、穩定的程式碼用,不用每次都自己做輪子。他們也很順手地,把 client 端的程式分享出來,讓大家都可以使用,真的是佛心來著。我認為,從這裡學習,也是獲益良多。

Omaha 的設計,考量到幾個目標:

  • 更新及安裝的系統需要在 windows 的各個不同平台可以共用。
  • 自動更新機制與產品之間沒有相依性,所以不同的產品可以使用同一套的伺服端及客戶端程式邏輯。
    • 一個自動更新伺服器,能夠接受每個不同產品的自動更新需求。不同的團隊不用各自佈署自己的伺服器。
    • 一個自動更新客戶端程式,讓所有的產品共用。避免不同的應用程式自己跑自己的更新程式。
  • 一個小的 meta-installer,它包含一個「客戶端更新程式」以及產品的安裝程式的參考。meta-installer 會知道如何安裝「客戶端更新程式」以及如何下載產品、安裝產品。
  • 當「客戶端更新程式」安裝好,可一鍵執行網路安裝。
  • 支援、控制多種版本更新,例如:不同的公開版本的釋出,beta 版釋出,開發版釋出,或是實驗版釋出。
  • 支援權限受限制的安裝環境,例如:使用者不具備管理者權限的安裝。
  • 提供共用的功能給所有的產品程式(客戶端程式),例如:程式當機報告。

參考:http://omaha.googlecode.com/svn/wiki/OmahaOverview.html

2013年1月10日 星期四

[aspx]access 資料庫壓縮

客戶家的資料庫,用得是 access,已經兩年,長得非常大,有 1G 這麼大。實在是會擔心,如果不小心壞了,那可是救都救不回來。還好,備份一個 access 的資料庫非常簡單,就把那個檔案複製一份,就解決了。甚至,還可以寫一個 aspx 網頁,來執行這個動作,讓我在任何地方,只要有網路,就可以用網頁來做備份,就算我用 iPad,iPhone,Android手機都可以。雖然是小題大作,一年不過做個兩、三次的事,但是,若能夠不讓客戶擔心的情況下,做完這些保險的事,也會有讓他們信任的感受。就算不是電腦自動化地來做,至少也是我自動地做,也算是自動化了啊!

但是,只有備份,仍然不夠,備份只解決了失效復原的第一步。接下來面臨的是舊資料越來越多,如果不刪除,檔案越來越大,查詢的時間越來越長,真的是無謂的浪費時間。所以,接下來完成了刪除舊資料的功能。但是,這又產生一個不滿足。雖然,資料刪了,查詢速度又回復以往的快速,但是,資料檔的大小,仍然維持一樣。著實想想真是不開心。

使用 office access,可以把 mdb 打開,然後在「主功能(左上的視窗)」->「管理」->「壓縮及修復資料庫」這個功能,把資料庫壓縮。

image

這麼做,就需要人工來做。並且要準備一台裝有 MS access 的電腦才行。

當然這工作,用指令也行,但還是要在裝有 MS access 的電腦執行指令,然後用工作排程器執行(參考)。

C:\Program Files (x86)\Microsoft Office\Office12\MSACCESS.EXE c:\Northwind.mdb /compact

這種若要想用網頁執行,則會因為某種限制而無法執行。猜測主要是因為 MSACCESS.exe 是桌面程式。執行後就卡住,沒有把工作做完。這應該只是設定的問題,因為在開發環境是可以正常使用。但是在 IIS 的環境,就是卡住。有人提醒 service 程式也許不能與桌面互動而導致問題(參考)。我試過這方法也是失敗。
我們以前嘗試過,如果是 console 程式,是可以的執行成功的。

為了堅持要用網頁執行,尋找許久,在微軟的開發環境裡,都會安裝一個 dao。它只是一個 dll。只要把 dao.dll 複製一份在 bin 裡面,然後引用它。只要用兩行就搞定了。



dao.DBEngine dbe = new DBEngine();
dbe.CompactDatabase(target_uncompact, target_compact, null, null, null);


如果,老闆問,為什麼兩行程式要寫快兩個星期,那……,要請曹操的好朋友來回答了。


註:網路上也有用 Jet 引擎來處理的,我累了,所以有空的人可以試試。參考

2013年1月2日 星期三

[hadoop]Hadoop 小象安裝測試在 Ubuntu (2)

前言

續前篇 http://codebeta.blogspot.tw/2012/12/hadoophadoop-ubuntu.html,接下來是試跑 wordcount 程式,驗證系統有安裝好。

下載所需資料

要執行 wordcount 程式,要先有資料才行。Noll 好心已經給了三個連結的文件讓你下載。

每一個電子書,請下載 UTF-8 的文字檔,放在你想要的位置。這裡選的是 /tmp/gutenberg

hduser@ubuntu:~$ ls -l /tmp/gutenberg/
total 3592
-rw-r--r-- 1 hduser hadoop  674566 Dec 23 07:37 pg20417.txt
-rw-r--r-- 1 hduser hadoop 1573150 Dec 23 07:39 pg4300.txt
-rw-r--r-- 1 hduser hadoop 1423801 Dec 23 07:38 pg5000.txt
hduser@ubuntu:~$

啟動 hadoop 叢集

hduser@ubuntu:~$ /usr/local/hadoop/bin/start-all.sh

複製資料到 HDFS (Hadoop 的檔案系統)

使用 hadoop 的指令,把檔案從真實檔案系統,送進 HDFS。

hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop dfs -copyFromLocal /tmp/gutenberg /user/hduser/gutenberg
hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop dfs -ls /user/hduser
Found 1 items
drwxr-xr-x   - hduser supergroup          0 2012-12-25 00:23 /user/hduser/gutenberg
hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop dfs -ls /user/hduser/gutenberg
Found 4 items
drwxr-xr-x   - hduser supergroup          0 2012-12-25 00:23 /user/hduser/gutenberg/gutenberg
-rw-r--r--   1 hduser supergroup     674566 2012-12-25 00:21 /user/hduser/gutenberg/pg20417.txt
-rw-r--r--   1 hduser supergroup    1573150 2012-12-25 00:21 /user/hduser/gutenberg/pg4300.txt
-rw-r--r--   1 hduser supergroup    1423801 2012-12-25 00:21 /user/hduser/gutenberg/pg5000.txt
hduser@ubuntu:~$

執行 MapReduce 程式

請注意執行的路徑:要先 cd 到 /usr/local/hadoop。

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop jar hadoop*examples*.jar wordcount /user/hduser/gutenberg/* /user/hduser/gutenberg-output

[註1]若在別的工作路徑,會發生:

hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop jar hadoop*examples*.jar wordcount /user/hduser/gutenberg /user/hduser/gutenberg-output
Exception in thread "main" java.io.IOException: Error opening job jar: hadoop*examples*.jar

[註2]在指令加 * 的理由在 http://stackoverflow.com/questions/6891600/how-to-get-hadoop-wordcount-example-working

[註3]如果已經執行過,想再執行一次,會因為 output 目錄已經存在而失敗。此時可以執行刪目錄的指令:

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -rmr /user/hduser/gutenberg-output
Deleted hdfs://localhost:54310/user/hduser/gutenberg-output
hduser@ubuntu:/usr/local/hadoop$

執行結果如下:

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop jar hadoop*examples*.jar wordcount /user/hduser/gutenberg/* /user/hduser/gutenberg-output
12/12/25 00:52:27 INFO input.FileInputFormat: Total input paths to process : 6
12/12/25 00:52:27 INFO util.NativeCodeLoader: Loaded the native-hadoop library
12/12/25 00:52:27 WARN snappy.LoadSnappy: Snappy native library not loaded
12/12/25 00:52:28 INFO mapred.JobClient: Running job: job_201212250016_0007
12/12/25 00:52:29 INFO mapred.JobClient:  map 0% reduce 0%
12/12/25 00:52:44 INFO mapred.JobClient:  map 16% reduce 0%
12/12/25 00:52:47 INFO mapred.JobClient:  map 33% reduce 0%
12/12/25 00:52:53 INFO mapred.JobClient:  map 50% reduce 0%
12/12/25 00:52:56 INFO mapred.JobClient:  map 66% reduce 11%
12/12/25 00:52:59 INFO mapred.JobClient:  map 83% reduce 11%
12/12/25 00:53:01 INFO mapred.JobClient:  map 100% reduce 11%
12/12/25 00:53:04 INFO mapred.JobClient:  map 100% reduce 22%
12/12/25 00:53:10 INFO mapred.JobClient:  map 100% reduce 100%
12/12/25 00:53:15 INFO mapred.JobClient: Job complete: job_201212250016_0007
12/12/25 00:53:15 INFO mapred.JobClient: Counters: 29
12/12/25 00:53:15 INFO mapred.JobClient:   Job Counters
12/12/25 00:53:15 INFO mapred.JobClient:     Launched reduce tasks=1
12/12/25 00:53:15 INFO mapred.JobClient:     SLOTS_MILLIS_MAPS=45175
12/12/25 00:53:15 INFO mapred.JobClient:     Total time spent by all reduces waiting after reserving slots (ms)=0
12/12/25 00:53:15 INFO mapred.JobClient:     Total time spent by all maps waiting after reserving slots (ms)=0
12/12/25 00:53:15 INFO mapred.JobClient:     Launched map tasks=6
12/12/25 00:53:15 INFO mapred.JobClient:     Data-local map tasks=6
12/12/25 00:53:15 INFO mapred.JobClient:     SLOTS_MILLIS_REDUCES=25718
12/12/25 00:53:15 INFO mapred.JobClient:   File Output Format Counters
12/12/25 00:53:15 INFO mapred.JobClient:     Bytes Written=886978
12/12/25 00:53:15 INFO mapred.JobClient:   FileSystemCounters
12/12/25 00:53:15 INFO mapred.JobClient:     FILE_BYTES_READ=4429692
12/12/25 00:53:15 INFO mapred.JobClient:     HDFS_BYTES_READ=7343786
12/12/25 00:53:15 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=7529522
12/12/25 00:53:15 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=886978
12/12/25 00:53:15 INFO mapred.JobClient:   File Input Format Counters
12/12/25 00:53:15 INFO mapred.JobClient:     Bytes Read=7343034
12/12/25 00:53:15 INFO mapred.JobClient:   Map-Reduce Framework
12/12/25 00:53:15 INFO mapred.JobClient:     Map output materialized bytes=2948682
12/12/25 00:53:15 INFO mapred.JobClient:     Map input records=155864
12/12/25 00:53:15 INFO mapred.JobClient:     Reduce shuffle bytes=2681669
12/12/25 00:53:15 INFO mapred.JobClient:     Spilled Records=511924
12/12/25 00:53:15 INFO mapred.JobClient:     Map output bytes=12152190
12/12/25 00:53:15 INFO mapred.JobClient:     Total committed heap usage (bytes)=978935808
12/12/25 00:53:15 INFO mapred.JobClient:     CPU time spent (ms)=7070
12/12/25 00:53:15 INFO mapred.JobClient:     Combine input records=1258344
12/12/25 00:53:15 INFO mapred.JobClient:     SPLIT_RAW_BYTES=752
12/12/25 00:53:15 INFO mapred.JobClient:     Reduce input records=204644
12/12/25 00:53:15 INFO mapred.JobClient:     Reduce input groups=82335
12/12/25 00:53:15 INFO mapred.JobClient:     Combine output records=204644
12/12/25 00:53:15 INFO mapred.JobClient:     Physical memory (bytes) snapshot=1124028416
12/12/25 00:53:15 INFO mapred.JobClient:     Reduce output records=82335
12/12/25 00:53:15 INFO mapred.JobClient:     Virtual memory (bytes) snapshot=2677747712
12/12/25 00:53:15 INFO mapred.JobClient:     Map output records=1258344

檢查輸出結果,使用以下指令:

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -ls /user/hduser/gutenberg-output
Found 3 items
-rw-r--r--   1 hduser supergroup          0 2012-12-25 00:53 /user/hduser/gutenberg-output/_SUCCESS
drwxr-xr-x   - hduser supergroup          0 2012-12-25 00:52 /user/hduser/gutenberg-output/_logs
-rw-r--r--   1 hduser supergroup     886978 2012-12-25 00:53 /user/hduser/gutenberg-output/part-r-00000
hduser@ubuntu:/usr/local/hadoop$

把結果的內容顯示出來的指令:

hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -cat /user/hduser/gutenberg-output/part-r-00000

把結果搬回真實檔案系統,然後看內容的指令:

hduser@ubuntu:/usr/local/hadoop$ mkdir /tmp/gutenberg-output
hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -getmerge /user/hduser/gutenberg-output /tmp/gutenberg-output
12/12/25 01:03:58 INFO util.NativeCodeLoader: Loaded the native-hadoop library
hduser@ubuntu:/usr/local/hadoop$ head /tmp/gutenberg-output/gutenberg-output
"(Lo)cra"    2
"1490    2
"1498,"    2
"35"    2
"40,"    2
"A    4
"AS-IS".    2
"A_    2
"Absoluti    2
"Alack!    2
hduser@ubuntu:/usr/local/hadoop$

Hadoop Web Interface

目前版本有提供 web 介面,只能看狀態,不能改。

  • http://localhost:50070/ – 可以看 NameNode 的狀態

  • http://localhost:50030/ – 可以看 JobTracker 的狀態

  • http://localhost:50060/ – 可以看 TaskTracker 的狀態

結語

到這裡,單電腦叢集的 Hadoop 系統,算是非常簡單的介紹完畢。可以從這裡的操作知道,若是需要一個可用的 Hadoop,要經過:(1)操作系統的安裝、(2)java系統的安裝、(3)hadoop系統的安裝、(4)以上三個系統的設定。要執行程式,則要:(1)程式資料的準備、(2)將資料搬進至Hadoop檔案系統、(3)撰寫執行 MapReduce 程式、(4)將資料搬出Hadoop檔案系統。這些工作都不是簡單買個套裝程式回來,拖一拖、拉一拉,或是按一按鈕就可以解決的事情。而且,這個單叢集系統,還不具備備援、分散式計算的功能,都還需要進一步的規劃及調整。

從這個最簡單的系統,接下來則會因著各人的工作項目而有不同的發展方向:

  • 系統工程師,要開始研究 hadoop 設定,使之成為分散式系統。並且建立備援機制。研究 hadoop 管理工具
  • 軟體工程師,依據需求,安裝 HBASE 或 Cassandra 資料庫,或者利用檔案來存放資料。研究 MapReduce 程式風格。建立自用的介面程式與資料系統、檔案系統做存取。

2012年12月24日 星期一

[hadoop]Hadoop 小象安裝測試在 Ubuntu

小象要開始跑

在了解大概 hadoop 能做什麼之後,就來安裝試試吧。Michael G. Noll 寫了幾份非常好的教學。 這裡就按照他的教學,一步步重做一遍。就從他的 Running Hadoop On Ubuntu Linux (Single-Node Cluster) 開始讓小象跑。

http://www.michael-noll.com/tutorials/running-hadoop-on-ubuntu-linux-single-node-cluster/

而我這篇是讓我自己這個新手能夠不忘記我是怎麼安裝的筆記。

安裝 ubuntu 在 vmware 裡,完成 vmware-tool 安裝。

這一步是原來教學沒有的步驟。為了大家可以在公司、或自家的電腦試用,所以用 vmware 裝一個虛擬電腦。首先要注意,vmware-tool 的安裝跟 vmware 版本有關。vmware-tool 最重要的是可以讓 host 系統 及 guest 系統用「拖拉」、「複製貼上」的方式,交換檔案及文字。我使用的版本是 vmware 8,在裝好 ubuntu 12.04 之後,vmware-tool 可使用隨附的 8.8.0 版安裝。(vmware 7 可裝 ubuntu 11.04 配合 6.0.2。)在確認完 vmware 版本之後,就不用擔心之後會有問題了。

http://www.ubuntu.com/download/desktop 下載 12.04 LTS,下載 iso 檔。選擇 desktop 是因為有桌面可用,比較方便。

將 ubuntu 安裝完畢,先加入一個使用者 hduser,這是之後專門執行 hadoop 程式的使用者。

$ sudo addgroup hadoop

$ sudo adduser --ingroup hadoop hduser

hduser 要加入 sudoer 名單中,才能安裝 vmware-tool。

先用安裝者的帳號執行

$ sudo visudo

再把 hduser (ALL:ALL)=ALL 加在 root (ALL:ALL)=ALL 底下。

或把 hduser 加到 admin 的 group 裡面。(首先要確定有 admin 的 group。可參考)

$ sudo usermod -g admin hduser

然後切換使用者為 hduser。

接下來,在 vmware 的「VM」選單,按下「install VMware tool」,在虛擬電腦裡,會 mount 一個檔案。點兩下,會使用 archie manager 開啟檔案,把裡面的目錄「vmware-tools-distrib」拖到桌面上。

啟動 terminal,切換到 ~/Desktop/vmware-tools-distrib,執行

$ sudo ./vmware-install.pl

中間經過一連串的問題,都是按 enter 通過。如果有因為任何的錯誤而停下,都是因為 vmware-tools 的版本與 ubuntu 版本不合導致。我花了很多冤枉時間,才知道是版本問題。vmware 出 vmware-tools 程式一定是可以用才釋出,把版本弄對就不用白花時間。

安裝完畢,重開機一次。

設定 SSH

因為 hadoop 使用 ssh 管理它的 node,接下來要設定 ssh。

首先,產生 ssh key。

$ su - hduser # 換成 root 權限
hduser@ubuntu:~$ ssh-keygen -t rsa -P ""
Generating public/private rsa key pair.
Enter file in which to save the key (/home/hduser/.ssh/id_rsa):
Created directory '/home/hduser/.ssh'.
Your identification has been saved in /home/hduser/.ssh/id_rsa.
Your public key has been saved in /home/hduser/.ssh/id_rsa.pub.
The key fingerprint is:
db:35:f4:ae:e3:79:48:d3:95:fa:2d:22:a8:43:5c:dd hduser@ubuntu
The key's randomart image is:
...
hduser@ubuntu:~$

第二行是產生一個不用密碼的 RSA key pari。這樣就不用 hadoop 與 node 溝通時,都要人去打密碼。

再來,把新產生的 key 放到已認證的 key 中。

hduser@ubuntu:~$ cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys

因為 desktop 版沒有 ssh server,因此,要加裝 openssh-server



hduser@ubuntu:~$ sudo apt-get install openssh-server


測試一下能不能連上 ssh server。因為這版的 server 預設使用 ECDSA 所以,ssh 的指令要強迫使用 rsa。



hduser@ubuntu:~$ ssh -oHostKeyAlgorithms='ssh-rsa' localhost

The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is a3:99:7f:2b:8e:92:34:20:59:2f:2d:10:94:c9:60:74.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
Welcome to Ubuntu 12.10 (GNU/Linux 3.5.0-17-generic i686)

* Documentation:  https://help.ubuntu.com/

222 packages can be updated.
52 updates are security updates.

Last login: Mon Dec 24 00:56:30 2012 from localhost
hduser@ubuntu:~$ exit
logout
Connection to localhost closed.
hduser@ubuntu:~$


另一個解決辦法是產生 ECDSA,並使用 ECDSA。


hduser@ubuntu:~$ ssh-keygen -t ecdsa -P ""
Generating public/private ecdsa key pair.
Enter file in which to save the key (/home/hduser/.ssh/id_ecdsa):
Your identification has been saved in /home/hduser/.ssh/id_ecdsa.
Your public key has been saved in /home/hduser/.ssh/id_ecdsa.pub.
The key fingerprint is:
27:64:63:de:16:4b:97:f4:58:96:11:46:6d:a2:24:7e hduser@ubuntu
The key's randomart image is:


因為後續的過程中,按照這個教學的話,hadoop 會自然的使用 ECDSA,所以,還是要用 ECDSA 的方式把 key 加到 .ssh/authorized_keys 裡面。


hduser@ubuntu:~$ cat $HOME/.ssh/id_ecdsa.pub >> $HOME/.ssh/authorized_keys


Noll 先生說,如果有遇到問題,要檢查一下在 /etc/ssh/sshd_config 裡:


  • PubkeyAuthentication 應該是 yes。
  • AllowUsers 如果有打開,則要把 hduser 加進去。
  • 如果 ssh server 的設定有異動,要強迫 ssh server 重載設定。 $ sudo /etc/init.d/ssh reload

安裝 java


java 至少要用到 ,我們可以使用指令來檢查 java 版本



hduser@ubuntu:~$ java -version
The program 'java' can be found in the following packages:
* default-jre
* gcj-4.6-jre-headless
* gcj-4.7-jre-headless
* openjdk-7-jre-headless
* openjdk-6-jre-headless
Try: sudo apt-get install <selected package>


新安裝的 ubuntu 12.04 desktop LTS 沒有裝 java runtime。要自己安裝。



hduser@ubuntu:~$ sudo apt-get install default-jre



hduser@ubuntu:~$ java -version
java version "1.7.0_09"
OpenJDK Runtime Environment (IcedTea7 2.3.3) (7u9-2.3.3-0ubuntu1~12.10.1)
OpenJDK Client VM (build 23.2-b09, mixed mode, sharing)
hduser@ubuntu:~$


 


安裝小象


從 Apache 下載 hadoop,目前穩定版是 1.0.4,到 http://www.apache.org/dyn/closer.cgi/hadoop/common/ 它會給你最近的 mirror 站點。下載 1.0.4 版的 hadoop-1.0.4.tar.gz。

 image

使用 firefox 下載,預設會放到 ~/Downloads 裡面。點兩下 hadoop-1.0.4.tar.gz,archive manager 會打開該壓縮檔,把裡面的目錄 hadoop-1.0.4 拉到桌面,改名為 hadoop,再移到 /usr/local 裡面去。使用指令


hduser@ubuntu:~$ sudo mv Desktop/hadoop/ /usr/local/
[sudo] password for hduser:
hduser@ubuntu:~$ ls -l /usr/local
total 36
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 bin
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 etc
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 games
drwxr-xr-x 14 hduser hadoop 4096 Dec 24 01:09 hadoop
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 include
drwxr-xr-x  4 root   root   4096 Oct 17 07:59 lib
lrwxrwxrwx  1 root   root      9 Dec 13 10:10 man -> share/man
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 sbin
drwxr-xr-x  7 root   root   4096 Oct 17 08:00 share
drwxr-xr-x  2 root   root   4096 Oct 17 07:56 src


接下來要設定 .bashrc。(ubuntu 預設是用 bash。)使用指令開啟 .bashrc 來改。


hduser@ubuntu:~$ gedit .bashrc


在檔案的最後加進以下的設定。(原文中的 HADOOP_HOME 的設定已經要改用 HADOOP_PREFIX。)


################# for hadoop settings ##############
# Set Hadoop-related environment variables
export HADOOP_PREFIX=/usr/local/hadoop

# Set JAVA_HOME (we will also configure JAVA_HOME directly for Hadoop later on)
export JAVA_HOME=/usr/lib/jvm/default-java

# Some convenient aliases and functions for running Hadoop-related commands
unalias fs &> /dev/null
alias fs="hadoop fs"
unalias hls &> /dev/null
alias hls="fs -ls"

# If you have LZO compression enabled in your Hadoop cluster and
# compress job outputs with LZOP (not covered in this tutorial):
# Conveniently inspect an LZOP compressed file from the command
# line; run via:
#
# $ lzohead /hdfs/path/to/lzop/compressed/file.lzo
#
# Requires installed 'lzop' command.
#
lzohead () {
    hadoop fs -cat $1 | lzop -dc | head -1000 | less
}

# Add Hadoop bin/ directory to PATH
export PATH=$PATH:$HADOOP_PREFIX/bin

 


其他使用者要用 hadoop 的,也要更新這個 ~/.bashrc


設定 hadoop -- 1


第一個要處理的是 hadoop-env.sh


hduser@ubuntu:~$ gedit /usr/local/hadoop/conf/hadoop-env.sh


把裡面的


# export JAVA_HOME=/usr/lib/j2sdk1.5-sun


的底下,加上


export JAVA_HOME=/usr/lib/jvm/default-java


再來要把 ipv6 關掉。檔案的最後加上

export HADOOP_OPTS=-Djava.net.preferIPv4Stack=true

 

設定 hadoop -- 2


接下來是 core-site.xml,這是設定 hadoop 要在真實檔案系統的位置。因此,先建立一個目錄給 hadoop 使用。


hduser@ubuntu:~$ sudo mkdir -p /app/hadoop/tmp
[sudo] password for hduser:
hduser@ubuntu:~$ ls -l /app/hadoop/
total 4
drwxr-xr-x 2 root root 4096 Dec 24 02:02 tmp
hduser@ubuntu:~$ sudo chown hduser:hadoop /app/hadoop/tmp
hduser@ubuntu:~$ ls -l /app/hadoop/
total 4
drwxr-xr-x 2 hduser hadoop 4096 Dec 24 02:02 tmp
hduser@ubuntu:~$ sudo chmod 750 /app/hadoop/tmp
hduser@ubuntu:~$ ls -l /app/hadoop/
total 4
drwxr-x--- 2 hduser hadoop 4096 Dec 24 02:02 tmp
hduser@ubuntu:~$


把下列的文字,加到 /usr/local/hadoop/conf/core-site.xml 的 <configuration> ... </configuration> 中間:

<!-- In: conf/core-site.xml -->
<property>
<name>hadoop.tmp.dir</name>
<value>/app/hadoop/tmp</value>
<description>A base for other temporary directories.</description>
</property>

<property>
<name>fs.default.name</name>
<value>hdfs://localhost:54310</value>
<description>The name of the default file system. A URI whose
scheme and authority determine the FileSystem implementation. The
uri's scheme determines the config property (fs.SCHEME.impl) naming
the FileSystem implementation class. The uri's authority is used to
determine the host, port, etc. for a filesystem.</description>
</property>

把下列的文字,加到 /usr/local/hadoop/conf/mapred-site.xml 的 <configuration> ... </configuration> 中間:

<!-- In: conf/mapred-site.xml -->
<property>
<name>mapred.job.tracker</name>
<value>localhost:54311</value>
<description>The host and port that the MapReduce job tracker runs
at. If "local", then jobs are run in-process as a single map
and reduce task.
</description>
</property>

把下列的文字,加到 /usr/local/hadoop/conf/hdfs-site.xml 的 <configuration> ... </configuration> 中間:

<!-- In: conf/hdfs-site.xml -->
<property>
<name>dfs.replication</name>
<value>1</value>
<description>Default block replication.
The actual number of replications can be specified when the file is created.
The default is used if replication is not specified in create time.
</description>
</property>

 


如果要對設定檔多了解,可以到以下連結查看:


http://wiki.apache.org/hadoop/GettingStartedWithHadoop


http://hadoop.apache.org/core/docs/current/api/overview-summary.html


格式化 HDFS 的檔案系統


Noll 先生在這非常強調,不要對正在使用中的系統做格式化的動作。該系統資料會消失。

我們這個新系統要啟用,則必須先格式化檔案系統。



hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop namenode -format


結果如下:


hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoop namenode -format
12/12/24 02:14:23 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:   host = ubuntu/127.0.1.1
STARTUP_MSG:   args = [-format]
STARTUP_MSG:   version = 1.0.4
STARTUP_MSG:   build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.0 -r 1393290; compiled by 'hortonfo' on Wed Oct  3 05:13:58 UTC 2012
************************************************************/
12/12/24 02:14:23 INFO util.GSet: VM type       = 32-bit
12/12/24 02:14:23 INFO util.GSet: 2% max memory = 19.33375 MB
12/12/24 02:14:23 INFO util.GSet: capacity      = 2^22 = 4194304 entries
12/12/24 02:14:23 INFO util.GSet: recommended=4194304, actual=4194304
12/12/24 02:14:24 INFO namenode.FSNamesystem: fsOwner=hduser
12/12/24 02:14:24 INFO namenode.FSNamesystem: supergroup=supergroup
12/12/24 02:14:24 INFO namenode.FSNamesystem: isPermissionEnabled=true
12/12/24 02:14:24 INFO namenode.FSNamesystem: dfs.block.invalidate.limit=100
12/12/24 02:14:24 INFO namenode.FSNamesystem: isAccessTokenEnabled=false accessKeyUpdateInterval=0 min(s), accessTokenLifetime=0 min(s)
12/12/24 02:14:24 INFO namenode.NameNode: Caching file names occuring more than 10 times
12/12/24 02:14:25 INFO common.Storage: Image file of size 112 saved in 0 seconds.
12/12/24 02:14:25 INFO common.Storage: Storage directory /app/hadoop/tmp/dfs/name has been successfully formatted.
12/12/24 02:14:25 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at ubuntu/127.0.1.1
************************************************************/
hduser@ubuntu:~$


啟動 cluster


到了要啟動系統的時候,使用指令:

hduser@ubuntu:~$ /usr/local/hadoop/bin/start-all.sh
看到以下的 log 就代表成功了。


hduser@ubuntu:~$ /usr/local/hadoop/bin/start-all.sh
starting namenode, logging to /usr/local/hadoop/libexec/../logs/hadoop-hduser-namenode-ubuntu.out
localhost: starting datanode, logging to /usr/local/hadoop/libexec/../logs/hadoop-hduser-datanode-ubuntu.out
localhost: starting secondarynamenode, logging to /usr/local/hadoop/libexec/../logs/hadoop-hduser-secondarynamenode-ubuntu.out
starting jobtracker, logging to /usr/local/hadoop/libexec/../logs/hadoop-hduser-jobtracker-ubuntu.out
localhost: starting tasktracker, logging to /usr/local/hadoop/libexec/../logs/hadoop-hduser-tasktracker-ubuntu.out
hduser@ubuntu:~$


 

利用 jps 來看是否已啟動


Noll 先生說可以使用 jps 來看啟動是否成功。但新裝的 ubuntu 沒有這東西。



The program 'jps' can be found in the following packages:
* openjdk-6-jdk
* openjdk-7-jdk
Ask your administrator to install one of them


於是,安裝 openjdk-7-jdk



sudo apt-get install openjdk-7-jdk




再試一次



hduser@ubuntu:~$ jps
7516 TaskTracker
7287 SecondaryNameNode
7839 DataNode
12038 Jps
6491 NameNode
6901 JobTracker
hduser@ubuntu:~$

 


也可以用 netstat 來看監聽的 port 是否有開。



hduser@ubuntu:~$ sudo netstat -plten | grep java


停止 single-node cluster

使用這個指令:


hduser@ubuntu:~$ /usr/local/hadoop/bin/stop-all.sh


會看到:



hduser@ubuntu:~$ /usr/local/hadoop/bin/stop-all.sh
stopping jobtracker
localhost: Agent admitted failure to sign using the key.
localhost: stopping tasktracker
stopping namenode
localhost: Agent admitted failure to sign using the key.
localhost: stopping datanode
localhost: Agent admitted failure to sign using the key.
localhost: no secondarynamenode to stop
hduser@ubuntu:~$


原篇照我的方式走,真的太長。因此下一篇來驗證,這個系統真的可以用。

2012年12月20日 星期四

[Android]Market 進不去

送修的 HTC Desire 回來了,要開始安裝 App,於是點了 Market 按鈕,居然發生 404

訊息顯示:

The requested URL /intl/%locale%/mobile/android/market-tos.html was not found on this server. That’s all we know.

嗯。你不知道,我也不知道,然後呢?

花了一、兩個小時爬 google。找到以下連結。

http://forum.xda-developers.com/showthread.php?t=767992

做法很簡單,(1)先把語系切到英文。(2)按一下 Market。讓它跑過去。(3)再切回原來的語系。

好了。要怪誰呢?