`

使用memcached进行并发控制(转)

    博客分类:
  • java
 
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。

引子

一个使用缓存进行并发控制的讨论,让我学习到成本与收益间的平衡,以及何为真正的可用性......

防止并发有多种方式,本文只涉及使用缓存memcached控制。

并发场景:

     用例:SNS系统中具有高级会员资格的人发起活动。

     业务规则:1.一个人同时只能创建一个活动。2.具有高级会员资格。

     基本流程如下:









这个流程中存在明显的并发问题,当进程A校验过会员M有资格,并且为创建过活动,但为开始执行创建操作,此时另一个进程B也进行了规则判断,顺利通过,并完成创建操作,此时A继续执行,则会产生两条M的活动。(这个并发场景很简单,很普遍)

最初的解决方案:

     计划利用memcached的add操作的原子性来控制并发,具体方式如下:

     1.申请锁:在校验是否创建过活动前,执行add操作key为memberId,如果add操作失败,则表示有另外的进程在并发的为该memberId创建活动,返回创建失败。否则表示无并发

     2.执行创建活动

     3.释放锁:创建活动完成后,执行delete操作,删除该memberId。

问题:

     如此实现存在一些问题:

     1.memcached中存放的值有有效期,即过期后自动失效,如add过M1后,M1失效,可以在此add成功

     2.即使通过配置,可以使memcached永久有效,即不设有效期,memcached有容量限制,当容量不够后会进行自动替换,即有可能add过M1后,M1被其他key值置换掉,则再次add可以成功。

     3.此外,memcached是基于内存的,掉电后数据会全部丢失,导致重启后所有memberId均可重新add。

应对问题:

     针对上述的几个问题,根本原因是add操作有时效性,过期,被替换,重启,都会是原来的add操作失效。解决该问题有两个方法:

     1.采用持久化的缓存解决方法,如TT(Tokyo Tyrant:http://fallabs.com/tokyotyrant/)

     2.减轻时效性的影响,使用memcached CAS(check and set)方式。

     第一种不必解释了,很简单,原来的所有问题都是时效性惹得祸,时效性源于memcached是基于内存的,那么采用持久话存储的TT可以彻底根治这个问题。

     第二种方式需要简单介绍下:

     memcached中除了add操作是原子的,还有另外两个操作也是原子的:incr和decr,使用CAS模式即:

     1.预先在memcached中设置一个key值,假设为CREATKEY=1

     2.每次创建活动时,在规则校验前先get出CREATEKEY=x;

     3.进行规则校验

     4.执行incr CREATEKEY操作,检验返回值是否为所期望的x+1,如果不是,则说明在此期间有另外的进程执行了incr操作,即存在并发,放弃更新。否则

     5.执行创建活动

     对比这两种方法,从效果上看可以发现第一种时100%可靠的,不存在问题;第二种,可能存在误判,即本来不存在并发,却被判为并发,如缓存重启,或key值失效后,incr值可能不同于期望值,导致误判。

     但是从成本上考虑,TT是持久化的缓存解决方案,完美意味着高成本,我们必须维护持久化数据,而使用memcached的CAS方式,可以以几乎0成本的方式解决时效性问题,尽管存在一点小缺陷,但这种缺陷可以通过简单的重试即可解决。考虑实际的产出比,采用memcached的CAS方式更适合实际情况。

     成本与收益间的平衡,做科学与做工程的区别~】




应用场景分析:

       如原来MEMCACHED中的KES的内容为A,客户端C1和客户端C2都把A取了出来,C1往准备往其中加B,C2准备往其中加C,这就会造成C1和C2执行后的CACHE KEYS要么是AB要么是AC,而不会出现我们期望的ABC。这种情况,如果不是在集群环境中,而只是单机服务器,可以通过在写CACHE KEYS时增加同步锁,就可以解决问题,可是在集群环境中,同步锁是显然解决不了问题的。

memcached是原子的吗?宏观
         所有的被发送到memcached的单个命令是完全原子的。如果您针对同一份数据同时发送了一个set命令和一个get命令,它们不会影响对方。它们将被串行化、先后执行。即使在多线程模式,所有的命令都是原子的;命令序列不是原子的。如果您通过get命令获取了一个item,修改了它,然后想把它set回memcached,我们不保证这个item没有被其他进程(process,未必是操作系统中的进程)操作过。在并发的情况下,您也可能覆写了一个被其他进程set的item。
memcached 1.2.5以及更高版本,提供了gets和cas命令,它们可以解决上面的问题。如果您使用gets命令查询某个key的item,memcached会 给您返回该item当前值的唯一标识。如果您覆写了这个item并想把它写回到memcached中,您可以通过cas命令把那个唯一标识一起发送给 memcached。如果该item存放在memcached中的唯一标识与您提供的一致,您的写操作将会成功。如果另一个进程在这期间也修改了这个 item,那么该item存放在memcached中的唯一标识将会改变,您的写操作就会失败。

微观分析

memcache为了避免一些竞争,加入了一些特殊原子操作:add cas incr decr

"add" means "store this data, but only if the server *doesn't* already;

“cas” is a check and set operation which means “store this data but only if no one else has updated since I last fetched it.” ;

它们的实现原理基于CAS(check and save)模式:

下面是一个全新的CAS模式实现:

     1.预先在memcached中设置一个key值,假设为CREATKEY=1

     2.每次创建活动时,在规则校验前先get出CREATEKEY=x;

     3.进行规则校验

     4.执行incr CREATEKEY操作,检验返回值是否为所期望的x+1,如果不是,则说明在此期间有另外的进程执行了incr操作,即存在并发,放弃更新。否则

     5.执行创建活动

memcached保存的key value都有一个唯一标识casUnique,在进行incr decr操作时,首先获取casUnique,执行incr,检验返回值是否casUnique+1,如果是,则更新,否则,失败不更新!

尽管这种设计在处理并发时还存在缺陷,但可以通过简单的重试来解决问题!

接口分析:

返回MemcachedItem对象:

public MemcachedItem gets(String key) {
               return client.gets(key);
          }

public MemcachedItem gets(String key, Integer hashCode) {
                   return gets(OPCODE_GET, key, hashCode, false);
         }

普通的get方法,返回Value对象

public Object get(String key) {
              return client.get(key);
         }

casUnique:是唯一标识
        public boolean cas(String key, Object value, long casUnique) {
             return client.cas(key, value, casUnique);
        }

public boolean cas(String key, Object value, long casUnique) {
               return set(OPCODE_SET, key, value, null, null, casUnique, primitiveAsString);
          }

MemcachedItem类结构:

public final class MemcachedItem {
              public long casUnique;
               public Object value;

}

其它约束:

32位无符号整数

下面一片文章是对memcache add原子性实际应用的使用:

原文出自:http://blog.csdn.net/jiangbo_hit/article/details/6211704

引子

一个使用缓存进行并发控制的讨论,让我学习到成本与收益间的平衡,以及何为真正的可用性......

防止并发有多种方式,本文只涉及使用缓存memcached控制。

并发场景:

     用例:SNS系统中具有高级会员资格的人发起活动。

     业务规则:1.一个人同时只能创建一个活动。2.具有高级会员资格。

     基本流程如下:






这个流程中存在明显的并发问题,当进程A校验过会员M有资格,并且为创建过活动,但为开始执行创建操作,此时另一个进程B也进行了规则判断,顺利通过,并完成创建操作,此时A继续执行,则会产生两条M的活动。(这个并发场景很简单,很普遍)

最初的解决方案:

     计划利用memcached的add操作的原子性来控制并发,具体方式如下:

     1.申请锁:在校验是否创建过活动前,执行add操作key为memberId,如果add操作失败,则表示有另外的进程在并发的为该memberId创建活动,返回创建失败。否则表示无并发

     2.执行创建活动

     3.释放锁:创建活动完成后,执行delete操作,删除该memberId。

问题:

     如此实现存在一些问题:

     1.memcached中存放的值有有效期,即过期后自动失效,如add过M1后,M1失效,可以在此add成功

     2.即使通过配置,可以使memcached永久有效,即不设有效期,memcached有容量限制,当容量不够后会进行自动替换,即有可能add过M1后,M1被其他key值置换掉,则再次add可以成功。

     3.此外,memcached是基于内存的,掉电后数据会全部丢失,导致重启后所有memberId均可重新add。

应对问题:

     针对上述的几个问题,根本原因是add操作有时效性,过期,被替换,重启,都会是原来的add操作失效。解决该问题有两个方法:

     1.采用持久化的缓存解决方法,如TT(Tokyo Tyrant:http://fallabs.com/tokyotyrant/)

     2.减轻时效性的影响,使用memcached CAS(check and set)方式。

     第一种不必解释了,很简单,原来的所有问题都是时效性惹得祸,时效性源于memcached是基于内存的,那么采用持久话存储的TT可以彻底根治这个问题。

     第二种方式需要简单介绍下:

     memcached中除了add操作是原子的,还有另外两个操作也是原子的:incr和decr,使用CAS模式即:

     1.预先在memcached中设置一个key值,假设为CREATKEY=1

     2.每次创建活动时,在规则校验前先get出CREATEKEY=x;

     3.进行规则校验

     4.执行incr CREATEKEY操作,检验返回值是否为所期望的x+1,如果不是,则说明在此期间有另外的进程执行了incr操作,即存在并发,放弃更新。否则

     5.执行创建活动

     对比这两种方法,从效果上看可以发现第一种时100%可靠的,不存在问题;第二种,可能存在误判,即本来不存在并发,却被判为并发,如缓存重启,或key值失效后,incr值可能不同于期望值,导致误判。

     但是从成本上考虑,TT是持久化的缓存解决方案,完美意味着高成本,我们必须维护持久化数据,而使用memcached的CAS方式,可以以几乎0成本的方式解决时效性问题,尽管存在一点小缺陷,但这种缺陷可以通过简单的重试即可解决。考虑实际的产出比,采用memcached的CAS方式更适合实际情况。

     成本与收益间的平衡,做科学与做工程的区别~

http://blog.csdn.net/jiangbo_hit/article/details/6211704
http://zhengjunwei2007.blog.163.com/blog/static/3529794220117325112464/
分享到:
评论

相关推荐

    Memcached使用点滴 服务集成平台需要对服务有所监控,包括访问频率控制以及访问次数控制

    在服务集成平台中,可以使用 Memcached 的计数器功能来实现访问频率控制和访问次数控制。例如,可以使用 Memcached 的incr 命令来增加计数器的值,每当服务被访问时,计数器的值就会增加。如果计数器的值超过了指定...

    Memcached使用点滴总结分享.docx

    作者选择了使用 Memcached 作为缓存机制,因为它可以集中式地存储数据,并且可以解决高并发下的读写不一致性问题。 3. 实现频率控制 作者在实现频率控制时,需要记录访问数据和分析计数器,以决定是否将用户列入黑...

    memcached C++ 客户端 源码

    **标题与描述解析** ...综上所述,这份源码涵盖了memcached客户端的实现,涉及了网络编程、并发控制、内存管理等多个C++编程的关键领域,同时也体现了良好的软件工程实践,如测试驱动开发和持续集成。

    memcached工具类源码

    - **并发控制**:对于多线程环境,可能需要使用锁或其他并发控制机制,确保数据的一致性和完整性。 5. **性能优化** - **预取策略**:根据访问模式预测可能需要的数据,提前加载到缓存中,减少延迟。 - **缓存...

    memcached和js版本控制

    在IT行业中,版本控制和缓存管理是两个关键的领域,尤其在开发高并发、高性能的Web应用时显得尤为重要。本文将围绕“memcached”和“js版本控制”这两个主题展开,分享一些在实际项目中积累的技巧。 首先,让我们...

    memcached+tomcat的session共享

    - 数据一致性:虽然memcached提供了一定程度的并发控制,但并非强一致性模型,可能在某些情况下出现数据不一致。 - 依赖外部服务:应用的正常运行依赖于memcached服务的可用性,一旦memcached出现问题,可能影响整个...

    内核态memcached模块

    3. **锁和并发控制**:由于在内核环境中,多线程和中断处理是常见的,因此内核态memcached必须考虑并发访问的同步问题,可能使用自旋锁、读写锁等同步原语来保证数据一致性。 4. **网络协议栈集成**:内核态的...

    Memcached使用点滴.docx

    在本文中,我们将探讨 Memcached 的使用及其在服务访问控制中的应用。 首先,Memcached 的客户端库是其易用性的重要组成部分。文中提到了 Whalin 的 Java 客户端,这是一个高效的实现,提供了对 Memcached 协议的...

    memcached命令

    3. **-d**:控制memcached服务的状态,支持以下操作: - `start`:启动memcached服务。 - `restart`:重启memcached服务。 - `stop` 或 `shutdown`:停止memcached服务。 - `install`:安装memcached服务。 - `...

    Tomcat memcached Session依赖jar包

    6. **性能优化**:通过调整memcached客户端和Tomcat的Session Manager配置,可以优化Session的读写性能,如设置合适的超时时间、连接池大小和并发控制等。 7. **故障转移和一致性**:由于memcached是无状态的,所以...

    memcached全面剖析.pdf

    通过案例研究,我们可以了解到如何在服务器配置、数量、memcached进程管理、客户端使用方法等方面进行优化。此外,memcached的兼容性也让它能够适用于多种不同的应用程序,比如Tokyo Tyrant。 总结而言,memcached...

    分布式缓存客户端MemcachedProviders最新下载

    在高并发场景下,需要考虑使用适当的并发控制策略,如锁机制。 2. **过期策略**:理解并合理设置数据过期时间,避免因内存耗尽导致的服务不稳定。 3. **故障恢复**:在分布式环境中,需要考虑服务器故障时的数据恢复...

    php实现的memcached队列类

    它提供了丰富的接口,使得开发者能够方便地进行数据的入队、出队、监控以及并发控制。在实际项目中,这样的队列类可以应用于任务调度、消息传递、数据流处理等场景,提升系统的响应速度和效率。 为了充分利用这个类...

    memcached源代码分析

    4. **并发控制**:解释单线程模型如何处理并发请求,以及如何利用libevent进行事件处理。 5. **性能优化**:分析memcached如何通过内存预分配、异步I/O、零拷贝等技术提高性能。 6. **扩展性设计**:讨论分布式...

    memcached完全剖析

    memcached采用libevent来进行事件处理,这使得它可以轻松处理大量并发连接。 3. **内置内存存储方式**:memcached将数据存储在内存中,以提供极快的数据访问速度。 4. **memcached不互相通信的分布式**:每个...

    memcached源码

    这种设计简化了并发控制,并且在多核CPU环境下通过libevent库进行IO复用,实现了高效的资源利用。 2. **网络通信** - 使用libevent库处理网络事件,如TCP连接的建立、读写操作等。 - 使用非阻塞I/O模式,避免了因...

    memcached简单封装

    同时,根据实际使用情况,可能需要对连接池、并发控制等方面进行优化。 **技术文档要点** 1. **基本概念**:介绍Memcached的基本原理、工作模式,以及分布式缓存的重要性。 2. **安装指南**:详细说明如何在不同...

    Memcached 服务端,客户端,C#

    4. 并发控制:确保多线程环境下的数据一致性。 5. 超时控制:设置操作超时时间,防止阻塞。 6. 分布式哈希:在多台Memcached服务器集群中自动分配键值对,实现负载均衡。 使用C#客户端连接Memcached的步骤大致如下...

    memcached-1.4.0-rc1.tar.gz

    4. 并发控制:源代码中采用了锁机制来处理并发操作,确保数据一致性。 四、应用实践 1. 安装部署:用户可以通过编译源代码安装memcached,配置参数包括监听端口、最大内存大小、日志位置等。 2. 客户端接口:各种...

    memcached+asp.net4.0

    5. **使用示例**:在ASP.NET MVC或Web Forms项目中,可以在控制器或业务逻辑层使用memcached客户端库,缓存用户会话数据、常用查询结果或其他静态内容。 6. **性能优化**:理解如何合理设置缓存过期策略,避免数据...

Global site tag (gtag.js) - Google Analytics