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 儲存服務」。

這一系列文章包括:

  1. PHP 應用程式執行環境
  2. 部署PHP應用程式
  3. 資料庫的選擇: MySQL or SQL Database
  4. 使用Windows Azure Storage – Blob storage 處理靜態檔案
  5. 使用Windows Azure Storage – Table Service處理 Session物件
  6. 使用Windows Azure Service Bus與其它系統進行通訊
  7. 實例說明:簡單購物網站實例

Table儲存服務簡介

Windows Azure 儲存體服務提供了多種資料儲存服務,Table 儲存服務是一種 NoSQL 的資料儲存服務,它適合用來儲存非關聯式的資料,並且能夠快速地用鍵值(Key)來存取,適合用在會產生大量資料的應用程式服務中。它的結構概念就像這張圖示:

Windows Azure Storage Table Service

一個 Windows Azure 儲存體帳號可以建立多個 Table,而資料則是儲存在 Table之中,每一筆儲存的資料(a set of properties)視為一個 Entity,它有以下幾個特性:

  1. 每一個 Entity 可以擁有 252 個屬性(property),系統會自動產生 3 個屬性,分別為 partition key、row key以及 timestamp。
  2. Entity 的階層為 Table -> Partition -> Row,也就是說同一個 Table 下的 partition keys 都是唯一的,而同一個 Partition 下的 row keys 也分別是唯一的。
  3. Entity 可儲存的資料大小上限是 1MB

如同大多數的 Windows Azure 服務一樣,你可以使用 RESTful Web Service的方式存取Table儲存服務的資料,不過本文章的例子會使用 Windows Azure SDK for PHP 來做介紹。(可參考前一篇文章介紹的安裝方式)

PHP 的 Session 物件

很多 PHP 應用程式會使用 Session 物件(PHP 中的程式中的 $_SESSION)來處理應用程式的「狀態」,比方說目前登入中的使用者身份、購物車的內容、編輯中的資料等等。而多數的 PHP 執行環境在預設狀況下都是以檔案系統來儲存 Session 物件的資料,所以一樣會碰到應用程式在擴展上的困難(前一篇文章提及的狀況),我們現在已經知道怎麼用 Windows Azure儲存體服務中的 Blob 儲存服務來儲存檔案,當然也可以使用 Blob 儲存體來處理 Session 物件,不過這裡會用 Table 儲存服務來示範。

PHP Session物件的實作

既然 PHP 預設用檔案操作的方式來儲存 Session 物件的資料,要改成 Table 儲存服務來儲存只要改掉 Session 物件的行為就好。還好這個任務還不必去改 PHP 直譯器的程式碼,PHP提供了一個簡單的作法:

  1. 實作 SessionHandlerInterface 介面,實作你處理 Session 資料的方式。
  2. 開始使用 $_SESSION 前,使用 session_set_save_handler() 方法設定自己設計的 SessionHandler。

所以我們的目標只要做出一個 SessionHandler,當它要去存取資料時使用 Table 儲存服務就好了。以下的實例會建立一個名為「phpsessions」的Table,然後 Session 資料都放在名為「sessions」的 Partition下,而 $_SESSION 物件的鍵值則作為 row key 來存放資料。

實作 SessionHandlerInterface

於是我們可以產生一個 WindowsAzureTableSessionHandler 的類別來實作 SessionHandlerInterface

接著逐一來看每一個方法如何實作。

建構與解構函式

每當PHP執行環境要使用 Session 物件時,就會呼叫 SessionHandler 的建構函式,所以在建構函式中可以透過Windows Azure SDK for PHP 來建立連接 Table 儲存服務的實體,同時也宣告當不使用 Session 物件時呼叫 session_write_close 函式。同樣地,解構函式就直接呼叫 session_write_close() 即可。

Open/Close 方法

Open 方法也是在開始使用 Session 物件時會呼叫的方法,因為我們使用 Table 儲存體服務不用特別開關檔案,不過這裡我順著 SDK 的設計:先試著取得 table,若是產生 exception 則建立 table。

Close 則是不做任何事,單純回傳 TRUE 表示運作正常。

Write 方法

當程式中使用了 $_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 時會用到)。

Read 方法

如果程式中使用 $val = $_SESSION['value']; 這樣的呼叫時,Session Handler 就會產生一個 read 方法的呼叫,'value' 便是作為 $sessionId 傳入方法,所以我們用它來作為 row key,與 table name (container) 以及 partition key (containerPartition) 組合後來取得資料,若操作產生 exception 表示還沒有這份資料,按照PHP的規格,回傳空字串。

如果順利取得 Entity,則按照我們寫入的方式逆向解開被 base64 編碼及 serialize 的字串,便能夠正確地回傳資料。

Destroy 方法

當 Session 物件被記憶體回收時,便會產生一個 destroy 的呼叫,這裡直接將 table name、partition key 以及row key 對應到的 Entity 刪除即可。

gc 方法

當PHP執行環境決定要進行 Session 物件的 garbage collection 操作時便會呼叫 gc 方法,這裡我們可以用 Table 儲存服務的搜尋語法,找出需要被清除的 session 物件,然後將這些 entities 刪除即可。

改寫後的Session物件

只要在呼叫 session_start(); 之前,加入像這樣的程式碼,那麼在應用程式中使用 $_SESSION 的方式完全不必更動,自然就會使用 Table 儲存服務來處理了。

完整的 WindowsAzureSessionHandler 實作可以參考這裡

結論

使用 Table 儲存服務來處理 Session 物件雖然也有運用到雲端儲存的優勢(資料穩定、容易擴充等),不過它也有它的限制(如:一個 Entity 只能儲存1MB的資料),要怎麼運用仍舊需要根據系統狀況評估。