前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis 并发竞争key问题如何解决?

Redis 并发竞争key问题如何解决?

作者头像
dys
发布2019-11-10 22:16:12
7.8K2
发布2019-11-10 22:16:12
举报
文章被收录于专栏:性能与架构性能与架构

1. 问题描述

并发竞争key这个问题简单讲就是:

同时有多个客户端去set一个key。

示例场景 1

例如有多个请求一起去对某个商品减库存,通常操作流程是:

  • 取出当前库存值
  • 计算新库存值
  • 写入新库存值

假设当前库存值为 20,现在有2个连接都要减 5,结果库存值应该是 10 才对,但存在下面这种情况:

示例场景 2

比如有3个请求有序的修改某个key,按正常顺序的话,数据版本应该是 1->2->3,最后应该是 3

但如果第二个请求由于网络原因迟到了,数据版本就变为了 1->3->2,最后值为 2,出问题了。

2. 解决方案

2.1 乐观锁

乐观锁适用于大家一起抢着改同一个key,对修改顺序没有要求的场景。

watch 命令可以方便的实现乐观锁。

需要注意的是,如果你的 redis 使用了数据分片的方式,那么这个方法就不适用了。

watch 命令会监视给定的每一个key,当 exec 时如果监视的任一个key自从调用watch后发生过变化,则整个事务会回滚,不执行任何动作。

2.2 分布式锁

适合分布式环境,不用关心 redis 是否为分片集群模式。

在业务层进行控制,操作 redis 之前,先去申请一个分布式锁,拿到锁的才能操作。

分布式锁的实现方式很多,比如 ZooKeeper、Redis 等。

2.3 时间戳

适合有序需求场景,例如 A 需要把 key 设置为 a,然后 B 设置为 bC 再设置为 c,最后的值应该是 c

这时就可以考虑使用时间戳的方式:

A => set key1 {a 11:01} B => set key1 {b 11:02} C => set key1 {c 11:03}

就是在写入时保存一个时间戳,写入前先比较自己的时间戳是不是早于现有记录的时间戳,如果早于,就不写入了。

假设 B 先执行了,key1 的值为 {b 11:02},当A执行时,发现自己的时间戳11:01早于现有值,就不执行 set 操作了。

2.4 消息队列

在并发量很大的情况下,可以通过消息队列进行串行化处理。这在高并发场景中是一种很常见的解决方案。

3. 小结

“Redis 并发竞争” 问题就是高并发写同一个key时导致的值错误。

常用的解决方法:

  • 乐观锁,注意不要在分片集群中使用
  • 分布式锁,适合分布式系统环境
  • 时间戳,适合有序场景
  • 消息队列,串行化处理
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JAVA高性能架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题描述
    • 示例场景 1
      • 示例场景 2
      • 2. 解决方案
        • 2.1 乐观锁
          • 2.2 分布式锁
            • 2.3 时间戳
              • 2.4 消息队列
              • 3. 小结
              相关产品与服务
              消息队列 CMQ 版
              消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档