redis在.net架构中的应用(2)--并发和原子操作不可兼得
在上一篇文章中,我主要向大家介绍了利用servicestack连接redis以及一些redis的基本数据类型,传送门
本文中,我将通过一个具体应用场景为大家介绍redis中的并发和原子操作
其中用到的redis命令,请大家去redis官网查询http://www.redis.io/commands
一 一个投票统计的应用场景
假设我要做一个实时统计投票数的应用,这个投票总共有A、B、C、D四个选项,因为是一个高并发的场景,所以我准备用redis来存储投票数
我们首先利用redis-cli模拟这个过程,打开命令终端,新建一个hash类型的key,叫做TicketCount, 编号为1,然后我们将选项作为其field值,
redis命令如下:

然后我们利用servicestack模拟投票场景,代码如下:
static void Main(string[] args)
{ RedisClient[] redisCli = new RedisClient[]{
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", ),
new RedisClient("192.168.101.165", )
};
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "A");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "A");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "B");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "B");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "C");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "C");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "D");
});
ThreadPool.QueueUserWorkItem(o =>
{
testTicketCount(redisCli[], "D");
}); Console.Read();
}
/// <summary>
/// 对某个选项进行投票,投票数加1
/// </summary>
/// <param name="rediscli"></param>
/// <param name="field"></param>
internal static void testTicketCount(IRedisClient rediscli, string field)
{
int k = ;
for (int i = ; i <= ; i++)
{ k = int.Parse(rediscli.GetValueFromHash("TicketCount", field))+;
rediscli.SetEntryInHash("TicketCount", field, k.ToString());
}
}
我们设想的结果是A、B、C、D四个选项各获得了200票,但是对多线程比较熟悉的同学马上就能看出问题了,
事实上最终的结果是

没错,在一个线程执行GetValueFromHash和SetEntryInHash两条命令的时候,另一个线程修改了key的值,破坏了操作的原子性

这个过程中,A选项明显丢掉了一张投票。
二 Nosql中的原子性
要保证数据操作的原子性,在传统的RDBMS应用中,我们首先想到的就是事物和锁,但是在这个场景中,我们需要获得保证{get key;set key}这两步
操作的原子性,我们需要获得key的值,所以无法用到事物。
让我们回到nosql的本质上来,来谈谈锁的运用,有兴趣的同学可以看看关于nosql的CAP原则和传统的RDBMS的ACID原则:


从上图中,我们可以看到,NoSQL系统更加注重性能,是不保证一客户端的两个操作的原子性保证的
(redis中的事物比较特殊,我将会在下一篇文章中讨论)
三 利用hincrby
幸亏redis还提供hincrby命令,也就是直接对hset某个字段的值加上某个整数
也就是对某个hash key中的某个value 值 提供加一操作。我们可以将TicketCount函数修改一下:
internal static void testTicketCount(IRedisClient rediscli, string field)
{
int k = ;
for (int i = ; i <= ; i++)
{
rediscli.IncrementValueInHash("TicketCount", field, );
//k = int.Parse(rediscli.GetValueFromHash("TicketCount", field))+1;
//rediscli.SetEntryInHash("TicketCount", field, k.ToString());
}
}
但是问题是,如果换了一个应用场景,A中存储的不是数值而是字符串呢?
四 并发和原子操作
这两个特性是完全矛盾的,nosql的设计理念就是为了支持高并发,所以它注定就对原子操作的支持性不高。
因为原子操作必然要涉及到数据库级别的锁,会带来各种性能损耗。
至于redis中的事物,完全是和redis的实现机制有关的,我将会在下一篇文章中和大家讨论
有同学提到了乐观锁机制,servicestack中也已经实现了乐观锁,我也会在下一篇中提到
作者:Mars
出处:http://www.cnblogs.com/marsblog/
本文基于署名-非商业性使用 3.0中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 Mars (包含链接)
redis在.net架构中的应用(2)--并发和原子操作不可兼得的更多相关文章
- redis在.net架构中的应用(1)--使用servicestack连接redis(转)
引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...
- redis在.net架构中的应用(1)--使用servicestack连接redis
引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...
- redis在.net架构中的应用(1)--利用servicestack连接redis
引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...
- 微信小程序大型系统架构中应用Redis缓存要点
在大型分布式系统架构中,必须选择适合的缓存技术以应对高并发,实现系统相应的高性能,酷客多小程序经过慎重选型,选择了采用基于腾讯云服务的Redis弹性缓存技术,结合Redis官方推荐的.NET驱动类库S ...
- 39、生鲜电商平台-redis缓存在商品中的设计与架构
说明:Java开源生鲜电商平台-redis缓存在商品中的设计与架构. 1. 各种计数,商品维度计数和用户维度计数 说起电商,肯定离不开商品,而附带商品有各种计数(喜欢数,评论数,鉴定数,浏览数,etc ...
- Java生鲜电商平台-redis缓存在商品中的设计与架构
Java生鲜电商平台-redis缓存在商品中的设计与架构 说明:Java开源生鲜电商平台-redis缓存在商品中的设计与架构. 1. 各种计数,商品维度计数和用户维度计数 说起电商,肯定离不开商品,而 ...
- 微服务架构中的Redis
了解如何将Redis与Spring Cloud和Spring Data一起使用以提供配置服务器,消息代理和数据库. Redis可以广泛用于微服务架构中.它可能是少数流行的软件解决方案之一,你的应用程序 ...
- 庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存
一.介绍 1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...
- 分享一个CQRS/ES架构中基于写文件的EventStore的设计思路
最近打算用C#实现一个基于文件的EventStore. 什么是EventStore 关于什么是EventStore,如果还不清楚的朋友可以去了解下CQRS/Event Sourcing这种架构,我博客 ...
随机推荐
- Oracle- 复杂查询及总结
一.复杂查询 1. 列出至少有一个员工的所有部门编号.名称,并统计出这些部门的平均工资.最低工资.最高工资. 1.确定所需要的数据表: emp表:可以查询出员工的数量: dept表:部门名称: emp ...
- Python发送短信提醒
Python发送短信可借助腾讯云平台提供的短信服务 发送短信需要的及格参数: 1.SDK_AppID和SDK_Key 2.签名: 3.模板ID 下面贴出源码DEMO: from qcloudsms_p ...
- Connect the Cities(hdu3371)并查集(附测试数据)
Connect the Cities Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Java - "JUC" ReentrantReadWriteLock
Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock ReadWriteLock 和 ReentrantReadWriteLock介绍 ReadWriteLo ...
- js中Date 方法
Date (对象) Date 对象能够使你获得相对于国际标准时间(格林威治标准时间,现在被称为 UTC-Universal Coordinated Time)或者是 Flash 播放器正运行的操作系统 ...
- Hadoop HDFS 的 HttpFS
参考 Hadoop权威指南 第3章中3.4节 背景 要写一个操作HDFS的web后台(文件CRUD),虽然可以直接使用HDFS提供的FileSystem类然后通过get方法获取到一个Distribut ...
- Jquery 清除空白字符
$.grep(“jQuery数组”, function(n) { return $.trim(n).length > 0; }); /*仅过滤空数组,不过滤相同数组*/
- MySQL数据库图文安装详解及相关问题
(尊重劳动成果,转载请注明出处: http://blog.csdn.net/qq_25827845/article/details/53366444冷血之心的博客) 首先说明:安装目录中不能有中文和空 ...
- Python 基于python实现的http接口自动化测试框架(含源码)
基于python实现的http+json协议接口自动化测试框架(含源码) by:授客 QQ:1033553122 欢迎加入软件性能测试交流 QQ群:7156436 由于篇幅问题,采用百度网 ...
- 类与接口(五)java多态、方法重写、隐藏
一.Java多态性 面向对象的三大特性:封装.继承.多态. 多态的类型,分为以下两种: 编译时多态: 指的是 方法重载.编译时多态是在编译时确定调用处选择那个重载方法,所以也叫 静态多态,算不上真正的 ...