读改写序列被插入的回调打断时数据互相覆盖(分段锁篇讲过交错来源),乐观锁换一种思路:不加锁,写入时携带"我读到的版本号",版本对不上说明中途有人改过,拒绝写入并重读重试。数据格式加一个 version 前缀字段:读时连版本一起读,写时校验版本一致才落盘并把版本加一。乐观锁赌的是冲突罕见——冲突少的场景零等待,冲突多的场景重试成本上升。
版本读写与重试。示例代码如下:
local function loadRecord(key)
local blob = tostring(getsysvar(key) or "")
local ver, data = string.match(blob, "^(%d+)|(.*)$")
return tonumber(ver) or 0, data or ""
end
local function saveRecord(key, ver, data)
local curVer = loadRecord(key)
if curVer ~= ver then
return false
end
setsysvarex(key, (ver + 1) .. "|" .. data, 1)
return true
end
行会的沙巴克集结公告更新接线。示例代码如下:
local function updateNotice(key, newNotice)
for attempt = 1, 3 do
local ver = loadRecord(key)
if saveRecord(key, ver, newNotice) then
return true
end
end
return false
end
updateNotice 最多重试 3 次:每次重读最新版本再尝试写入,3 次都失败说明争用激烈,返回 false 交由上层决定提示或入队。
低冲突场景(每小时几次写入)乐观锁零等待、无额外查询;冲突率 5% 时平均重试 1.05 次,耗时增加约 5%;冲突率 50% 的高争用下平均要重试 2 次且失败率明显上升,此时该换成分段锁或队列串行化。版本字段本身只多 4 到 6 字节存储,读取路径多一次字符串解析,微秒级。
三个不适用场景:一是同一键每秒多次写的高争用场景,重试风暴让 CPU 空转,改用队列串行化;二是写入方无法感知失败的场景(单向推送),静默失败比数据延迟更糟;三是多键需同时更新的复合操作,单个版本号罩不住,要么合并成单串要么升级为段锁。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏】 一、一行代码拆解:if price < WATCH[goods] then notify end —— 关注降价的…
【游戏】 一、业务场景:赛季结算发现一名玩家胜率 10% 却排在黄金段——历史计分只加不减,积分体系失效 3 个月;积分赛—…
【语法】 一、抛坑提问:3 对括号能组成多少种合法序列?答案是 5——卡塔兰数列:每一项等于前一项乘 2 倍的 2n 减 1…
【语法】 一、抛坑提问:不想用全局随机函数(怕多处共享种子互相干扰),可自实现一个独立随机序列——线性同余法三行核心:乘、加…
【游戏】 一、一行代码拆解:PENDING[outId] = {by = actor, at = now} —— 双人复核的…
【语法】 一、隐蔽陷阱:圆周率小数位背不出更多就不算理解随机模拟?用蒙地卡罗法随机撒点统计,10 万个点能把圆周率估到两位小…