• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Redis zadd导致的一次线上问题排查和处理

武飞扬头像
小泥洼
帮助5

背景

最近有用户反馈,主播收了1881数值礼物,头像下数字显示881, 正常来说,应该显示1881的数值。

学新通

经过排查,是因为redis zadd在并发情况下导致数据不一致的问题。

问题排查

经过对送礼日志的排查,发现mongodb数据更新正常,但是redis数据异常,查看业务代码后发现了问题。

业务代码如下: 学新通

这里的逻辑是先更新 mongodb, 然后对redis数值进行zadd覆盖. 一般情况下没啥问题, 但如果稍微遇到高并发:

  1. A线程跟B线程同时对mongo进行修改操作, 在数据库层面, B的修改后于A的修改.
  2. 但在进程中, 线程B先于线程A调用redis修改, 线程A对redis的修改覆盖了B的数值.
  3. 导致redis中数据维护错误.

问题修复

使用Lua脚本修改redis值,并发情况下不处理覆盖逻辑, 避免旧值覆盖新值,利用mongodb自增保证原子性。 代码如下:

学新通

Lua脚本如下:

SAFE_ZADD_SCRIPT = """
    local key = KEYS[1]
    local field = ARGV[1]
    local new_value = tonumber(ARGV[2])
    local old_value = redis.call("zscore", key, field)
    local res = nil
    
    if (not old_value) or (tonumber(old_value) < new_value)
    then
        res = redis.call('zadd', key, new_value, field)
    end
    
    return res
"""

为啥不使用zincrby?

zincrby虽然保证不会有并发问题,但是如果key失效或者被清理,会导致排行榜从0开始计数,导致数据错误。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhebkhgg
系列文章
更多 icon
同类精品
更多 icon
继续加载