v1.9 带来 12 个新场景 - dr 模块再添十个,新的 tiered-storage 模块两个 - 并让 Kafka Simulator 的课程体系达到 134 个中的 112 个。它还公开了模拟器从一开始就依赖的一样东西:它的链接格式。
v1.9 里有什么
更多灾难恢复(dr,10 个场景)。 两种平台层面的答案,回应 v1.8 借 MirrorMaker 2 提出的那些问题:
- Multi-Region Cluster 的 observer - 跟随日志、但不加入 ISR 的副本,因此一份远端副本不会给写入路径带来任何代价。它们滞后多远、该放在哪里、如何被提升 - 包括这样一种情况:提升需要一个已经无法联系到的 leader。
- Cluster Linking - 逐字节的镜像,保留 offset,因此完成故障切换的消费者无需任何转换。镜像主题在被提升之前一直是只读的,已提交的消费者 offset 会原样经由链路同步,链路可以原地反转以实现干净的回切,还有一个场景在同一拓扑上把它与 MirrorMaker 2 并排运行。自由模式也获得了相应的控件:双区域拓扑上的区域与镜像链路编辑器,其中每条链路可以是 MirrorMaker 2 或 Cluster Linking,并且可以反转。
分层存储(tiered-storage,2 个场景)。 旧的日志段被卸载到对象存储:卸载、读回和过期的完整生命周期,伴随着 localStartOffset 与 logStartOffset 逐渐分开 - 以及无限保留:老化的日志段离开本地磁盘,但一个滞后的消费者仍会把它们逐一读回来。
每个会话都是一个链接
演练场把它的全部状态都保存在 URL 里。一个链接可以在指定步骤打开一个脚本化场景、重放一串集群操作,或者搭起一个自定义的自由模式集群 - 模拟器里每一个「分享」按钮正是这样工作的。
从 v1.9 开始,这套格式公开并有文档记录(英文):查询参数、动作日志的语法、集群形态的编码,以及演练场如何处理它无法解析的条目。规范中的每个示例都会被模拟器自己的测试套件解码,因此文档不可能与代码脱节。
有文档的格式意味着链接可以来自演练场之外的地方 - 一个脚本、一个 CI 任务,或者一个 AI 代理。第一个生成器随本次发布一同推出。
monedula-sim-link:把真实集群变成一个链接
手动描述你真正关心的集群 - 一个个 broker、一个个主题地写 - 既繁琐又容易出错。monedula-sim-link 是一个小巧的 Go CLI,它以只读方式连接到真实的 Kafka 集群,并打印出将其可视化的演练场链接:
$ go install github.com/monedula-dev/monedula-sim-link/cmd/monedula-sim-link@latest
$ monedula-sim-link connect --brokers localhost:9092 --topics orders,payments
https://monedula.dev/kafka-simulator/playground?scenario=free&actions=…&size=…
这个链接会把运行中的集群作为一个模拟器打开:broker、主题、分区分布、副本因子、离线的 broker、ISR 缺口、带成员信息的消费者组、主题配置,以及数据量的抽样 - 一幅你可以暂停、单步执行、在不触碰生产环境的情况下搞坏的画面,还可以在事故处理中途把它发给同事,而不必写一段文字去描述。
只读,并且在一个文件里就能审计。 把一个工具指向生产集群是一个信任决定,所以这项保证范围窄且明确。connect 只发出读取请求 - ApiVersions、Metadata、ListOffsets,以及针对消费者组和配置的 ListGroups、DescribeGroups、OffsetFetch 和 DescribeConfigs。Metadata 请求会设置 AllowAutoTopicCreation=false,因此即使只是查找一个主题,也永远不会创建它。整个过程不生产任何记录、不修改任何配置、不加入任何消费者组,也不提交任何 offset。整个客户端接触面都在一个文件里,即 snapshot/kafka.go,并配有测试,证明一次失败的查找不会自动创建该主题,而读取一个消费者组的 offset 也永远不会改变它们。
适配集群的安全配置方式。 支持 TLS、双向 TLS 和 SASL/SCRAM,密码从 MONEDULA_SIM_LINK_PASSWORD 读取,因此不会留在 shell 历史中:
export MONEDULA_SIM_LINK_PASSWORD='…'
monedula-sim-link connect --brokers broker1:9093,broker2:9093 \
--tls --ca-cert ./cluster-ca.pem \
--sasl-mechanism scram-sha-512 --username viewer
主题可以按精确名称、按正则表达式或两者结合来选择,而 --dry-run 会在把 URL 交给你之前,打印真实名称到模拟器名称的映射,以及推导出的集群规模。链接所编码的一切,只是对形态的紧凑描述和数据量的抽样;模拟器没有后端,因此你的数据永远不会离开你的机器。
面向 AI 代理的 MCP 服务器
monedula-sim-link mcp 通过 stdio 使用 Model Context Protocol 通信,因此 Claude Code、Claude Desktop 或任何其他 MCP 客户端都能按需构建链接。你可以说「给我看一个 6 broker 的集群,其中 orders 的 leader 挂掉」或者「把我们的 staging 集群可视化」,代理就会返回一个恰好打开这些内容的链接。它提供四个工具:
build_playground_url- 根据声明式描述生成一个自由模式会话:一个拓扑、一个集群形态(broker;带有分区数、RF、min.insync.replicas和清理策略的主题;机架感知),以及一个有序的定时动作列表 - 生产记录、杀掉并重启 broker、添加生产者和消费者组、配置变更、重分配、分层存储卸载、限流。open_scenario- 按带点号的 ID(例如00.1.3)给出某个精选脚本化场景的链接。validate_actions- 对于一个原始的actions字符串或一个完整 URL,演练场实际会加载什么:保留下来的动作、每个被丢弃的条目及其原因,以及长度和数量相对于编解码器上限的情况。cluster_to_url- 以工具形式提供的connect快照,带有同样的只读保证。
把 URL 的构建交给 LLM,正是事情会悄无声息地出错的地方 - 一个被弄乱的分隔符、一个模拟器不接受的配置路径、一个超出长度上限的 actions 值 - 而演练场会悄悄丢弃它无法解析的内容。所以每个工具都和 CLI 一样经过同一个快速失败的编解码器,只有当 URL 的 actions 值能解码回完全相同的日志时,才会返回这个 URL。校验失败时,错误信息会指明出问题的字段、分隔符或配置路径,这样代理就能修正自己的输入,而不是交出一个被截断的链接。
在 Claude Code 中注册它只需一行:
claude mcp add monedula-sim-link -- monedula-sim-link mcp
对于 Claude Desktop,把它添加到 claude_desktop_config.json 中:
{
"mcpServers": {
"monedula-sim-link": {
"command": "monedula-sim-link",
"args": ["mcp", "--base-url", "https://monedula.dev/kafka-simulator/playground"]
}
}
}
--base-url 是可选的;把它指向 http://localhost:4321/kafka-simulator/playground,就能生成指向本地开发服务器的链接。这个服务器基于官方的 modelcontextprotocol/go-sdk 构建。
monedula-sim-link 位于它自己的开源仓库中,即 GitHub 上的 monedula-dev/monedula-sim-link - 一个采用 Apache-2.0 许可证的自包含 Go 模块,可以用 go install 安装,也可以从发布页面获取适用于 Linux、macOS 和 Windows 的预编译二进制文件。它不发送任何遥测数据,并且是这套 URL 格式的参考生成器:它生成的链接在演练场中解码后,恰好就是它写入的那份日志。
像 Kafka 那样扩缩集群
自由模式现在会像真实集群那样改变 broker 数量。在 v1.9 之前,添加一个 broker 会悄悄地把分区再均衡到它上面 - 正如一位读者指出的,这并不是 Kafka 的做法。现在你添加的 broker 加入时是空的:不会有任何分区自行迁移到它上面,集群检查器也会说明这一点,旁边还有一个 Rebalance partitions 按钮。在终端中,kafka-reassign-partitions --generate 会根据主题列表和 broker 列表提出一个方案,--execute 启动它,--verify 确认它。反方向也遵循同样的规则:仍持有分区的 broker 必须先被排空,才能被移除,顺序与你下线一个真实 broker 时相同。
打开模拟器,用 Cluster Linking 对一个区域执行故障切换,然后分享链接。