1、NoSQL简介html
NoSQL并非No SQL(再也不须要SQL),而是指Not Only SQL(不只仅只有SQL)。NoSQL并非用来替代关系型数据库的,而是在某些使用关系型数据库不合适的场景中,可使用NoSQL数据库进行优化,而在系统中主要的、常规的数据仍然使用关系型数据库。
经常使用的NoSQL数据库有Memcached、Redis、MongoDB等,其中前二者属于键值对数据库,后者属于文档数据库。它们都有各自的优缺点以及使用场景。
算法
2、Memcached介绍与安装数据库
Memcached是一个专门用来作缓存的数据库,缓存的数据都是在内存当中,当数据库重启以后,数据也就都丢失了。其至关于一个Dictionary键值对集合,根据Key值取Value值。缓存
从网上下载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实例中,以下图所示: