feat(nginx-log): 多节点适配(node_id 全链路 + 全局/按节点聚合 + 节点筛选 + v2.4.0 升级脚本)

- 6 张表加 node_id 字段 + position/stat 改复合唯一键(migration)
- 6 个 Scheme 同步 node_id 注解 + 唯一键
- Reader 带 node_id 参数 + 懒加载接管(getLastPosition 回退查 node_id='')
- Aggregator 全局行(node_id='')+ 按节点循环 insertAggregatesForScope
- Stat 所有查询方法加 where node_id 条件
- Dashboard 控制器/视图加节点筛选下拉框 + AJAX 带 node_id
- AccessLog 列表加节点列 + 采集进度卡片显示节点信息
- import 定时任务 run_type 改 all(每节点采集自己的日志)
- v2.4.0 升级脚本追加 ALTER TABLE(幂等 check-then-alter)
- 菜单调整:去掉 Nginx 顶级菜单 + 读取位置管理,改为系统管理下挂两个子菜单
- ulthon-timer 文档补充 run_type=all 多节点部署注意事项
This commit is contained in:
augushong
2026-08-08 10:33:20 +08:00
parent f1a2e8fd5d
commit 8faa52ce90
21 changed files with 578 additions and 206 deletions

View File

@@ -0,0 +1,70 @@
<?php
use think\migration\Migrator;
/**
* nginx 日志表新增 node_id 字段(多节点采集支持)
*
* 变更内容:
* - 6 张表全部新增 node_id varchar(64) default ''(采集节点 ID空=全局汇总)
* - position / 4 张 stat 表的唯一键前置 node_id多节点隔离避免聚合 INSERT 触发 duplicate key
* - raw 表nginx_access_log加 node_id + time_local 普通索引,无唯一键变更
*
* 注意:
* - 不回填历史 raw/stat 数据(旧数据 node_id 为空,视为全局汇总)
* - 不在 migration 中 UPDATE position 的 node_id多节点共享 DB 下第一个节点会抢走所有 position
* position 迁移改为 getLastPosition() 懒加载接管,见配套 Task
* - phinx 表名不带 ul_ 前缀phinx 自动加前缀)
*/
class NginxLogAddNodeId extends Migrator
{
public function change()
{
// ==================== 1. nginx_log_position ====================
// 旧唯一键 uniq_file_path(file_path) → 新 uniq_node_file(node_id, file_path)
$this->table('nginx_log_position')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->removeIndexByName('uniq_file_path')
->addIndex(['node_id', 'file_path'], ['unique' => true, 'name' => 'uniq_node_file'])
->update();
// ==================== 2. nginx_access_lograw 表)====================
// 仅加字段 + 普通索引(按节点 + 时间查询),无唯一键变更
$this->table('nginx_access_log')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->addIndex(['node_id', 'time_local'], ['name' => 'idx_node_time'])
->update();
// ==================== 3. nginx_stat_hour ====================
// 旧唯一键 uniq_date_hour(stat_date, stat_hour) → uniq_node_date_hour(node_id, stat_date, stat_hour)
$this->table('nginx_stat_hour')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->removeIndexByName('uniq_date_hour')
->addIndex(['node_id', 'stat_date', 'stat_hour'], ['unique' => true, 'name' => 'uniq_node_date_hour'])
->update();
// ==================== 4. nginx_stat_url ====================
// 旧唯一键 uniq_date_uri(stat_date, uri) → uniq_node_date_uri(node_id, stat_date, uri)
$this->table('nginx_stat_url')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->removeIndexByName('uniq_date_uri')
->addIndex(['node_id', 'stat_date', 'uri'], ['unique' => true, 'name' => 'uniq_node_date_uri'])
->update();
// ==================== 5. nginx_stat_referer ====================
// 旧唯一键 uniq_date_referer(stat_date, referer_domain) → uniq_node_date_referer(node_id, stat_date, referer_domain)
$this->table('nginx_stat_referer')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->removeIndexByName('uniq_date_referer')
->addIndex(['node_id', 'stat_date', 'referer_domain'], ['unique' => true, 'name' => 'uniq_node_date_referer'])
->update();
// ==================== 6. nginx_stat_ua ====================
// 旧唯一键 uniq_date_type_name(stat_date, ua_type, ua_name) → uniq_node_date_type_name(node_id, stat_date, ua_type, ua_name)
$this->table('nginx_stat_ua')
->addColumn('node_id', 'string', ['limit' => 64, 'default' => '', 'comment' => '采集节点 ID空=全局汇总)'])
->removeIndexByName('uniq_date_type_name')
->addIndex(['node_id', 'stat_date', 'ua_type', 'ua_name'], ['unique' => true, 'name' => 'uniq_node_date_type_name'])
->update();
}
}