The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

Membase Server 與 Enyim Memcached Client 使用心得筆記

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
  • 啟用自動複寫機制後不能隨意將主機重開機,必須按以下程序循序重開機,以免叢集發生找不到對方主機的狀況(遇到這種狀況也會導致資料無法寫入)
    1. 先透過 Node 1 的 Web Console 執行以下動作
      • 移除 Node 2 (請使用 Remove 功能,而非 Fail-Over 喔)
      • 執行 Rebalance 讓 Node 2 的資料先同步到 Node 1 來
    2. 到 Node 2 移除 Membase Server 並重新安裝 Membase Server,Node 2 安裝好之後重新加入 Membase Cluster ( 加入 Node 1 )
    3. 透過 Node 2 的 Web Console 執行以下動作
      • 加入完成後必須重新執行 Rebalance 動作
      • 移除 Node 1 (請使用 Remove 功能,而非 Fail-Over 喔)
      • 執行 Rebalance 讓 Node 1 的資料先同步到 Node 2 來
    4. 到 Node 1 移除 Membase Server 並重新安裝 Membase Server,Node 1 安裝好之後重新加入 Membase Cluster ( 加入 Node 2 )
    5. 透過 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 工具):
    1. 建立工作目錄 ( e.g.  G:\MemcachedProvider )
      1. mkdir G:\MemcachedProvider
      2. cd /D G:\MemcachedProvider
    2. 取得最新原始碼
      1. git clone https://github.com/enyim/memcached-providers.git
      2. cd memcached-providers\lib
      3. git clone https://github.com/enyim/EnyimMemcached.git
    3. 啟動 Visual Studio 2010 進行編譯
      1. cd ..
      2. 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-providersOutputCache 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 這個區段的設定,不過並不會參考 bucketbucketPassword 等額外的屬性。

 

為什麼預設的 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);
}

相關連結

留言評論