181 lines
7.2 KiB
MySQL
181 lines
7.2 KiB
MySQL
|
|
-- AI-Ops 初始化 schema
|
|||
|
|
-- 表前缀 ai_ops_,避免与桥项目表名冲突
|
|||
|
|
|
|||
|
|
-- 1. 告警规则
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_rules (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
name VARCHAR(128) NOT NULL,
|
|||
|
|
metric_source VARCHAR(64) NOT NULL,
|
|||
|
|
metric_name VARCHAR(128) NOT NULL,
|
|||
|
|
threshold_type VARCHAR(16) NOT NULL CHECK (threshold_type IN ('>', '<', '=', 'regex')),
|
|||
|
|
threshold_value TEXT NOT NULL,
|
|||
|
|
duration_min INT NOT NULL DEFAULT 1 CHECK (duration_min >= 1),
|
|||
|
|
level VARCHAR(8) NOT NULL CHECK (level IN ('P0', 'P1', 'P2', 'P3')),
|
|||
|
|
channel_ids UUID[] NOT NULL DEFAULT '{}',
|
|||
|
|
healing_action VARCHAR(32) DEFAULT NULL,
|
|||
|
|
healing_config JSONB DEFAULT NULL,
|
|||
|
|
is_sandboxed BOOLEAN NOT NULL DEFAULT FALSE,
|
|||
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
created_by VARCHAR(64) NOT NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
version INT NOT NULL DEFAULT 1,
|
|||
|
|
CONSTRAINT uq_rules_name UNIQUE (name)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_rules_enabled ON ai_ops_rules(enabled);
|
|||
|
|
|
|||
|
|
-- 2. 告警事件
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_alerts (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
rule_id UUID NOT NULL REFERENCES ai_ops_rules(id) ON DELETE CASCADE,
|
|||
|
|
level VARCHAR(8) NOT NULL,
|
|||
|
|
resource_type VARCHAR(64) NOT NULL,
|
|||
|
|
resource_id VARCHAR(128) NOT NULL,
|
|||
|
|
current_value TEXT NOT NULL,
|
|||
|
|
threshold_value TEXT NOT NULL,
|
|||
|
|
status VARCHAR(16) NOT NULL DEFAULT 'triggered'
|
|||
|
|
CHECK (status IN ('triggered', 'notified', 'healing', 'resolved', 'escalated', 'acknowledged')),
|
|||
|
|
is_aggregated BOOLEAN NOT NULL DEFAULT FALSE,
|
|||
|
|
aggregated_count INT DEFAULT 0,
|
|||
|
|
parent_alert_id UUID NULL REFERENCES ai_ops_alerts(id) ON DELETE SET NULL,
|
|||
|
|
started_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
resolved_at TIMESTAMPTZ NULL,
|
|||
|
|
acknowledged_by VARCHAR(64) NULL,
|
|||
|
|
acknowledged_at TIMESTAMPTZ NULL
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_alerts_status ON ai_ops_alerts(status);
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_alerts_started_at ON ai_ops_alerts(started_at DESC);
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_alerts_resource ON ai_ops_alerts(resource_type, resource_id);
|
|||
|
|
|
|||
|
|
-- 3. 自愈执行记录
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_healings (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
alert_id UUID NOT NULL REFERENCES ai_ops_alerts(id) ON DELETE CASCADE,
|
|||
|
|
action_type VARCHAR(32) NOT NULL
|
|||
|
|
CHECK (action_type IN ('switch_route', 'throttle', 'restart_instance', 'invoke_script', 'isolate_node')),
|
|||
|
|
config JSONB NOT NULL,
|
|||
|
|
status VARCHAR(16) NOT NULL DEFAULT 'pending'
|
|||
|
|
CHECK (status IN ('pending', 'succeeded', 'failed', 'rolled_back')),
|
|||
|
|
dry_run BOOLEAN NOT NULL DEFAULT FALSE,
|
|||
|
|
result_detail JSONB NULL,
|
|||
|
|
error_code VARCHAR(16) NULL,
|
|||
|
|
started_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
completed_at TIMESTAMPTZ NULL
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_healings_alert ON ai_ops_healings(alert_id);
|
|||
|
|
|
|||
|
|
-- 4. 通知渠道
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_channels (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
name VARCHAR(128) NOT NULL,
|
|||
|
|
channel_type VARCHAR(32) NOT NULL
|
|||
|
|
CHECK (channel_type IN ('webhook', 'email', 'feishu', 'wechat', 'sms')),
|
|||
|
|
config JSONB NOT NULL,
|
|||
|
|
priority INT NOT NULL DEFAULT 1,
|
|||
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 5. 审计日志(append-only,禁止更新和删除)
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_audits (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
tenant_id VARCHAR(64) NOT NULL,
|
|||
|
|
object_type VARCHAR(64) NOT NULL,
|
|||
|
|
object_id VARCHAR(128) NOT NULL,
|
|||
|
|
action VARCHAR(32) NOT NULL
|
|||
|
|
CHECK (action IN ('create', 'update', 'delete', 'rollback')),
|
|||
|
|
before_state JSONB NULL,
|
|||
|
|
after_state JSONB NULL,
|
|||
|
|
request_id VARCHAR(64) NOT NULL,
|
|||
|
|
result_code VARCHAR(16) NOT NULL,
|
|||
|
|
source_ip VARCHAR(45) NOT NULL,
|
|||
|
|
actor_id VARCHAR(64) NOT NULL,
|
|||
|
|
risk_level VARCHAR(8) NOT NULL DEFAULT 'normal'
|
|||
|
|
CHECK (risk_level IN ('normal', 'high', 'critical')),
|
|||
|
|
parent_audit_id UUID NULL REFERENCES ai_ops_audits(id) ON DELETE SET NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_audits_tenant_created ON ai_ops_audits(tenant_id, created_at DESC);
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_audits_object ON ai_ops_audits(object_type, object_id);
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_audits_actor ON ai_ops_audits(actor_id, created_at DESC);
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_audits_request ON ai_ops_audits(request_id);
|
|||
|
|
|
|||
|
|
-- 审计日志防篡改触发器(仅允许插入,禁止更新和删除)
|
|||
|
|
CREATE OR REPLACE FUNCTION ai_ops_audit_readonly()
|
|||
|
|
RETURNS TRIGGER AS $$
|
|||
|
|
BEGIN
|
|||
|
|
RAISE EXCEPTION 'ai_ops_audits is append-only. Updates and deletes are not allowed.';
|
|||
|
|
END;
|
|||
|
|
$$ LANGUAGE plpgsql;
|
|||
|
|
|
|||
|
|
DROP TRIGGER IF EXISTS trg_ai_ops_audits_no_update ON ai_ops_audits;
|
|||
|
|
CREATE TRIGGER trg_ai_ops_audits_no_update
|
|||
|
|
BEFORE UPDATE ON ai_ops_audits
|
|||
|
|
FOR EACH ROW
|
|||
|
|
EXECUTE FUNCTION ai_ops_audit_readonly();
|
|||
|
|
|
|||
|
|
DROP TRIGGER IF EXISTS trg_ai_ops_audits_no_delete ON ai_ops_audits;
|
|||
|
|
CREATE TRIGGER trg_ai_ops_audits_no_delete
|
|||
|
|
BEFORE DELETE ON ai_ops_audits
|
|||
|
|
FOR EACH ROW
|
|||
|
|
EXECUTE FUNCTION ai_ops_audit_readonly();
|
|||
|
|
|
|||
|
|
-- 6. 时序指标缓存(降级方案,主存储推荐 Prometheus / VictoriaMetrics)
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_metrics (
|
|||
|
|
id BIGSERIAL PRIMARY KEY,
|
|||
|
|
metric_name VARCHAR(128) NOT NULL,
|
|||
|
|
labels JSONB NOT NULL DEFAULT '{}',
|
|||
|
|
value DOUBLE PRECISION NOT NULL,
|
|||
|
|
recorded_at TIMESTAMPTZ NOT NULL
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_metrics_name_time ON ai_ops_metrics(metric_name, recorded_at DESC);
|
|||
|
|
|
|||
|
|
-- 分区表(按天分区,自动清理 > 7 天的分区)
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_metrics_p (
|
|||
|
|
id BIGSERIAL NOT NULL,
|
|||
|
|
metric_name VARCHAR(128) NOT NULL,
|
|||
|
|
labels JSONB NOT NULL DEFAULT '{}',
|
|||
|
|
value DOUBLE PRECISION NOT NULL,
|
|||
|
|
recorded_at TIMESTAMPTZ NOT NULL,
|
|||
|
|
PRIMARY KEY (id, recorded_at)
|
|||
|
|
) PARTITION BY RANGE (recorded_at);
|
|||
|
|
|
|||
|
|
-- 创建当前日分区
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_metrics_p_default PARTITION OF ai_ops_metrics_p
|
|||
|
|
DEFAULT;
|
|||
|
|
|
|||
|
|
-- 启用 pg_partman 扩展后可自动管理分区(建议生产环境使用)
|
|||
|
|
-- SELECT partman.create_parent('public.ai_ops_metrics_p', 'recorded_at', 'native', 'daily');
|
|||
|
|
|
|||
|
|
-- 7. 配置版本管理(支持审计回滚)
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_configs (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
object_type VARCHAR(64) NOT NULL,
|
|||
|
|
object_id VARCHAR(128) NOT NULL,
|
|||
|
|
config_data JSONB NOT NULL,
|
|||
|
|
version INT NOT NULL DEFAULT 1,
|
|||
|
|
created_by VARCHAR(64) NOT NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|||
|
|
CONSTRAINT uq_configs_object_version UNIQUE (object_type, object_id, version)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_configs_object ON ai_ops_configs(object_type, object_id, created_at DESC);
|
|||
|
|
|
|||
|
|
-- 8. 状态快照(自愈回滚用)
|
|||
|
|
CREATE TABLE IF NOT EXISTS ai_ops_snapshots (
|
|||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|||
|
|
healing_id UUID NOT NULL REFERENCES ai_ops_healings(id) ON DELETE CASCADE,
|
|||
|
|
snapshot_type VARCHAR(32) NOT NULL
|
|||
|
|
CHECK (snapshot_type IN ('route', 'rate_limit', 'instance', 'script', 'node')),
|
|||
|
|
before_state JSONB NOT NULL,
|
|||
|
|
after_state JSONB NULL,
|
|||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS idx_snapshots_healing ON ai_ops_snapshots(healing_id);
|