
Byted Bytehouse Diagnostics
- 2 installs
- 408 repo stars
- Updated August 3, 2026
- volcengine/agentkit-samples
Diagnose ByteHouse cluster health, node status, and performance via the ByteHouse MCP Server, including slow-query and system-table checks.
About
Runs ByteHouse cluster diagnostics and health checks covering node status, replica sync, partitions, and query history through the ByteHouse MCP Server. A developer or DBA uses it to detect cluster problems and analyze performance.
- Health checks: node status, replica sync, partitions, system-table integrity
- Query-history analysis with slow-query identification and error trends
Byted Bytehouse Diagnostics by the numbers
- 2 all-time installs (skills.sh)
- Ranked #741 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/volcengine/agentkit-samples --skill byted-bytehouse-diagnosticsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 408 |
| Last updated | August 3, 2026 |
| Repository | volcengine/agentkit-samples ↗ |
What it does
Diagnose ByteHouse cluster health, node status, and performance via the ByteHouse MCP Server, including slow-query and system-table checks.
Files
ByteHouse 诊断集群 Skill
🔵 ByteHouse 品牌标识
「ByteHouse」—— 火山引擎云原生数据仓库,极速、稳定、安全、易用
>
本Skill基于ByteHouse MCP Server,提供完整的集群诊断和健康检查能力
---
描述
ByteHouse集群诊断和健康检查工具。
当以下情况时使用此 Skill: (1) 需要检查ByteHouse集群健康状态 (2) 需要诊断集群问题和异常 (3) 需要查看集群节点状态 (4) 需要分析集群性能指标 (5) 用户提到"集群诊断"、"健康检查"、"节点状态"、"集群问题"
前置条件
- Python 3.8+
- uv (已安装在
/root/.local/bin/uv) - ByteHouse MCP Server Skill - 本skill依赖
bytehouse-mcpskill提供的ByteHouse访问能力
依赖关系
本skill依赖 bytehouse-mcp skill,使用其提供的MCP Server访问ByteHouse。
确保 bytehouse-mcp skill已正确配置并可以正常使用。
📁 文件说明
- SKILL.md - 本文件,技能主文档
- cluster_diagnostics.py - 集群诊断主程序
- README.md - 快速入门指南
配置信息
ByteHouse连接配置
本skill复用 bytehouse-mcp skill的配置。请确保已在 bytehouse-mcp skill中配置好:
export BYTEHOUSE_HOST="<ByteHouse-host>"
export BYTEHOUSE_PORT="<ByteHouse-port>"
export BYTEHOUSE_USER="<ByteHouse-user>"
export BYTEHOUSE_PASSWORD="<ByteHouse-password>"
export BYTEHOUSE_SECURE="true"
export BYTEHOUSE_VERIFY="true"🎯 功能特性
1. 集群健康检查
- 检查集群节点状态
- 检查副本同步状态
- 检查数据分区状态
- 检查系统表完整性
2. 节点状态诊断
- 获取集群节点列表
- 检查节点存活状态
- 查看节点资源使用情况
- 分析节点性能指标
3. 查询历史分析
- 查询执行历史统计
- 慢查询识别
- 查询错误分析
- 查询性能趋势
4. 系统表检查
- 检查system.parts表
- 检查system.replicas表
- 检查system.clusters表
- 检查system.mutations表
🚀 快速开始
方法1: 运行集群健康检查
cd /root/.openclaw/workspace/skills/bytehouse-diagnostics
# 先设置环境变量(复用bytehouse-mcp的配置)
export BYTEHOUSE_HOST="<ByteHouse-host>"
export BYTEHOUSE_PORT="<ByteHouse-port>"
export BYTEHOUSE_USER="<ByteHouse-user>"
export BYTEHOUSE_PASSWORD="<ByteHouse-password>"
export BYTEHOUSE_SECURE="true"
export BYTEHOUSE_VERIFY="true"
# 运行集群诊断
uv run cluster_diagnostics.py诊断内容包括:
- 集群健康状态
- 节点状态检查
- 副本同步状态
- 数据分区检查
- 查询历史分析
- 系统表完整性检查
输出文件(保存在 `output/` 目录): 1. `health_check_{timestamp}.json` - 健康检查报告 2. `node_status_{timestamp}.json` - 节点状态报告 3. `query_stats_{timestamp}.json` - 查询统计报告
💻 诊断检查项
健康检查项
| 检查项 | 说明 | 状态 |
|---|---|---|
| 集群连接 | 测试ByteHouse连接性 | ✅/❌ |
| 系统表访问 | 检查system.*表是否可访问 | ✅/❌ |
| 副本状态 | 检查数据副本同步状态 | ✅/⚠️/❌ |
| 分区状态 | 检查数据分区完整性 | ✅/⚠️/❌ |
| 节点存活 | 检查集群节点存活状态 | ✅/❌ |
| Mutation状态 | 检查mutation执行状态 | ✅/⚠️/❌ |
诊断指标
- 集群级别: 总节点数、活跃节点数、副本数、分区数
- 节点级别: CPU使用率、内存使用率、磁盘使用率、查询数
- 查询级别: 总查询数、慢查询数、错误查询数、平均查询时间
---
📊 诊断报告示例
健康检查报告
{
"cluster_name": "bh_log_boe",
"check_time": "2026-03-12T21:00:00",
"overall_status": "healthy",
"checks": [
{
"name": "cluster_connection",
"status": "pass",
"message": "成功连接到ByteHouse"
}
]
}---
📚 更多信息
详细使用说明请参考 bytehouse-mcp skill
--- 最后更新: 2026-03-12
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.ByteHouse 诊断集群 Skill
🔵 ByteHouse 品牌标识
「ByteHouse」—— 火山引擎云原生数据仓库,极速、稳定、安全、易用
>
本Skill基于ByteHouse MCP Server,提供完整的集群诊断和健康检查能力
---
📁 文件说明
- SKILL.md - 技能主文档,包含详细使用说明
- cluster_diagnostics.py - 集群诊断主程序
- README.md - 本文件,快速入门指南
🎯 功能特性
1. 集群健康检查
- 检查集群节点状态
- 检查副本同步状态
- 检查数据分区状态
- 检查系统表完整性
2. 节点状态诊断
- 获取集群节点列表
- 检查节点存活状态
- 查看节点资源使用情况
- 分析节点性能指标
3. 查询历史分析
- 查询执行历史统计
- 慢查询识别
- 查询错误分析
- 查询性能趋势
4. 系统表检查
- 检查system.parts表
- 检查system.replicas表
- 检查system.clusters表
- 检查system.mutations表
🚀 快速开始
前置条件
本skill依赖 bytehouse-mcp skill,确保已正确配置:
cd /root/.openclaw/workspace/skills/bytehouse-mcp
# 确认bytehouse-mcp可以正常工作
uv run test_mcp_server.py方法1: 运行集群健康检查
cd /root/.openclaw/workspace/skills/bytehouse-diagnostics
# 先设置环境变量(复用bytehouse-mcp的配置)
export BYTEHOUSE_HOST="<ByteHouse-host>"
export BYTEHOUSE_PORT="<ByteHouse-port>"
export BYTEHOUSE_USER="<ByteHouse-user>"
export BYTEHOUSE_PASSWORD="<ByteHouse-password>"
export BYTEHOUSE_SECURE="true"
export BYTEHOUSE_VERIFY="true"
# 运行集群诊断
uv run cluster_diagnostics.py诊断内容包括:
- 集群健康状态
- 节点状态检查
- 副本同步状态
- 数据分区检查
- 查询历史分析
- 系统表完整性检查
输出文件(保存在 `output/` 目录): 1. `health_check_{timestamp}.json` - 健康检查报告 2. `node_status_{timestamp}.json` - 节点状态报告 3. `query_stats_{timestamp}.json` - 查询统计报告
📊 诊断检查项
健康检查项
| 检查项 | 说明 | 状态 |
|---|---|---|
| 集群连接 | 测试ByteHouse连接性 | ✅/❌ |
| 系统表访问 | 检查system.*表是否可访问 | ✅/❌ |
| 副本状态 | 检查数据副本同步状态 | ✅/⚠️/❌ |
| 分区状态 | 检查数据分区完整性 | ✅/⚠️/❌ |
| 节点存活 | 检查集群节点存活状态 | ✅/❌ |
| Mutation状态 | 检查mutation执行状态 | ✅/⚠️/❌ |
📚 更多信息
详细使用说明请参考 SKILL.md
ByteHouse访问配置请参考 bytehouse-mcp skill
--- 最后更新: 2026-03-12
#!/usr/bin/env python3
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
ByteHouse 集群诊断工具
检查集群健康状态、节点状态、副本同步等
"""
# /// script
# dependencies = [
# "mcp>=1.0.0",
# ]
# ///
import asyncio
import os
import json
from datetime import datetime
from typing import Dict, List, Any
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
def is_cdw_environment():
"""检测是否为CDW环境
根据BYTEHOUSE_HOST判断:
- CDW: tenant-xxxx-cn-shanghai-public.bytehouse.volces.com
- CE: xxxx-public.bytehouse-ce.volces.com
"""
host = os.environ.get('BYTEHOUSE_HOST', '')
return '.bytehouse.volces.com' in host and '.bytehouse-ce.volces.com' not in host
def get_system_table_name(table_name):
"""根据环境返回正确的系统表名
"""
if is_cdw_environment():
table_mapping = {
'query_log': 'bh_system.query_log',
'processes': 'system.processes',
'parts': 'system.cnch_parts_info',
'replicas': None, # CDW不需要
'clusters': None, # CDW不需要
'mutations': 'system.mutations' # CDW可能支持
}
return table_mapping.get(table_name, table_name)
else:
return f'system.{table_name}'
def get_parts_table_columns():
"""根据环境返回parts表的正确字段名
"""
if is_cdw_environment():
# CDW system.cnch_parts_info 表字段
return {
'rows': 'total_rows_count',
'bytes': 'total_parts_size',
'active': 'ready_state',
'active_condition': "ready_state = 'Loaded'"
}
else:
# CE system.parts 表字段
return {
'rows': 'rows',
'bytes': 'bytes',
'active': 'active',
'active_condition': 'active'
}
async def run_cluster_diagnostics():
"""运行集群诊断"""
print("=" * 80)
print("ByteHouse 集群诊断工具")
print("=" * 80)
print()
print("⚠️ 请确保已设置以下环境变量:")
print(" - BYTEHOUSE_HOST")
print(" - BYTEHOUSE_PORT")
print(" - BYTEHOUSE_USER")
print(" - BYTEHOUSE_PASSWORD")
print()
# 检测环境类型
env_type = "CDW" if is_cdw_environment() else "CE"
print(f"🔍 检测到环境类型: {env_type}")
print()
# 从环境变量获取配置
env = os.environ.copy()
# MCP Server参数
server_params = StdioServerParameters(
command='/root/.local/bin/uvx',
args=[
'--from',
'git+https://github.com/volcengine/mcp-server@main#subdirectory=server/mcp_server_bytehouse',
'mcp_bytehouse',
'-t',
'stdio'
],
env=env
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
print("✅ 连接成功!")
# 诊断结果
diagnostics = {
"diagnosis_time": datetime.now().isoformat(),
"checks": [],
"overall_status": "unknown",
"recommendations": []
}
# 1. 测试连接 - list_databases
print("\n1️⃣ 检查集群连接...")
try:
result = await session.call_tool("list_databases", {})
databases = []
for content in result.content:
if content.type == 'text':
databases = [db.strip() for db in content.text.split('\n') if db.strip()]
diagnostics["checks"].append({
"name": "cluster_connection",
"status": "pass",
"message": f"成功连接到ByteHouse,找到 {len(databases)} 个数据库",
"details": {"databases": databases}
})
print(f" ✅ 通过 - 找到 {len(databases)} 个数据库")
except Exception as e:
diagnostics["checks"].append({
"name": "cluster_connection",
"status": "fail",
"message": f"连接失败: {str(e)}"
})
print(f" ❌ 失败: {e}")
# 2. 检查数据分区状态
print("\n2️⃣ 检查数据分区状态...")
try:
parts_table = get_system_table_name('parts')
if not parts_table:
diagnostics["checks"].append({
"name": "parts_status",
"status": "info",
"message": "环境不支持parts表检查"
})
print(" ℹ️ 信息: 环境不支持parts表检查")
else:
parts_columns = get_parts_table_columns()
sql = f"""
SELECT
database,
table,
count(*) as part_count,
sum({parts_columns['rows']}) as total_rows,
sum({parts_columns['bytes']}) as total_bytes,
sum(if({parts_columns['active_condition']}, 1, 0)) as active_parts
FROM {parts_table}
GROUP BY database, table
LIMIT 20
"""
result = await session.call_tool("run_select_query", {"query": sql})
part_info = []
for content in result.content:
if content.type == 'text':
part_info = content.text
diagnostics["checks"].append({
"name": "parts_status",
"status": "pass",
"message": f"成功查询{parts_table}表",
"details": {"part_info": part_info}
})
print(f" ✅ 通过 - {parts_table}表正常")
except Exception as e:
diagnostics["checks"].append({
"name": "parts_status",
"status": "warn",
"message": f"查询system.parts表失败: {str(e)}"
})
print(f" ⚠️ 警告: {e}")
# 3. 检查system.mutations表
print("\n3️⃣ 检查Mutation状态...")
try:
sql = """
SELECT
count(*) as pending_mutations,
sum(if(is_done=0, 1, 0)) as incomplete_mutations
FROM system.mutations
"""
result = await session.call_tool("run_select_query", {"query": sql})
mutation_info = []
for content in result.content:
if content.type == 'text':
mutation_info = content.text
diagnostics["checks"].append({
"name": "mutation_status",
"status": "pass",
"message": "成功查询system.mutations表",
"details": {"mutation_info": mutation_info}
})
print(" ✅ 通过 - system.mutations表正常")
except Exception as e:
diagnostics["checks"].append({
"name": "mutation_status",
"status": "warn",
"message": f"查询system.mutations表失败: {str(e)}"
})
print(f" ⚠️ 警告: {e}")
# 4. 检查副本状态(仅CE环境)
print("\n4️⃣ 检查副本状态...")
try:
replicas_table = get_system_table_name('replicas')
if is_cdw_environment() or not replicas_table:
# CDW是存算分离架构,不需要副本检查
diagnostics["checks"].append({
"name": "replica_status",
"status": "info",
"message": "CDW环境不需要副本状态检查(存算分离架构)"
})
print(" ℹ️ 信息: CDW环境不需要副本状态检查")
else:
sql = f"SELECT count(*) as replica_count FROM {replicas_table}"
result = await session.call_tool("run_select_query", {"query": sql})
replica_info = []
for content in result.content:
if content.type == 'text':
replica_info = content.text
diagnostics["checks"].append({
"name": "replica_status",
"status": "pass",
"message": f"成功查询{replicas_table}表",
"details": {"replica_info": replica_info}
})
print(f" ✅ 通过 - {replicas_table}表正常")
except Exception as e:
diagnostics["checks"].append({
"name": "replica_status",
"status": "info",
"message": f"查询system.replicas表: {str(e)}"
})
print(f" ℹ️ 信息: {e}")
# 5. 获取最近查询统计
print("\n5️⃣ 获取查询统计...")
try:
query_log_table = get_system_table_name('query_log')
if not query_log_table:
diagnostics["checks"].append({
"name": "query_stats",
"status": "info",
"message": "环境不支持查询统计"
})
print(" ℹ️ 信息: 环境不支持查询统计")
else:
sql = f"""
SELECT
count(*) as query_count,
sum(if(query_duration_ms > 1000, 1, 0)) as slow_query_count
FROM {query_log_table}
WHERE event_time > now() - interval 1 hour
"""
result = await session.call_tool("run_select_query", {"query": sql})
query_stats = []
for content in result.content:
if content.type == 'text':
query_stats = content.text
diagnostics["checks"].append({
"name": "query_stats",
"status": "pass",
"message": "成功获取查询统计",
"details": {"query_stats": query_stats}
})
print(" ✅ 通过 - 查询统计正常")
except Exception as e:
diagnostics["checks"].append({
"name": "query_stats",
"status": "info",
"message": f"获取查询统计: {str(e)}"
})
print(f" ℹ️ 信息: {e}")
# 计算整体状态
pass_count = sum(1 for c in diagnostics["checks"] if c["status"] == "pass")
warn_count = sum(1 for c in diagnostics["checks"] if c["status"] == "warn")
fail_count = sum(1 for c in diagnostics["checks"] if c["status"] == "fail")
if fail_count > 0:
diagnostics["overall_status"] = "unhealthy"
elif warn_count > 0:
diagnostics["overall_status"] = "warning"
else:
diagnostics["overall_status"] = "healthy"
# 生成建议
if diagnostics["overall_status"] == "unhealthy":
diagnostics["recommendations"].append("需要立即检查集群状态,解决失败的检查项")
elif diagnostics["overall_status"] == "warning":
diagnostics["recommendations"].append("关注警告项,建议进一步调查")
else:
diagnostics["recommendations"].append("集群状态健康,建议继续保持监控")
# 保存诊断结果
output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "output")
os.makedirs(output_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = os.path.join(output_dir, f"cluster_diagnostics_{timestamp}.json")
with open(output_file, "w", encoding="utf-8") as f:
json.dump(diagnostics, f, ensure_ascii=False, indent=2)
# 打印诊断摘要
print("\n" + "=" * 80)
print("📊 诊断摘要")
print("=" * 80)
print(f"\n整体状态: {diagnostics['overall_status'].upper()}")
print(f"\n检查结果:")
print(f" ✅ 通过: {pass_count}")
print(f" ⚠️ 警告: {warn_count}")
print(f" ❌ 失败: {fail_count}")
print(f"\n建议:")
for rec in diagnostics["recommendations"]:
print(f" - {rec}")
print(f"\n📁 诊断报告已保存到: {output_file}")
print("\n" + "=" * 80)
async def main():
"""主函数"""
try:
await run_cluster_diagnostics()
print("\n✅ 诊断完成!")
except Exception as e:
print(f"\n❌ 诊断失败: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())