# tiup-web **Repository Path**: fengshuhui/tiup-web ## Basic Information - **Project Name**: tiup-web - **Description**: tidb数据库 tiup-web可视化工具 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-17 - **Last Updated**: 2026-09-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TiScope · TiDB 集群透视仪 把 `tiup`、`pd-ctl`、`cdc` 这三套命令行,变成一张**会动、能解释自己**的集群架构图。 图上每个方块都是真实集群里跑出来的节点,每一段注解都在回答「为什么会是这样」: Region 怎么切、TiFlash 为什么是 Raft Learner、store limit 为什么是「水龙头」不是开关、 缩容为什么必须先排空再 prune。
更多截图 | PD 运维:store 列表 | TiCDC:同步任务与报错 | | --- | --- | | ![PD](docs/screenshot-pd.png) | ![TiCDC](docs/screenshot-cdc.png) | | 关于本作品:六段技术解读 | 浅色主题 | | --- | --- | | ![关于](docs/screenshot-about.png) | ![浅色](docs/screenshot-topo-light.png) |
## 30 秒看懂 | | | | ---------------- | ------------------------------------------------------------------------------------------------------------------- | | **看得见** | 分层拓扑 + 数据流动画:SQL 层 → 调度层 → 存储层,再分叉成**列存副本**与**增量同步**两条链路,一路画到 MySQL / Kafka 下游 | | **讲得清** | 6 段技术解读(架构 / Multi-Raft / HTAP / 调度 / TiCDC / 扩缩容),每层图旁边就地展开 | | **用得上** | 不是截图工具。扩缩容、PD 配置与调度限速、TiCDC 同步任务管理都能在图旁边直接下发 | | **打不开也能看** | 内置 17 节点仿真集群(含 1 个故障节点、1 个异常同步任务),点「演示模式」即可,不需要 TiDB 环境 | ## 启动 ```bash python server.py --port 8686 # 浏览器打开 http://127.0.0.1:8686 ``` Windows 双击 `start.bat` 也可以。 > 服务只监听 `127.0.0.1`,请勿直接暴露到公网。 ### 演示模式(没有集群也能看) 右上角点「演示模式」,或在首次引导弹窗里选「先看演示数据」: - 会用一套内置仿真集群接管全部取数:**3 PD / 2 TiDB / 5 TiKV / 2 TiFlash / 2 TiCDC,共 17 节点** ,外加 32000 个 Region、4 个 changefeed(其中 1 个异常、1 个已暂停); - 拦截发生在**最底层**——只替换「执行命令」「调 PD API」「调 TiCDC API」三个入口, 上层所有页面、解析、渲染逻辑与真实模式完全一致,所以演示里看到的就是真实集群里会看到的; - 写操作(暂停 / 恢复 / 删除 changefeed、改 store limit)只改内存里的仿真状态, 不会碰任何真实环境;右上角「退出演示」或点「重置」即可还原。 > **演示模式不会动你的真实配置。** 进演示时会先把你的 `cluster / version / PD / TiCDC` > 快照进 `demo_backup`,退出时原样还原;演示期间在「连接设置」里保存的内容会写进这份 > 快照,退出演示后生效 —— 也就是说演示里看到的 `tidb-demo` 只是临时的显示层, > 你的生产集群信息一直在。回归测试见 `tests/demo_cfg_check.py`。 ```bash python server.py --port 8686 # 浏览器打开 http://127.0.0.1:8686 ``` Windows 双击 `start.bat` 也可以。 > 默认监听 `0.0.0.0`。只想本机访问时加 `--host 127.0.0.1`; > 放到中控机上请配防火墙或反代,不要直接暴露到公网。 ## 首次使用:两个必填项 第一件事是填 **集群名** 和 **数据库版本号**。这两个值决定了所有 `tiup` 命令长什么样: | 必填项 | 影响 | | --- | --- | | 集群名 | 自动代入 `tiup cluster <集群名>`,例如 `display` → `tiup cluster display tidb-prod` | | 数据库版本号 | 决定 `ctl:<版本>` / `cdc:<版本>`,例如填 `7.5.7` → `tiup ctl:v7.5.7 pd -u ...`,不会再出现「填 7.5.7 却跑 v8.5.0」 | 打开页面时会**自动从 `tiup cluster list` 读出集群名和版本号**并预填,弹窗只是让你确认一下。 如果自动识别不到(tiup 不在 PATH、SSH 连不上等),弹窗就变成必填: - 缺这两个值时,后端会拦住所有 `cluster` 命令(`list` / `help` 等不需要集群名的除外), 并弹出引导窗口让你补全; - 补全后原命令会自动重试一次,不用手动再点一遍。 版本号支持 `7.5.7`、`v7.5.7`、`7.5.7-nightly` 等写法,会自动补 `v` 前缀。**兼容范围 v6.0 ~ v8.5**, 超出范围会提示但仍然按你填的保存。 填的版本和集群真实版本不一致时,页面顶部会弹提示条,可以一键「用集群版本覆盖」。 ## 连接设置 右上角「连接设置」: | 配置项 | 说明 | | --- | --- | | 执行通道 | `本机执行`:在跑这个工具的机器上直接调用 CLI;`SSH 远程`:通过本机 OpenSSH 连到中控机执行 | | 集群名称 | `tiup cluster` 里的集群名 | | PD 地址 | 如 `http://10.0.0.11:2379`。点「从集群拓扑识别」会用 `tiup cluster display` 自动填 | | **PD 执行方式** | **`PD HTTP API 直连`(默认,推荐):直接打 `/pd/api/v1/*`,不经过 tiup,7.5 / 8.5 通用且最快**;`pd-ctl 命令行`:走 `tiup ctl:<版本>`,组件没装时会先联网下载 | | TiCDC 服务地址 | 如 `http://10.0.0.12:8300`,`cdc cli` 用它做 `--server`;留空则回退用 PD 发现 | | CTL 调用方式 | `tiup ctl:` 或直接调用本机二进制 | | 集群版本 | **必填**。可从 `tiup cluster list` / `display` 自动识别,如 `v7.5.7` / `v8.5.0` | | 审计范围 | 默认只记录**变更类**操作;勾选后只读查询也一并记录 | | SSH 参数 | 主机/端口/用户/私钥/额外选项,建议使用免密密钥 | 点「环境探测」可以看到:tiup 版本、已安装组件清单、`pd` / `cdc` 每种命令形态逐一探测的结果 (哪个能用就用哪个)、以及 PD API 是否连通。 ### 7.5 与 8.5 的兼容处理 ### TiCDC 执行方式:OpenAPI 直连 vs cdc cli TiCDC 页面顶部有一个「执行方式」下拉,也可以在「连接设置 → TiCDC 执行方式」里改: | | OpenAPI 直连(默认,推荐) | cdc cli | |---|---|---| | 依赖 | 只要能访问 `http://:8300` | 需要 tiup 的 `cdc` 组件 | | 首次使用 | 不用下载任何东西 | 要先拉约 100~300MB | | 内网镜像缺版本 | 不受影响 | 装不上,且重试无效 | 直连走 TiCDC 自带的 OpenAPI(`/api/v1/*`,v6.1+ 提供,v6.5 / v7.5 / v8.5 路径一致), 覆盖:changefeed 列表 / 详情 / 创建 / 暂停 / 恢复 / 删除、capture、processor、owner resign。 页面会把界面上的操作翻译成对应的 HTTP 请求,也会把两种通道的返回归一化成同一张表格。 唯一要求是**先填「TiCDC 服务地址」**(连接设置里,形如 `http://10.0.0.12:8300`)。 点集群拓扑页的「自动识别」会顺带把这个地址填上。没填的话页面顶部会红字提示。 ### 组件预检:别再等到超时 `tiup` 第一次用到某个组件(比如 `ctl`)时会**先联网下载约 400MB**,页面在这期间只能干等到超时, 且没有任何提示。现在: 1. 页面加载时自动跑 `tiup list --installed`(结果缓存 60 秒),算出 `pd` / `cdc` 各自需要的组件 2. 执行 `pd` / `cdc` 命令**之前**先检查,缺组件直接拦住并弹窗提示 3. 点「安装」走**后台任务**:每秒轮询,实时显示百分比、已下载/总大小、已用时和滚动日志 4. 装完自动重试原命令(重试时跳过预检,不会死循环) 5. 已有**同大版本**的组件(如需要 `ctl:v7.5.0` 但已装 `ctl:v7.5.7`)视为可用,不拦截 6. tiup 不可用(查不出清单)时不拦截,避免误报 ### 6.0 ~ 8.5 的其它兼容处理 - **PD 默认走 HTTP API 直连**(`/pd/api/v1/*`),这条路径在 v6.0 / v7.5 / v8.5 上完全一致, 彻底绕开「tiup 首次要联网拉 ctl 组件 → 卡住 → 超时」的问题。PD 页面顶部可随时切回 pd-ctl。 - **PD 写入会尝试多种 body 形态**:老版本 PD 只认 `{"schedule.xxx": v}`,新版也接受 `{"schedule": {...}}` 或裸值,逐个试到成功为止。 - **pd-ctl / cdc 的命令形态会自动探测**:`tiup ctl:<版本> pd`、`tiup ctl pd`、本机 `pd-ctl`、 `tiup cdc:<版本> cli`、`tiup cdc cli`、`cdc cli` 逐个试 `--version`,选中第一个可用的并缓存。 - 万一还是超时,输出区会直接给出两个按钮:**预装 ctl 组件**(执行 `tiup install ctl:<版本>`) 和 **PD 改用 API 直连**。 ## 功能模块 - **集群拓扑**(默认首页,本作品的主视觉): - **分层架构图**:`① SQL 层 → ② 调度层 → ③ 存储层 → ④ 列存副本 / ⑤ 增量同步 → ⑥ 下游系统`, 层间用流动虚线画出数据流向,节点按角色着色、带状态圆点,异常节点整块变红 - **版式随节点数自适应**:画布宽度按「一行摆得下」算,1 个 TiFlash + 5 个 TiCDC 时 自动加宽而不是把最右边的节点切掉;节点再多就折行,层带长高而不是缩字号。 同一层的两条分支(列存 / 增量)说明**合成一行**,不会两个标签叠在一起; 地址太长时打省略号收进卡片,鼠标悬停显示完整值 - **一台机器只画一个芯片**:节点来自四个数据源(PD `members` / PD `stores` / TiCDC `captures` / `tiup cluster display`),同一台 TiCDC 天然会被报到两次。 聚合时按 `(角色, 主机)` 合并,但**端口不同不合并** —— 一台机器跑两个 TiKV 实例是合法的; 合并结果与数据源先后顺序无关,且保留 `Owner / Capture` 这种信息量更大的标注 (节点已经 Down 时才改口成 `Down`,不会让停掉的 Capture 还顶着 Owner 的帽子) - **同步链路**:changefeed 不是集群节点,但画出来才讲得清终点,所以单独一层渲染 MySQL / Kafka 下游(密码段自动脱敏) - **Region 分布**:每个 TiKV 的 Region 数横条对比,一眼看出数据是否倾斜 - **副本与角色分布**:TiKV 有 Leader、TiFlash 恒为 0 —— 这张表就是 Raft Learner 的证据 - **技术解读**:6 段可折叠注解就地解释「为什么是这样」 - 数据来源 `/api/topo`:真实模式聚合 PD `members` / `stores`、TiCDC `captures`、`changefeeds` 与 `tiup cluster display`;演示模式直接返回仿真数据,字段完全一致 - **集群概览**:`tiup cluster list` + `display`,组件数量、状态分布、版本信息,可开自动刷新 - **数据量统计**(看体征 · 之一):回答「我有多少数据」和「磁盘占了多少」 - **逻辑数据量 vs 物理占用**:PD 报的 `used_size` 是**单个 store 上那一份副本**的大小, 所有 store 加起来是 N 份副本的总和。所以逻辑量要按 `TiKV 用量 ÷ max-replicas + TiFlash 用量` 折算(TiFlash 是 Raft Learner,不在副本数内,必须单算),物理占用才是磁盘上真实占的量 - **Region 总量**:优先用 PD `regions/count`;老版本没有这个接口时,退回「所有 store 的 peer 数 ÷ 副本数」估算,并明确标注来源,不让读者误以为二者等价 - **分布倾斜**:Region 副本(管容量均衡)与 Leader(管读写压力)分开看。 **Region 均衡但 Leader 集中**是线上最常见的隐性热点,只看容量是发现不了的。 均值样本只取 TiKV —— 混进 TiFlash(只有几十个 Region)会把每台 TiKV 都误判成失衡 - **热点 Top N**:拉取 PD 读写热点 Region,落到具体 store 上 - **按库 / 按表的数据量**:回答「到底是哪一张表在膨胀」—— 这是上面那些集群级数字 答不了的问题,而"磁盘涨得莫名其妙"绝大多数时候就是某一张表或它的某个二级索引 - 读 `information_schema.tables`,**按大小倒序**,膨胀的那张一定在最上面; 数据与索引分开列,索引比数据还大时一眼看得出来 - 先按库汇总(条数与数据量同屏),再看某个库里最大的 20 张表 - **行数标了「估算」**:`TABLE_ROWS` 是 InnoDB 的**采样统计**(analyze 之后才更新, 常见偏差 ±20%),拿它去对账会得出"数据丢了"的结论。每张表都能点**「精算」** 跑一次 `COUNT(*)`,并把估算值、精确值、偏差百分比一起显示出来 - 系统库(`information_schema` / `performance_schema` / `metrics_schema` / `mysql` / `sys`) 不计入业务数据量 - 走独立的 SQL 通道,**它连不上不会把整页拖成空白**:面板原地给「去配置数据库连接」, PD 那份容量与 Region 数据照常显示 - **增长趋势**:每次采样写 `data-history.json`(同一数值不重复落盘,上限 400 条, 采样同时带健康分),画出 Region 数与物理占用的长期曲线,回答「这个集群在怎么长」 - **磁盘水位预测**:对历史采样做最小二乘线性外推,回答「照当前增速还有**几天**到 80% 水位线(附预计日期)」—— 磁盘满是慢性病,扩容+排空要好几天,等红了才动手就晚了。 样本 <3 个或跨度 <1 天时**明说无法外推**而不是硬给一个数字;<7 天到水位会标红提醒。 顺带点名已越过 80% 的个别 store(集群整体水位未到不代表每台都健康) - 数据来源 `/api/insight`,两个视图共用一次拉取,15 秒内切换不重复打 PD - **节点健康度**(看体征 · 之二):把「通不通」升级成「为什么不好」 - **5 类检查项**:副本状态(Up / Disconnected / Down / **Tombstone 不算故障**)、磁盘余量、 版本一致性(滚动升级中途会被认出来)、进程探活、组件自身状态 - **版本一致性先归一化再比**:同一个版本在三个地方有三种写法 —— PD 写 `v7.5.7`、 store 里写 `7.5.7`、TiDB 的 `/status` 写 `8.0.11-TiDB-v7.5.7`(前面那段是 MySQL 兼容版本)。 不归一化直接比字符串,版本整齐的集群会被报成一堆「滚动升级未完成」。 监控组件(Grafana / Prometheus)用的是各自上游的版本号,不参与集群版本比较 - **`/health` 两种返回形状都认**:裸数组 `[{member_id, health}]` 与 `{"healths": [...], "total_count": 1}` 都见过;成员匹配同时支持 `member_id` 与 `host:port`, 不依赖单一字段 - **100 分制**:`notice -8`、`warn -22`、`critical` 直接归零,**`unknown` 不扣分** —— SSH 通道下本工具常常访问不到集群内网,探不到不等于有故障 - **探活降级**:若所有节点都探不通(`net_blind`),探活类检查一律降级成 `unknown` 而非告警。宁可承认不知道,也不制造满屏假红让人从此不信这个页面 - **「未探明项」单列一份**:卡片给条数,下面逐条写出**是哪一项、为什么拿不到**。 只给一个问号等于把问题原样丢回给用户 - **集群总分 = 均值 × 0.4 + 最低分 × 0.6**:纯取平均会让「一个节点死了」被稀释, 而分布式集群恰恰是最弱一环决定可用性;纯取最低又会让「一个次要组件挂了」拖垮整体 - **「待处理问题」只统计 `warn` / `critical`**,页面提示栏写明了这一点 —— 卡片的数字和提示的口径对不上,用户就会开始怀疑整页的数据 - 每个节点可展开看到**每一条检查项的判定依据**,不是只给一个分数 - **参数调优**(知道要改什么 → 改成多少 → 怎么改,三步都在一页): - **三层参数放一起**:PD 配置(集群怎么调度与容灾)、组件运行参数(TiKV / PD / TiFlash 单机怎么分配资源)、TiDB 系统变量(一条 SQL 怎么执行)。线上调参几乎从来不是只改一层, 拆成三个页反而对不上 - **集群画像 + 档位**:从 TiKV / PD / TiDB / TiFlash 台数、逻辑数据量、Region 总数、 副本数、磁盘水位自动判档(tiny / small / medium / large), **两个维度取更高的一档** —— 3 台 TiKV 装了 20 TiB 的集群,压力来自数据量而不是节点数, 只按台数判会把它判成小型,调度并发就给小了。场景档(业务高峰 / 扩容追赶 / 故障恢复) 推不出来,只能手选 - **每条建议都带理由**:建议值不是「最优解」,是与该档位相称的起点。 理由写清楚是为了让你判断它适不适合你 —— 磁盘是 NVMe、有明确低峰窗口,就按自己的判断覆盖它 - **TiDB 系统变量**:内置 195 个变量的中文说明(作用、默认值、作用域、风险等级), 再叠加集群里实时读到的当前值。**字典没收录的变量也会列出来**(真实集群有 600+ 个, 只覆盖字典那部分等于没列全)。可一键 `SET GLOBAL`,也可只复制 SQL 自己去执行 - **组件运行参数**:`SHOW CONFIG` 按组件聚合并标出**实例间取值是否一致** (一个 5 节点集群里 2 台块缓存是 8GiB、1 台是 10GiB,这种不一致必须看得见), 支持 `SET CONFIG` 在线改并持久化到 PD - **PD 全量配置**:所有配置项都能改,改动过的行会高亮,应用前可先生成等价的 `pd-ctl config set` 命令核对;**逐项下发**而不是合成一个大请求 —— 某一项被这个版本的 PD 拒绝时,只会有那一项失败并告诉你 PD 回了什么,不会连累其它项 - **改不了的会明说**:会话级变量不给代改(改了只影响工具自己的连接,等于骗人), PD 的启动参数(`name` / `data-dir` / `client-urls` / 证书路径)在线改会被 PD 忽略, 这里直接拦下来并提示「改 tiup 拓扑后滚动重启」,而不是假装成功 - **SQL 通道**:系统变量与组件参数走 `mysql` 客户端,跟随现有的「本机 / SSH」执行通道。 密码**只保存在服务进程内存里,不写 `config.json`**,也不用 `-p密码`(会出现在 `ps` 里), 而是走 `MYSQL_PWD`;想免密就配 `~/.my.cnf`。连不上也不影响查说明、生成 SQL - **连不上时不再甩英文报错**:这是真机上最常撞到的一堵墙 —— 页面只弹一行 `ERROR 1045 (28000): Access denied for user 'root'@'127.0.0.1' (using password NO)`, 用户既分不清是「密码没填」还是「语句写错」,也不知道下一步干什么。 现在把 mysql 的错误码归一成 11 类(没带密码 / 密码不对 / 库名不存在 / 端口不通 / socket 不存在 / 来源地址被拒 / 超时 / 语法错 / 版本不支持 …),换成中文结论, 并弹一个框直接给出口:**「未配置 → 是否配置数据库连接?」** - 能靠改连接解决的才引导去改;语法错误不会被误导去改连接(改了也没用) - 原始报错折在弹框里可展开核对 —— 结论给人看,证据留给要核对的人 - SQL 地址还指着 `127.0.0.1` 而集群在别处时,会**从 PD 地址推出一个更可能对的地址** 并给出「一键改成 x.x.x.x:4000」。这个坑看起来像密码问题,其实是连错了机器 —— `127.0.0.1` 指的是工具自己,不是 TiDB - 顶部状态徽标同步改口为「SQL 连接失败」,不再一边失败一边显示绿色「已连接」 - 进页面自动弹,但**同一条错误只弹一次**(每刷一次弹一次的话,用户只会条件反射关掉它) - **一键巡检报告**(健康页「导出巡检报告」):把健康度结论、待处理问题逐条、 数据量与水位预测、近 10 次采样的分数趋势拼成一份 Markdown 下载。 老板/客户问「集群最近怎么样」时,不再截一堆 Grafana 图拼邮件。 纯前端拼装(数据全部来自刚拉的体检结果),不新增后端接口 = 不新增出错面 - **健康度告警**(连接设置 → 告警推送):服务端后台线程盯健康度,配了 企业微信/钉钉群机器人 Webhook 就会把「变坏 / 升级 / 恢复」推到群里 - 只在**状态迁移**时推:变坏(ok→warn)、升级(warn→critical)、恢复(warn→ok) 各一条;持续保持坏状态不重复推 —— 刷屏的告警很快就会被人忽略 - **三种情况明确不推**:演示模式(demo 里埋的故障是演的)、PD 探不到 (探不到 ≠ 集群挂了,网络问题该修网络而不是吓人)、等级 unknown (既不算坏也不算恢复) - 发送失败保留旧状态自动重试;改配置即时生效,不用重启服务 - **集群概览**:`tiup cluster list` + `display`,组件数量、状态分布、版本信息,可开自动刷新 - **关于本作品**:一屏讲清它是什么、怎么读数的、安全边界在哪,以及完整的技术解读索引 - **集群与启停**:拓扑表格(节点/角色/端口/状态/目录),集群级与节点级 `start / stop / restart / reload`、`show-config`、`audit` - **扩容 / 缩容 / 清理**(集群页顶部工具栏): - `扩容`:填 `scale-out.yaml`(内置 TiKV / TiFlash 模板),一键写到**执行 tiup 的那台机器**上 (SSH 通道走 base64 写远端文件),确认后执行 `tiup cluster scale-out <集群名> ` - `缩容`:从最新拓扑里勾选节点,可勾 `--force`,确认后 `tiup cluster scale-in <集群名> -N host:port` - `清理残留`:缩容后节点会变成 Tombstone,Grafana / Prometheus 里还挂着。执行 `tiup cluster prune <集群名>` 清掉,缩容成功后页面会自动提示你执行 - **PD 运维**(默认 HTTP API 直连,可切 pd-ctl): - **Store**:容量 / 可用 / Region / Leader 统计,可查看单个 store、下线 store - **标出 TiKV 还是 TiFlash**:TiKV 和 TiFlash **混在同一份 store 列表里**, PD 不会直接给类型(只能靠 `labels` 里的 `engine` 或端口判断),而这个判断在前端做不了 —— 表格会把嵌套对象拍平成 `[object Object]`,所以由服务端在 `normalize_pd` 里标注。 不标出来的话,"某台 Leaders 恒为 0" 会被当成故障,其实那只是 TiFlash: 它是**列存副本(Raft Learner),只同步不投票**,Leaders 天然是 0,容量也是单独一块盘。 徽标上鼠标悬停有这句解释 - **可用比例不会再算出负数**:PD 返回的 `capacity` / `available` 是**带单位的字符串** (`"1.719TiB"` 对 `"786.8GiB"`),直接 `parseFloat` 会得到 `1.719` 和 `786.8` 两个不同量纲的数,一相减就是 `-45671%`。现在先按单位统一折算成 GiB 再算, 徽标显示的是**「已用 N%」**(≥80% 红、≥60% 黄,到 80% PD 会开始拒绝往这台机器调度), 悬停能看到 `已用 x / y GiB` 的具体口径 - 表脚写了这两列该怎么读、两种引擎的区别 - 调度器:查看、新增、移除、按秒暂停 - Region:按 ID 查询、`topread/topwrite/topconfver/...`、副本缺失检查 - **热点**:`hot read / write / store`。PD 的输出不是一张表,这里做成了人能读的样子: - **热点 Store**:PD 给的是「指标 → store → 速率」的**嵌套结构**,直接拍平渲染会让列名 变成 `bytes-write-rate` 这种 key。现在**转置成一行一台 store**,列名换成中文 (写入流量 / 读取流量 / 写入 Key 速率 / 读取 Key 速率),速率带单位(`MiB/s`、`keys/s`), 按首个指标倒序并配流量条 —— 谁最高一眼就见 - **热点 Region**:PD 7.x 的形态是 `as_peer` / `as_leader` 两个视角下面按 store 聚合、 明细藏在 `statistics` 数组里。这里按 store 汇总成行(热点 Region 数 / 流量合计 / Key 速率 / Query 速率),**Region 明细折叠进 `
`**,展开只挑人看得懂的列 (Region、角色 Leader/Follower/Learner、热度、流量、Key 速率),不再把 JSON 塞进单元格 - 同一个 Region 在 `as_peer` 和 `as_leader` 里都会出现,结果**按 region_id 去重**(保留流量更大的那条) - **写热点只看 `as_leader`**(客户端写请求只发给 leader),读热点两个视角都要看 (Follower Read 会把读分到 peer 上)—— 这句区别写在面板底部 - `{"regions": [...]}` 这种老形态(PD 5.x / pd-ctl)同样认,不会在新代码里失效 - **配置与调度速度**(扩容后最常用的就在这里): - 顶部显示副本数(`max-replicas`)等副本信息 - **调度速度预设**:停止 / 缓慢 / 标准 / 快速,一次确认整体下发 (对应 `leader-schedule-limit`、`region-schedule-limit`、`replica-schedule-limit`、 `merge-schedule-limit`、`hot-region-schedule-limit`、`max-snapshot-count`、 `max-pending-peer-count`、`store-balance-rate`) - **全量配置编辑器**:不再写死 8 个参数,而是把 PD `/pd/api/v1/config` 返回的 **全部配置项**(演示集群实测 55 项)按分区列出,每项带中文名、说明、默认值、生效性, 可单独改、可一键填入建议值、可批量应用。 与「参数调优 → PD 全量配置」是同一个编辑器实例,两处看到的完全一致 - **Store Limit**:查看全部或单个 store 的限流值,直接设置 `rate` (等价于 `pd-ctl store limit `) - 底部可展开查看 PD 完整配置 - **TiCDC**(默认 OpenAPI 直连,可切 cdc cli):changefeed 列表(含 state 与 checkpoint)、 详情、暂停、恢复、删除;表单化创建;capture 与 processor 列表 - **命令控制台**:白名单内直接敲命令,支持自动/表格/JSON/文本四种输出解析; 命令类型多了 `PD API 直连` 和 `TiCDC API 直连`(直接填 `GET stores` / `GET changefeeds` 这种) - **操作审计**:本工具所有执行记录(命令、通道、退出码、耗时),落盘到 `audit.log`; **默认只记录变更类操作**,只读查询不入审计(可在「连接设置 → 审计范围」打开)。 集群页的「操作记录」是 `tiup cluster audit` 的历史(列表 + 点开看详情 + 关键字过滤) ## 输出配色规则 - **退出码 0 时**,`stderr` 一律按**黄色提示**渲染 —— tiup / pd-ctl 常把「新版本提醒」 「等待中」之类信息写进 stderr,这不是错误 - **退出码非 0**(含超时 -2、连不上 -1)才标红为错误,并在超时场景下给出自救按钮 ## 安全设计 1. **命令白名单**:可执行程序只允许 `tiup`、`pd-ctl`、`cdc`;`tiup cluster` 与 `pd-ctl`/`cdc cli` 的子命令也各自白名单 2. **参数校验**:`shell=False` + 参数数组传递;额外拦截 `; & | $ \` < > ( )` 与换行,防止拼接注入(SSH 场景会经远程 shell) 3. **危险操作二次确认**:`start/stop/restart/reload/scale-in/scale-out/prune`、`store delete`、`scheduler add/remove/pause`、`config set`、PD 配置写入、`changefeed create/pause/resume/remove` 等会弹窗要求输入目标名(集群名 / store id / changefeed id)才执行;后端在未带 `confirm` 时直接拒绝,前端弹窗只是第一道 4. **地址规范化**:PD 地址会自动补 `http://` 与默认端口 `2379`,并校验主机名合法性, 避免出现 `-u http://0.0.0.2379` 这种无效地址 5. **只监听回环地址**,不开放外部访问(`--host` 可改,详见部署一节) 6. **审计**:变更类操作写入 `audit.log` 7. **SQL 通道只放行读与 SET**:`SHOW` / `SELECT` / `SET` / `EXPLAIN` / `DESC` / `USE` 之外的动词一律拒绝;一次只能一条语句(引号内的分号不算分隔);禁止注释 (`--` / `/*` / `#` —— 这是最常见的绕行手段);`SET` 必须是 `GLOBAL` / `SESSION` / `CONFIG` / `@@` 形态。 **这个页面的职责是调参数,不是给人一个随手能 `DROP` 表的入口** —— 想跑 DDL/DML 请去命令控制台 8. **`SET PASSWORD` 点名拦掉**:它语法上完全合法(`SET x = v`),但效果是改掉数据库账号的密码, 不属于调参数。这类"看着不像危险"的语句不能靠形态判断,只能点名 9. **不保存任何密码**:SQL 通道的密码只存在于服务进程内存,重启即失效,不写 `config.json`; 传给客户端走 `MYSQL_PWD` 环境变量而不是 `-p密码`(后者会出现在 `ps` 输出里) ## 已知边界 - `upgrade` / `destroy` / `rename` 等复杂命令建议走「命令控制台」 - SSH 通道依赖本机 `ssh` 客户端,不支持交互式密码登录 - 扩容的 `scale-out.yaml` 需要自己填(内置 TiKV / TiFlash 模板);新节点的目录、端口 要和目标机器现状一致,tiup 会在执行时校验 - PD HTTP API 直连、TiCDC OpenAPI 直连都是从**本工具所在机器**发起的;SSH 通道下若这台机器 访问不到集群内网,请把「PD 执行方式」切成 pd-ctl、「TiCDC 执行方式」切成 cdc cli - OpenAPI 只支持 TiCDC v6.1+;更老的版本请切回 cdc cli - 通过 OpenAPI 创建 changefeed 时,cdc cli 专属的 `--config` 文件与 GC 开关不生效 (OpenAPI 只接受 `changefeed_id` / `sink_uri` / `start_ts`),要带配置文件请用 cdc cli 模式 - 集群首次 `display` 解析依赖 tiup 的等宽表格输出;如遇格式差异会退回按空白切分 ## 排错 **「unknown api: /api/probe」** 说明浏览器加载的是新版前端、但后端 `server.py` 还是旧的(两者要一起更新)。 `/api/probe`(环境检测)在新版里同时注册了 GET 和 POST,旧后端只有 POST, 所以「环境检测」按钮会 404。重新解压完整包、`./restart.sh` 重启即可。 **一直弹「安装 tiup 组件」,点了却怎么都装不成功** 先确认报的是哪一种错: - `version v7.5.7 ... for component cdc not found: unknown version` → **不是网络问题,也不是命令拼错**:你用的 tiup 仓库/镜像里没有 `cdc` 的这个补丁版本。 很多内网镜像只同步了部分版本(`v7.5.6` 有、`v7.5.7` 没有很常见),重试多少次结果都一样。 现在工具会在**开下载任务之前**先 `tiup list --all cdc` 问一遍仓库,版本不存在就直接 告诉你「仓库里有哪些版本」并给出两个按钮:**改装建议版本**(如 `cdc:v7.5.6`)、 **改用 OpenAPI 直连**(对 TiCDC 来说后者完全不用下载,推荐)。 - 一直在下载、进度条不动 → 才是真的网络/镜像慢,看进度条和已用时判断。 - `command not found: tiup` → 连接设置里把 `tiup` 改成完整路径(如 `/root/.tiup/bin/tiup`)。 组件名是 `cdc` 不是 `ticdc`(`tiup list --all ticdc` 查不到是正常的)。 **页面显示「首次使用请先填写集群名和数据库版本号」** 说明后端配置里 `cluster` / `version` 是空的。正常情况打开页面就会自动识别填上; 识别不到时点弹窗里的「保存并开始」,或在「连接设置」里手填这两个值。 ## 部署到 Linux 中控机 ```bash unzip -P '你的密码' tiup-web.zip # 若报 unsupported compression method 99,见下方说明 cd tiup-web chmod +x restart.sh start.sh ./restart.sh # 默认动作 = 重启,监听 0.0.0.0:8686 ``` `restart.sh` 用法(后台常驻,日志写 `server.log`,PID 写 `tiup-web.pid`): ```bash ./restart.sh # 重启(默认) ./restart.sh start # 启动 ./restart.sh stop # 停止 ./restart.sh status # 查看运行状态 ./restart.sh log # tail -f 跟踪日志 PORT=9000 HOST=127.0.0.1 ./restart.sh start # 改端口/监听地址 ``` **监听地址**:默认 `0.0.0.0`,方便直接从办公机浏览器打开。如果端口暴露面较大,建议改回 `127.0.0.1` 并走 SSH 隧道,安全性更好: ```bash HOST=127.0.0.1 ./restart.sh start # 本地再开一条隧道:ssh -L 8686:127.0.0.1:8686 user@中控机 ``` **Python 版本**:最低 Python 3.6(CentOS 7 自带的 3.6.8 可用)。3.7+ 用 `ThreadingHTTPServer`, 3.6 会自动回退到 `socketserver.ThreadingMixIn + HTTPServer`。另外 SSH 通道在 CentOS 7 的 OpenSSH 7.4 下会自动把 `StrictHostKeyChecking=accept-new` 降级为 `no`(7.4 不认识该选项)。 > **关于压缩包加密**:打包请用 ZipCrypto(传统 PKWARE 加密)而非 WinZip AES。 > Linux 自带 `unzip` 不支持 AES,会报 `unsupported compression method 99`。 > 7-Zip 打包时加 `-mem=ZipCrypto`;或用本项目同目录的 `pack.py`(见下一节)。 > 若机器上装了 `p7zip`,也可以 `7z x -p密码 tiup-web.zip` 解 AES 包。 ## 文件 ``` server.py 后端:配置、执行器、白名单、解析、审计、/api/topo 拓扑聚合 demo.py 演示模式:内置 17 节点仿真集群,拦截执行/取数入口 restart.sh Linux 后台启停/重启脚本(start|stop|restart|status|log) start.sh Linux 前台启动脚本(调试用) start.bat Windows 启动脚本 catalog.py 参数知识库:195 个 TiDB 系统变量 + 79 项 PD 配置的中文字典、 4 个规模档 + 4 个场景档的建议值与理由、按集群画像自动判档(纯数据 + 纯函数) public/ 前端页面(index.html / app.js / style.css) docs/ 投稿材料:21 张截图 + demo.mp4 演示视频 + COMMUNITY_POST.md 社区帖子全文 + GITHUB_RELEASE.md 发版清单(含脱敏自检) tests/ 开发与校验脚本,不进部署包 pack.py 打包脚本(ZipCrypto,Linux unzip 可直接解) .github/workflows/ CI:后端 6 套回归(Python 3.8 / 3.12)+ 前端语法检查与 jsdom 冒烟 config.example.json 配置模板(复制为 config.json 后按需修改;config.json 含真实环境信息,已 gitignore) config.json 连接配置(首次保存后生成,不入库) audit.log 操作审计(自动生成) data-history.json 数据量采样历史,「增长趋势」折线的数据源(自动生成,演示模式不写入) ``` ### tests 目录说明 | 脚本 | 用途 | | --- | --- | | `check_ids.py` | HTML id ↔ JS 引用交叉校验、CSS class 是否定义(纯静态分析,秒级) | | `demo_check.py` | 演示模式 39 项回归:7 个 pd-ctl 子命令 / cdc cli / PD API / TiCDC API | | `demo_cfg_check.py` | **演示模式不许碰真实配置** 42 项回归:进演示快照 / 退出还原 / 演示中改配置 / 脏输入 / 重启安全 | | `topo_check.py` | **真实模式** 75 项回归:mock PD / TiCDC / `tiup cluster display` 跑 `build_topo`,不需要真集群 | | `insight_check.py` | **数据体检** 158 项回归:演示↔真实字段对称对齐、副本/逻辑量换算、评分模型、5 类检查项判定、探活降级、倾斜均值、历史落盘、演示数据自洽性、磁盘水位外推、告警判定与 webhook 发送(本机回环)、PD /health 两种返回形状、版本号归一化 | | `tune_check.py` | **参数调优** 102 项回归:变量/PD 字典数据完整性、建议值指向真实参数、档位自动识别、SQL 白名单与注入拦截、演示模式 PD 改动真的落盘、类型强转(uint64 / bool)、启动参数被拦 | | `smoke.js` | jsdom 无浏览器冒烟:148 项(渲染项、视图切换、主题、演示开关与配置隔离、参数调优三个页签、PD 全量编辑器、连接失败弹框与恢复、部分数据失败提示、**PD Store 表的容量换算与 TiKV/TiFlash 区分、热点 Store / 热点 Region 的可读化、按库按表数据量、库表通道失败时不影响 PD 数据**) | | `shots.js` | 用本机 Edge 出投稿截图(含封面与各功能页) | | `record.js` | 用本机 Edge 录制演示视频,自动加字幕条与鼠标光圈,输出 mp4 | | `inspect.js` | 切到每个视图 dump 高度 / 元素数,用来确认页面不是空壳 | | `shot_warn.js` | 拍「部分数据拿不到」时的页面,验证提示条出现且不遮挡内容 | | `shot_demo_cfg.js` | 真浏览器验证「演示模式不动真实配置」:开演示 → 看表单 → 退出 → 比对还原,并出图 | | `shot_insight.js` | 真浏览器端到端验证两个新建视图(数据量统计 / 节点健康度),检查渲染项与残留空态,出两张图 | | `shot_pd.js` | 真浏览器验证 PD 里那两张最容易看错的表:Store 表(引擎标注、可用比例无负数、不横向溢出)与热点表(列名不是 metric key、无 `[object Object]`、有 leader/peer 双视角),出两张图 | | `audit_all.js` | **全站低级错误横扫**:真浏览器遍历 11 个视图 + 12 个子面板,自动抓 `[object Object]` / `NaN` / `undefined` / 负百分比 / 四位以上百分比 / metric key 当表头 / 13 位以上裸数字 / 表格横向溢出 / 填了内容却还挂着「暂无数据」样式。用户连续反馈的都是同一类问题,修一处不够,得有脚本兜底 | | `shot_tune.js` | 真浏览器**量**参数调优页的列宽:说明块必须跨满整行(≥400px)且不被竖排,出四张图 | | `shot_sqlerr.js` | 真浏览器验证「连接失败 → 弹框问是否配置」:乱码检查、按钮文案、跳转设置框并带上上次报错,出两张图 | | `topo_fit.js` | 真浏览器**量**拓扑图版式:层说明之间不许重叠、不许被卡片压住、卡片不许越出画布、卡片之间不许互相压、卡片里的字不许戳出边框。跑三种形状(演示 / 用户报障形状 / 12 TiKV 压力),重叠与越界这类问题 jsdom 断言不出来 | | `shot_topo.js` | 拍拓扑图三张(暗色 / 亮色 / 1 TiFlash + 5 TiCDC),并断言每个层说明各占一行基线 | | `fake_topo_dup.py` | 造一个**真实模式**的假集群:`build_topo` 保持原样不替换,只换掉 PD / TiCDC / tiup 三个下游入口。3 台 TiCDC 在 captures 与 display 里各出现一次 —— 用户报「只有 3 个却列了 6 个」的形状 | | `shot_topo_dup.js` | 真浏览器验证去重:接口与页面各数一遍 TiCDC 芯片,断言 3 个、地址不带端口、标注仍是 Owner/Capture、无重复芯片,出图 | | `video_cards.html` | 演示视频的 5 张标题卡(片头 / 痛点 / 做法 / 上手 / 片尾),与产品同一套暗色科技风 | | `shot_cards.js` | 用本机 Edge 把上面 5 张卡渲染成 1280×720 PNG,供 ffmpeg 合成 | | `make_video.py` | 视频合成:5 张卡 + 8 张产品截图 = 13 段,统一缩放到 1280×720 / 25fps,`drawtext`(`msyh.ttc`)+ `zoompan` 做缓慢推近,段间 `xfade` 叠化,输出 `docs/demo.mp4`。Windows 下 `drawtext` 的字幕文件路径要盘符后转正斜杠、冒号转义成 `\:`,否则报 `Unable to open` | | `comic_panel.html` | 四格漫画的排版模板:暗色科技风 + 编号徽标 + 中文文案 + 页脚。AI 画的插画里一个汉字都不放(画中文必乱码),文案全交给它排 | | `comic_panel.js` | 把 4 张 AI 插画拼成一张带文案的四格漫画,输出 `docs/comic-4panel.png`。**关键一步是去水印** —— 图像生成工具会在右下角烙「AI生成 / WORKBUDDY」,而活动规则要求剔除水印。水印离边缘只剩 4px 裁不掉,改用 ffmpeg `delogo` 对框内做像素插值(周围是干净的暗色渐变,填回去看不出来)。另外会自动跳过体积 <100KB 的图 —— 生成失败时模型会给一张近乎全黑的图,实测 13KB vs 正常 1.1MB | | `secret_scan.py` | **发布前脱敏自检**:扫整个仓库,找漏出去的真实集群名 / PD 地址 / 明文密码 / SSH 私钥路径。签名不写死在脚本里,而是运行时从 `config.json` 读(CI 上没有该文件就只跑通用规则)—— 写死的话,批量替换脱敏串时会连检测器的特征一起换掉,检测器就废了 | ## 自检 ```bash python tests/check_ids.py # HTML id 与 JS 引用是否对得上 python tests/demo_check.py # 演示模式 31 项回归(不需要起服务) python tests/demo_cfg_check.py # 演示模式 ↔ 真实配置隔离 42 项(不需要起服务) python tests/topo_check.py # 真实模式 75 项回归(mock 集群数据,不需要真集群) python tests/insight_check.py # 数据体检 158 项回归(含水位外推、告警、版本归一化、热点新形态解析) python tests/tune_check.py # 参数调优 102 项回归(字典、SQL 白名单、报错归类、演示链路) python -m py_compile server.py demo.py catalog.py pack.py # 语法检查(CentOS 7 用 python3.6 跑) # 前端冒烟:起服务后用 jsdom 真跑一遍页面,检查渲染项 + 11 个视图切换 + 主题/演示开关 SMOKE_PORT=8686 node tests/smoke.js # 截图 / 录屏(需要 playwright-core + 本机 Edge) node tests/shots.js 8686 node tests/shot_insight.js 8686 # 只拍数据体检这两页 node tests/shot_tune.js 8686 # 拍参数调优三页签,并量出说明块的列宽 python tests/fake_sql_fail.py 8688 & # 造一个"SQL 一定失败"的服务 node tests/shot_sqlerr.js 8688 # 拍连接失败弹框,并验证跳转与文案 node tests/topo_fit.js 8686 # 量拓扑图版式(重叠 / 越界 / 文字戳出边框 / 芯片互压) node tests/shot_topo.js 8686 # 拍拓扑图三张(暗色 / 亮色 / 5 个 TiCDC) python tests/fake_topo_dup.py 8689 & # 造一个真实模式的假集群(3 台 TiCDC 两路各报一次) node tests/shot_topo_dup.js 8689 # 验证去重:接口与页面都得是 3 个 TiCDC node tests/record.js 8686 ``` > 演示模式走的是 `demo.py` 里的假数据,测不到真实链路的解析问题; > `topo_check.py` 专门补这一块 —— 它把 `call_pd_api` / `call_cdc_api` / `run_command` > 换掉,直接测 `build_topo` 的聚合逻辑,PD 挂了、display 挂了、返回脏数据都覆盖了。 > 里面 `_CDC_ROWS` 那组假数据是有来历的:**tiup cluster display 的表里本来就有 TiCDC 行**, > 早期夹具漏了这一行,于是"同一台 TiCDC 被两路各报一次"这个 bug 一直测不出来 —— > 线上表现就是 3 台 TiCDC 在拓扑图上画成 6 个。 > `demo_cfg_check.py` 把 `CONFIG_PATH` 指到临时目录,所以随便跑它都不会动你的 > `config.json`。它守的是一条硬规矩:**演示模式只换数据源,绝不改用户的真实配置。** > `insight_check.py` 守的是另一条:**演示数据必须与真实聚合链路逐字段对齐**(连顶层 > `unreachable` 这种字段也做对称差,只查一个方向是不行的)。演示能看、一接真实集群就报错,对这类小工具来说是最致命的事故 —— 而对黑客松作品,那是直接归零。 > `record.js` 第一次跑会提示缺 playwright 的 ffmpeg。 > 解决办法:`npm i ffmpeg-static`,再把 `node_modules/ffmpeg-static/ffmpeg.exe` > 复制到 `%LOCALAPPDATA%\ms-playwright\ffmpeg-<版本号>\ffmpeg-win64.exe`。 ## 技术栈 - **后端**:Python 标准库(无第三方依赖),兼容 Python 3.6+ - **前端**:原生 HTML / CSS / JavaScript,无构建步骤、无框架、无 CDN 依赖 - **配色**:CSS 变量 + `html[data-theme]`,深浅两套主题共用同一组语义变量 > 零依赖不是炫技。这工具的部署目标是**生产集群的中控机** —— 那种机器上装个包要 > 走审批、pip 源可能不通、Python 版本可能是 3.6。能 `python server.py` 直接跑起来, > 比用什么框架重要得多。 ## English TiScope visualizes the `tiup` / `pd-ctl` / `cdc` CLIs as a live, self-explaining cluster topology. Zero dependencies — Python standard library only, no build step, no framework, no CDN. ```bash python server.py --port 8686 # then open http://127.0.0.1:8686 # No TiDB cluster at hand? Toggle 演示模式 (Demo Mode) — a built-in 17-node # simulated cluster, including one failed node and one failing changefeed. ``` Requires Python 3.6+ (tested on 3.8 / 3.12). Backend regressions live in `tests/*.py`; the frontend has a browser-free jsdom smoke test (`node tests/smoke.js`) and a real-browser audit that sweeps every view for rendering mistakes (`node tests/audit_all.js `). See [`CHANGELOG.md`](CHANGELOG.md). ## 许可 [Apache License 2.0](LICENSE) —— 与 TiDB 生态保持一致。 > 部署到生产中控机时请只监听内网(`--host 127.0.0.1` 或配合防火墙)。 > 本工具能下发扩缩容、PD 配置、TiCDC 任务等变更操作,虽然内置了危险命令拦截 > 与二次确认,也不应暴露到公网。