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这种架构,我博客 ...
随机推荐
- 设计模式之工厂方法(FactoryMethod)模式
在五大设计原则的基础上经过GOF(四人组)的总结,得出了23种经典设计模式,其中分为三大类:创建型(5种).结构型(7种).行为型(11种).今天对创建型中的工厂方法(FactoryMethod)模式 ...
- 数据结构与算法--最小生成树之Prim算法
数据结构与算法--最小生成树之Prim算法 加权图是一种为每条边关联一个权值或称为成本的图模型.所谓生成树,是某图的一棵含有全部n个顶点的无环连通子图,它有n - 1条边.最小生成树(MST)是加权图 ...
- Lucene 学习-安装 Elasticsearch 服务器
全文搜索属于最常见的需求,开源的 Elasticsearch 是目前全文搜索引擎的首选,它的底层是开源库 Lucene.但是我们没法直接使用 Lucene,必须自己写代码去调用它的接口. Elasti ...
- 最小公倍数(BNUOJ30195)
最小公倍数 Time Limit: 0 ms Case Time Limit: 0 ms Memory Limit: 0 KBSubmit: 17 Accepted: 1 This problem w ...
- 浙大月赛ZOJ Monthly, August 2014
Abs Problem Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge Alice and Bob is playing a ga ...
- sql语句之from子句
如何从表中查询一个字端的数据 select 字段名 from 表名: 演示:从s_emp表中把月薪查询出来 select salary from s_emp ; (分号代表结束) 如何从表中查询 ...
- hadoop学习之hdfs文件系统
一.hdfs的概念 Hadoop 实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS. Hadoop是Apache Lucene创始人Doug Cu ...
- Linux常用基本命令(more)
more命令 作用:相比cat一次性显示文件内容,more用于分页显示内容,less比more更强大,大多数的参数类似 more [option] [file] -num : 每页显示num行 +nu ...
- 说说gogoTester-nodejs 的实现
一直在使用goagent,所以对于查找google可用ip有了很大的兴趣,在github上面发现有一个项目是gogoTester,是用来查找google ip的,于是突发奇想自己用nodejs写了一个 ...
- JPA命名规则
jpa中方法的命名规则必须按照严格的要求来写.不能随便的命名方法名字,具体的方法操作如下. 参照方法地址:https://blog.csdn.net/csdnchen666666/article/de ...