2015年5月31日 星期日

IKEA NOT 立燈 / 上照落地燈 / 閱讀燈 (燈架 ONLY)



其實也才去過 IKEA 兩次而已,結果現在買傢俱都會想到它 XD 事情是這樣發展的,想說家中有人常常仰望天花板,時機也差不多到了,該砸點錢買居家用品,以前一張 SDCard、一隻 USB 都不需想太多,花錢就買,現在一台立燈(上照燈)倒讓我想了許多許多。



花了不少學費研究這款燈具(因為買了多顆燈泡 XD),我買的是有閱讀燈的。這台使用 E14 (閱讀燈) 跟 E27 (上照燈) 接頭的,當時就在燈區附近買了電燈泡(每顆均一價179元):



但回家後發現燈泡的亮度不是我想要的 :P 例如上照燈還不夠亮(此例是省電15W)、閱讀燈太亮(此例 12W)。接著跑去夜市內的傳統商店逛:



逛了才知道 E14 的燈泡其實並不常見 XD 在傳統店發現有 PHILIPS 省電 5W 的 T2 燈泡(約150元附近),且附近剛好有買 E14 轉 E27 的轉接頭(69元)可轉換!接著再買更亮一點的上照燈(省電27W 230元)

經過教訓後,買燈泡的錢大概快追上買燈架的錢了!聊些好玩的,有興趣可以去露天看看,宅經濟正夯!有人在幫忙代買,大概含運費約貴 130 左右,好處是可以超商取貨!這個立燈在 IKEA 賣的包裝品下也是一個提袋可以帶走的,搭捷運也還好,但不輕是真的。至於為何最後去 IKEA 買?單純是一種信仰吧? XD (網路上看到的上照燈也都不便宜...)

2015年5月29日 星期五

AWS企業主管高峰會 2015 Taipei / AWS Enterprise Executive Summit 2015 Taipei

臺北市政府站

今年辦在 W Hotal ,由 Intel 主力贊助,共有四個 talk ,除了第一位大咖跟最後一位偏傳道士外,其實收穫還不少的:http://aws.amazon.com/tw/summits/taipei/agenda/

第一位是 Stephen Orban, Head of Enterprise Strategy, Amazon Web Services,花了不少在講自己的經歷 :) 說真的還滿帥的 (畫錯重點),因為還滿著重在經歷,就讓我我想到,還滿多科技都是 CTO 兼 co-founder 的。

其中有張圖是列出 CEO/CTO/CFO/CMO/CISO/CRO 的負責項目跟 AWS Value (Experience/Pace of Innovation/Service Delph & Breadth/Pricing Philosophy/Ecosystem/Global)的對照,說真的我十分認同。把玩 AWS 幾年了,真的越來越有那種 startup 欠的東風快補齊了,畢竟 startup 其實就是在管理資源,而 AWS 是一個很讚的資源管理方式,熟了之後,要錢時也能說出個所以然,而不是獅子大開口的要自己的薪資。

接著第二位是 NextMedia 的技術總監,簡介壹傳媒的角色以及經歷黃色雨傘的心得,並且花了3個月完成搬遷至 AWS 的工作,目前使用量約 120 EC2 instances。我認為他壹傳媒的角色跟故事都說的很棒!至於挑選 AWS 的主因應該跟黃色雨傘事件(ISP/CDN)的經歷有關,並且認為 AWS 在資安角度做得很讚等,總之,不見得是因為是錢,而是 Global、Security 等概念,當然,Auto Scaling 也是資源管控的大項目之一。而有一頁架構頭有提到他們有用 MongoDB。

第三位是 HTC Creative Labs - Clifford Chen,可以去 linkedin 看一下,履歷也不錯。聽他講解我才知道 HTC 做了那些不錯的服務,我自己也丟訊息給在 HTC 的朋友(講師的同事),他也很納悶,為何大家都不知道 HTC 的付出 XD 或是為何大家都不用 HTC :P 我自己是單純用 CP 來講啦 XD 例如小米手機的崛起。其他則是聊到 Android/iOS 生態一直不斷侵蝕到一些創意東西,例如 Android 4.0 Camera 已經內建一堆圖片特效,這叫其他 Android app developer 該怎樣活 XD 回到主體,透過 Clifford 簡介,發現 HTC 也有在用 Docker ,並且用了約 700 個 EC2 instances。最重要的是 ZOE 服務上線一年有三百萬個用戶,這是一個幫使用者快速把照片製作成影片。

第四位是 AWS Solution Architect - Olivier Klein,竟然有 live demo,還兩次 XD 果真也是個 full-stack 高手!主要是進行 AWS Lambda 傳道,這個 AWS Taipei 業務也有一直叫我去用 Orz 真是沒空。不過簡單對 AWS Lambda 評語:真是個好物,有錢是大爺!總之,就不再需要類似 Architect 角色,只要 RD 不用 OP 似的。此外,其他的心得是 Vimeo 本身把免費跟付費切開,讓付費用戶享用 Auto Scaling 架構。

整體上,對於我自己已經稍微略懂 AWS 的開發者而言,這場的收穫依舊不錯!

2015年5月22日 星期五

Google API 筆記 - 使用 Google OAuth 2.0 API @ Ubuntu 14.04, PHP 5.5


準備替服務整合 Google Plus 登入方式,因此研究了一下 Google OAuth 2.0 API 的用法:
  • 在 Google Developer Console 建立一個 Google Project
  • 開啟此 Google Project 的 OAuth 使用,並設置"重新導向 URI",此處 URI 雖然不支援萬用符號,但支援輸入多筆,還算夠用。
整個過程下來,得到 client_id、client_secret 兩筆資料,如此一來就可以進行 OAuth 使用:

先組出 Google OAuth 所需的網址提供使用者授權,需要填寫 scope, response_type, redirect_uri, access_type, approval_prompt, client_id,例如:

$init_url = 'https://accounts.google.com/o/oauth2/auth?'. http_build_query( array(
'scope' => 'email profile',
'response_type' => 'code',
'redirect_uri' => $google_oauth_callback_url,
'access_type' => 'offline',
'approval_prompt' => 'force',
'client_id' => $google_project_client_id,
));
header('Location: '.$init_url);


接著,在 callback_url 的網頁中,接了 Google OAuth 回傳的 code 後,從 server site 發 requests 進行處理:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.googleapis.com/oauth2/v3/token');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query( array(
'client_id' => $google_project_client_id,
'client_secret' => $google_project_secret_key,
'code' => $google_ret_code,
'grant_type' => 'authorization_code',
'redirect_uri' => $google_oauth_callback_url,
)));
$ret = @json_decode(curl_exec($ch), true);


若一切順利的話,在 $ret 中,就可以拿到 access_token 了(此例需開啟 Google+ API)

$profile = @json_decode(file_get_contents('https://www.googleapis.com/plus/v1/people/me?'.http_build_query( array(
'access_token' => $ret['access_token']
))), true);

print_r($profile);


最後,若測試完後,想要替自己用的 Google account 刪除 app 授權的話,可以這邊刪除:

https://security.google.com/settings/security/permissions?pli=1

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

2015年5月4日 星期一

GAE 筆記 - 將 Google App Engine 之儲存資料 DataStore 匯出處理

前陣子寫小的程式不斷地將資料儲存起來,最近想處理一下,打算用 offline 的方式處理。接著就是要把資料先匯出,再用程式分析每筆資料。

匯出方式很簡單,只需到 Google App Engine -> Application -> YourApp -> Data -> Datastore Admin -> 勾選想要的資料表(Entities) -> Backup Entities ,不一會兒就可看到 Backups 有資料了。

接著是下載方式,有一派是說用 gsutils ,但我沒試成功,可能跟 gsutils 使用時機有關,我則是透過網頁把各個檔案下載來使用:Google App Engine -> Application -> YourApp -> Data -> Blob Viewer -> 可看到幾個小檔資料,就簡易人工點擊下載。

最後,寫簡單的程式來分析吧:

import webapp2

from google.appengine.api.files import records
from google.appengine.datastore import entity_pb
from google.appengine.api import datastore

class MainPage(webapp2.RequestHandler):
        def get(self):
                self.response.headers['Content-Type'] = 'text/plain'
                for record in records.RecordsReader(open('file-part-1', 'r')):
                        entity_proto = entity_pb.EntityProto(contents=record)
                        entity = datastore.Entity.FromPb(entity_proto)
                        self.response.write(entity)

app = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)