koishi-plugin-auto-assign
v0.0.5
Published
自动负载均衡,参考插件bot,完善Bot不在对应channel处理
Readme
koishi-plugin-auto-assign
Koishi 频道自动负载均衡插件,智能分配频道给多个机器人,确保负载均衡且支持优先级配置。
功能特性
- ✅ 智能负载均衡:使用动态容量贪心算法,确保每个bot的负载尽可能均衡
- ✅ 自动容错:bot下线时自动将其负责的频道转移给其他bot
- ✅ 优先级配置:支持为特定频道配置bot优先级,实现相对固定的分配
- ✅ 实时响应:监听bot上下线、进退群事件,自动触发重新分配
- ✅ 平台过滤:支持指定启用的平台和排除的频道
核心数据结构
插件维护以下核心数据结构来追踪bot和频道的关系:
// 1. 频道 -> Bot映射
allChannels: Map<"platform:channelId", Set<botId>>
// 记录每个频道中有哪些bot
// 2. Bot -> 频道映射
botChannels: Map<"platform:botId", Set<channelId>>
// 记录每个bot在哪些频道中
// 3. Bot负载统计
botAssignCount: Map<"platform:botId", number>
// 记录每个bot当前分配的频道数量
// 4. 活跃Bot列表
activeBots: Map<platform, Set<botId>>
// 记录每个平台上当前在线的bot数据维护机制
- 初始化:通过
bot.getGuildList()获取每个bot的群列表,构建双向索引 - Bot上线:获取群列表,更新映射,触发负载均衡
- Bot下线:清理映射,触发负载均衡
- Bot进群:增量更新映射,延迟触发负载均衡
- Bot退群:增量更新映射,如果群还有其他bot则触发负载均衡
负载均衡算法
动态容量贪心算法
算法目标:让每个bot分配到的频道数量尽可能接近,最小化负载方差。
算法步骤
初始化剩余容量
for (每个频道) { for (该频道中的每个bot) { botRemainingCapacity[bot]++ // 统计每个bot能处理的频道数 } }动态分配
for (每个待分配的频道) { validBots = 该频道中的活跃bot列表 // 优先级检查 if (频道有优先级配置) { 按优先级列表选择第一个可用的bot } else { // 贪心策略:选择剩余容量最小的bot selectedBot = validBots中剩余容量最小的bot // 如果容量相同,选择当前负载最小的bot } 分配频道给selectedBot // 关键:动态更新所有在该频道中的bot的剩余容量 for (该频道中的所有bot) { botRemainingCapacity[bot]-- } }
算法优势
- 优先满足容量小的bot:确保"选择少"的bot优先被分配,避免后期无法分配
- 动态更新容量:每次分配后更新所有相关bot的剩余容量,确保全局最优
- 负载均衡:在容量约束下,尽可能让每个bot的负载接近
示例
假设有3个频道和3个bot:
- Channel1: [BotA, BotB]
- Channel2: [BotB, BotC]
- Channel3: [BotA, BotC]
初始容量:BotA=2, BotB=2, BotC=2
- 分配Channel1 → BotA(随机选择)
- 更新容量:BotA=1, BotB=1, BotC=2
- 分配Channel2 → BotB(容量最小)
- 更新容量:BotA=1, BotB=0, BotC=1
- 分配Channel3 → BotA或BotC(容量都是1)
- 最终负载:接近均衡
配置项
interface Config {
// 负载均衡间隔(秒),最小60秒
balanceInterval: number // 默认: 600
// 启用的平台列表,留空表示所有平台
enabledPlatforms: string[] // 默认: ['onebot']
// 排除的频道列表,支持 "platform:channelId" 或 "channelId" 格式
excludeChannels: string[] // 默认: []
// 频道Bot优先级配置
channelBotPriority: Record<string, string[]> // 默认: {}
}优先级配置示例
channelBotPriority:
"onebot:123456789": ["bot1", "bot2", "bot3"] # 完整格式
"987654321": ["bot2", "bot1"] # 简写格式- 优先级列表按顺序匹配,选择第一个可用的bot
- 如果所有优先级bot都不可用,自动使用贪心算法
- 如果优先级bot不在该频道,自动跳过
触发场景
插件会在以下场景自动触发负载均衡:
| 场景 | 延迟 | 说明 | |------|------|------| | 插件启动 | 立即 | 初始化分配 | | Bot状态变化 | 5秒 | 上线/下线状态变化 | | Bot上线 | 5秒 | 新bot可以分担负载 | | Bot下线 | 5秒 | 需要转移该bot负责的频道 | | Bot加入群 | 10秒 | 新群可能需要重新分配 | | Bot退群 | 5秒 | 如果群还有其他bot,需要重新分配 | | 定时器 | 600秒 | 定期检查和调整 |
日志输出
[I] auto-assign 执行负载均衡(动态容量贪心算法)...
[I] auto-assign 平台 onebot 负载均衡完成,分配了 288 个频道
[I] auto-assign 负载分布: [bot1:96, bot2:96, bot3:96],平均: 96.0,标准差: 0.00- 负载分布:每个bot实际分配的频道数
- 平均值:所有bot的平均负载
- 标准差:越小越均衡(0表示完全均衡)
使用场景
场景1:多bot负载均衡
有3个bot,希望它们平均分担所有频道的消息处理。
balanceInterval: 600
enabledPlatforms: ['onebot']场景2:特定频道固定bot
某些重要频道希望固定由特定bot处理,但bot下线时自动切换。
channelBotPriority:
"onebot:重要群A": ["主力bot", "备用bot1", "备用bot2"]
"onebot:重要群B": ["主力bot"]场景3:排除特定频道
某些频道不希望被自动分配。
excludeChannels:
- "onebot:测试群"
- "987654321"注意事项
- channel表的作用:本插件通过修改
channel表的assignee字段来实现分配,该表是应用分配结果的工具 - 数据源:插件通过
bot.getGuildList()获取bot的实际群列表,不依赖channel表 - 延迟触发:为避免频繁重新分配,大部分事件都有延迟触发机制
- 容量约束:bot只能被分配到它实际加入的频道
License
MIT
