在上一篇文章中,我主要向大家介绍了利用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)--并发和原子操作不可兼得的更多相关文章

  1. redis在.net架构中的应用(1)--使用servicestack连接redis(转)

    引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...

  2. redis在.net架构中的应用(1)--使用servicestack连接redis

    引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...

  3. redis在.net架构中的应用(1)--利用servicestack连接redis

    引言:作为少有的.net架构下的大型网站,stackoverflow曾发表了一篇文章,介绍了其技术体系,原文链接http://highscalability.com/blog/2011/3/3/sta ...

  4. 微信小程序大型系统架构中应用Redis缓存要点

    在大型分布式系统架构中,必须选择适合的缓存技术以应对高并发,实现系统相应的高性能,酷客多小程序经过慎重选型,选择了采用基于腾讯云服务的Redis弹性缓存技术,结合Redis官方推荐的.NET驱动类库S ...

  5. 39、生鲜电商平台-redis缓存在商品中的设计与架构

    说明:Java开源生鲜电商平台-redis缓存在商品中的设计与架构. 1. 各种计数,商品维度计数和用户维度计数 说起电商,肯定离不开商品,而附带商品有各种计数(喜欢数,评论数,鉴定数,浏览数,etc ...

  6. Java生鲜电商平台-redis缓存在商品中的设计与架构

    Java生鲜电商平台-redis缓存在商品中的设计与架构 说明:Java开源生鲜电商平台-redis缓存在商品中的设计与架构. 1. 各种计数,商品维度计数和用户维度计数 说起电商,肯定离不开商品,而 ...

  7. 微服务架构中的Redis

    了解如何将Redis与Spring Cloud和Spring Data一起使用以提供配置服务器,消息代理和数据库. Redis可以广泛用于微服务架构中.它可能是少数流行的软件解决方案之一,你的应用程序 ...

  8. 庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存

    一.介绍     1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...

  9. 分享一个CQRS/ES架构中基于写文件的EventStore的设计思路

    最近打算用C#实现一个基于文件的EventStore. 什么是EventStore 关于什么是EventStore,如果还不清楚的朋友可以去了解下CQRS/Event Sourcing这种架构,我博客 ...

随机推荐

  1. 方格填数-2015决赛C语言A组第一题

    在2行5列的格子中填入1到10的数字. 要求: 相邻的格子中的数,右边的大于左边的,下边的大于上边的. 如[图1.png]所示的2种,就是合格的填法.请你计算一共有多少种可能的方案.请提交该整数,不要 ...

  2. 常系数线性递推的第n项及前n项和 (Fibonacci数列,矩阵)

      (一)Fibonacci数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n项的快速求法(不考虑高精度). 解法: 考虑1×2的矩阵[f[n-2],f[n-1]].根据fibon ...

  3. css优化,提高性能

    CSS 优化主要是四个方面: 加载性能比如不要用 @import 等等,@import会影响css文件的加载速度,考虑加载性能时,主要是从减少文件体积.减少阻塞加载.提高并发方面入手,任何 hint ...

  4. JavaScript--事件对象(25)

    // JavaScript事件的一个重要的方面是它们拥有一些相对一致的特点,可以给开发提供强大的功能; // 最方便和强大的就是事件对象,它们可以帮你处理鼠标事件和键盘敲击方面的情况; // 此外还可 ...

  5. 设计模式(11)--Flyweight(享元模式)--结构型

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.模式定义: 享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 2.模式特点: 享元模 ...

  6. BZOJ3601 一个人的数论

    Description 定义 \[ f_k(n)=\sum_{\substack{1\leq i\leq n\\gcd(i,n)=1}}i^k \] 给出\(n=\prod_{i=1}^w p_i^{ ...

  7. LOJ#6085. 「美团 CodeM 资格赛」优惠券(set)

    题意 题目链接 Sol 考虑不合法的情况只有两种: 进去了 再次进去 没进去 但是出来了 显然可以用未知记录抵消掉 直接开个set维护一下所有未知记录的位置 最优策略一定是最后一次操作位置的后继 同时 ...

  8. ajax的type为get的时候报405错误,改成post就OK,这是为什么?老师写的get可以请求成功,我的就不行,附图

    报错: 我是在慕课跟着老师敲的,老师那边get可以请求成功,但是我这个地方type只能是post才请求成功,get就报405,不理解是为什么?

  9. 【java】开发中常用字符串方法

    java字符串的功能可以说非常强大, 它的每一种方法也都很有用. java字符串中常用的有两种字符串类, 分别是String类和StringBuffer类. Sting类 String类的对象是不可变 ...

  10. php 去除所有空格 包括中文空格圆角空格

    有的中文的半角,圆角空格或者段落符显示为空白的.可以用正则来处理 preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/","" ...