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这种架构,我博客 ...
随机推荐
- 关于ASPxComboBox通过ClientInstanceName,js获取不到控件的问题
今天突然遇到一个很奇葩的问题 ASPxComboBox中设置了ClientInstanceName.但是通过cmbOrganization.GetValue()获取不到值. 报错cmbOrganiza ...
- 第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case
第20课-数据库开发及ado.net 可空值类型,资料管理器,多条件查询,Case SqlHelper using System; using System.Collections.Generic; ...
- 转载-iOS SDK开发
最近帮兄弟公司的做支付业务sdk,积累了 sdk 封装的经验!下面我会从零开始把我的 sdk 封装和调试经历分享给大家,希望能给看到这篇文章的人有所帮助! 本文我会从以下几个方面来讲述: Framew ...
- 【Tomcat】tomcat配置文件详解
Tomcat Server的结构图 结构框架,如下 属性表格 元素名 属性 解释 server(它代表整个容器,是Tomcat实例的顶层元素.由org.apache.catalina.Server接口 ...
- SWT table性能改善 -- 使用VirtualTable
在SWT程序中使用table展示数据时,如果数据过多,执行起来会比较慢,不过,我们可以借助VirtualTable来解决这一问题. Eclipse官网中关于VirtualTable的说明见:http: ...
- 9102年了,你还在用for循环操作集合?
本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 前段时间公司书架多了一本<Java8 实战>,毕竟久闻lambda的大名,于是借来一阅.这一看,简直 ...
- web自动化开发环境配置详解
1.安装 nodejs Grunt和所有grunt插件都是基于nodejs来运行的, https://nodejs.org/ 安装完成之后在终端 node -v 查看安装版本 2.安装 grunt-C ...
- Intellij Idea出现 unable to establish loopback connection
项目一运行就出现这个情况,好几次了,最后发现只要防火墙关闭,项目就可以运行成功.错误提示:“C:\Program Files\Java\jdk1.8.020\bin\java” -Xmx700m -D ...
- JavaScript实现时间查询
首先要引入js文件和css文件 <script src="jquery-1.11.2.min.js"></script> <script src=&q ...
- CentOS 7下安装Python3.5
CentOS 7下安装Python3.5 •安装python3.5可能使用的依赖 yum install openssl-devel bzip2-devel expat-devel gdbm-deve ...