Active Job 的佈署實例

當我們在 Web 處理 Request 的執行緒做一些消耗性能但是又不緊急的工作,流量大時不免會變成系統效能的瓶頸。

Async => 非同步的設計在這時候可以幫我們降低同一個執行緒要處理的工作消耗,可以用來處理類似發信,寫檔案,緩慢寫入讀取資料的事情。

在 Rails 要做到很簡單,Rails 有 Active Job 可以搭配許多 Queue framework,這邊我用的 Resque 就是其中之一。設定並不困難,安裝了 gem 然後在 #{env}.rb 設定

config.active_job.queue_adapter = :resque
config.active_job.queue_name_prefix  = "app_#{Rails.env}"

這邊要說的是…部署這些 Job 的方式。

之前有提到的專案應用上,我使用的系統是 Ubuntu 16。Rails 的 Application 裡用的是 foreman 來管理啟動 unicorn server。

web: bundle exec unicorn -c ./config/unicorn.rb

Worker 也可以這樣使用。在我們佈署到上線的環境時,我們會需要把這些 Worker 的執行程式包裝成服務來啟動。醬可以藉由設定讓他在 Server 重啟之後自己繼續執行。

Woker 的 Procfile 會像這樣:

mailer: rake environment resque:work QUEUE=store_${RAILS_ENV}_mailers
logger: rake environment resque:work QUEUE=store_${RAILS_ENV}_logger
filegen: rake environment resque:work QUEUE=store_${RAILS_ENV}_file_generation

Foreman 可以幫我們做到這點。它提供了許多匯出成系統服務的指令。我使用的指令如下:

$ sudo foreman export systemd --env .production-env --app storeworkers --user store /etc/systemd/system

這個指令會依照當下執行目錄的 Procfile 加上 --env 指定的環境變數來產生服務設定檔,放在指定的 /etc/systemd/system 裡。

產生的 /etc/systemd/system/storeworkers.target 會包含 Procfile 指定的所有工作,而每一個 Procfile 指定的工作內容將會被定義匯出在 /etc/systemd/system 裡。

匯出後我們可以透過 systemctl 來設定。

$ sudo systemctl [start|restart|enable] storeworkers.target

設定為 enable 後將可以在系統啟動後一併執行服務。

status 則可以查看該 worker 的最近幾筆紀錄

sudo systemctl status storeworkers.target

● storeworker.target
   Loaded: loaded (/etc/systemd/system/storeworkers.target; enabled; vendor preset: enabled)
   Active: active since Thu 2017-06-29 02:59:04 UTC; 20min ago

Jun 29 02:59:04 storeworkers systemd[1]: Stopped target storeworkers.target.
Jun 29 02:59:04 storeworkers systemd[1]: Stopping storeworkers.target.
Jun 29 02:59:04 storeworkers systemd[1]: Reached target storeworkers.target.

體驗 Elasticsearch 的魅力 – Part 1 :: Docker

目的

目前手上專案系統的 Log 仍然存在 MS SQL Server 裡。原因是因為系統後台一開始就建置了 Log 查詢的頁面功能。讓管理人員可以查詢系統登入、運作狀況以及 API 交換的每一筆訊息紀錄。這功能讓技術克服人員與開發人員很方便的進來系統撈取 Debug 錯誤時所需的有用資訊。

在初期快速開發的階段這些功能都是用 Entity Framework 建造以求開發迅速。但當系統上線後每日運轉下來 Log 的成長量也已大大超乎預期。雖然已經因為資料庫負荷沉重把 Log 搬離主要的交易資料庫放在較為次級的 SQL Server。但每日都有相當成長量讓我們不得不面對找尋完善的 Log 管理機制。

這個測試,我們需要在不改變系統功能的前提下評估:

  1. Elasticsearch 的 REST API 是否足夠讓我們建置客製化的 API 來包裝讓並使用現有系統後台 Log 查詢機制來查詢 (不再用 Linq + Entity Framework 查 SQL Server)。
  2. Elasticsearch 完全替代 MS SQL 來存 Log:
    1. 備份與資料維護
    2. Clustering
    3. Failover 機制
    4. SSRS 報表的替代方案

相關應用

  • Docker
  • Elasticsearch
  • Kibana
  • Logstash

動手

首先我們需要把 Elasticsearch 與 Kibana 設定好,然後倒一些 Log 進 Elasticsearch 並且試試 Kibana 上的查詢功能。

這篇先寫第一部分,關於 Docker 的使用與設定。

設定 Docker

用 Docker 來測試 ELK。可以避免在日常開發機器上裝太多不常用的系統服務。

Docker Repository 上已經有許多 ELK 的 Image, 我選了 sebp/elk,並有提供詳細的 文件說明

這個 docker image 上有所有 ELK Stack,啟動時需要指定開啟各服務所需要的連接埠讓本機可與 Container 溝通。執行方式如下:

docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 -it --name elk sebp/elk

指定三個連接埠 (-p) 分別代表:

  • 9200: Elasticsearch
  • 5601: Kibana
  • 5044: Logstash beats

Dockerfile

這個測試主要的目的是學習如何使用 ELK 達成目的。在不修改任何程式的前提下,第一階段要取得Log 資料須由 MS SQL 匯出到 Logstash。

因為有些 Container 相關的設定,所以我用了 Dockerfile 來把設定檔塞到 Container 裡:

FROM sebp/elk
# 在Container 建立一個工作資料夾,我們在本機編輯好的設定檔與其他必要檔案都可透過這個資料夾與Container交換
RUN mkdir /workspace
WORKDIR /workspace
ADD . /workspace

#另外我在本機有編輯了 logstash 的設定檔需要一開始就塞進 Container 裡。這邊可以將檔案加到指定的 Container 上的路徑
ADD logstash-mssql.conf /etc/logstash/conf.d/logstash-mssql.conf

#這個測試會用到 logstash 的 JDBC plugin。用以下這個步驟安裝
RUN gosu logstash /opt/logstash/bin/logstash-plugin install logstash-input-jdbc

logstash-input-jdbc 並沒有包含不同資料庫所需要的驅動程式。我們所使用的資料庫是 SQL Server。我們需要自己 下載 JDBC 驅動程式。

下載後解開壓縮檔把 sqljdbc42.jar 跟 Dockerfile 放在同一個資料夾。

docker-compose

目前只有一個 image/container,應該是用不到 docker-compose 來管理。但用 docker-compose 可以幫助我們記得要指定的連接埠。省的啟動 container 得打一大串指令。

version: '2'
services:
elk:
build: . # 要 docker-compose 執行時建置同目錄下的 Dockerfile
container_name: elk # 幫 Container 命名,之後比較好打指令
volumes:
- .:/workspace # 將本地資料夾掛在Container的 /workspace 資料夾下 [host:container]
ports:
- "9200:9200" # 對應本地與 Container 的連接埠
- "5601:5601"
- "5044:5044"

同樣跟 Dockerfile 放一起。在該資料夾下執行

docker-compose up

就可以啟動 container

設定 Logstash

sebp/elk 裡已經設定好一些 Logstash 設定檔。可以抓 beats, 系統記錄檔等等,並會把結果輸出在 localhost:9200 的 Elasticsearh 。在 container 裡的 /etc/logstash/conf.d/ 可以找到這些設定檔。之前提到需要撈 SQL Server 的設定檔也需要放在 /etc/logstash/conf.d/ Logstash 啟動時方可一併載入。

Docerfile 裡的 ADD logstash-mssql.conf /etc/logstash/conf.d/logstash-mssql.conf 這行就是要幫我們在 container 建立時把同資料夾裡的 logstash-mssql.conf 塞到 Container 的 /etc/logstash/conf.d/ 資料夾。

以下是我們設定 Logstash 撈取 SQL Server 資料庫的設定檔:

 
input{
  jdbc {
    jdbc_driver_library => "/workplace/sqljdbc42.jar"
    jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"
    jdbc_connection_string => "jdbc:sqlserver://10.0.75.1:1433;databaseName=LogDatabase"
    jdbc_user => "sa"
    jdbc_password => "sa"
    jdbc_validate_connection => true
    statement => "SELECT * FROM Logs"
  }
}

output {
  elasticsearch {
    hosts => "localhost:9200"
    index => "apilogs"
    document_id => "%{id}"
    document_type => "ApiLog"
  }
}

jdbc 區段可設定資料抓取方式。以及 SQL Server 伺服器的連線資訊。這邊要注意 SQL Server 是在本機 (Windows) 上執行的 SQL Server Express。從 Container 裡面用 JDBC 連線到 SQL Server 需要透過 HTTP 通訊協定,但 SQL SERVER 預設是禁止 HTTP 連線存取的。所以我們還需要修改一下 SQL SERVER 的設定:

Sql Server Configuration Manager > SQL Server Network Configuration > Protocols for MSSQLSERVER > TCP/IP 設為 Enabled 後重新啟動資料庫服務即可。

另外,我的 docker container 與本機 連線的方式 用的是 Bridge Driver。可以在本機使用 docker network inspect bridge 指令來查看網路介面的設定狀況。

回到 Logstash config 檔:

jdbc_connection_string => "jdbc:sqlserver://10.0.75.1:1433;databaseName=LogDatabase"
在這裡我直接將連線資訊指向 Docker 在 Host 機器上安裝的網路介面。

statement => "SELECT * FROM Logs"
撈資料時使用的 SQL Statement

設定檔好之後,可以使用 Logstash 的指令來跑跑看︰

首先我們要取得 Container 的 Shell 指令介面,在Windows 的指令模式下輸入:

docker exec -it elk /bin/bash

首先確保 Dockerfile 所執行複製進 Container 是正確的 Logstash .conf 檔,可用 vim 等純文字編輯程式開來看看:

vim /etc/logstash/conf.d/logstash-mssql.conf

無誤後 :q! 退出 vim 就可跑跑 Logstash 看看效果如何了

/opt/logstash/bin/logstash -f /etc/logstash/conf.d/logstash-mssql.conf

型爸日記 :: Days 75 Daddy’s Birthday

小龍貓來臨之後許多事都得放在一邊,其中當然包括爸媽的生日(媽媽的生日還得提早去吃大餐跳過產檢的日期XD)。今年初上任型爸的第一個生日禮物,當然就是可愛的小龍貓!媽媽特別幫他換上新衣服綁上緞帶,回家看到小龍貓這副樣子都快笑翻了。不過在笑翻了的背後有另外一種溫馨的感覺。不是當了爸爸我想很難體會的出矣。

生活雖然沒有過的很爽,尤其這幾個月,工作也頗忙碌,加上有了小龍貓後基本上把我們夫妻倆人禁足了好幾個月。要出門總是先考慮到想去的地方是不是適合扛著小龍貓一起去。即使如此,仍然甘之如飴的每天看著她漸漸長大(又有點不太想要她這麼快長大,矛盾矣)。

型爸的生日有一個小小的蛋糕!一家三人窩在客廳吃起來特別好吃(夫妻一人一半 ˋ ˊ 小龍貓在旁邊哼哼哼踢踢踢踏踏踏)至於願望就不用說~任何新上任的爸爸願望應該都大同小異吧。總之,32歲的今年,這個女兒出生讓我又多承諾了許多事。往後可要努力兌現啊!

在沙發上不安份的扭來扭去

在沙發上不安份的扭來扭去

型爸日記 :: Day 37 第二劑預防針

帶小龍貓去打第二劑預防針的時候小龍貓算是剛滿月,也是第一次扛出門。當天在醫院很巧的碰見跟我們在醫院產後病房同房的夫妻檔。當初他們的運氣比較不好,剛住進來的第一天是小龍貓最鬧的剛出生第二天的晚上。然後隔天就馬上轉到單人房去了留下我們獨自佔據雙人床的房間一天(開心)。老魏本來目光空洞的抱著小龍貓在護理站等著護士幫她體重,目光跟那個把拔對上之後看到他跟我點頭才想起來。當下就跑去跟他們打招呼。順便互相打量彼此差一天出生的兒子女兒。

隔了一個月再次看到該位爸爸,臉上充滿了開心的光芒,初為人父的這種特質,真的很奇妙啊!大夥閒聊了幾句,因為等待的人頗多,只好專心去診療室門口蹲著等護士玉手招喚呼喊小龍貓的名字,以免不小心漏掉了又得往後排好幾號。

好容易等到醫生大人來幫小龍貓做基本的檢查。看來小龍貓頭好非常壯,沒啥堪憂的。且聽說成長指數正常得很,出生一個月多成長約 50% — 4.3kg & 53公分高!小妞好吃好睡看來成果不錯。 檢查完以後刺激的戲碼就是捉住小龍貓給護士阿姨打針啦。領了疫苗後戰戰兢兢的走到打針房(比我自己挨針還要緊張),此時剛好一對爸媽帶著剛打完針大哭的小嬰兒出來。還在想說打針不知道會是啥場面的時候就被護士阿姨招喚去她隔壁坐好,並教把小龍貓扶好坐在我腿上要我捉住她的腿。

護士阿姨依照程序跟我確認好疫苗後,飛快的把疫苗抽好在針筒裡,就把針戳在小龍貓小嫩嫩的大腿上。 起先小龍貓跟她老爸都一起楞了一下,小龍貓就開始在她親愛的老爸也就是老魏的懷中大哭起來,身為爸爸的敝人費了好大的一番功夫才按奈住想要一拳把親愛的護士阿姨打飛的反射動作。(抱歉的緊,這真的是下意識反應,還好沒做出如此危險的動作,內心也偷偷地跟護士阿姨道歉矣)。我想聽到自己女兒痛到大哭這是很難控制的… 打完針後小龍貓楞楞地哭了幾聲就懶得哭了,在我懷裡扭了幾下喬好姿勢後就昏昏的睡倒。

回家吃著醫院餐廳買回來的便當一面想著,時間過的真的好快哪…

通常把拔在家的時候都是這樣黏住

型爸日記 :: Day 27 報戶口

報戶口最麻煩的事情不是手續,而是幫小孩取名字。

在我們家算是非常開明的了,長輩爸媽都對取名字沒有太多的意見。小龍貓出生以前已經聽過太多因為取名字跟長輩喬不攏的案例,幸好通通都沒發生在我們身上。頭痛的就是,不要太大眾化,不拗口,有氣質,諧音不要太奇怪的名字實在是不好取。

小龍貓的爸媽也就是敝人賢伉儷二人多番討論後,仍然由老婆大人出馬把名字想出來。小龍貓的老爸不是沒有想,而是絞盡腦汁想出來的名字都被駁回,實在是令人感嘆時不我與矣。

取好名字後因為媽媽還在坐月子的狀態,於是仍然由龍貓老爸親自出面,在下班後殺開台北市忙碌的下班車潮向八點下班的戶政事務所突進。辦戶口的步驟多且繁雜,我想在那邊上班的人員每天要對付白天人潮擁擠有一堆單子要處理的時候真的是辛苦了,可以想像某某張先生要申請啥啥謄本,就得調檔案印之蓋章。某某李太太要跟老公鬧分居,就又得命她跟冤家取印章在許多雜亂的紙上蓋之。還沒回神某某王媽媽又要幫小孩報戶口,還要申請生育獎金,又得向該媽媽索討零零總總文件核對之。

如果運氣不好,碰上龍貓爸爸這樣容易忘東忘西,填單子填的雜亂無章,又次序顛倒。人多的時候真的讓排隊的大眾群起跳高。

還好下班後再來申辦,偌大的區戶政事務所都已空空無人啦。雖然填單子仍然填的龍貓爸爸滿身大汗,不過仍然趕著八點前把文件都處理完畢,不然連線的電腦關機下班可就得擇日再來矣。

今天把拔好像有幫我報好戶口哩!

型爸日記 :: Day 11 肚臍

這個週末來了許多親朋好友帶了禮物和紅包歡迎小龍貓來到這個世界。小龍貓的阿公阿嬤和祖也隆重的北上來看這個可愛的孫女兒。看到小龍貓這麼可愛大家愛不釋手的搶著抱,身為她的爸媽也是於有榮焉。小龍貓的老爸一直被交代說不可以太寵小孩,不過照這情勢…不知道是誰會比較寵啊!!

今天的洗澡活動仍然在小龍貓狂暴的哭聲下結束,身為爸爸的我仍然面不改色的在驚濤駭浪的哭聲中硬起心腸幫她洗乾淨。相對於昨天一位有經驗的媽媽朋友示範幫小龍貓洗澡的時候的安靜無聲,小龍貓簡直是衝著她老爸來的不給臺階下,不過今天她的老爸仍有嘴硬說詞,曰:『昨天友人幫她洗澡時剛餵飽奶矣,今天剛睡醒肚子餓啦想喝奶,可是被抓去泡在水裡,任誰也會不開心也。』

相較於小龍貓慘烈的哭聲,她老爸嘴硬的說詞相對微弱的很….

另,另外,小龍貓的肚臍也在一陣混亂的洗澡盆內鄭重的脫落了。可惜我這個幫他洗澡的當爸爸的當時正在手忙腳亂的幫他擦身體,遂由她老母代勞幫忙撿起肚臍。算了算現在小龍貓也已經11天大,這幾天忙壞了她老母每天要把她掛在奶上餵奶變成她的專屬移動式自動奶瓶機。她老爸則是變成令她討厭的洗澡機器人和晚上抱著她押她睡覺的機動式自走搖籃的綜合體。

小龍貓的肚臍已經被慎重的收到防潮箱放好,目前並沒有打算做肚臍章,不過聽他阿嬤當年跟她老爸說,考試的時候帶著肚臍運氣會比較好,也不知道是不是真的…(小龍貓老爸當年考證照時倒是有偷偷帶在身上,不知道是不是因為這樣而考過的 …)反正就先保存下來給她以後留作紀念吧!

把拔洗澡技術真差~

型爸日記 :: Day 6

海葵颱風沒有登入,往大陸地區去了,希望不會造成太大損失。上午新北市的風還是呼呼的吹著!

小龍貓的姑婆有來看她,說小龍貓哭起來頗兇(難道真的是獅子女孩兒的關係嗎?)笑著說是颱風天出生的小女生,脾氣恰一點以後也不會給人家欺負,呵!

今天晚上幫小龍貓洗澡的時候仍然哭的驚天震地,不過做爸爸的已經習慣了,反而慢條斯理的幫他清洗四肢和皺折處。剛出生第五天,小龍貓算是苗條的寶寶,如果是米其林寶寶的話可能小龍貓會哭到累翻掉吧。

驚人的哭聲在幫小龍貓翻過來趴在手臂上洗背部的時候突然的安靜,猜想小龍貓應該是很怕沒有安全感!嘿嘿,現在三公斤左右…之後可不好說,我們當爸媽的看來要勤練臂力和腰力了!小龍貓的驚人哭聲從洗好背部後又重新開始一直到臍帶護理結束,快速塞到媽媽的懷裡餵奶才算告一段落。

對於能幫自己的小孩洗澡這件事其實頗為驕傲。之後跟朋友出來聚會的時候又是一項可以拿來說嘴的驕傲,這也是成為型爸的必備條件喔!(隨然不知道有沒有洗乾淨)

喝飽奶洗乾淨的小龍貓現在睡的舒服的很,當爸爸是很奇妙的事情!

洗香香餵飽飽!

睡的很安穩

*小龍貓現在喝奶的習慣仍然很自我,喝個幾分鐘就慢慢進入超然忘我的境界,對親喂的媽媽來說是件苦差事,不過根據媽媽的說法餵奶的時候感覺很難形容的奇妙,也就先順著小龍貓的習慣。之後再看看有沒有辦法慢慢拉長她喝奶的習慣吧!