游戏后端分布式学习——分布式锁与选主
概念为何引入分布式锁分布式锁是最直接、最成熟的方案尤其适合短时间、高频次的互斥操作对一致性要求极高不能出现重复奖励需要跨服务器协调分布式锁在mmo游戏中常见场景简易分布式锁实现用于后续场景中分布式锁的使用importtimeimportuuidimportredisclassDistributedLock:def__init__(self,redis_client,lock_key,expire10):self.redisredis_client self.lock_keylock_key self.expireexpire self.owner_idstr(uuid.uuid4())# 唯一标识持有者defacquire(self):尝试获取锁成功返回 True失败返回 False# SET key value NX EX seconds —— 原子操作resultself.redis.set(self.lock_key,self.owner_id,nxTrue,exself.expire)returnresultisnotNone# Redis 返回 OK 表示成功defrelease(self):释放锁只释放属于自己的锁# 使用 Lua 脚本保证原子性检查 owner 再删除lua_script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end self.redis.eval(lua_script,1,self.lock_key,self.owner_id)def__enter__(self):self.acquire()returnselfdef__exit__(self,exc_type,exc_val,exc_tb):self.release()限量活动发放全服只发 100 份限量皮肤10 万玩家同时抢——需要锁保证发到第 100 份时立即停止。场景全服限量 100 份绝版坐骑10 万玩家同时抢 并发极高瞬间万级 QPS 幂等重复发放意味着超发资损必须用分布式锁 Lua 原子扣减-- 限量活动发放的原子操作locallua_script[[ local remain_key KEYS[1] local lock_key KEYS[2] local token ARGV[1] local player_id ARGV[2] local item_id ARGV[3] -- 尝试获取锁 if redis.call(SET, lock_key, token, NX, EX, 5) then local remain redis.call(GET, remain_key) if remain and tonumber(remain) 0 then redis.call(DECR, remain_key) -- 发放物品这里简化实际需要调用游戏服 API redis.call(LPUSH, item_grant_queue, player_id .. : .. item_id) redis.call(DEL, lock_key) return 1 -- 成功 else redis.call(DEL, lock_key) return 0 -- 已发完 end else return -1 -- 获取锁失败 end ]]世界 Boss 击杀判定假设游戏里有 3 台战斗服务器分别承载不同区域的玩家。一只世界 Boss 血条归零的那一刻三个服务器都可能检测到自己区域内的某个玩家打出了“最后一击”。如果没有锁服务器 A 判定玩家 X 击杀 → 发放奖励服务器 B 也判定玩家 Y 击杀 → 同样发放奖励服务器 C 也可能凑热闹……因为“发放奖励”这个操作必须是互斥的——同一时刻只允许一台服务器执行。分布式锁正是用来在多个独立进程之间协调对共享资源的独占访问的完美工具。设计要点锁的粒度按 Boss 实例 ID 加锁比如 lock:boss:worldboss_001不同 Boss 互不影响。锁的超时设置合理超时比如 10 秒防止拿到锁的服务器突然宕机导致死锁。锁的持有者标识每个服务器生成唯一 ID如 server_A释放锁时检查是不是自己的锁避免误删别人的锁。原子性操作加锁和设超时要一起完成Redis 的 SET key value NX EX seconds。为什么不直接用数据库事务数据库事务比如 MySQL 行锁也可以做到互斥但性能开销大高并发下数据库会成为瓶颈。数据库连接可能不稳定事务超时回滚复杂。分布式环境下多个服务器可能连不同的数据库实例分库分表事务无法跨库。而 Redis 等内存型锁性能极高适合高频短时间的互斥操作。defworld_boss_kill_handler(boss_id,server_name): 模拟世界 Boss 击杀处理 boss_id: 世界 Boss 的唯一标识 server_name: 当前服务器的名字比如 Server-A rredis.Redis(hostlocalhost,port6379,decode_responsesTrue)lockDistributedLock(r,flock:boss:{boss_id},expire10)iflock.acquire():try:print(f[{server_name}] 抢到了 Boss{boss_id}的锁开始发放奖励...)# 这里执行真正的奖励发放逻辑检查击杀者、发邮件等time.sleep(1)# 模拟耗时操作print(f[{server_name}] 奖励发放完毕释放锁。)finally:lock.release()else:print(f[{server_name}] 没抢到锁放弃处理。)# 模拟三个服务器同时尝试处理importthreading threads[]fornamein[Server-A,Server-B,Server-C]:tthreading.Thread(targetworld_boss_kill_handler,args(worldboss_001,name))threads.append(t)t.start()fortinthreads:t.join()跨服匹配跨服匹配池是一个全局队列里面排着来自不同服务器的玩家。多个匹配服务器Match Server同时从这个队列里取人组队。如果没有锁匹配服务器 A 取了玩家 P1、P2准备组队。匹配服务器 B 也取了玩家 P1、P3准备组队。结果 P1 同时出现在两个队伍里游戏逻辑错乱。从匹配池取玩家这个操作必须是原子的——要么整个取走要么不取。分布式锁可以保证同一时刻只有一个匹配服务器在执行“取出并标记”的操作。设计要点锁的粒度按匹配池 ID 加锁比如 lock:matching:pool_1也可以更细粒度到“批次”。锁的持有时间匹配操作很快毫秒级锁超时可设为 1~2 秒。配合队列原子操作实际项目中常用 Redis 的 LPOP/RPOP 或 BLPOP 结合 Lua 脚本但分布式锁提供了额外的安全边界。防重复匹配拿到锁后还要二次校验玩家是否已被匹配双重检查模式。为什么不直接用 Redis 事务或 Lua 脚本Lua 脚本确实可以实现原子性但如果脚本执行时间较长比如涉及多个键操作会阻塞 Redis 主线程影响其他请求。而分布式锁可以让业务逻辑在应用层完成锁只保证互斥不阻塞 Redis。更常见的做法是用 Lua 脚本原子性地 pop 玩家再配合分布式锁防止多个匹配服务器同时执行该脚本。defmatch_players(match_pool_key,server_name): 从匹配池中取出一对玩家进行匹配 match_pool_key: Redis 列表的 key存放等待匹配的玩家 ID server_name: 当前匹配服务器名称 rredis.Redis(hostlocalhost,port6379,decode_responsesTrue)lockDistributedLock(r,flock:matching:{match_pool_key},expire2)iflock.acquire():try:# 拿到锁后从队列中取出两个玩家如果有player1r.lpop(match_pool_key)ifplayer1isNone:print(f[{server_name}] 匹配池为空无事可做。)returnplayer2r.lpop(match_pool_key)ifplayer2isNone:# 如果只取到一个放回去保持公平r.rpush(match_pool_key,player1)print(f[{server_name}] 匹配池人数不足将{player1}放回。)return# 执行匹配逻辑创建对局等print(f[{server_name}] 成功匹配{player1}和{player2})# 实际项目还会把匹配结果写入数据库finally:lock.release()else:print(f[{server_name}] 没抢到锁稍后重试。)# 模拟先向匹配池插入一些玩家rredis.Redis(hostlocalhost,port6379,decode_responsesTrue)r.delete(matching:pool_1)r.rpush(matching:pool_1,Player1,Player2,Player3,Player4)# 三个匹配服务器并发工作threads[]fornamein[Match-Server-1,Match-Server-2,Match-Server-3]:tthreading.Thread(targetmatch_players,args(matching:pool_1,name))threads.append(t)t.start()fortinthreads:t.join()选主在游戏中的常见场景

相关新闻

黑苹果BCM94360Z4蓝牙固件魔改:实现原生级AirDrop与睡眠唤醒

黑苹果BCM94360Z4蓝牙固件魔改:实现原生级AirDrop与睡眠唤醒

1. 项目概述:从“能用”到“完美”的最后一公里折腾黑苹果的朋友,对博通(Broadcom)的无线网卡一定不陌生。在苹果逐步转向自研芯片和定制无线模块的今天,那些被遗留在Intel平台上的“原装”博通网卡,成了黑…

2026/11/12 15:40:15 阅读更多 →
猫抓浏览器扩展终极指南:简单快速免费下载网页视频资源

猫抓浏览器扩展终极指南:简单快速免费下载网页视频资源

猫抓浏览器扩展终极指南:简单快速免费下载网页视频资源 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓(cat-catch&…

2026/11/13 15:35:01 阅读更多 →
Dify平台智能体开发实战:挑战与优化策略

Dify平台智能体开发实战:挑战与优化策略

1. 智能体与Dify平台的现状解析最近半年,AI智能体(AI Agent)突然成为技术圈的热门话题。作为从业者,我观察到几乎每周都有新的智能体框架或平台发布,而Dify作为国内较早开放的大模型应用开发平台,其智能体功…

2026/11/7 7:48:34 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/13 5:13:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/13 5:13:25 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/13 5:13:25 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/12 18:22:26 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/12 18:22:25 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/13 5:13:25 阅读更多 →

日新闻

周新闻

月新闻