2015年5月19日 星期二

透過 jq, sed, grep 從 wikipedia api 取出台灣地區鄉鎮市區列表 @ Ubuntu 14.04

靈光一想,想到撈一下台灣各地區,看到了這個:wiki 中華民國臺灣地區鄉鎮市區列表

http://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8

接著想抓個鄉鎮對應表,就想起 wiki api:

http://zh.wikipedia.org/w/api.php?action=query&titles=%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8&prop=revisions&rvprop=content&format=json

接著,再搭配 jq、sed、grep 縮一下資料量:

$ curl 'http://zh.wikipedia.org/w/api.php?action=query&titles=%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8&prop=revisions&rvprop=content&format=json' | jq  '.query.pages[].revisions[0]|to_entries[0].value' | sed 's/\\n/\n/g' | grep -P '<small>(.*)</small> \[\[(.*)\]\]' -o | sed 's/<small>\(.*\)<\/small> \[\[\(.*\)\]\]/\1\t\2/g' | sed 's/\(.*\)\t\(.*\)|\(.*\)/\1\t\3/g'

成果:

基隆市 仁愛區
基隆市 中正區
基隆市 信義區
基隆市 中山區
基隆市 安樂區
基隆市 暖暖區
基隆市 七堵區
臺北市 中正區
臺北市 大同區
臺北市 中山區
臺北市 松山區
臺北市 大安區
臺北市 萬華區
臺北市 信義區
臺北市 士林區
臺北市 北投區
臺北市 內湖區
臺北市 南港區
臺北市 文山區
新北市 板橋區
新北市 新莊區
新北市 中和區
新北市 永和區
新北市 土城區
新北市 樹林區
新北市 三峽區
新北市 鶯歌區
新北市 三重區
新北市 蘆洲區
新北市 五股區
新北市 泰山區
新北市 林口區
新北市 淡水區
新北市 金山區
新北市 八里區
新北市 萬里區
新北市 石門區
新北市 三芝區
新北市 瑞芳區
新北市 汐止區
新北市 平溪區
新北市 貢寮區
新北市 雙溪區
新北市 深坑區
新北市 石碇區
新北市 新店區
新北市 坪林區
新北市 烏來區
桃園市 桃園區
桃園市 中壢區
桃園市 平鎮區
桃園市 八德區
桃園市 楊梅區
桃園市 蘆竹區
桃園市 大溪區
桃園市 龍潭區
桃園市 龜山區
桃園市 大園區
桃園市 觀音區
桃園市 新屋區
桃園市 復興區
新竹市 東區
新竹市 北區
新竹市 香山區
新竹縣 竹北市
新竹縣 竹東鎮
新竹縣 新埔鎮
新竹縣 關西鎮
新竹縣 湖口鄉
新竹縣 新豐鄉
新竹縣 峨眉鄉
新竹縣 寶山鄉
新竹縣 北埔鄉
新竹縣 芎林鄉
新竹縣 橫山鄉
新竹縣 尖石鄉
新竹縣 五峰鄉
宜蘭縣 宜蘭市
宜蘭縣 頭城鎮
宜蘭縣 礁溪鄉
宜蘭縣 壯圍鄉
宜蘭縣 員山鄉
宜蘭縣 羅東鎮
宜蘭縣 蘇澳鎮
宜蘭縣 五結鄉
宜蘭縣 三星鄉
宜蘭縣 冬山鄉
宜蘭縣 大同鄉
宜蘭縣 南澳鄉
苗栗縣 苗栗市
苗栗縣 造橋鄉
苗栗縣 西湖鄉
苗栗縣 頭屋鄉
苗栗縣 公館鄉
苗栗縣 銅鑼鄉
苗栗縣 三義鄉
苗栗縣 大湖鄉
苗栗縣 獅潭鄉
苗栗縣 卓蘭鎮
苗栗縣 竹南鎮
苗栗縣 頭份鎮
苗栗縣 三灣鄉
苗栗縣 南庄鄉
苗栗縣 後龍鎮
苗栗縣 通霄鎮
苗栗縣 苑裡鎮
苗栗縣 泰安鄉
臺中市 中區
臺中市 東區
臺中市 南區
臺中市 西區
臺中市 北區
臺中市 北屯區
臺中市 西屯區
臺中市 南屯區
臺中市 太平區
臺中市 大里區
臺中市 霧峰區
臺中市 烏日區
臺中市 豐原區
臺中市 后里區
臺中市 石岡區
臺中市 東勢區
臺中市 和平區
臺中市 新社區
臺中市 潭子區
臺中市 大雅區
臺中市 神岡區
臺中市 大肚區
臺中市 沙鹿區
臺中市 龍井區
臺中市 梧棲區
臺中市 清水區
臺中市 大甲區
臺中市 外埔區
臺中市 大安區
彰化縣 彰化市
彰化縣 員林鎮
彰化縣 和美鎮
彰化縣 鹿港鎮
彰化縣 溪湖鎮
彰化縣 二林鎮
彰化縣 田中鎮
彰化縣 北斗鎮
彰化縣 花壇鄉
彰化縣 芬園鄉
彰化縣 大村鄉
彰化縣 永靖鄉
彰化縣 伸港鄉
彰化縣 線西鄉
彰化縣 福興鄉
彰化縣 秀水鄉
彰化縣 埔心鄉
彰化縣 埔鹽鄉
彰化縣 大城鄉
彰化縣 芳苑鄉
彰化縣 竹塘鄉
彰化縣 社頭鄉
彰化縣 二水鄉
彰化縣 田尾鄉
彰化縣 埤頭鄉
彰化縣 溪州鄉
南投縣 南投市
南投縣 埔里鎮
南投縣 草屯鎮
南投縣 竹山鎮
南投縣 集集鎮
南投縣 名間鄉
南投縣 鹿谷鄉
南投縣 中寮鄉
南投縣 魚池鄉
南投縣 國姓鄉
南投縣 水-{里}-鄉
南投縣 信義鄉
南投縣 仁愛鄉
雲林縣 斗六市
雲林縣 斗南鎮
雲林縣 林內鄉
雲林縣 古坑鄉
雲林縣 大埤鄉
雲林縣 莿桐鄉
雲林縣 虎尾鎮
雲林縣 西螺鎮
雲林縣 土庫鎮
雲林縣 褒忠鄉
雲林縣 二崙鄉
雲林縣 崙背鄉
雲林縣 麥寮鄉
雲林縣 臺西鄉
雲林縣 東勢鄉
雲林縣 北港鎮
雲林縣 元長鄉
雲林縣 四湖鄉
雲林縣 口湖鄉
雲林縣 水林鄉
嘉義市 東區
嘉義市 西區
嘉義縣 太保市
嘉義縣 朴子市
嘉義縣 布袋鎮
嘉義縣 大林鎮
嘉義縣 民雄鄉
嘉義縣 溪口鄉
嘉義縣 新港鄉
嘉義縣 六腳鄉
嘉義縣 東石鄉
嘉義縣 義竹鄉
嘉義縣 鹿草鄉
嘉義縣 水上鄉
嘉義縣 中埔鄉
嘉義縣 竹崎鄉
嘉義縣 梅山鄉
嘉義縣 番路鄉
嘉義縣 大埔鄉
嘉義縣 阿里山鄉
臺南市 中西區
臺南市 東區
臺南市 南區
臺南市 北區
臺南市 安平區
臺南市 安南區
臺南市 永康區
臺南市 歸仁區
臺南市 新化區
臺南市 左鎮區
臺南市 玉井區
臺南市 楠西區
臺南市 南化區
臺南市 仁德區
臺南市 關廟區
臺南市 龍崎區
臺南市 官田區
臺南市 麻豆區
臺南市 佳里區
臺南市 西港區
臺南市 七股區
臺南市 將軍區
臺南市 學甲區
臺南市 北門區
臺南市 新營區
臺南市 後壁區
臺南市 白河區
臺南市 東山區
臺南市 六甲區
臺南市 下營區
臺南市 柳營區
臺南市 鹽水區
臺南市 善化區
臺南市 大內區
臺南市 山上區
臺南市 新市區
臺南市 安定區
高雄市 楠梓區
高雄市 左營區
高雄市 鼓山區
高雄市 三民區
高雄市 鹽埕區
高雄市 前金區
高雄市 新興區
高雄市 苓雅區
高雄市 前鎮區
高雄市 旗津區
高雄市 小港區
高雄市 鳳山區
高雄市 大寮區
高雄市 鳥松區
高雄市 林園區
高雄市 仁武區
高雄市 大樹區
高雄市 大社區
高雄市 岡山區
高雄市 路竹區
高雄市 橋頭區
高雄市 梓官區
高雄市 彌陀區
高雄市 永安區
高雄市 燕巢區
高雄市 田寮區
高雄市 阿蓮區
高雄市 茄萣區
高雄市 湖內區
高雄市 旗山區
高雄市 美濃區
高雄市 內門區
高雄市 杉林區
高雄市 甲仙區
高雄市 六龜區
高雄市 茂林區
高雄市 桃源區
高雄市 那瑪夏區
屏東縣 屏東市
屏東縣 潮州鎮
屏東縣 東港鎮
屏東縣 恆春鎮
屏東縣 萬丹鄉
屏東縣 崁頂鄉
屏東縣 新園鄉
屏東縣 林邊鄉
屏東縣 南州鄉
屏東縣 琉球鄉
屏東縣 枋寮鄉
屏東縣 枋山鄉
屏東縣 車城鄉
屏東縣 滿州鄉
屏東縣 高樹鄉
屏東縣 九如鄉
屏東縣 鹽埔鄉
屏東縣 里港鄉
屏東縣 內埔鄉
屏東縣 竹田鄉
屏東縣 長治鄉
屏東縣 麟洛鄉
屏東縣 萬巒鄉
屏東縣 新埤鄉
屏東縣 佳冬鄉
屏東縣 霧台鄉
屏東縣 泰武鄉
屏東縣 瑪家鄉
屏東縣 來義鄉
屏東縣 春日鄉
屏東縣 獅子鄉
屏東縣 牡丹鄉
屏東縣 三地門鄉
澎湖縣 馬公市
澎湖縣 湖西鄉
澎湖縣 白沙鄉
澎湖縣 西嶼鄉
澎湖縣 望安鄉
澎湖縣 七美鄉
花蓮縣 花蓮市
花蓮縣 鳳林鎮
花蓮縣 玉里鎮
花蓮縣 新城鄉
花蓮縣 吉安鄉
花蓮縣 壽豐鄉
花蓮縣 光復鄉
花蓮縣 豐濱鄉
花蓮縣 瑞穗鄉
花蓮縣 富里鄉
花蓮縣 秀林鄉
花蓮縣 萬榮鄉
花蓮縣 卓溪鄉
臺東縣 臺東市
臺東縣 成功鎮
臺東縣 關山鎮
臺東縣 長濱鄉
臺東縣 池上鄉
臺東縣 東河鄉
臺東縣 鹿野鄉
臺東縣 卑南鄉
臺東縣 大武鄉
臺東縣 綠島鄉
臺東縣 太麻里鄉
臺東縣 海端鄉
臺東縣 延平鄉
臺東縣 金峰鄉
臺東縣 達仁鄉
臺東縣 蘭嶼鄉
金門縣 金城鎮
金門縣 金湖鎮
金門縣 金沙鎮
金門縣 金寧鄉
金門縣 烈嶼鄉
金門縣 烏坵鄉
連江縣 南竿鄉
連江縣 北竿鄉
連江縣 莒光鄉
連江縣 東引鄉

GAE 筆記 - 在 Ubuntu Server 上傳 Google App Engine 程式碼 @ Ubuntu 14.04

最近嘗試在 Ubuntu server 開發,以前常在 Windows 、 Ubuntu Desktop 和 Mac OSX 等視窗介面,最近 Google App engine 也把認證的部分換了,以前是在 Google App engine tools 上輸入帳號密碼,現在都改用 OAuth 認證方式,實在方便。

若要在 Ubuntu server 上運行 Google App Engine ,透過 Command line 即可完成測試跟發佈:

測試:

$ cd /path/gae/project
$ python -m py_compile *.py && dev_appserver.py --port=8080 .


發佈:

$ cd /path/gae/project
$ python -m py_compile *.py && appcfg.py --oauth2 --noauth_local_webserver -A YourGAEProjectID update .

過程只需再用 browser 瀏覽指定的 link 以及完成 oauth 的認證即可發布啦!

2015年5月16日 星期六

Bash 筆記 - 使用時間區間備份 MySQL 資料表

由於資料屬性的關係,剛好有幾個 table 都有 timestamp 這個資訊,拿來備份恰恰好,設計一下備份方式:
  • 一次備份 n 個月
  • 限制每 n 個月一次或是每次執行只備份前面符合條件的 n 個月
例如 n=6 時,在 1~6 月只能備份去年 7~12 月資料,在 7~12 月時,才能 1~6 月份的資料,並且讓程式能夠小小容錯,例如以產生過的資料就不要再匯出、匯出的資料要做壓縮、壓縮完要測試解壓縮、產生 md5 驗證等。

總之,技術細項:
  1. 使用 data 指令得知現況時間並計算出備份範圍
  2. 使用 mysqldump 搭配 --where 指令匯出指定 timestamp 資料
  3. 使用 tar -zcvf 備份資料為 tar.gz 格式
  4. 使用 gunzip -t 測試壓縮資料
  5. 使用 md5sum 建立壓縮檔案的驗證檔
執行方式,採用 bash, mysqldump, tar, gunzip, md5sum, date 指令:

#!/bin/bash
month_offset=0
month_range=6

current_month=`date +"%m"`
if [ ${current_month:0:1} -eq '0' ] ; then
        current_month=${current_month:1:1}
fi
month_offset=$(( $(($current_month + $month_range - 1)) % $month_range  ))
timestamp_begin_date=`date +"%Y-%m-01 00:00:00" -d "-$(($month_offset + $month_range)) month"`
timestamp_end_date=`date +"%Y-%m-01 00:00:00" -d "-$month_offset month"`
timestamp_init_date=`date +"%Y-%m-01"  -d "-$month_offset month"`
timestamp_out_date=`date +"%Y-%m-%d" -d "$timestamp_init_date -1 day" `
job_id=`date +"%Y-%m" -d "-$(($month_offset + 1)) month"`

DIR=/data/routine
log_dir=$DIR/log
dump_dir=$DIR/db
mkdir -p $log_dir $dump_dir
echo "[INFO] Job ID: $job_id , Begin: $timestamp_begin_date , End: $timestamp_end_date"
echo "[INFO] Working Dir: $DIR , log: $log_dir , export: $dump_dir"
echo "[INFO] Output suffix: $timestamp_out_date"
echo

arget_host=MyDBServerIP
target_user=UserID
target_pass=UserPassword
target_db=DatabaseName
target_table=("table1" "table2" "table3")
for table in "${target_table[@]}" ;do
if [ ! -f "$dump_dir/$table.$timestamp_out_date.sql" ] ; then
cmd="time mysqldump -h $target_host -u $target_user -p$target_pass --where \"timestamp >= '$timestamp_begin_date' AND timestamp < '$timestamp_end_date'\" --single-transaction --databases $target_db --tables $table > $dump_dir/$table.$timestamp_out_date.sql"
echo $cmd;
        fi        
done

echo
echo -n "Wanna go (y/N): "
read ans

if [ "$ans" == 'Y' ] || [ "$ans" == 'y' ] ; then
for table in "${target_table[@]}" ;do
output_file=$table.$timestamp_out_date.sql
output_archive_file=$output_file.tar.gz
output_archive_check_file=$output_archive_file.md5
echo
echo "build target: $output_file"
echo "\t$output_archive_file"
echo "\t$output_archive_check_file"
echo "..."
if [ ! -f "$dump_dir/$output_file" ] ; then
cmd="time mysqldump -h $target_host -u $target_user -p$target_pass --databases $target_db --tables $table --single-transaction --where \"timestamp >= '$timestamp_begin_date' AND timestamp < '$timestamp_end_date'\" > $dump_dir/$output_file"
echo $cmd
time mysqldump -h $target_host -u $target_user -p$target_pass --databases $target_db --tables $table --single-transaction --where "timestamp >= '$timestamp_begin_date' AND timestamp < '$timestamp_end_date'" > $dump_dir/$output_file
fi
if [ ! -f "$dump_dir/$output_archive_file" ] ; then
echo "time tar -zcf \"$table.$timestamp_out_date.sql.tar.gz\" \"$table.$timestamp_out_date.sql\""
cd $dump_dir && time tar -zcf "$output_archive_file" "$output_file"
fi
if [ -f "$dump_dir/$output_archive_file" ] && [ ! -f "$dump_dir/$output_archive_check_file" ] ; then
echo "time gunzip -t $output_archive_file && time md5sum $output_archive_file > $output_archive_check_file"
cd $dump_dir && time gunzip -t $output_archive_file && time md5sum $output_archive_file > $output_archive_check_file
fi
done
fi


若還有其他興趣的話,可以再結合 AWS glacier 的上傳,例如:

aws_glacier_bin="java -jar /path/uploader-0.0.8-SNAPSHOT-jar-with-dependencies.jar "
aws_glacier_region=https://glacier.region-id.amazonaws.com
aws_glacier_dir=db-log
aws_glacier_partsize=134217728

if [ "$aws_glacier" == 'Y' ] || [ "$aws_glacier" == 'y' ] ; then
for table in "${target_table[@]}" ;do
output_file=$table.$timestamp_out_date.sql
output_archive_file=$output_file.tar.gz
output_archive_check_file=$output_archive_file.md5
echo
echo "selected: $output_archive_file"
if [ -f "$dump_dir/$output_archive_file" ] && [ -f "$dump_dir/$output_archive_check_file" ] ; then
echo "do upload: $output_archive_file"
cmd="time $aws_glacier_bin --endpoint \"$aws_glacier_region\" -v \"$aws_glacier_dir\" --multipartupload \"$output_archive_file\" --partsize $aws_glacier_partsize  "
echo $cmd;
cd $dump_dir && eval $cmd;
fi
done
fi

2015年5月14日 星期四

AWS 筆記 - 關於 Amazon EC2、Elastic Load Balancer (ELB)、Auto Scaling 與 CPU loading 過低問題 @ Ubuntu 14.04, Apache 2.4

使用 ELB + Auto Scaling 好一陣子了,最近因為服務量變大導致 Web Server 變多,然而,在部署程式方面就累了許多,因此朝 Scaling up 來進行一下,限縮機器數量並提升機器規格。

在這個過程中,從 m3.medium 改到 m3.large 或 m3.xlarge 等,卻發現越高級的機器,其 CPU Loading 衝不上去,並且限縮機器後導致服務極為不穩,連 Health check 也發現。但明明機器都不忙啊?!

接著因為非常忙,拖了兩個禮拜才正視這個問題。追了許多後,發現...只是 Apache Multi-Processing Module (MPM) 設定未同步拉高 XD 好蠢的一件事啊。此外,由於服務眾多,尚未有空最佳化,就先繼續用 prefork 架構了。

$ apache2 -v
Server version: Apache/2.4.7 (Ubuntu)
Server built:   Mar 10 2015 13:05:59
$ sudo vim /etc/apache2/mods-enabled/mpm_prefork.conf
<IfModule mpm_prefork_module>
        ServerLimit                7500 # 預設才 256
        StartServers               20
        MinSpareServers           15
        MaxSpareServers            50
        MaxRequestWorkers          7500 # 預設才 256
        MaxConnectionsPerChild     0
</IfModule>


總之,ServerLimit 跟 MaxRequestWorkers 就看當下的機器資訊,例如記憶體等等。

透過 Web server 執行的環境調整,機器的負載度自然可以提升,接著 Auto Scaling 的機制就可用啦!原先在 m3.medium 的機器是單核,而在 m3.large 開始就是多核心了!效能就能更往上衝囉。很妙地用系統預設的 prefork.conf 在 m3.medium 還混的不錯 :P 包含 CPU 會依照 requests 量變化,不像同樣的設定檔搬到多核心後就失效了,CPU 衝不起來,導致 Auto Scaling 也失效!

整體上,這次碰到 service 不穩的主因:

total requests 一直保持一個數量,而原先開 m3.medium x N ,想說機器提升成 m3.large 就把數量調整成一半,結果 web server 數量降低,再加上 prefork.conf 的設定,導致能服務的 requests 量也降低!而 Health check 無法正常被驗證,接著 AWS Scaling 會判斷機器出事要下線,甚至 requests 不導過去,頻頻出現:

503 Service Unavailable: Back-end server is at capacity

如今終於解掉了 :P Health check requests 也能被服務到,機器自然就不會被判斷成有問題,自然就解掉 503 Service Unavailable 現象。

最後,如果要追蹤網路流量,可以試試 nload 這個指令,看整體流量還滿方便的。

2015年5月7日 星期四

Javascript 開發筆記 - 使用 Yuotube Player API for iframe Embeds 將 videos 串成 playlist

透過 Youtube Player API 可以動態把一堆 Youtube video 串成一個 playlist 來播放。網路上不少範例,但很少看到處理多則 video 的方式,有也是一則 video 搭配一個 player 架構,摸了一下終於搞懂其設計架構,片段程式碼:

<div id="player"></div>
<script>
var player;
var videos = ['LzHFD1sEqpE', 'iV8JDbtXZm4', '-sjfQWGkGF4'];
(function() {
if (videos.length) {
var tag = document.createElement('script');
tag.onload = function() {
YT.ready(function() {
player = new YT.Player('player', {
playerVars: {
playlist: videos.join(","),
}
});
});
}
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
})();
</script>


更多資訊請參考:https://developers.google.com/youtube/iframe_api_reference