NoSQL之一:Memcached

1、NoSQL簡介html

       NoSQL並非No SQL(再也不須要SQL),而是指Not Only SQL(不只僅只有SQL)。NoSQL並非用來替代關係型數據庫的,而是在某些使用關係型數據庫不合適的場景中,可使用NoSQL數據庫進行優化,而在系統中主要的、常規的數據仍然使用關係型數據庫。
  經常使用的NoSQL數據庫有Memcached、Redis、MongoDB等,其中前二者屬於鍵值對數據庫,後者屬於文檔數據庫。它們都有各自的優缺點以及使用場景。

算法

2、Memcached介紹與安裝數據庫

       Memcached是一個專門用來作緩存的數據庫,緩存的數據都是在內存當中,當數據庫重啓以後,數據也就都丟失了。其至關於一個Dictionary鍵值對集合,根據Key值取Value值。緩存

  一、Memcached安裝

         從網上下載Memcached-win64-1.4.4-14.zip安裝包。解壓後,經過管理員權限執行以下命令,可將其安裝成服務:服務器

G:\MemcachedAfterInstall>memcached.exe -d install

   二、Memcached可視化工具併發

    TreeNMS是一款Redis、Memcached可視化客戶端工具,實現基於Web方式對Redis、Memcached數據庫進行管理、維護。可經過以下連接http://www.treesoft.cn/dms.html進行下載。async

    下圖即該工具的使用界面:memcached



 3、在.Net Core中的使用工具

  一、組件包的安裝與使用優化

    在.Net Core項目中調用Memcached數據庫的資源,可使用EnyimMemcachedCore客戶端組件包。

    經過該組件向Memcached數據庫存入數據有三種模式,分別以下:

      1)Set:存在則覆蓋,不存在則新增;

      2)Replace:若是存在則覆蓋,而且返回true;若是不存在則不處理,而且返回false;

      3)Add:若是不存在則新增,而且返回true;若是存在則不處理,而且返回false;

    故,根據以上可知,若是沒有特殊要求通常用Set便可。

    注意:Memcached數據庫中的key的長度最高爲250個字符,value的值最大爲1M。

  二、案例演示

    爲了演示方便,建立了一個基於.Net Core3.1版本的WPF項目,界面以下:

 

 

 

 

 

 

 

 

 

     1)存儲數據、讀取數據 

public partial class MainWindow : Window {   private readonly MemcachedClient _memcachedClient;   private static readonly ILoggerFactory _loggerFactory = new LoggerFactory();   public MainWindow()   {     InitializeComponent();     var options = new MemcachedClientOptions();     options.AddServer("127.0.0.1", 11211);     _memcachedClient = new MemcachedClient(_loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options));   } } private void btnStorage_Click(object sender, RoutedEventArgs e) {   var result = _memcachedClient.Store(StoreMode.Set, "supersnow", "yao");   MessageBox.Show($"保存成功?{result}"); } private void btnRead_Click(object sender, RoutedEventArgs e) {   var result = _memcachedClient.Get("supersnow");   MessageBox.Show($"讀取結果:{result}"); }  

  

     2)存儲類數據、讀取類數據

private async void btnStorage_Class_Click(object sender, RoutedEventArgs e) {   var person = new Person   {     Name = "SuperSnow",     Age = 25   };   var result = await _memcachedClient.StoreAsync(StoreMode.Set, "person_key", person, TimeSpan.FromSeconds(3600));   MessageBox.Show($"保存Person成功?{result}"); }
private async void btnRead_Class_Click(object sender, RoutedEventArgs e) {   var result = await _memcachedClient.GetAsync<Person>("person_key");   if (result.Value == null)     MessageBox.Show("數據已經失效");   else     MessageBox.Show($"讀取Person結果:{result.Value.Name}:{result.Value.Age}"); } public class Person {   public string Name { get; set; }   public int Age { get; set; } }
  

  

     3)讀取數據異常

    對於讀取數據失敗時,返回結果爲false。可是,此時並不知道失敗的緣由是什麼,能夠經過以下方法獲取失敗緣由:

 private void btnRead_Exception_Click(object sender, RoutedEventArgs e) { var result = _memcachedClient.ExecuteRemove("abc"); MessageBox.Show($"結果:{result.Success},Message:{result.Message},Exception:{result.Exception},StatusCode:{result.StatusCode},InnerResult:{result.InnerResult.Message}"); } 

  

     4)Memcached Cas操做

    Cas操做相似於關係型數據庫中的「樂觀鎖」,查詢的時候會順帶查出一個Cas值,在寫入的時候會帶着這個Cas值,若是發現Cas值改變了,則說明已經有其餘操做提早修改了相應的值。本質上來講Cas就是用來解決併發問題,經過讀取一個值,而後作一些處理或判斷,而後再寫回到數據庫中,這種操做有可能產生併發問題。

private CasResult<Person> casResult; private void btnA_Read_Click(object sender, RoutedEventArgs e) { casResult = _memcachedClient.GetWithCas<Person>("person_key"); if (casResult.Result != null) MessageBox.Show($"讀取Person結果:{casResult.Result.Name}:{casResult.Result.Age}"); else MessageBox.Show("沒有結果"); } private void btnB_Save_Click(object sender, RoutedEventArgs e) { var result = _memcachedClient.GetWithCas<Person>("person_key"); if (result.Result.Age >= 25) result.Result.Age++; var tag = _memcachedClient.Cas(StoreMode.Set, "person_key", result.Result, result.Cas); if (tag.Result) MessageBox.Show("修改爲功"); else MessageBox.Show("修改失敗"); } private void btnA_Save_Click(object sender, RoutedEventArgs e) { if (casResult.Result.Age >= 25) casResult.Result.Age++; else casResult.Result.Age++; var tag = _memcachedClient.Cas(StoreMode.Set, "person_key", casResult.Result, casResult.Cas); if (tag.Result) MessageBox.Show("修改爲功"); else MessageBox.Show("修改失敗"); }

 

     5)Memcached集羣

    Memcached重啓以後,在短期內大量的請求會涌入數據庫,給數據庫形成巨大壓力,解決此類問題的方法就是使用集羣,即便用多Memcached服務器提供服務。

    除此以外,Memcached還有可能面臨「雪崩」問題,若是全部緩存設置過時時間是同樣的,或者失效時間在一個短距離的範圍內。那麼每隔一段時間就會形成一次數據庫訪問的高峯。此類問題的解決方法就是將不一樣緩存的緩存失效時間設置成不同,如對失效時間加上隨機數。

    Memcached集羣的節點之間不用進行通信和數據同步,只須要在多個服務器上啓動多個Memcached數據庫便可。客戶端決定了將數據寫入不一樣的Memcached實例,不用作主從複製操做。

    節點定位算法有不少種,最經常使用的就是Ketama算法,該算法根據Key算出一個hash值,而後根據hash值再得出服務器。以下例所示:

private readonly MemcachedClient _memcachedClient; private static readonly ILoggerFactory _loggerFactory = new LoggerFactory(); public MainWindow() { InitializeComponent(); var options = new MemcachedClientOptions(); options.AddServer("127.0.0.1", 11211); options.AddServer("127.0.0.1", 11212); options.NodeLocatorFactory = new DefaultNodeLocatorFactory(11211); _memcachedClient = new MemcachedClient(_loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options)); } private void btnA_Save_Cluster_Click(object sender, RoutedEventArgs e) { var person = new Person { Name = "張三", Age = 25 }; var result =  _memcachedClient.Store(StoreMode.Set, "1", person); MessageBox.Show($"保存Person成功?{result}"); } private void btnA_Read_Cluster_Click(object sender, RoutedEventArgs e) { var result = _memcachedClient.Get<Person>("1"); if (result == null) MessageBox.Show("數據已經失效"); else MessageBox.Show($"讀取Person結果:{result.Name}:{result.Age}"); } private void btnB_Save_Cluster_Click(object sender, RoutedEventArgs e) { var person = new Person { Name = "李四", Age = 23 }; var result = _memcachedClient.Store(StoreMode.Set, "2", person); MessageBox.Show($"保存Person成功?{result}"); } private void btnB_Read_Cluster_Click(object sender, RoutedEventArgs e) { var result = _memcachedClient.Get<Person>("2"); if (result == null) MessageBox.Show("數據已經失效"); else MessageBox.Show($"讀取Person結果:{result.Name}:{result.Age}"); } 

 

     經過以下命令分別啓動兩個Memcached實例:

G:\MemcachedAfterInstall>memcached.exe -p 11212 G:\MemcachedAfterInstall>memcached.exe -p 11211

    在TreeNMS系統中配置兩個數據庫鏈接:

    因爲Key=1和Key=2的hash值不一樣,因此緩存數據分別存在於兩個Memcached實例中,以下圖所示:

 

 

相關文章
相關標籤/搜索