一、NoSQL簡介
NoSQL并不是No SQL(不再需要SQL),而是指Not Only SQL(不僅僅只有SQL),NoSQL并不是用來替代關系型資料庫的,而是在某些使用關系型資料庫不合適的場景中,可以使用NoSQL資料庫進行優化,而在系統中主要的、常規的資料仍然使用關系型資料庫,
常用的NoSQL資料庫有Memcached、Redis、MongoDB等,其中前兩者屬于鍵值對資料庫,后者屬于檔案資料庫,它們都有各自的優缺點以及使用場景,
二、Memcached介紹與安裝
Memcached是一個專門用來做快取的資料庫,快取的資料都是在記憶體當中,當資料庫重啟之后,資料也就都丟失了,其相當于一個Dictionary鍵值對集合,根據Key值取Value值,
1、Memcached安裝
從網上下載Memcached-win64-1.4.4-14.zip安裝包,解壓后,通過管理員權限執行如下命令,可將其安裝成服務:
G:\MemcachedAfterInstall>memcached.exe -d install
2、Memcached可視化工具
TreeNMS是一款Redis、Memcached可視化客戶端工具,實作基于Web方式對Redis、Memcached資料庫進行管理、維護,可通過如下鏈接http://www.treesoft.cn/dms.html進行下載,
下圖即該工具的使用界面:

3、Memcached優缺點
優點:
1)多執行緒,可以充分利用CPU多核的處理性能;
2)做快取性能高;
缺點:
1)只能保存鍵值對資料,鍵值只能是字串,如果有物件資料只能自己序列化Json字串;
2)資料只保存在記憶體中,重啟后會丟失;
3)Key最大長度250個字符,Value最長1M;
三、在.Net Core中的使用
1、組件包的安裝與使用
在.Net Core專案中呼叫Memcached資料庫的資源,可以使用EnyimMemcachedCore客戶端組件包,
通過該組件向Memcached資料庫存入資料有三種模式,分別如下:
1)Set:存在則覆寫,不存在則新增;
2)Replace:如果存在則覆寫,并且回傳true;如果不存在則不處理,并且回傳false;
3)Add:如果不存在則新增,并且回傳true;如果存在則不處理,并且回傳false;
故,根據以上可知,如果沒有特殊要求一般用Set即可,
注意:Memcached資料庫中的key的長度最高為250個字符,value的值最大為1M,
2、案例演示
為了演示方便,創建了一個基于.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 =https://www.cnblogs.com/supersnowyao/p/= 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實體中,如下圖所示:


轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/3176.html
標籤:NoSQL
上一篇:Redis學習筆記(七) 資料庫
