如何在Ubuntu 18.04上安裝與設定HP印表機工具

前言

因為辦公室是使用HP印表機進行影印,以往我在辦公室有文件需要列印的時候,我都是使用辦公室所配發的Win 10筆電進行列印,這樣其實是不方便的。

因為每次都要在辦公桌上切換不同的電腦進行列印的操作,熟悉我的人都知道,我基本上都是使用Ubuntu/Linux筆電進工作,所以我最近找了一些文章並把HP印表機工具,在Ubuntu 18.04上的設定記錄下來。

讓大家知道,HP印表機在筆電上要怎麼運作的。

前置環境

在開始本篇的教學前,需要注意下面的幾點事項:

  • 準備好Ubuntu 18.04的筆電或是電腦

安裝相關所需要的套件

在使用HP印表機工具前,需要透過下面的指令來更新與安裝我們所需要的套件


sudo apt-get update

sudo apt-get install hplip hplip-gui hplip-data hplip-doc hpijs-ppds libsane-hpaio printer-driver-hpcups printer-driver-hpijs

安裝好之後,我們可以透過指令的方式啟動HP-setup,這是印表機設定工具


python3 $(which hp-setup)

這邊要注意的是,需要使用Python3開啟,因為大多數環境預設,python指令為Python2。

所以要在最前面指定python3當作執行的程式。

執行下去之後,會看到下面的畫面:

這是一個HP裝置管理器,透過它可以幫我們快速找到印表機裝置的位置,裡面有幾種選項可以選擇,分別是:

  • USB找尋印表機裝置
  • 透過網路(包含無線,有線等網路)直接連線印表機裝置
  • 無線網路,需要暫時連接USB網路
  • 序列port方式連接

以我在辦公室來說,通常大部分都是選擇第二個選項,我們可以透過區域網路方式,找尋到確的印表機位置。

可是當你選擇下去並按下「Next」之後,會出現如下的錯誤:

這是因為,HPLIP沒有辦法自動找到網路上的印表機,這時候,需要打開「Show Advanced options」並勾選「Manual Discovery」手動將印表機所在的IP填上去:

 

填完之後再去按下「Next」,這時候就會順利找到了。如下圖,就會有那台印表機的資訊

接著再按下「Next」就會把印表機安裝好了。到這裡,就是把印表機設定好完成的步驟,那接下來後面就是可以開始列印文件了。

首先,我們先開啟一份PDF檔案,我使用「Document Viewer」做開啟的動作。

接著,按下「Print」選項,如下圖:

按下去之後,會有印表機裝置清單:

接著切換到「Advanced」選項,如下截圖:

我們從截圖中可以看到有一個選項叫做「Page Source」,可以選擇紙夾的部份,裡面有紙夾1,紙夾2與自動偵測可以選擇。那因為我本來是用自動偵測的選項,可是不知道為什麼,每次檢查完紙夾1之後就不能往下檢查了,會卡在紙夾1中沒有紙張。

我為了要解決上述的問題,我就直接指定紙夾2當作列印紙張的來源,後來就可以順利的列印出文件了,沒有任何的問題。

參考資料

  • https://askubuntu.com/questions/1058742/how-to-install-hp-printer-in-ubuntu-18-04

如何利用在Azure上的Azure Web App部署一個Docker容器

前言

相信在看這篇文章之前,已經先看過這篇文章了。從前一篇文章,我們可以得知該如何利用Azure Web App上部署的方法把我們的專案部署上去。

可是,這個沒辦法滿足下列的要求

  • 以PHP環境來說,預設在Azure Web App上的環境是PHP + Apache,那如果我們要PHP + Nginx呢?
  • Azure Web App部署上去會觸發Azure所客製的部署引擎Kudu,若不熟悉腳本語言,還需要再花額外的時間去學習

為了要解決上述的問題,Azure Web App提供另一項的部署方式,那就是用Docker container方式,透過編寫的Dockerfile或docker-compose.yml方式,Azure Web App會在部署的時候讀取它們並部署成一個container,即是一個容器為一個Web App Service的概念。

本文章,就是要使用Azure Web App並透過載入Docker 映像來達到部署Web App Service。

登入Azure portal

首先,先登入Azure portal,Web方式管理Azure雲端運算平台的服務。

接著,在利用Docker container部署一個Azure Web App之前,需要將我們需要用到的Docker 映像發怖到網路上的平台,因為Azure Web App用Docker容器部署的時候,可以接受以下幾種方式:

  • 從外部Docker Hub載入
  • 從Azure Container Registry載入
  • 快速入門
  • 私人存放Docker映像檔server

本章節中,我們只使用「Azure Container Registry」這種方式載入我們所需要的Docker映像檔。原因是因為:

  • 我們需要建立一個Docker私人映像檔
  • 客製化Docker映像,因此快速入門所預設好的映像不適合這次的文章要求
  • 我們沒有私人存放Docker映像檔的server,因此此方法也不適合
  • Azure Container登錄,就是在Azure雲端運算平台上面建立一個私人的Docker Hub,透過它可以在Azure Web App部署的時候指定來源的Docker映像,進而達到部署的效果

我們在上圖中的「搜尋資源,服務及文件的地方」輸入「容器登錄」就可以得到如下的截圖:

因為我在之前有建立一個Docker容器登錄的位址,因此截圖上有出現在清單中,接著按下「新增」,就會看到下面的截圖:

就先取好自己的Docker container Registry名字,還有其他選項,如下圖所示:

都確認之後,接著按下「建立」的按鈕,就會開始建立Azure Container Registry位置了。

建立完成之後,在清單中就會看到剛剛建立的Azure Container Registry了。

點擊剛剛所建立好的容器登錄。

就會看到這樣的截圖如下:

點擊「存取金鑰」並把管理使用者「啟用」,這樣就可以允許Azure Web App在部署的時候去存取此Azure Container Registry上的Docker映像了。

接著,打開終端機,假設已經把「az」安裝好了(若沒有安裝,請先讀這篇文章),我們可以輸入如下的指令進行登入:


az acr login --name=your-acr-name

登入成功後,會出現下列的訊息


Login Succeeded

接下來,就可以把本地建置好的Docker映像發怖到我們先前所建立好的Azure Container Registry了

我們先標記目前的Docker映像的版本,這樣在Azure Container Registry上選擇版本的時候更加容易,可以利用下面的指令來達成


docker tag database-adminer your-acr-name.azurecr.io/database-adminer:v1

database-adminer是我在本地端Docker映像檔的名稱,而「your-acr-name」是之前步驟建立Azure Container Registry的名稱。

建立好標籤之後,接著再用下面的指令將本地端的Docker映像傳輸到先前所建立的Azure Container Registry。


docker push multidbp.azurecr.io/database-adminer:v1

都建立完成之後,回到Azure Container Registry頁面並點選「存放庫」可以發現剛剛所建立的Docker映像已經在上面了,如下截圖:

接著點選進去,就可以看到目前推送上去所有的的標籤清單了

我們完成了Docker映像的推送後,接下來可以用Azure Web App部署了

首先,我們先進到如下圖的「Azure Web應用程式」頁面並再新增一個新的Web應用程式,選擇相關的選項如下圖:

在圖中我們可以得知,我們取一個Web App名字叫做「database-adminer-docker」並把部署方式選擇「Docker映像」,其他選項都用與之前文章相同即可。接著點選「下一步:Docker」,就會到下面的截圖:

我們選擇「單一容器」,映像來源選擇「Azure Container Registry」,接著選擇登錄容器的名稱,映像以及標籤版本,啟動命令留下空白,這裡是因人而異,原因是因為我們在「Dockerfile」裡面已經有明確的指定要執行的指令,因此不需要再額外輸入需要執行指令。

接著就「下一步 標籤」再接著按「下一步 檢閱及建立」,最後就按下「建立」,如下截圖。

接著就跑起來了,如下截圖:

參考資料

  • https://docs.microsoft.com/zh-tw/azure/app-service/containers/tutorial-custom-docker-image
  • https://blog.miniasp.com/post/2015/05/04/Intro-Azure-Web-App-Kudu-engine
  • 文章所使用到的專案:https://github.com/peter279k/database-adminer

如何在Azure上使用Azure Web App部署一個Web應用程式

前言

在開始本文章前,先講個故事。

回到2018年,剛進去公司的時候,我有一個快要離職的同事,它知道我要開一個新計畫需要建置一個資料視覺化的系統並要在移入廠商內網之前,要在外面一個地方做一個展示。

他就說:「那可以在Azure上面開一個虛擬機器」

所以那因為這樣,我就在Azure雲端運算平台上面開一台虛擬機器了。開了之後,發現辦公室裡面大家也是這樣開虛擬機器,我都懷疑這樣不是就沒有用到Azure的雲端服務的優勢了嘛?

後來,我又想到之前學的,雲端服務三層架構(不知道的可以去看此篇文章),我覺得,Azure應該也有PaaS的服務才對,那後來再跟其他人交流,講到在Azure上面的費用,聽到我們需要在平台上面一個月花上2萬多塊也感到不可思議,也認為這樣在雲端運算平台上面花太多錢了,他們聽完我講我們都在上面開很多虛擬機器跑服務,也都驚訝不已。

本文章,是要講述如何使用Azure上面所提供PaaS功能的「Azure Web 應用程式」來部署一個單一個PHP Web應用程式。

Azure Web App概覽

首先,我們可以先從下面截圖來一窺Azure Web App部署架構圖。

從上面的架構圖我們可以知道,在「Azure Web App」部署上有幾種方法可以成功部署成「Azure Web App」,相關部署方法如下:

  • FTP deployment, FTP部署,這個是屬於最基本的,就是透過FTP帳號與密碼把專案推送上去
  • GitHub deployment, GitHub部署,這個是利用GitHub OAuth的功能授權給Azure,讓Azure可以存取指定的專案達到部署的效果
  • Local Git, 本地端Git部署,這是利用本地端自己的Git專案,將其部署到Azure Web App上
  • BitBucket deployment, BitBucket部署,這個與GitHub相同,都是透過授權給Azure可以存取指定的專案(repositories),來達到部署
  • Azure repos, 這個是指可以利用「Azure DevOps」與持續整合與部署做結合

本文章,只會介紹前面四種的部署方式,至於「Azure repos」,因為步驟與建置較為複雜,因此後續的文章才會有此篇文章專門做此介紹

前置條件

在開始本篇文章操作之前,下面的東西是不可或缺且需要會的

  • Git
  • FTP使用
  • az command, Azure CLI, 若沒安裝,請先看此教學
  • 有GitHub帳號(若需要透過此帳號上面的專案進行部署)
  • 有BitBucket帳號(若需要透過此帳號上面的專案進行部署)

建立Azure Web應用程式

首先,我們先登入Azure portal,網址:https://portal.azure.com

接著,在下方截圖的搜尋欄位輸入「Azure Web App」,接著就會看到下方截圖的「應用程式服務」

接著就會看到所有的Web應用程式的清單,如下截圖。

接著,按下左上角的「新增」按鈕,我們就會跳到新增Web應用程式的頁面了,如下圖。

我們填完所屬的資源群組名稱後,接著,這個頁面往下拉一點,可以看到下面的截圖:

從上面的截圖可以知道,我們有下列的選項可以選擇:

  • 名稱,這裡是可以取名稱,使用「azurewebsites.net」的子網域名稱
    • 子網域部份,由於是大家一起共用這個主網域的,因此不可以跟其他人重複,這裡我取的範例是「database-adminer」
  • 發佈,這裡可以選擇「代碼」或是「Docker映像」。代碼指的是自己的專案,選擇「代碼之後」,並不需要再做額外的其他設定,選擇「Docker映像」還需要在設定
    •  Docker映像得來源位址
    • 這裡選擇是「代碼」,使用「Docker映像」部份則留到日後的文章再說
    • 選擇「代碼」之後,需要選擇「執行階段堆疊」,這裡要選擇需要在上面跑的程式語言,因為本文章範例是建立PHP Web應用程式,所以我們可以選擇如下截圖的PHP版本,我們這裡選擇PHP-7.3

  • 地區,就是希望在哪個地方運行這個Web應用程式,價錢會會隨著地方的不同而有所不同,有些地方價錢較高但是離需要服務的國家近等,自行選擇作取捨
  • APP SERVICE 方案,就是自行選擇所需要的方案,這裡我選擇「基本B1」方案,方案日後仍可以再自己再調整

按照上述的建議,設定好之後,按下「檢閱及建立」,檢查完成後,接著再按下「建立」,就會將此Web應用程式的實例建立起來了。

建立好之後,回到首頁,點選下面截圖的「應用程式服務」

接著,我們可以到所有應用程式服務的清單,並找到剛剛建立的「database-adminer」的應用程式服務。

點選「database-adminer」按鈕進去之後,就可以看到此應用程式的設定頁面了

從上面截圖的設定頁面,我們可以得知幾個事項:

  • URL網址
  • 目前的APP SERVICE方案
  • FTP位址
  • 左邊的列表我們可以看到,有「部署」的區塊,此區塊中的「部署中心」是下一章節會用到的

Azure Web應用程式部署設定

本章節,我們要點選上一張Web應用程式設定頁面截圖中,左邊的「部署中心」選項,點選之後,我們可以看到下面的截圖。

 

往下拉之後,會再看到下面有另外三個部署方法,如下截圖:

Azure Web應用程式GitHub部署設定

假設我們需要使用GitHub上的專案來部署到指定的Azure Web應用程式上面

首先,先附上利用GitHub的部署Azure Web應用程式架構圖。

  • 開發者會先授權給Azure Web App讓它可以讀取開發者GitHub帳號上的專案
  • 透過指定專案的方式,會建立Webhook,每當有新的commit更新上去的時候,就會自動推上去做更新

我們選擇GitHub並授權給Azure Web App存取上面的專案

點選之後,再按下「授權」按鈕會跳出授權的畫面,如下截圖

GitHub授權頁面往下拉,並按下「Authorize AzureAppService」按鈕,接著就授權完成了。有可能,GitHub會再度要求輸入一次使用者密碼以便確認授權。

完成之後,授權畫面就會關閉,並再回到部署設定頁面,這個時候就會發現GitHub帳號名稱就會在上面,這就表示已經授權成功了。

接著按下「繼續」按鈕,則會看到下面的選項:

  • 第一個服務是使用一個東西叫做「Kudu」服務透過服務定義的部署腳本進行自動部署程式碼或專案
  • Azure Pipelines,是使用「Azure DevOps」,並透過持續整合服務,將服務做持續部署的動作,因為這個服務牽涉到要開啟權限與DevOps的概念,因此本篇文章暫不討論

接著按下「繼續按鈕之後」,會來到選擇存放專案的地方,選擇適當的組織,存放庫名稱與分支。

接著選擇如下方的專案

接著按下「繼續」,再按下如下面截圖的「完成」就部署完成了

部署中心設定頁面就會變成下面截圖這樣了

我們再去打開「https://database-adminer.azurewebsites.net」網址,就會看到如下的畫面了

Azure Web應用程式BitBucket部署設定

與GitHub的步驟類似,可以選擇下面截圖之後,後面的步驟與「GitHub」部署專案章節步驟雷同

Azure Web應用程式Local Git部署設定

顧名思義,就是把本地的Git存放庫直接推到Azure Web App並透過Azure Web App進行內部的部署動作。

設定完成之後,Azure Web App會設定一個遠端的Git存放庫,讓本地端的Git存放庫可以推上去並進行部署

接著我們回到本地端的,打開終端機打上下面的指令將上述的遠端Git存放庫網址加入到本地端的遠端存放庫清單裡面


git remote add azure https://database-adminer.scm.azurewebsites.net:443/database-adminer.git

接著,我們利用下面的指令把專案推上去

接著,要為遠端Azure的存放庫設定一組帳號密碼,如此一來才可以將本地端的Git存放庫推上去並達到部署的效果

假設本地端已經有「az」指令,在終端機輸入:


az webapp deployment user set --user-name your-user-name --password your-password

最後會輸出像下面的response JSON

{
"id": null,
"kind": null,
"name": "web",
"publishingPassword": null,
"publishingPasswordHash": null,
"publishingPasswordHashSalt": null,
"publishingUserName": "multidbp",
"scmUri": null,
"type": "Microsoft.Web/publishingUsers/web"
}

設定好帳號與密碼之後,就可以透過下面的指令把專案推上去了


git push azure master

會問帳號與密碼,這時候就輸入剛剛所設定的帳號與密碼就可以通過遠端Azure存放庫的認證把本地Git專案部署上去了

推上去的過程會類似如下圖這樣:


Username for 'https://database-adminer.scm.azurewebsites.net:443': your-user-name
Password for 'https://multidbp@database-adminer.scm.azurewebsites.net:443':
Counting objects: 37, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (32/32), done.
Writing objects: 100% (37/37), 292.51 KiB | 6.80 MiB/s, done.
Total 37 (delta 13), reused 0 (delta 0)
remote: Updating branch 'master'.
remote: Updating submodules.
remote: Preparing deployment for commit id 'aee14e6771'.
remote: Running custom deployment command...
remote: Not setting execute permissions for bash deploy.sh
remote: Running deployment command...
remote: PHP deployment
remote: Kudu sync from: '/home/site/repository' to: '/home/site/wwwroot'
remote: Ignoring: .deployment
remote: Copying file: '.env.example'
remote: Copying file: '.htaccess'
remote: Copying file: '.htpasswd'
remote: Copying file: 'Dockerfile'
remote: Ignoring: deploy.sh
remote: Copying file: 'index.php'
remote: Copying file: 'nginx-default.conf'
remote: Deleting file: 'README.md'
remote: Ignoring: .git
remote: No COMPOSER_ARGS variable declared in App Settings, using the default settings
remote: Composer settings: --no-interaction --prefer-dist --optimize-autoloader --no-progress --no-dev --verbose
remote: /home/site/wwwroot
remote: /home/site/wwwroot
remote: Found entry .env.example
remote: ~/site/wwwroot ~/site/repository
remote: ~/site/repository
remote: Finished successfully.
remote: Running post deployment command(s)...
remote: Deployment successful.
remote: App container will begin restart within 10 seconds.
To https://database-adminer.scm.azurewebsites.net:443/database-adminer.git
* [new branch] master -> master

在推送的過程中,會將Git專案中的檔案一併做複製並做一些設定的動作

Azure Web應用程式FTP部署設定

這章節,是最簡易的部署,簡單來說,就是透過Azure給的FTP帳號與密碼,透過FTP傳輸檔案的方式把本地端的專案部署上去。

FTP本身已經是內建的功能了,如下截圖:

結論

  • 本文章都是用PHP作為範例來部署Web應用程式
  • 以PHP Web應用程式來說,進入點是「index.php」
  • 每當要換部署方式時,記得選擇「中斷連接」來取消當前的部署方式

  • 其他程式語言其實也是大同小異,需要再舉一反三即可

參考資料

  • https://docs.microsoft.com/zh-tw/azure/app-service/containers/tutorial-custom-docker-image
  • https://docs.microsoft.com/zh-tw/azure/app-service/containers/quickstart-docker-go
  • https://mikepfeiffer.io/azure-docker-containers.html
  • https://www.dragonbe.com/2018/02/deploy-docker-containers-fast-to.html
  • https://docs.microsoft.com/zh-tw/azure/app-service/deploy-local-git
  • 使用到的專案:https://github.com/peter279k/database-adminer

如何在Azure上部署一個Azure MySQL Database

前言

最近在公司裡,有在使用Azure雲端服務來架設各式各樣的服務,供測試與部署。

那隨著Azure金錢消耗量很大,負責管理Azure的人慢慢意識到Azure怎麼會這麼燒錢?

後來我慢慢的發現,最後得到下面這張結論圖:

原來是一開始大家就對於Azure的使用上弄錯了方向。其主要原因如下:

  • 不懂雲端運算平台的架構,導致大家都在IaaS層建立資源機器
  • 當然我前二個計畫也是在IaaS上開機器做服務出來,當然我開始了一些改變
    • 去年的時候,第一台機器所對應的計畫,就跟其他人一樣,都是開一台運算資源機器出來,上面架設需要的環境與安裝服務。
    • 第二台機器,一樣也是開資源機器起來,但是跟前一個不同的是,我把所有的服務做容器化,讓服務更好掌控與管理,不過還是一樣,還是需要在機器上建置Docker所需要的必要環境
    • 未來計畫,以Azure來說,會朝向使用PaaS,如「Azure Web App」等
      • 將每個需要的服務分開,並使用Azure MySQL/PgSQL/SQL 等DB的PaaS建立資料庫instance實例,以達到共用資料庫的目的

本文章,主要是要探討的內容如下:

  • 使用Azure上屬於PaaS種類包含
    • 「Azure Web App」與「Azure DB」
    • 以「Azure MySQL DB」服務建立MySQL資料庫

Azure Database介紹

在Azure雲端運算平台上,有現成的資料庫的服務可以使用與建立,那這些也算是PaaS期中的應用之一,其最主要的目的就是可以讓開發者省略設定與安裝資料庫的動作,透過Azure針對資料庫配置好的設定來建立資料庫,這樣的好處如下:

  • 開發者可以專心開發並不需要花費額外的心力在建置與設定資料庫上
  • 對於小型團隊,計畫有很大的幫助

Azure MySQL Database建立步驟

首先,我們可以先登入Azure portal,網址:https://portal.azure.com

登入之後,我們可以看到下面的截圖所示:

接著,點擊右邊的「新增資源」並會看到右邊有可以建置的資料庫種類清單,詳細如下面截圖

我們從上面的截圖可以找到我們要的「MySQL」資料庫,因此我們選擇「適用於 MySQL 的 Azure 資料庫」這個來建立本篇文章所要展示的資料庫

點擊下去之後,會有一些相關的設定需要填寫,如下截圖

因為我已經有建立一個名稱叫做「electric-data」的資料庫了,所以上面的截圖在資料庫名稱有紅色驚嘆號是很正常的。

其他的欄位如資料庫名稱,使用者帳號,密碼以及主機座落的位置以及MySQL版本等都可以自行填寫,這邊只是一個範例。

接著,都填寫完成之後,按下「建立」按鈕就可以開始把需要的資料庫建置起來了。

回到首頁,我們在搜尋欄位地方輸入「MySQL」就可以找到「適用於 MySQL 伺服器的 Azure 資料庫」這個名字,點選下去之後,就會看到所有MySQL資料庫的清單列表。

從上面截圖可以得知,我們有一個叫做「electric-data-store」的資料庫可以選擇,那點擊下去之後,就會有此MySQL資料庫相關設定頁面可以選擇。

下面截圖可以得知,裡面會有Azure MySQL資料庫相關的所有設定

從上面截圖,我們可以知道相關設定如下

  • 資料庫系統管理員帳號與密碼設定
  • 資料庫SSL連線啟動與設定
  • 連線設定「Connection security」

資料庫連線設定

點選左邊列表的「Connection security」,我們可以發現有防火牆規則與SSL連線設定可以設置,那這邊就是加入可以允許連線的IP位址範圍。

結論

本文章中,利用Azure portal管理介面去示範新增一個「Azure MySQL Database」並可以透過上面的資料庫設定頁面可以設定相關與MySQL資料庫有關的設定。

當然,Azure雲端運算平台上面還有其他得資料庫可以新增與使用,這就要留到後面有用到再說吧,不過我覺得其他新增資料庫的方式應該也是大同小異,與新建「MySQL」資料庫的方式不會差太多才對。

淺談雲端服務與市面上的各式雲端運算平台服務

前言

其實這個概念已經是老掉牙了,這個技術大概是在2008年開始有相關研究一直到現在,還是有很多人不知道這個最基礎的概念與雲端運算架構。

為什麼要知道這個概念?不知道不是也可以使用部署相關的服務也可以用的好好的嘛?

這個原因,其實主要如下:

  • 若是知道概念的話,才會知道在雲端運算平台上,每一種價格會是不一樣,需要依照目前自己需要的服務做選擇,而不是每次都在開VM,虛擬機器解決一切的問題,那個花費是很高昂的。
  • 另外一個原因,是因為,我目前服務公司所使用的Azure平台很花錢。
    • 從大家行為模式來看,其實可以發現,大家不會善用Azure平台上的服務
    • 而最終大家都去選擇最花錢的服務:開啟運算VM (IaaS)。

本文章,是要淺談何謂「雲端運算」,雲端運算中分成哪幾層,以及對應到目前市面上的雲端服務有哪幾層。

什麼是雲端運算?

簡單來說就是,把服務,運算等功能都部署到網路上,而網路上主機通常都是有好幾個機房所組織而成的,那整個各地機房組起來就稱為「雲」,那上去的服務你不知道放在哪個地方,只知道你的服務座落在某一個城市或是地點而已,確切的地方不知道。

服務與運算上雲端,有幾個好處:

  • 不需要自行管理伺服器server等相關工作,把那些時間節省並專心在開發服務上
  • 雲端平台上把所有服務與資源都切開,也就是把服務最小化,因此我們要部署一個服務,或是網頁應用程式,並不需要像以前一樣租一台server並從頭到尾建設自己要的環境。
  • 切成一個個服務就對應到一個容器(Container),這樣一來在管理與部署上會顯的更方便
  • 在價錢方面來說,開啟一個運算資源的虛擬機器,毋庸置疑在雲端運算平台上是一個奢侈的行為,而這樣的行為是最貴的,以一個容器化的概念去對應到一個實例(instance),這樣價錢是最便宜且實用

我認為的缺點如下:

  • 每個雲端運算平台服務所提供的功能不盡相同,需要多花額外的時間學習與設定,導致學習曲線較長。
  • 要達到善用雲端運算平台服務,需要有一些前置條件
    • 了解何謂容器化(Docker container)與虛擬機器(VM)的差別
    • 了解部署的整個流程
    • 了解與熟悉Linux作業系統上的指令操作

一般主機租用與雲端運算平台差異

在雲端運算平台這個概念還沒有出來以前,可能聽過,像是VPS,shared hosting以及dedicated hosting等服務。那這個跟雲端運算平台有什麼差別?其實差別蠻大的。

首先,先以傳統主機的介紹如下:

  • shared hosting,共享主機,他的架構很簡單,就是在一台機器上面,切出一個空間,讓你放置需要執行的程式,那這個空間對於整體主機來說所有的資源都是共享的,所以當資源很大的鄰居的時候,就會有很明顯的影響,比如說網頁速度載入會變慢等。慢慢的這種主機效率不佳之後,就逐漸式微了。
  • VPS,Virtual Private Server,全名叫做「虛擬私人主機」,這個指的是,會利用虛擬化的技術將一台實體主機區分成好幾個虛擬機器,這些虛擬機器並不會互相共用自己的資源,所以會比一般的共享主機要來的好。那主要的虛擬化技術有
    • KVM,這個會模擬Kernel出來,所以內部虛擬機器可以自行升級Kernel,也可以在此虛擬機器底下建置多個所需要的Docker container
    • OpenVZ,這個會與實體主機上的Kernel共用,所以無法自行更改Kernel,而也無法模擬出Docker container在此虛擬化出來的機器上
  • Dedicated hosting,實體主機,這其實就是一台或多台主機,完全可以按照自己的需求來建置與部署多個虛擬機器,自由度最高。

所以我們可以從上面得到一個表格:

比較的項目共享主機
Shared Hosting
虛擬私人主機
Virtual Private Server
實體主機
Dedicated Server
自由度?較高最高
資源共享?高,且資源會隨著鄰居而有影響較低,資源都是在一個既定空間上,自己使用無此問題
費用?較低較高
虛擬化技術?無,完全是一個放置網頁專案空間中,可以自行使用配置的資源與空間
效能?較低較高

雲端運算平台

在講雲端運算平台前,需要先知道雲端運算架構圖

首先,我們先從上述的架構圖中的最底層開始。

  • IaaS,指的是「基礎設施即服務」,由Wiki介紹可以知道:
    • 是提供消費者處理、儲存、網路以及各種基礎運算資源,以部署與執行作業系統或應用程式等各種軟體。
    • 可以控制作業系統、儲存裝置、已部署的應用程式,有時也可以有限度地控制特定的網路元件。
    • 與 PaaS 的區別是,用戶需要自己控制底層,實現基礎設施的使用邏輯。
    • 有提供IaaS的服務有:
      1. Amazon EC2
      2. Linode
      3. DigitalOcean
      4. OpenStack
      5. Azure Computing machine
      6. IBM Cloud resource computing machine
  • PaaS,指的是「平台即時服務」,由Wiki可以知道有幾個特點:
    • 提供使用者將雲端基礎設施部署與建立至用戶端
    • 藉此獲得使用程式語言、程式庫與服務
    • 使用者不需要管理與控制雲端基礎設施(包含網路、伺服器、作業系統或儲存)
    • 但是需要控制上層的應用程式部署與應用代管的環境
    • 將軟體研發的平台做為一種服務,以軟體即服務(SaaS)模式交付給用戶
    • PaaS的出現可以加快SaaS的發展,尤其是加快SaaS應用的開發速度
    • PaaS 提供軟體部署平台(runtime),抽象掉了硬體和作業系統細節,可以無縫地擴充(scaling)。
    • 開發者只需要關注自己的業務邏輯與開發,不需要關注底層。
    • 下面這些都屬於 PaaS。
      1. Heroku
      2. RedHat OpenShift
      3. Google App engine
      4. Amazon Elastic Beanstalk
      5. Azure Web App
  • SaaS,「軟體即時服務」,其特性如下:
    1. 在交付模式中雲端集中式代管軟體及其相關的資料,軟體僅需透過網際網路,而不須透過安裝即可使用。
    2. 用戶通常使用精簡用戶端經由一個網頁瀏覽器來存取軟體即服務。
    3. 建立與部署在PaaS上的服務。

雲端運算平台與傳統主機供應商比較

比較項目傳統主機供應商雲端運算平台服務
種類?有共享主機(Shared hosting)
有VPS(Virtual private server)
實體主機(dedicated server)
IaaS
PaaS
SaaS
價格?共享主機最便宜
VPS適中
實體主機較貴
IaaS較貴
PaaS適中
SaaS看提供服務廠商,通常比上述兩者便宜
開發者專注?除了共享主機,其他都需要再花額外的力氣做建置系統建置IaaS需要花額外力氣
利用PaaS部署可以花較多時間在SaaS做開發
服務效率?VPS與實體主機較好IaaS運算較高,但是需要自行調整
PaaS運算度隨著方案選擇做變動
SaaS取決於PaaS方案而變動表現

結論

有此可見,下列要點有:

  • 雲端運算會比一般傳統主機供應商要來的有優勢
    • 主要是把服務與運算資源機器切離,讓開發者可以專心在服務的開發與部署
    • 相關機器的設定與係數的優化就交給雲端運算平台的服務廠商或是專職的DevOps建置的IaaS就好
    • 盡量讓開發者少碰基礎設施運算中的設定越好,以便增加開發上的效率

參考資料

  • https://zh.wikipedia.org/wiki/%E5%9F%BA%E7%A4%8E%E8%A8%AD%E6%96%BD%E5%8D%B3%E6%9C%8D%E5%8B%99
  • https://zh.wikipedia.org/wiki/%E5%B9%B3%E5%8F%B0%E5%8D%B3%E6%9C%8D%E5%8A%A1
  • https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E5%8D%B3%E6%9C%8D%E5%8A%A1

那些在MySQL上的分區方式

前言

最近因緣際會之下,有一個與能源相關的研究案,需要處理將近2億筆的資料,如果只做到用SQL做查詢的時候,把常搜尋的欄位加入index索引,或是避免一些欄位重複,加入的主鍵primary key。

上述這些方式在資料量大的時候,容易產生一些瓶頸,因為利用BTree概念所作的索引是有搜尋的極限。

為了增加查詢的速度,我們可以考慮的方式如下:

  • 依照年度劃分出個別的資料表
  • 每個年度的資料表用月份為單位劃分成多個分區,總計是12個分區

分區的好處如下:

  • 在資料表中做查詢的時候,可以指定分區,那只會找指定分區中的資料,而不會整張資料表做查詢,進而加快查詢的速度
  • 在分區資料表中,可以允許我們指定那個分區進行刪除資料的動作
  • 從MySQL 5.6之後,可以允許我們指定一個或多個分區中找尋我們要的資料
  • 使用了分區之後,也會影響對資料修改相關的SQL語法,包含: DELETE, INSERT, REPLACE, UPDATE, and LOAD DATA, LOAD XML等

本文章,利用MySQL上面的分區功能實踐查詢的速度。

分區種類介紹

在講分區之前,我們可以從上面的示意圖知道,分區可以在Web應用程式在存取某個大張資料表的時候,先利用分區進行找尋範圍縮小的功能,接著在從指定的分區中尋找我們要的資料出來。分區的方式種類如下:

RANGE Partitioning

範圍分區,指的是自己定義某一個欄位,像是日期這種,就可以定義範圍做分區。

比如說,我們有一個2018 年整年的電量資料表叫做electric,裡面有電號,測量時間,測量的值等。所以依照敘述,我們可以建立出下面的資料表:


CREATE TABLE `electric_data_2018` (
`electricID` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '電號',
`date` datetime NOT NULL COMMENT '當下測量用電時間',
`mwh` double DEFAULT NULL COMMENT '用電量,單位wh'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='1000戶各用戶各時段用電量';

那我們可以利用測量的時間做分區,分區呈現的方式如下12個分區:

  • 2018-01-01到2018-01-31,即是「小於」2018-02-01 00:00:00
  • 2018-02-01到2018-02-28,即是「小於」2018-03-01 00:00:00
  • 2018-03-01到2018-03-31,即是「小於」2018-04-01 00:00:00
  • 2018-04-01到2018-04-30,即是「小於」2018-05-01 00:00:00
  • 2018-05-01到2018-05-31,即是「小於」2018-06-01 00:00:00
  • 2018-06-01到2018-06-30,即是「小於」2018-07-01 00:00:00
  • 2018-07-01到2018-07-31,即是「小於」2018-08-01 00:00:00
  • 2018-08-01到2018-08-31,即是「小於」2018-09-01 00:00:00
  • 2018-09-01到2018-09-30,即是「小於」2018-10-01 00:00:00
  • 2018-10-01到2018-10-31,即是「小於」2018-11-01 00:00:00
  • 2018-11-01到2018-11-30,即是「小於」2018-12-01 00:00:00
  • 2018-12-01到2018-12-31,即是「小於」2019-01-01 00:00:00

那以SQL方式建立帶有分區資料表方式如下:


ALTER TABLE `electric_data_2018`
PARTITION BY RANGE (TO_DAYS(`date`))
(
PARTITION p_201802 VALUES LESS THAN (TO_DAYS('2018-02-01 00:00:00')),
PARTITION p_201803 VALUES LESS THAN (TO_DAYS('2018-03-01 00:00:00')),
PARTITION p_201804 VALUES LESS THAN (TO_DAYS('2018-04-01 00:00:00')),
PARTITION p_201805 VALUES LESS THAN (TO_DAYS('2018-05-01 00:00:00')),
PARTITION p_201806 VALUES LESS THAN (TO_DAYS('2018-06-01 00:00:00')),
PARTITION p_201807 VALUES LESS THAN (TO_DAYS('2018-07-01 00:00:00')),
PARTITION p_201808 VALUES LESS THAN (TO_DAYS('2018-08-01 00:00:00')),
PARTITION p_201809 VALUES LESS THAN (TO_DAYS('2018-09-01 00:00:00')),
PARTITION p_201810 VALUES LESS THAN (TO_DAYS('2018-10-01 00:00:00')),
PARTITION p_201811 VALUES LESS THAN (TO_DAYS('2018-11-01 00:00:00')),
PARTITION p_201812 VALUES LESS THAN (TO_DAYS('2018-12-01 00:00:00')),
PARTITION p_201901 VALUES LESS THAN (TO_DAYS('2019-01-01 00:00:00')),
PARTITION p_max_future_dates VALUES LESS THAN MAXVALUE
);

  • 上述建立分區的意思就是,把「測量日期」欄位轉變成距離year 0有多少天數,將日期轉變成數字之後,我們就可以利用這個天數來進行所謂範圍分區的動作。
  • 其中,…..LESS THAN…..就是小於的意思,舉例來說,第一個分區指的是1月所有電量資料,則小於「2018-02-01 00:00:00」即是這個意思。
  • 當然,只要可以將天數轉換成數字當作範圍,都可以用來進行範圍分區,所以我們也可以轉換成UNIX TIMESTAMP的值做範圍分區。相關建立此分區方式如下:

ALTER TABLE `electric_data_2018`
PARTITION BY RANGE (UNIX_TIMESTAMP(`date`))
(
PARTITION p_201802 VALUES LESS THAN (UNIX_TIMESTAMP('2018-02-01 00:00:00')),
PARTITION p_201803 VALUES LESS THAN (UNIX_TIMESTAMP('2018-03-01 00:00:00')),
PARTITION p_201804 VALUES LESS THAN (UNIX_TIMESTAMP('2018-04-01 00:00:00')),
PARTITION p_201805 VALUES LESS THAN (UNIX_TIMESTAMP('2018-05-01 00:00:00')),
PARTITION p_201806 VALUES LESS THAN (UNIX_TIMESTAMP('2018-06-01 00:00:00')),
PARTITION p_201807 VALUES LESS THAN (UNIX_TIMESTAMP('2018-07-01 00:00:00')),
PARTITION p_201808 VALUES LESS THAN (UNIX_TIMESTAMP('2018-08-01 00:00:00')),
PARTITION p_201809 VALUES LESS THAN (UNIX_TIMESTAMP('2018-09-01 00:00:00')),
PARTITION p_201810 VALUES LESS THAN (UNIX_TIMESTAMP('2018-10-01 00:00:00')),
PARTITION p_201811 VALUES LESS THAN (UNIX_TIMESTAMP('2018-11-01 00:00:00')),
PARTITION p_201812 VALUES LESS THAN (UNIX_TIMESTAMP('2018-12-01 00:00:00')),
PARTITION p_201901 VALUES LESS THAN (UNIX_TIMESTAMP('2019-01-01 00:00:00')),
PARTITION p_max_future_dates VALUES LESS THAN MAXVALUE
);

若我們要看所有分區名稱在此資料表的資訊,我們可以使用下列的SQL做到。


SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='electric_data_2018';

當然,範圍分區也可以用在數值,比如說,我們可以利用用電量「mwh」這個欄位,將數值區分成下列幾塊:

  • partition p0 ( mwh < 100 )
  • partition p1 ( mwh < 500 )
  • partition p2 ( mwh <1000 )
  • partition p3 ( mwh <1500 )

相關SQL語法就會變成:


ALTER TABLE `electric_data_2018`
PARTITION BY RANGE (`mwh`)
(
PARTITION p0 VALUES LESS THAN (100),
PARTITION p1 VALUES LESS THAN (500),
PARTITION p2 VALUES LESS THAN (1000),
PARTITION p3 VALUES LESS THAN (1500)
);

若我們想要刪除某一個分區,我們可以使用下列的SQL語法做到:


ALTER TABLE electric_data_2018 TRUNCATE PARTITION p0;

LIST Partitioning

清單分區,指的是,假設一張資料表,已經有一個預設的集合,假設如下:

上述表格意思是:

  • 有一個欄位叫做「agent_code」表示這三個城市的代碼
  • City A代碼是1,2,3
  • City B代碼是4,5,6
  • City B代碼是7,8,9,10,11

那用LIST分區所建立SQL語法如下:


CREATE TABLE sale_mast2 (bill_no INT NOT NULL, bill_date TIMESTAMP NOT NULL,
agent_codE INT NOT NULL, amount INT NOT NULL)
PARTITION BY LIST(agent_code) (
PARTITION pA VALUES IN (1,2,3),
PARTITION pB VALUES IN (4,5,6),
PARTITION pC VALUES IN (7,8,9,10,11));

意思是:

  • 將欄位「agent_code」城市代碼當作LIST分區
  • 若代碼1,2,3的放在pA分區名稱中,亦即City A
  • 若代碼4,5,6的方在pB分區中,亦即City B
  • 若代碼7,8,9,10,11放在pC分區中,亦即City C

由上述的分區概念,我們可以知道幾件事情:

  • 使用LIST做分區是指的是那個欄位可以分類成不同的種類/集合

COLUMNS Partitioning

以欄位名稱做分區,指的是,將一組欄位並將裡面的值當作範圍或是集合進行分區的概念,那又可以分成:

  • RANGE COLUMN Partitioning
  • LIST COLUMN Partitioning

RANGE COLUMN Partitioning

我們可以直接看下列的SQL語法範例:


CREATE TABLE table3 (col1 INT, col2 INT, col3 CHAR(5), col4 INT)
PARTITION BY RANGE COLUMNS(col1, col2, col3)
(PARTITION p0 VALUES LESS THAN (50, 100, 'aaaaa'),
PARTITION p1 VALUES LESS THAN (100,200,'bbbbb'),
PARTITION p2 VALUES LESS THAN (150,300,'ccccc'),
PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE, MAXVALUE));

  • 我們建立一個資料表叫做「table3」,而裡面的欄位分別有:「col1」,「col2」,「col3」與「col4」
  • 前三個欄位分別依序排列成col1, col2, clo3並在每一個分區作為一組
  • 每一個值列表使用定義好的條件進行用值當作範圍的分區
  • 篩選的時候,裡面資料的欄位順序需要相同

LIST COLUMNS partitioning

跟先前的「list partitioning」有點類似,不過這是以「COLUMNS」欄位做它配的欄位列表分區。我們城市代碼列表如下:

我們可以從下面SQL語法知道:


CREATE TABLE salemast ( agent_id VARCHAR(15), agent_name VARCHAR(50),
agent_address VARCHAR(100), city_code VARCHAR(10))
PARTITION BY LIST COLUMNS(agent_id) (
PARTITION pcity_a VALUES IN('A1', 'A2', 'A3'),
PARTITION pcity_b VALUES IN('B1', 'B2', 'B3'),
PARTITION pcity_c VALUES IN ('C1', 'C2', 'C3', 'C4', 'C5'));

  • 首先,先建立一個叫做「salemast」的資料表,欄位裡面包含了帳單ID,帳單的地址,名稱城市代碼等
  • 建立三種不同的分區,每個分區分別代表三個城市,因為每一個城市代碼會有不同但是有類似,那就可以用這種方法,利用城市代碼用來「LIST COLUMN Partitioning」

除了使用欄位有城市代碼之外,也可以使用欄位有「DATE」或是「DATETIMESTAMP」的型別來做「LIST COLUMN Partitioning」分區

我們用上述的「electric_data_2018」資料表當作例子,那分區的定就可以改成:


ALTER TABLE `electric_data_2018`

PARTITION BY RANGE COLUMNS (`date`)

(

PARTITION p_201802 VALUES LESS THAN ('2018-02-01 00:00:00'),

PARTITION p_201803 VALUES LESS THAN ('2018-03-01 00:00:00'),

PARTITION p_201804 VALUES LESS THAN ('2018-04-01 00:00:00'),

PARTITION p_201805 VALUES LESS THAN ('2018-05-01 00:00:00'),

PARTITION p_201806 VALUES LESS THAN ('2018-06-01 00:00:00'),

PARTITION p_201807 VALUES LESS THAN ('2018-07-01 00:00:00'),

PARTITION p_201808 VALUES LESS THAN ('2018-08-01 00:00:00'),

PARTITION p_201809 VALUES LESS THAN ('2018-09-01 00:00:00'),

PARTITION p_201810 VALUES LESS THAN ('2018-10-01 00:00:00'),

PARTITION p_201811 VALUES LESS THAN ('2018-11-01 00:00:00'),

PARTITION p_201812 VALUES LESS THAN ('2018-12-01 00:00:00'),

PARTITION p_201901 VALUES LESS THAN ('2019-01-01 00:00:00')

);

上述的分區方式就是指:

  • 利用「date」欄位是「datetime」型別,並用LIST COLUMN分區中的「RANGE COLUMN」分區
  • 分區就是「RANGE BY COLUMN」,並以月份做分區,總共分成12個月

HASH Partitioning

HASH分區指的是,利用某一個欄位,把它做內建的MySQL HASH雜湊之後得到的結果,並指定分區個數讓MySQL進行預先分區的動作。SQL範例如下:


CREATE TABLE student (student_id INT NOT NULL,
class VARCHAR(8), name VARCHAR(40),
date_of_admission DATE NOT NULL DEFAULT '2000-01-01')
PARTITION BY HASH(student_id)
PARTITIONS 4;

KEY Partitioning

此種分區方法是HASH分區中裡面的其中一種,主要是用來把主鍵或是設定UNIQUE唯一值的欄位拿去做雜湊之後並透過指定分區的數量分散到那些分區之中。SQL範例如下:


CREATE TABLE table1 ( id INT NOT NULL PRIMARY KEY,
fname VARCHAR(25), lname VARCHAR(25))
PARTITION BY KEY()
PARTITIONS 2;


CREATE TABLE table2 ( id INT NOT NULL, fname VARCHAR(25),
lname VARCHAR(25),
UNIQUE KEY (id))
PARTITION BY KEY()
PARTITIONS 2;

Sub partitioning

子分區,就是把原先的第一層分區,再做細分下去。其SQL範例如下:


CREATE TABLE table10 (BILL_NO INT, sale_date DATE, cust_code VARCHAR(15),
AMOUNT DECIMAL(8,2))
PARTITION BY RANGE(YEAR(sale_date) )
SUBPARTITION BY HASH(TO_DAYS(sale_date))
SUBPARTITIONS 4 (
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN (2010),
PARTITION p3 VALUES LESS THAN MAXVALUE
);

上述這個分區指的是:

  • 先把銷售日期取得年份,當作第一層分區
  • 接著,再第二層子分區為p0, p1, p2, p3並分成1990, 2000, 2010年份
  • 所以這樣就會有4 * 4 = 16 個分區,即p0, p1, p2, p3各有4個分區

 

參考資料

  • http://acmeextension.com/mysql-table-partitioning
  • https://www.w3resource.com/mysql/mysql-partition.php
  • https://www.w3schools.com/sql/func_mysql_to_days.asp

如何透過Greenplum查詢Hadoop HDFS上的資料

前言

這篇文章,是我在開發的資料視覺化系統的過程中,所猜測的資料庫結構,因為這個開發系統是這樣的:

  • 資料視覺化系統由我們開發,資料庫以及資料來源的建置由另外一間案主請的外包公司負責
  • 當初在開發的時候,我從專案經理得到的訊息為:之後他們資料庫所使用的是「PostgreSQL」,所以我在開發與測試環境中都使用此資料庫作為我們系統測試資料庫
  • 在移入內部網路時候,才發現資料庫的架構之不對勁

本文章中,是在探討我在將系統移入的過程中,如何一步步的發現資料庫的架構

資料庫架構

原本一開始聽到的架構是,我以為是長這樣的

  • 「1」的部份,我認為是我們系統透過PostgrSQL溝通,查詢我們要的資料
  • 「2」的部份,我認為是有固定排程工作(?),Hadoop上的放在HDFS上的資料會匯入到PostgreSQL資料庫中
  • 當初我聽到這樣資料庫的架構,我一直處在半信半疑的狀態,不過為了系統開發的時程,那時候也沒有想太多,就直接先按照這樣的架構去建立一個PostgrSQL來當作測試資料庫後開始開發系統了

後來,到後面的移入內網的時候,我慢慢從它們講的名詞猜出其實是長下面這樣子的架構。

一開始我還猜資料(HDFS)部份有使用HBase,不過後來廠商說只使用HDFS。

其架構流程如下:

  • 「1」的部份,就是我們系統會去向Greenplum資料庫請求我們要的資料
  • 「2」的部份,則是我們Greenplum資料庫會向放在Hadoop的HDFS上的資料載入到資料表並做查詢

資料庫架構差異

這兩者其實有很大的差異,其差別如下:

  • 我所想的是利用完全的PostgreSQL的所有特性,我們面對查詢的部份只有SQL查詢優化
  • 廠商所設計的架構,是目的為了要讓存放在HDFS上面的檔案可以透過SQL方式查詢,因此使用了基於PostgreSQL所改良的資料庫,叫做Greenplum
  • 透過此資料庫,可以建立外部資料表並指定HDFS上的檔案進行檔案的載入

Greenplum 資料庫建立外部資料表

本章節,就是在描述如何使用建立外部資料表來載入HDFS上的資料。

首先,先要了解,Greenplum 可以當作是一個查詢的介面,透過它去查詢資料。

並藉由此機制建立readable external table,可以讀取的協定如下:

  • host file system檔案系統上的檔案
  • an NFS server上的檔案 (NFS=Network file system)
  • Hadoop file system (HDFS).

外部資料表(external table)相關介紹

從官方文件中可以得知,這類的external table有分成下列幾種

  • CREATE EXTERNAL TABLE or CREATE EXTERNAL WEB TABLE
    • 這類是建立一個readable可以讀取的外部資料表,通常是載入外部的儲存資料空間做使用
    • 那也不能在此外部資料表上建立索引(indexes)
    • UPDATE, INSERT, DELETE, or TRUNCATE 等操作都不被允許
  • CREATE WRITABLE EXTERNAL TABLE or CREATE WRITABLE EXTERNAL WEB TABLE
    • 這類是建立一個可寫入資料的外部資料表,通常是要載入外部資料庫之後,變成單獨的資料表且會存放在Greenplum資料庫中
    • 此類型的外部資料表允許可以INSERT插入資料的動作
    • SELECT, UPDATE, DELETE or TRUNCATE 等操作都不被允許

在Greenplum官方範例文件中,有如下的敘述:

假設我們有一個資料庫檔案,叫做 sales,分區資料表方式如下圖:

其分區資料表概念就是,有一個資料表是parent table,那依照以月分區的方式建立多個child tables

分區的方式如下:

  • range partitioning: division of data based on a numerical range, such as date or price. (這個指的是利用某個欄位可以做日期範圍的分區,如此一來就可以)
  • list partitioning: division of data based on a list of values, such as sales territory or product line. (列表分區,以銷售資料來說,就是可以用銷售資料的類型或是產品線種類進行分區)

Example Exchanging a Partition with an External Table

本章節,會以Greenplum官方文件做範例,透過官方提供的sales範例來呈現如何做到建立外部資料表並將它們做成分區,以及如何讀取它們。

從上面解釋外部資料表的不同類型,我們可以知道可寫跟可讀的資料表上的差異,那為了要讓資料表可以寫入資料與查詢,我們要做的建立外部資料表方式步驟如下:

首先,我們需要先建立一個名叫sales的資料表,其SQL語法如下:


CREATE TABLE sales (id int, year int, qtr int, day int, region text)
DISTRIBUTED BY (id)
PARTITION BY RANGE (year)
( PARTITION yr START (2010) END (2014) EVERY (1) ) ;

  • 裡面包含了id, 年分, qtr 某個訊息的值, 日期以及地區
  • 這裡分區的方式是用年份來區分,那在我們外包的資料庫廠商則是用日期(年月日)作為分區的範圍
  • 分區會有一個範圍,則是起始與結束的年份,那用日期則是,開始日期到結束的日期,以上述的例子來說,就是建立2010到2013年份之間的sales資料

接著,要確定讀取外部資料的來源是存放在哪個地方,在此範例中,假設外部要存取的檔案是放在 gpfdist (Greenplum Parallel File Server)

接著先建立一個可以寫入的外部資料表,相關SQL語法如下:


CREATE WRITABLE EXTERNAL TABLE my_sales_ext ( LIKE sales_1_prt_yr_1 )
LOCATION ( 'gpfdist://gpdb_test/sales_2010' )
FORMAT 'csv'
DISTRIBUTED BY (id) ;

接著在建立一個readable可以讀取的外部資料表


CREATE EXTERNAL TABLE sales_2010_ext ( LIKE sales_1_prt_yr_1)
LOCATION ( 'gpfdist://gpdb_test/sales_2010' )
FORMAT 'csv' ;

接著從leaf child partition上的資料寫進先前步驟建立的external table中


INSERT INTO my_sales_ext SELECT * FROM sales_1_prt_yr_1 ;

接著把先前建立的external table與目前存在的leaf child partition table互相交換,相關SQL語法如下:


ALTER TABLE sales ALTER PARTITION yr_1
EXCHANGE PARTITION yr_1
WITH TABLE sales_2010_ext WITHOUT VALIDATION;

上面步驟做完之後,資料表就會變成:

  • 原來external table sales_1_prt_yr_1 就會變成 leaf child partition table
  • 原本的leaf child partition table sales_2010_ext就會變成 external table

接著把sales_2010_ext資料表,因為交喚之後,我們不需要external table了,所以可以把它移除。


DROP TABLE sales_2010_ext ;

接著我們把分區名稱,做一個修改,因為本來,分區名稱在建立sales資料表的時候是下列的分區名稱:

  • yr_1
  • yr_2
  • yr_3
  • yr_4

那也可以透過更改分區名稱,把 sales_1_prt_yr_1 資料表標註成這是一個external table,那這是一個可選的工作。相關語法如下:


ALTER TABLE sales RENAME PARTITION yr_1 TO yr_1_ext ;

讀取外部資料

從上述的章節,我們可以初步的知道如何建立外部資料表載入外部檔案並成為分區資料表的方式。那如果是要載入其他檔案系統上的檔案呢?

我們可以以廠商使用的HDFS為例:

在官方文件中,Greenplum 5.2.0版本時候,gphdfs已經廢棄了,這是一個Greenplum設計的協定,並專門去讀取在HDFS上的檔案用的。

官方強烈建議使用它們設計的另一個協定,叫做PXF (The Greenplum Platform Extension Framework),這是一個Greenplum所設計的統一介面協定。

所以建立外部資料表方式就可以改成:


CREATE EXTERNAL TABLE pxf_hdfs_text(location text, month text, num_orders int, total_sales float8)
LOCATION ('pxf://data/pxf_examples/pxf_hdfs_simple.txt?PROFILE=hdfs:text')
FORMAT 'TEXT' (delimiter=E',');

CSV 檔,也可以使用上述的SQL語法去建立相關的資料表

結論

  • 開發的系統與資料庫分開給不同的人做,讓我感覺就是在一開始的時候,就要知道對方確切的資料庫架構會長什麼樣子,以便日後開發系統上的順利。
    而不是等到系統已經完成,進入維護的時候,我才發現資料庫的架構是長這個樣子。要再去改動SQL查詢的時候的成本就會變得很高。
  • 一個專案經理懂不懂技術,就可以從一個案子知道。
    因為當初我所聽到的架構與我和廠商DBA做完溝通之後,完全想到跟猜測的根本是不一樣的東西。
  • 這種資料庫架構來說,不能說是不好,這是一個可以用SQL上讀取放在HDFS或是其他檔案系統上的檔案,這樣的方式也是讓其他人能夠較輕易的讀取Haddop HDFS 上的檔案。

參考資料

  • NFS
  • https://gpdb.docs.pivotal.io/5200/pxf/access_hdfs.html
  • https://gpdb.docs.pivotal.io/5200/pxf/hdfs_text.html#profile_text
  •  http://docs.greenplum.org/5160/admin_guide/ddl/ddl-partition.html#topic_yhz_gpn_qs
    • 「Exchanging a Leaf Child Partition with an External Table」之章節
  • https://gpdb.docs.pivotal.io/5200/admin_guide/external/g-working-with-file-based-ext-tables.html
  • https://gpdb.docs.pivotal.io/560/ref_guide/sql_commands/CREATE_EXTERNAL_TABLE.html

如何改善MySQL 5.7新增資料的速度

前言

  • 在文章中,我們會介紹與示範MySQL資料庫中,如何改善新增資料的速度
  • 並對照改善前與改善後的速度做一個比較的結果

前置環境

  • Ubuntu 16.04
  • MySQL 5.7版本

MySQL資料庫引擎介紹

在討論增加資料速度之前,需要先探討MySQL兩個常用的資料庫引擎,因為選擇不同的資料庫引擎,在新增資料的速度上也是會有差異的。

MyISAM

  • 此資料庫引擎簡易的設計與使用,給入門MySQL的人好使用
  • 在查詢速度上會比InnoDB快
  • 可以支援全文字搜尋,像是 …..WHERE column_name LIKE ‘%full_text_search%’
    • 這個特性在5.6以後,InnoDB已經有支援了
  • 使用的硬碟量大小會比InnoDB小,因為MyISAM會針對資料量的大小進行壓縮

MyISAM限制

  • 沒有外來鍵(foreign keys)的支援
  • 沒有交易(transaction)的機制可以使用
  • 每一個資料表最多只有有64個索引(index)
  • 每個資料表最大大小上限為 256TB

InnoDB

  • 有支援交易機制(transaction)
  • Row-level table locking 資料表鎖定
    • 這裡鎖定指的是,在寫入資料的同時,有使用者做查詢的動作。
    • 在InnoDB上來說,遭遇到上述的狀況,查詢速度並不會慢到哪裡去。
    • 但在MyISAM上遇到上述情形的話,會從本來同一個SQL查詢時間只要0.01秒,變成要3秒
  • 支援外來鍵(foreign keys)
  • MyISAM相關特性較少會增加,日後版本(MySQL 8.0)上,增加相關新特性都會以InnoDB為主

InnoDB限制

  • 沒有全文搜尋(前面有提過),但在MySQL 5.6版本以後就沒有這個問題
  • 資料量無法有效的壓縮,在MySQL 5.5之後有ROW_FORMAT=COMPRESSED可以設定
  • 資料表最大到64TB儲存(取決於InnoDB page size)

資料庫引擎的選擇方向與重點

  • 以我們所需要儲存的電量資料來說
    • 用MyISAM要承受的缺點
      • 在寫入資料表的時候會鎖定(lock),導致在這同時查詢的速度會變慢(Table locking)
      • 似乎無法做Cluster等分散式資料庫,在MySQL官網中只有提及InnoDB與NDB
      • 只可以做Replication master-slave主從架構
    • 可以選擇MyISAM的原因是
      • 如果大部分時間都是用來讀取電量資料,效能會更好
      • 在此電量資料中,沒有transaction需求
      • 也沒有外來鍵需求
      • 資料量大小較小,有壓縮過
  • 如下圖顯示,我們可以知道,在資料數一樣多的情況下,MyISAM大小比InnoDB小

插入資料步驟

  • 連接到資料庫server
  • 傳送SQL查詢給server
  • server解析SQL query
  • 插入一筆(row) (1 x size of row)
  • 插入索引(indexes) (1 x number of indexes)
  • 關閉server
  • 因為每次的插入資料,都會重複上述一系列的動作,那在打開資料表會造成overhead
  • 資料在插入的時候,會一併插入定義的索引,因此每次插入一筆資料的時候會變慢。(假設index是使用B-tree indexes)

插入資料效能改善

  • 首先,我們先讓bulk_insert_buffer_size設定成較高的大小
  • 用LOAD DATA載入檔案方式取代INSERT,原因是因為用INSERT寫入資料表會較慢
  • 在輸入資料的資料表中,若有欄位有設定預設值,若不需要改變預設值的情況下,不要設定值給此欄位,這樣會增加插入資料的速度

bulk_insert_buffer_size的修改

 

 

 

 

如上附圖可以知道此設定的相關資訊,下面有幾點此設定的特性。

  • 若資料表使用的引擎為MyISAM的話,在加入資料時候,它會使用特別的類似像樹概念快取讓區塊插入資料更快。這會影響到INSERT與LOAD DATA
  • 這個設定的值限制取決於在每一個位元下與thread,快取樹大小
  • 設定0則關閉這個優化,預設設定值為:8 MB

bulk_insert_buffer_size設定

如下的SQL指令可以設定此bulk_insert_buffer_size值

  • SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 256
    • 這意思是將bulk_insert_buffer_size設定成:256 MB

MyISAM插入資料優化

  • 把bulk_insert_buffer_size設定成256 MB
    • 寫入2億筆用電量資料
      • 原本時間:2天左右
      • 設定後:5小時

InnoDB插入資料優化

  • 把bulk_insert_buffer_size設定成256 MB
    • 寫入2億筆用電量資料
      • 原本時間:2天左右
      • 設定後:約1天左右

因為InnoDB所支援的特性較多,因此需要將transaction commit,UNIQUE檢查與foreign key檢查關閉之後,再寫入資料會加速插入資料的時間。

關閉transaction auto commit check


set autocommit=0;

SQL query statement;

commit;

關閉unique checks


set unique_checks=0;

SQL query statement;

set unique_checks=1;

關閉foreign key checks


set foreign_key_checks=0;

SQL query statement;

set foreign_key_checks=1;

LOAD DATA使用方式

如下是使用LOAD DATA方式將用電量的CSV檔案匯入到資料表裡面

資料表的綱要如下:

欄位名稱欄位型態編碼與排序
electricIDVARCHAR(15)utf8mb4_unicode_ci
datedatetime
mwhdouble

LOAD DATA相關SQL語法如下:


LOAD DATA LOCAL INFILE '/path/to/electric_data.csv'

INTO TABLE electric_data_table

FIELDS TERMINATED BY ','

ENCLOSED BY '"'

LINES TERMINATED BY '\n'

IGNORE 1 ROWS;

由上述的SQL插入資料語法,我們可以得到如下的資訊:

  • 指定本地端的CSV檔,有指定的路徑
  • 並指定寫入的資料表
  • 每個欄位之間設定以逗號「,」隔開
  • 每個封閉的欄位使用「”」隔開
    • 這個意思是,因為有一些欄位中的值會包含「,」,為了要避免解析的錯誤,我們通常會將此資料的值用「”」括起來,這樣的話在解析時候這個值就會成功的解析出來
    • 舉例來說,有一行(row)資料為:fields,”this is for enclosed fields,”,value
      • 有設定enclosed by ‘”‘的話,這個「this is for enclosed fields,」就會當成一個這個欄位的值解析出來了
  • 每一行斷行的字元為「\n」
  • 忽略第一行,這可以取決於CSV檔案內容,因為有一些CSV檔案內容第一行為欄位名稱,我們需要將它省略掉,因為此欄位名稱不需要進入到資料表中

結論

評估項目名稱MyISAMInnoDB
需要全文字搜尋
(full-text search)
Yes5.6.4開始支援
需要交易
(transactions)
Yes
需要頻繁的查詢
(frequent select queries)
Yes
需要頻繁的新增,修改與刪除
(frequent select, insert,update)
Yes
需要資料表在插入同時,也有良好的查詢效果Yes
需要關聯式資料表設計
(foreign keys等)
Yes
  • 如果有頻繁的讀取,沒有頻繁的新增,修改與刪除→MyISAM
  • 若使用MySQL版本比5.6還舊且需要full text search→MyISAM

參考資料

  • https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html
  • https://gist.github.com/peter279k/225b7b4803b4f80400840777ed1583a3

作者群

Elasticsearch與MySQL上之資料查詢效率評估

前言

在本文章中,主要討論的是有關於Elasticsearch與MySQL資料庫之間對於資料查詢的速度間的差異與比較。(針對的是用電量資料做兩者查詢速度的評估,因為筆數較多)

透過我們所設計的查詢評估,來得到結論之外,同時也會有結論我們選擇哪一種資料庫來儲存我們的資料。

前置環境

在此文章開始前,有幾點需要去注意。

  • 主機:Ubuntu 16.04
  • Elasticsearch已經安裝好
  • MySQL也已經安裝好

資料集介紹

  • 我們所用的資料集是有關於共有約1000個用戶的用電資料
  • 一整年總共有總共有約2億筆的用電資料

MySQL

  • 我們使用的版本為:mysqld Ver 5.7.26-0ubuntu0.16.04.1 for Linux on x86_64 ((Ubuntu))
  • 它是一個關聯式的資料庫

用電資料在MySQL上的資料表設定

  • 用電資料量很大,有到2億筆的資料,欄位包含:測量日期date, 電號electricID與用電量mwh
  • 所以我們除了對此用電量資料裡的「測量日期」與「電號」做主鍵之外,我們也針對測量日期做分區(partition)並以月來區分
  • 那資料表部份就以年來區分,比如說是2018年的電量資料,則資料表名稱為:「electric_data_2018」

建立資料表SQL方式如下


CREATE TABLE `electric_data_2019` (
`electricID` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '電號',
`date` datetime NOT NULL COMMENT '當下測量用電時間',
`mwh` double DEFAULT NULL COMMENT '用電量,單位wh'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='1000戶各用戶各時段用電量';


電量資料分區方式如下


ALTER TABLE `electric_data_2019`
PARTITION BY RANGE (TO_DAYS(`date`))
(
PARTITION p_201902 VALUES LESS THAN (TO_DAYS('2019-02-01 00:00:00')),
PARTITION p_201903 VALUES LESS THAN (TO_DAYS('2019-03-01 00:00:00')),
PARTITION p_201904 VALUES LESS THAN (TO_DAYS('2019-04-01 00:00:00')),
PARTITION p_201905 VALUES LESS THAN (TO_DAYS('2019-05-01 00:00:00')),
PARTITION p_201906 VALUES LESS THAN (TO_DAYS('2019-06-01 00:00:00')),
PARTITION p_201907 VALUES LESS THAN (TO_DAYS('2019-07-01 00:00:00')),
PARTITION p_201908 VALUES LESS THAN (TO_DAYS('2019-08-01 00:00:00')),
PARTITION p_201909 VALUES LESS THAN (TO_DAYS('2019-09-01 00:00:00')),
PARTITION p_201910 VALUES LESS THAN (TO_DAYS('2019-10-01 00:00:00')),
PARTITION p_201911 VALUES LESS THAN (TO_DAYS('2019-11-01 00:00:00')),
PARTITION p_201912 VALUES LESS THAN (TO_DAYS('2019-12-01 00:00:00')),
PARTITION p_202001 VALUES LESS THAN (TO_DAYS('2020-01-01 00:00:00')),
PARTITION p_max_future_dates VALUES LESS THAN MAXVALUE
);


分區的意思就是將2019年1月到12月分式,用月來分區

電量資料表建立索引方式


ALTER TABLE `electric_data_2019`
ADD PRIMARY KEY (`electricID`,`date`),
ADD KEY `electricID` (`electricID`),
ADD KEY `date` (`date`);


因為一個電號在一個時間下只會有一筆值,有鑑於此,在主鍵設定上將電號和測量日期看成一組主鍵。

Elasticsearch

  • 我們使用的版本為:6.8
  • 它是一個非關聯式的資料庫
  • 每一個index為一個用戶,並以電號表示,並在底下document中存放用電資料
  • 內部document中,分別儲存:electricID, date與mwh這三個欄位

查詢速度評估

我們針對查詢方式如下:

  • 針對用電量資料做查詢評估
  • 指定某一個電號在六月的時候查詢所有的用電資料
  • 指定某一個電號在六月中某一天所有的用電量資料
  • 上述的兩種查詢方式各執行10次,並取得平均的時間
  • 查詢的動作皆在本地端完成

查詢速度評估結果

  • 指定某一個電號在六月的時候查詢所有的用電資料
    • MySQL: 平均查詢時間為:0.12秒
    • Elasticearch: 平均查詢時間為:0.28秒
  • 指定某一個電號在六月中某一天所有的用電量資料
    • MySQL: 平均查詢時間為:0.01秒
    • Elasticsearch: 平均查詢時間為:0.01秒

指定某一個電號在六月的時候查詢所有的用電資料所使用的bash script

evaluate_mysql_query_time.sh


#!/bin/bash
# DB: MySQL
# 指定某電號與月份下的所有資料

rm -f ./evaluate_mysql.sql
rm -f ./evaluate_mysql_result.txt

electric_number=$1
specific_month=$2
table_name="\`electric_data_2019\`"
sql_cmd=$(printf "select electricID, date, mwh from %s partition(p_%s) where electricID='%s';" "$table_name" "$specific_month" "$electric_number")

echo $sql_cmd >> ./evaluate_mysql.sql

counter=1
while [ $counter -le 10 ]
do
mysql -vvv -u root -p"password" -e"use electric_data; source evaluate_mysql.sql;" >> evaluate_mysql_result.txt
((counter++))
done

sum=0
evaluate_results=$(cat evaluate_mysql_result.txt | grep "rows in set" | awk '{print $5}' | sed 's/(//g')

for evaluate_result in $evaluate_results;
do
printf "execution time is %.2f sec\n" $evaluate_result
sum=$(echo "$sum+$evaluate_result" | bc)
done

echo "scale=2; $sum/10" | bc | awk '{printf "avaerage execution time is %.2f sec\n", $0}'

evaluate_es_query_time.sh


#!/bin/bash
# DB: ElasticSearch
# 指定某電號與月份下的所有資料

rm -f result.json

curl -o /dev/null -s -X PUT 127.0.0.1:9200/electric_number/_settings -d '{ "index.max_result_window" :"45000"}' -H "Content-Type: application/json"
printf "\n"

size=45000
start_date="20180601"
end_date="20180701"
counter=1
sum=0

form_data=$(printf '
{
"size": "%d",
"query": {
"range": {
"date": {
"gte": "%s",
"lt": "%s",
"format": "yyyyMMdd"
}
}
}
}
' $size $start_date $end_date)

while [ $counter -le 10 ]
do
execution_time=$(curl -o result.json -s -w '%{time_total}\n' -X GET "127.0.0.1:9200/electric_number/_search" -H 'Content-Type: application/json' -d "$form_data")

records=$(cat result.json | jq '.hits.hits | length')

sum=$(echo "scale=3; $sum+$execution_time" | bc)

counter=$(($counter+1))

done;

echo "scale=3; $sum/10" | bc | awk '{printf "average execution time is %.3f sec\n", $0}'

定某一個電號在六月中某一天所有的用電量資料所使用的bash script

evaluate_mysql_query_perday.sh


#!/bin/bash
# DB: MySQL
# 指定某電號與月份下的某一天所有資料

rm -f ./evaluate_mysql.sql
rm -f ./evaluate_mysql_result.txt

electric_number=$1
specific_month=$2
table_name="\`electric_data_2019\`"
sql_cmd=$(printf "select electricID, date, mwh from %s partition(p_%s) where electricID='%s' and date>='%s' and date<'%s';" "$table_name" "$specific_month" "$electric_number" "20190601" "20190602")

echo $sql_cmd >> ./evaluate_mysql.sql

counter=1
while [ $counter -le 10 ]
do
mysql -vvv -u root -p"password" -e"use electric_data; source evaluate_mysql.sql;" >> evaluate_mysql_result.txt
((counter++))
done

sum=0
evaluate_results=$(cat evaluate_mysql_result.txt | grep "rows in set" | awk '{print $5}' | sed 's/(//g')

for evaluate_result in $evaluate_results;
do
printf "execution time is %.2f sec\n" $evaluate_result
sum=$(echo "$sum+$evaluate_result" | bc)
done

echo "scale=3; $sum/10" | bc | awk '{printf "avaerage execution time is %.2f sec\n", $0}'

evaluate_es_query_perday.sh


#!/bin/bash
# DB: ElasticSearch
# 指定某電號與月份下的一天所有資料

rm -f result.json

counter=1
size=10000
start_date="20190601"
end_date="20190602"
sum=0
rows=0
while [ $counter -le 10 ]
do

form_data=$(printf '
{
"size": %d,
"query": {
"range": {
"date": {
"gte": "%s",
"lt": "%s",
"format": "yyyyMMdd"
}
}
}
}
' $size $start_date $end_date)

execution_time=$(curl -o result.json -s -w '%{time_total}\n' -X GET "127.0.0.1:9200/electric_number/_search" -H 'Content-Type: application/json' -d "$form_data")

records=$(cat result.json | jq '.hits.hits | length')

sum=$(echo "scale=4; $sum+$execution_time" | bc)

rm -f result.json

counter=$(($counter+1))

done;

echo "scale=4; $sum/10" | bc | awk '{printf "average execution time is %.4f sec\n", $0}'

結論

  • Elasticsearch
    • 由於提供的查詢API對於回應的資料數量有限制,預設是 10,000筆,為了要一次查詢便可以將所有筆數的資料查詢回來,在查詢之前,Elasticsearch都會修改查詢資料筆數的上限
  • MySQL
    • 資料表已經有優化過,並以指定分區的方式進行查詢
    • 查詢指定某個月與某一天的時候,與Elasticsearch之執行時間幾乎是一樣
    • 若超出非分區等方式的查詢SQL,執行時間上Elasticesearch較快
  • 若我們針對電號在用電資料表中做模糊查詢,例如:從用電資料表中找到電號裡面有「1234」的所有用電資料
    • MySQL:查詢約2分鐘
    • Elasticsearch:0.315秒
  • 查詢某一電號在用電資料表中的總筆數
    • MySQL:查詢時間為0.16秒左右
    • Elasticsearch:查詢時間為0.001秒左右
  • 因為在我們日後的服務上面,並未有模糊查詢的需求,在此考量之下,我們選擇使用了MySQL當作我們日後服務開發後面的資料庫儲存

參考資料

  • http://www.mysqltutorial.org/import-csv-file-mysql-table
  • https://github.com/moshe/elasticsearch_loader
  • https://stackoverflow.com/questions/15880154/how-do-i-create-a-partition-for-every-month-of-the-current-year

作者群

OWASP TechDay Taiwan 2019 心得

前言

身為一個網站後端兼前端的開發者,多少也是需要知道Web 應用程式安全相關的技術

OWASP,全名是「Open Web Application Security Project」。在我三年前的時候,我已經知道有OWASP Web Top 10的報告,內容在描述目前前十大的網站應用程式安全。

當然,有我們熟知的SQL injection, XSS, 還有 CSRF 跨站請求偽造等。

有攻擊的手法與防禦的方法。

那這次的Workshop我想去的原因是因為,我想要補充這個組織相關的發展。

剛好看到 OWASP 台灣社群有這個相關活動訊息,所以我就向公司申請了一下就去參加了。

議程感想

因為早上下個超大西北雨,有議程落掉了,因此我只擷取我聽到的部份。

我在OWASP的一千零一夜,Top 10的故事!

內容已經是後半段了,大部份是在介紹在OWASP社群裡面發生的事情,當志工的經歷,還有介紹目前OWASP目前有什麼樣的資源。

完全免費! 活用OWASP文件與工具強化資安

本議程,也是在講述在OWASP有什麼樣的資源,像是除了有Web Top 10之外,也有IoT Top 10,也有privacy Top 10等相關白皮書。

那也有講到一個重點,通常都是在網站應用程式開發得初期就要有資安危機意識,因為在軟體/系統開發期間,越後面期間,修漏洞所花費的成本與金錢越高。

舉例來說,在開發過程發現錯誤或是漏洞,修改大概是成本的5%,到了開發環境上線,像是Beta版本等,發現漏洞所花成本大概是成本的10%,但是到的線上環境的時候,要改成本已經來到成本的15%,那在營運一段過程中,發現有問題,要修正,已經是成本的25%了。

Discover Vulnerabilities in IoT devices

此議程是唯一技術有關的議程,由Bamboofox co-funder 陳仲寬大帶來的IoT裝置安全與研究。

看起來像是他之前所做的此方面研究的論文,描述整個IoT的架構,包含嵌入式作業系統,韌體(firmware),還有再更上層的應用程式等。

利用一連串方法,如猜測SQL組出的字串去猜測SQL查詢語法的注入點等。

內容是很豐富但是講者講到超過時間了XD,後面像是在趕火車的講過去,感覺要去看這幾篇引用的論文來看看。

才知道每種的方法跟詳細的對IoT裝置安全上所做的方法與分析。

工作坊感想

吃完午餐之後,接下來就是平行的工作坊時間了。主要有兩個議程在報名的時候可以做選擇。

分別是「Workshop-ZAP」與「Workshop-DVWA」前者是跟網路探測有關,而後者是跟網頁應用程式安全有關,那我本身是網站開發人員,自然想要對網站應用程式多一些的了解,因此我選擇了後者當做下午的Workshop

那一開始,講者使用他在CDX2.0平台上所建立的帳號作為練習此課程的環境。

因為透過此帳號,我們可以選定上面平台提供的上課課程包,透過開始上課課程包就可以讓我們輕易的部署好此課程所需要的學習環境。

接著安裝一些工具,像是「BurpSuite」,還有「Fortis SSL Client」等。

整個Workshop都圍繞在OWASP Web Top 10 的議題上,透過DVWA這個漏洞展示網頁應用程式上操作與教導該如何找到這些漏洞。

那我預計後面的文章,會有一篇介紹透過DVWA所操作得到的漏洞還有分析程式碼,也就是代碼審查。利用上述這樣的操作,來達到日後開發網站應用系統上的避免開發出漏洞的技巧。

參考資料