微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

提升 Redis Lua 脚本性能 逻辑数据解决方案3.每个实体的 Lua 调用 - 单个 HM更多性能和信息

如何解决提升 Redis Lua 脚本性能 逻辑数据解决方案3.每个实体的 Lua 调用 - 单个 HM更多性能和信息

我正在尝试将实体保存到 redis 中。每个实体都是一个 JSON(我不对该 json 进行任何操作,所以我认为 (?) redis-json 不会在这里帮助我)。

我的服务接收(通过 kafka 主题)很多实体。其中一些是其他实体的更新。

每个实体都有一个“eventId”(类似于“category”)、“bms”(类似于“entity-id”)。具有相同 eventId 的多个实体可能具有不同的 bms

为了能够支持消费者组(多个 kafka 消费者),所有这些消费者组都将实体保存在 Redis 中:每个实体都有一个版本(整数 >=0)。

逻辑

仅当 new(来自 kafka)实体的版本 > current(redis 内部)实体的版本时才保存实体。

数据

我的服务每秒从 kafka 消耗多达 1k 个实体。这意味着我每秒最多需要 SET 1k 次。

解决方

  • 我从 kafka 主题中批量读取,因此我可以使用 multipipeline 调用 redis
  • 在比较“新”版本和“当前”版本时,我认为没有办法避免 lua 的原子性。

1.每个实体的 Lua 调用

local event_id = KEYS[1]
local bms = ARGV[1]
local new_version = tonumber(ARGV[2])
local new_offer = ARGV[3]

local bms_offer_hm_key = 'bms-offers--' .. event_id
local bms_version_hm_key = 'bms-version--' .. event_id

local current_version = tonumber(redis.call('HMGET',bms_version_hm_key,bms))

if current_version == nil or current_version < new_version then
  redis.call('HMSET',bms,new_version)
  redis.call('HMSET',bms_offer_hm_key,new_offer)
  return 1
else
  return 0
end

性能

  • redis 1k 插入 -> 0.050s
  • redis 2k 插入器 -> 0.100s
  • redis 10k 插入 -> 0.400s

2.所有实体的 Lua 调用

local j=1
for i=1,#KEYS do
  local event_id = KEYS[i]
  local bms = ARGV[j]
  local new_version = tonumber(ARGV[j+1])
  local new_offer = ARGV[j+2]

  local bms_offer_hm_key = 'bms-offers--' .. event_id
  local bms_version_hm_key = 'bms-version--' .. event_id
  
  local current_version = tonumber(redis.call('HMGET',bms))
  
  if current_version == nil or current_version < new_version then
    redis.call('HMSET',new_version)
    redis.call('HMSET',new_offer)
  end
  j=j+3
end

性能

  • redis 1k 插入 -> 0.200s

3.每个实体的 Lua 调用 - 单个 HM

  • 现在我使用 HSET 而不是 HMSET。感谢@raina77ow。
local molly_event_id = KEYS[1]
local bms = ARGV[1]
local new_version = tonumber(ARGV[2])
local new_offer = ARGV[3]

local key = 'molly-offers::' .. molly_event_id
local bms_sub_key = "bms::" .. bms
local version_sub_key = "version::" .. bms

local current_version = tonumber(redis.call('HMGET',key,version_sub_key))

if current_version == nil or current_version < new_version then
  redis.call('HSET',version_sub_key,new_offer,bms_sub_key,new_version)
  return 1
else
  return 0
end

性能

  • redis 1k 插入 -> 0.040s
  • redis 2k 插入器 -> 0.080s
  • redis 10k 插入 -> 0.400s

更多性能和信息

我的上述指标基于 macbook pro 上的 docker-redis

macos catalina 10.15.1 (19B2093)
2.6 GHz 6-Core Intel Core i7
16 GB 2667 MHz DDR4

当尝试运行 1k 个随机集(具有相同的实体)(没有 lua 脚本)时:

  • 1k 插入 -> 0.025s
  • 2k 插入 -> 0.050 秒
  • 10k 插入 -> 0.211s
  • 45k 插入 -> 1.000s

我还没有投入生产,但是当我投入生产时,redis 将在 k8s pod 上运行。


问题

  1. 有没有办法让 lua 脚本更快?我愿意接受任何更改!
  2. 我可能会在 lua 脚本阻止 redis 时阻止其他客户端读取实体。多节点会产生额外的分布式逻辑复杂性,如果可能,我想避免这种复杂性。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。