PHP on Windows Azure開發實戰(五) - 使用 Windows Azure Storage – Table Service 處理 Session 物件
前一篇文章介紹了在 Windows Azure 儲存體服務中,使用「Blob儲存服務」來儲存檔案,這一篇要介紹的是 Windows Azure 儲存體服務的另一個儲存服務 ——「Table 儲存服務」。Table 儲存服務是 Windows Azure 上提供的一種 NoSQL 資料儲存服務,它可以用來儲存多種格式的資料,並且以鍵值(key)來存取資料,這篇文章將以實作處理 PHP Session 物件的例子來介紹 Windows Azure 儲存體服務的「Table 儲存服務」。
這一系列文章包括:
- PHP 應用程式執行環境
- 部署PHP應用程式
- 資料庫的選擇: MySQL or SQL Database
- 使用Windows Azure Storage – Blob storage 處理靜態檔案
- 使用Windows Azure Storage – Table Service處理 Session物件
- 使用Windows Azure Service Bus與其它系統進行通訊
- 實例說明:簡單購物網站實例
Windows Azure 儲存體服務提供了多種資料儲存服務,Table 儲存服務是一種 NoSQL 的資料儲存服務,它適合用來儲存非關聯式的資料,並且能夠快速地用鍵值(Key)來存取,適合用在會產生大量資料的應用程式服務中。它的結構概念就像這張圖示:
一個 Windows Azure 儲存體帳號可以建立多個 Table,而資料則是儲存在 Table之中,每一筆儲存的資料(a set of properties)視為一個 Entity,它有以下幾個特性:
- 每一個 Entity 可以擁有 252 個屬性(property),系統會自動產生 3 個屬性,分別為 partition key、row key以及 timestamp。
- Entity 的階層為 Table -> Partition -> Row,也就是說同一個 Table 下的 partition keys 都是唯一的,而同一個 Partition 下的 row keys 也分別是唯一的。
- Entity 可儲存的資料大小上限是 1MB。
如同大多數的 Windows Azure 服務一樣,你可以使用 RESTful Web Service的方式存取Table儲存服務的資料,不過本文章的例子會使用 Windows Azure SDK for PHP 來做介紹。(可參考前一篇文章介紹的安裝方式)
很多 PHP 應用程式會使用 Session 物件(PHP 中的程式中的 $_SESSION
)來處理應用程式的「狀態」,比方說目前登入中的使用者身份、購物車的內容、編輯中的資料等等。而多數的 PHP 執行環境在預設狀況下都是以檔案系統來儲存 Session 物件的資料,所以一樣會碰到應用程式在擴展上的困難(前一篇文章提及的狀況),我們現在已經知道怎麼用 Windows Azure儲存體服務中的 Blob 儲存服務來儲存檔案,當然也可以使用 Blob 儲存體來處理 Session 物件,不過這裡會用 Table 儲存服務來示範。
既然 PHP 預設用檔案操作的方式來儲存 Session 物件的資料,要改成 Table 儲存服務來儲存只要改掉 Session 物件的行為就好。還好這個任務還不必去改 PHP 直譯器的程式碼,PHP提供了一個簡單的作法:
- 實作
SessionHandlerInterface
介面,實作你處理 Session 資料的方式。 - 開始使用
$_SESSION
前,使用session_set_save_handler()
方法設定自己設計的 SessionHandler。
所以我們的目標只要做出一個 SessionHandler,當它要去存取資料時使用 Table 儲存服務就好了。以下的實例會建立一個名為「phpsessions」的Table,然後 Session 資料都放在名為「sessions」的 Partition下,而 $_SESSION
物件的鍵值則作為 row key 來存放資料。
於是我們可以產生一個 WindowsAzureTableSessionHandler 的類別來實作 SessionHandlerInterface
:
接著逐一來看每一個方法如何實作。
每當PHP執行環境要使用 Session 物件時,就會呼叫 SessionHandler 的建構函式,所以在建構函式中可以透過Windows Azure SDK for PHP 來建立連接 Table 儲存服務的實體,同時也宣告當不使用 Session 物件時呼叫 session_write_close
函式。同樣地,解構函式就直接呼叫 session_write_close()
即可。
Open 方法也是在開始使用 Session 物件時會呼叫的方法,因為我們使用 Table 儲存體服務不用特別開關檔案,不過這裡我順著 SDK 的設計:先試著取得 table,若是產生 exception 則建立 table。
Close 則是不做任何事,單純回傳 TRUE 表示運作正常。
當程式中使用了 $_SESSION['value'] = $val;
這樣的敘述後,就是將資料寫入或更新 Session 物件中,所以在這個方法中,先用 $sessionId
(也就是 'value'
)與 table name (container) 以及 partition key (containerPartition) 組合起來取得 Entity,如果順利取得則更新內容,而要是產生 exception 則表示該 entity 不存在,就產生新的 Entity 來儲存資料。
在這裡我們使用兩個屬性來儲存 session 資料($val
也就是傳入的 $sessionData
):data 以及 expires,一個將資料 serialize 並且 base64 編碼後,以字串的方式儲存在 data 屬性內;另一個則是儲存資料更新時的時間戳記(時間戳記在後面 garbage collection 時會用到)。
如果程式中使用 $val = $_SESSION['value'];
這樣的呼叫時,Session Handler 就會產生一個 read 方法的呼叫,'value'
便是作為 $sessionId
傳入方法,所以我們用它來作為 row key,與 table name (container) 以及 partition key (containerPartition) 組合後來取得資料,若操作產生 exception 表示還沒有這份資料,按照PHP的規格,回傳空字串。
如果順利取得 Entity,則按照我們寫入的方式逆向解開被 base64 編碼及 serialize 的字串,便能夠正確地回傳資料。
當 Session 物件被記憶體回收時,便會產生一個 destroy 的呼叫,這裡直接將 table name、partition key 以及row key 對應到的 Entity 刪除即可。
當PHP執行環境決定要進行 Session 物件的 garbage collection 操作時便會呼叫 gc 方法,這裡我們可以用 Table 儲存服務的搜尋語法,找出需要被清除的 session 物件,然後將這些 entities 刪除即可。
只要在呼叫 session_start();
之前,加入像這樣的程式碼,那麼在應用程式中使用 $_SESSION
的方式完全不必更動,自然就會使用 Table 儲存服務來處理了。
完整的 WindowsAzureSessionHandler 實作可以參考這裡。
使用 Table 儲存服務來處理 Session 物件雖然也有運用到雲端儲存的優勢(資料穩定、容易擴充等),不過它也有它的限制(如:一個 Entity 只能儲存1MB的資料),要怎麼運用仍舊需要根據系統狀況評估。