架构设计
┌─────────────────┐
│ SectManager │ // 全局管理器,负责创建/销毁/查找帮派
├─────────────────┤
│ Sect │ // 单个帮派对象,继承自 StorageBase
├─────────────────┤
│ StorageBase │ // 抽象存储基类,提供 save() / load()
├─────────────────┤
│ CacheLayer(opt) │ // 可选缓存层,封装热数据访问(非直接操作 Redis)
└─────────────────┘
-
SectManager:单例,持有所有活跃帮派的引用(dictguild_id, Guild),提供线程安全的访问接口。负责帮派创建、解散、跨服迁移时的生命周期管理。
-
Sect:每个帮派的业务逻辑实体,继承 StorageBase,自身拥有 members、level、assets 等字段。所有成员相关的变更操作都封装在此类中,以保证数据内聚。
-
StorageBase:抽象类,定义 save()(全量落盘)和 load(guild_id)(从持久化介质重建)。子类可对接 MySQL/MongoDB 或文件系统。
-
CacheLayer:可选组件,用于加速高频读取(如成员列表、帮派等级)。不直接操作 Redis,而是通过接口抽象,内部可用 LRU + 定时同步策略。
常见功能实现
单机部署
python
import time
from enum import IntEnum
from typing import Dict, List, Optional
class Position(IntEnum):
LEADER = 1 # 帮主
VICE_LEADER = 2 # 副帮主
ELITE = 3 # 精英
MEMBER = 4 # 普通成员
class Member:
__slots__ = ('player_id', 'name', 'position', 'contribution', 'join_time')
def __init__(self, player_id: int, name: str, position: Position = Position.MEMBER,
contribution: int = 0, join_time: float = None):
self.player_id = player_id
self.name = name
self.position = position
self.contribution = contribution
self.join_time = join_time or time.time()
class Guild(StorageMixin):
def __init__(self, guild_id: int, name: str, leader_id: int,
max_members: int = 100, level: int = 1):
self.guild_id = guild_id
self.name = name
self.level = level
self.max_members = max_members
self.members: Dict[int, Member] = {} # player_id -> Member
self.leader_id = leader_id
self.create_time = time.time()
self.notice = ""
# 初始化帮主
self.add_member(leader_id, "帮主", Position.LEADER)
# ---------- 成员管理 ----------
def add_member(self, player_id: int, name: str, position: Position = Position.MEMBER) -> bool:
if len(self.members) >= self.max_members:
return False
if player_id in self.members:
return False
self.members[player_id] = Member(player_id, name, position)
return True
def remove_member(self, player_id: int) -> bool:
if player_id not in self.members:
return False
# 不能踢帮主(除非转让)
if self.members[player_id].position == Position.LEADER:
return False
del self.members[player_id]
return True
def change_position(self, operator_id: int, target_id: int, new_pos: Position) -> bool:
"""权限校验:只有帮主或副帮主可调整职位(副帮主不能调整帮主)"""
op = self.members.get(operator_id)
if not op or op.position > Position.VICE_LEADER:
return False
target = self.members.get(target_id)
if not target:
return False
# 副帮主不能操作帮主和副帮主
if op.position == Position.VICE_LEADER and target.position <= Position.VICE_LEADER:
return False
target.position = new_pos
return True
def transfer_leader(self, from_id: int, to_id: int) -> bool:
"""转让帮主:原帮主执行,目标必须是副帮主或精英"""
if from_id != self.leader_id:
return False
target = self.members.get(to_id)
if not target or target.position > Position.ELITE:
return False
# 交换职位
self.members[self.leader_id].position = Position.VICE_LEADER
target.position = Position.LEADER
self.leader_id = to_id
return True
# ---------- 其他业务 ----------
def is_full(self) -> bool:
return len(self.members) >= self.max_members
def get_online_count(self, online_service) -> int:
"""通过在线服务获取在线人数(性能敏感点,后面讲优化)"""
return sum(1 for pid in self.members if online_service.is_online(pid))
分布式部署
如果帮派服务部署在多个节点,跨帮派的全局操作就需要考虑同个玩家的对不同帮派的同个请求(例如申请假如两个不同的帮派),所以需要引入分布式锁。
性能热点分析与优化
热点1:帮派列表/搜索
-
场景:玩家打开帮派申请界面,需要分页展示所有帮派(按等级、人数排序)。
-
问题:全表扫描或频繁查询数据库。
-
优化:
-
使用缓存:搜索结果缓存10~30秒,因为帮派列表变化不频繁。
-
索引:数据库中对 name 字段建前缀索引,对 level、member_count 建组合索引。
-
定期刷新:后台任务每5分钟将热门关键词的搜索结果预热到缓存。
-
热点2:成员在线状态
-
场景:帮派面板显示在线人数,每次打开都需要查询每个成员的在线状态。
-
问题:若帮派200人,每次查询200次RPC调用,压力巨大。
-
优化:
-
批量查询:在线服务提供批量接口 batch_is_online(player_ids),一次网络IO返回全部状态。
-
本地缓存:在 Guild 对象中维护一个 online_cache: Dictint, bool,每隔10秒通过异步任务刷新整个帮派的在线状态,前端请求时直接读缓存(允许短暂延迟)。
-
推送更新:玩家上下线时通过事件总线通知帮派模块,增量更新 online_cache。
-
热点3:帮派排行榜(财富、战力等)
-
场景:全服帮派排名,实时性要求不高。
-
优化:
-
使用定时任务(每分钟)计算排名,写入缓存(ZSET结构),前端读取缓存即可。
-
如果使用 Redis,可以用 Sorted Set 天然支持;若不用 Redis,可在内存中用堆排序,然后存到本地缓存。
-
热点4:大量成员同时操作(如帮战报名)
-
场景:帮战开启瞬间,数百人同时点击报名。
-
优化:
-
使用队列削峰:报名请求先进入消息队列,后端顺序消费,避免并发写冲突。
-
帮派对象的锁粒度尽量细:只在修改成员列表时才加锁,读操作无锁(使用读写锁或 copy-on-write)。
-