Membase Server 是我目前看到支援 Memcached 最專業的一套產品,因此花了些時間研究他,除此之外 Enyim Memcached Client 也是我目前看到與 Membase Server 整合度最高的 .NET 函式庫,以下是我這陣子的研究心得筆記。
Membase Server 注意事項
- 安裝時會取得當下的主機 IP 位址,如果事後發生 IP 異動會導致 Membase Server 的 Memcached 無法再寫入任何資料。
- 如果是自己的開發主機要安裝 Membase Server 以進行測試,建議執行以下指令重新註冊 Membase Server 的伺服器 IP 位址為 127.0.0.1,不過這樣設定的缺點是無法啟用自動複寫機制。如果是叢集架構下,就可以將 127.0.0.1 換成你的伺服器 IP 位址,或是不要加上 ns_1@127.0.0.1 這個參數就代表程式會自動取得目前 IP 位址。
cd /D "C:\Program Files\Membase\Server\bin"
service_stop.bat
service_unregister.bat
service_register.bat ns_1@127.0.0.1
service_start.bat
- 啟用自動複寫機制後不能隨意將主機重開機,必須按以下程序循序重開機,以免叢集發生找不到對方主機的狀況(遇到這種狀況也會導致資料無法寫入)
- 先透過 Node 1 的 Web Console 執行以下動作
- 移除 Node 2 (請使用 Remove 功能,而非 Fail-Over 喔)
- 執行 Rebalance 讓 Node 2 的資料先同步到 Node 1 來
- 到 Node 2 移除 Membase Server 並重新安裝 Membase Server,Node 2 安裝好之後重新加入 Membase Cluster ( 加入 Node 1 )
- 透過 Node 2 的 Web Console 執行以下動作
- 加入完成後必須重新執行 Rebalance 動作
- 移除 Node 1 (請使用 Remove 功能,而非 Fail-Over 喔)
- 執行 Rebalance 讓 Node 1 的資料先同步到 Node 2 來
- 到 Node 1 移除 Membase Server 並重新安裝 Membase Server,Node 1 安裝好之後重新加入 Membase Cluster ( 加入 Node 2 )
- 透過 Node 1 的 Web Console 執行以下動作
- 執行 Rebalance 讓 Node 2 的資料先同步到 Node 1 來
- 如何備份 Membase Server 的資料庫
- cd /D "C:\Program Files\Membase\Server\bin\ep_engine\management\"
- ".\mbbackup.exe" "C:/Program Files/Membase/Server/data/ns_1/default" "C:/%BackupFolderName%"
- 如何還原 Membase Server 的資料庫
- cd /D "C:\Program Files\Membase\Server\bin\ep_engine\management\"
- .\mbrestore -a "C:/%BackupFolderName%/default" "C:/%BackupFolderName%/default-0.mb" "C:/%BackupFolderName%/default-1.mb" "C:/%BackupFolderName%/default-2.mb" "C:/%BackupFolderName%/default-3.mb"
Enyim Memcached Client 注意事項
- 編譯 memcached-providers 的步驟如下 (需先安裝 msysgit 工具):
- 建立工作目錄 ( e.g. G:\MemcachedProvider )
- mkdir G:\MemcachedProvider
- cd /D G:\MemcachedProvider
- 取得最新原始碼
- git clone https://github.com/enyim/memcached-providers.git
- cd memcached-providers\lib
- git clone https://github.com/enyim/EnyimMemcached.git
- 啟動 Visual Studio 2010 進行編譯
- cd ..
- start MemcachedProviders.sln
- 透過原始碼自行編譯的組件版本永遠是 2.4.6.0,組件編號定義在 VersionInfo.targets 檔案裡。
- 透過原始碼自行編譯的組件版本會透過 localbuild.snk 強式名稱金鑰檔進行簽署 (可換成自己的)
- 在 EnyimMemcached 專案裡有個 build\build.ps1 指令檔,可用來自動編譯新的組件 (改過才能用)
也可直接執行專案根目錄下的 build.cmd 批次檔
如何使用 Enyim Memcached Client 提供的 ASP.NET Session Provider ( .NET 3.5 )
在 GitHub 上的 enyim 提供了好幾個子專案,其中有個 memcached-providers 專案同時提供了 ASP.NET 的 Session Provider 與 OutputCache Provider,但由於 OutputCache Provider 是從 .NET 4.0 才提供的,因此若要使用在 ASP.NET 3.5 的專案就必須小做修改重新建置。
1. 切換 MemcachedProviders 專案的目標 Framework 至 .NET Framework 3.5
2. 刪除 Microsoft.CSharp 參考
3. 刪除MemcachedOutputCacheProvider.cs 檔案
4. 重新建置,完工!
如何將 Enyim Memcached Client 安裝至既有 ASP.NET 專案 (僅需修正 web.config 檔案)
加入以下宣告到 <configSections> 區段內
<sectionGroup name="enyim.com">
<section name="memcached"
type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
</sectionGroup>
<section name="membase" type="Membase.Configuration.MembaseClientSection, Membase"/>
加入 enyim.com 區段(這段要給 memcached-providers 的 OutputCache Provider 用的)
<enyim.com>
<memcached protocol="Binary">
<servers>
<add address="127.0.0.1" port="11211"/>
</servers>
</memcached>
</enyim.com>
加入 membase 區段,這段是讓 Session Provider 與未來在程式中使用 Membase API 所需的
<membase>
<servers bucket="default">
<add uri="http://127.0.0.1:8091/pools/default"/>
</servers>
</membase>
如果要使用含密碼的 vBucket 的話,必須加入 bucketPassword 屬性 (非預設的 bucket 都需要密碼)
<membase>
<servers bucket="BucketName" bucketPassword="BucketPassword">
<add uri="http://127.0.0.1:8091/pools/default"/>
</servers>
</membase>
加入 ASP.NET Session Provider 的宣告
<sessionState customProvider="Memcached" mode="Custom">
<providers>
<add name="Memcached"
type="Enyim.Caching.Web.MembaseSessionStateProvider, Enyim.Caching.Web"/>
</providers>
</sessionState>
加入 ASP.NET OutputCache Provider 的宣告(僅限於 ASP.NET 4.0 可用)
<caching>
<outputCache defaultProvider="Memcached">
<providers>
<add name="Memcached"
type="Enyim.Caching.Web.MemcachedOutputCacheProvider, Enyim.Caching.Web" />
</providers>
</outputCache>
</caching>
加入 NLog 提供者的設定如下(加入 NLog 可以紀錄非常完整的 Memcached 的存取記錄)
加入以下宣告到 <configSections> 區段內 (新增以下第 5 行那段)
<sectionGroup name="enyim.com">
<section name="memcached"
type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
<section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
</sectionGroup>
<section name="membase" type="Membase.Configuration.MembaseClientSection, Membase"/>
加入 enyim.com 區段(這段要給 memcached-providers 看的)(新增以下第 3 行那段)
<enyim.com>
<log factory="Enyim.Caching.NLogFactory, Enyim.Caching.NLogAdapter" />
<memcached protocol="Binary">
<servers>
<add address="127.0.0.1" port="11211"/>
</servers>
</memcached>
</enyim.com>
如何在程式碼中使用 Membase API ( 只要以上 web.config 都設定好了,就可以很簡單的使用他 )
var section = ConfigurationManager.GetSection("membase") as IMembaseClientConfiguration;
if (section == null) throw new InvalidOperationException("Invalid config section: " + section);
var client = new Membase.MembaseClient(section);
object data = client.Get("SomeKey");
如果直接使用 var client = new Membase.MembaseClient(); 的話,會自動抓取 membase 這個區段的設定,不過並不會參考 bucket 與 bucketPassword 等額外的屬性。
為什麼預設的 OutputCache Provider 會使用 Memcached 而非 Membase 呢?
從原始碼來看,他預設的工廠類別使用 DefaultClientFactory 而該類別只會使用 MemcachedClient 而非 MembaseClient,也因此在會在 web.config 中有兩段 Section 的情況 ( 即 enyim.com/memcached 與 membase 兩種 ):
如果要改用 Membase 當 Client 的話,可以在 OutputCache 宣告的 Provider 地方加上 factory 屬性:
<caching>
<outputCache defaultProvider="Memcached">
<providers>
<add name="Memcached"
factory="Enyim.Caching.Web.MembaseClientFactory, Enyim.Caching.Web"
type="Enyim.Caching.Web.MemcachedOutputCacheProvider, Enyim.Caching.Web" />
</providers>
</outputCache>
</caching>
如何讓 Session Provider、OutputCache Provider 與 Membase API 各使用不同的 vBucket 呢?
重新定義 configSections 區段,並新增三段 membase 的設定:
- 第一段為預設的 membase 設定,使用 default vBucket
註: 這個 membase 區段加上了 keyTransformer 設定是為了當 key 為中文或特殊字元時也能寫入
- 第二段專門給 OutputCache Provider 使用,我們將輸出快取資料寫入 OutputCache vBucket
- 第三段專門給 Session Provider 使用,我們將輸出快取資料寫入 SessionState vBucket
<configSections>
<section name="membase"
type="Membase.Configuration.MembaseClientSection, Membase" />
<section name="membaseOutputCache"
type="Membase.Configuration.MembaseClientSection, Membase" />
<section name="membaseSession"
type="Membase.Configuration.MembaseClientSection, Membase" />
</configSections>
<membase>
<servers bucket="default">
<add uri="http://127.0.0.1:8091/pools/default" />
</servers>
<keyTransformer type="Enyim.Caching.Memcached.Base64KeyTransformer, Enyim.Caching" />
</membase>
<membaseCache>
<servers bucket="OutputCache" bucketPassword="OutputCache">
<add uri="http://127.0.0.1:8091/pools/default" />
</servers>
</membaseCache>
<membaseSession>
<servers bucket="SessionState" bucketPassword="SessionState">
<add uri="http://127.0.0.1:8091/pools/default" />
</servers>
</membaseSession>
最後來定義 OutputCache Provider 與 Session Provider,加上 section 屬性即可 注意:OutputCache Provider 必須明確指定 factory 屬性才能搭配 Membase vBucket 運作。
<caching>
<outputCache defaultProvider="Memcached">
<providers>
<add name="Memcached" section="membaseOutputCache"
factory="Enyim.Caching.Web.MembaseClientFactory, Enyim.Caching.Web"
type="Enyim.Caching.Web.MemcachedOutputCacheProvider, Enyim.Caching.Web" />
</providers>
</outputCache>
</caching>
以下是加上 Session Provider 並指定 membaseSession 區段的方法,加上 section 屬性即可
<sessionState customProvider="Memcached" mode="Custom">
<providers>
<add name="Memcached" section="membaseSession"
type="Enyim.Caching.Web.MembaseSessionStateProvider, Enyim.Caching.Web" />
</providers>
</sessionState>
最後在程式裡要叫用 MembaseClient 時傳入正確的 Section 名稱即可:
var section = ConfigurationManager.GetSection("membase") as IMembaseClientConfiguration;
if (section == null) throw new InvalidOperationException("Invalid config section: " + section);
var client = new Membase.MembaseClient(section);
object data = client.Get("SomeKey");
透過這種設定方式,就可以完全去除 <enyim.com> 這個區段的定義了!
最後提醒
如果要在 ASP.NET 中使用 MembaseClient 的話,建議將 MembaseClient 物件定義成一個靜態物件,好讓整個 ASP.NET 網站只會共用一個 MembaseClient 就好,MembaseClient 會幫你處理掉多執行緒下的鎖定與同步的問題。註:你每 new 一次 MembaseClient() 物件他會幫你建立起一個 SocketPool 喔,所以沒必要在程式裡創造那麼多 MembaseClient 物件。
public static MembaseClient client { get; private set; }
static CacheHelper()
{
var section =
ConfigurationManager.GetSection("membase") as IMembaseClientConfiguration;
if (section == null)
throw new InvalidOperationException("Invalid config section: " + section);
client = new Membase.MembaseClient(section);
}
相關連結