NewAPI 的日志目前是单表存储,已经看到太多佬友因为日志撑爆磁盘了,下面给出一种解决方式,可能不完全兼容,但是个人测试下来没有什么问题 与 NewAPI 版本无关,基本所有版本都可以用,我用的版本是 1.0.0-rc.10 自带的日志删除 最常用的是使用 NewAPI 自带的 “清理历史日志” 来进行删除 // 代码逻辑如下 // 直接按照时间戳删除 LOG_DB.Where("created_at < ?", targetTimestamp).Limit(limit).Delete(&Log{}) 这里有两个问题: Delete 的效率不高,或者说在数据量过大的情况下使用 Delete 带来的 IO 可能成为灾难 Delete 之后磁盘空间并不会回收,需要手动回收 通过数据库分片解决日志删除 适用于 MySQL,如果您是其他的 DB 如 Postgres / SQLite,将下面的内容提供给 AI 相信也会有对应的解决方案 分片的核心逻辑是,将日志拆分到对应的日期上,比如分片 logs_20260601 只存储当天的数据,在超出需要删除的日期后,比如 1 个月后的 2026/07/01,直接删除 logs_20260601 分片,分片占用的空间会立刻释放,对应的日志数据也会直接删除 不过这里要提示您,所有的 DB 变更都可能引入风险,请您在执行前通过 mysqldump 或者类似工具,导出完整的数据结构和数据内容,确保执行出现异常可以随时回滚 执行下面的步骤前,建议停机,否则可能导致数据不完整 ,如果数据完整性不在考虑范围内,也可以在线更新 Step 1 检查数据符合预期 (Read) 执行下面的查询语句,确保 count 为 0,即所有的日志的创建时间不为空 SELECT COUNT(*) AS null_created_at_count FROM logs WHERE created_at IS NULL; Step 2 创建临时表 (Write) CREATE TABLE logs_new LIKE logs; Step 3 添加准备分区语句 (Read) 通过下面的 SQL,可以获得一个建表 SQL,对 DB 无任何副作用,可以放心执行 下面的 @start_date 和 @end_date 两行,可以按照您的实际数据存储情况调整,下面的配置为创建 180 天前到 7 天后的分区,如果您的日志已经回收或删除过了,可以考虑缩减分区数量 SET time_zone = '+08:00'; 这里可以按照您的需求调整为具体的时区 分区必须提前创建,否则插入数据会有问题 ,所以您至少需要创建 7 天后的备用 SET SESSION group_concat_max_len = 1024 * 1024; SET time_zone = '+08:00'; SET @start_date = DATE_SUB(CURDATE(), INTERVAL 180 DAY); SET @end_date = DATE_ADD(CURDATE(), INTERVAL 7 DAY); WITH RECURSIVE dates AS ( SELECT @start_date AS d UNION ALL SELECT DATE_ADD(d, INTERVAL 1 DAY) FROM dates WHERE d < @end_date ) SELECT GROUP_CONCAT( CONCAT( ' PARTITION p', DATE_FORMAT(d, '%Y%m%d'), ' VALUES LESS THAN (', UNIX_TIMESTAMP(DATE_ADD(d, INTERVAL 1 DAY)), ')' ) ORDER BY d SEPARATOR ',\n' ) INTO @parts FROM dates; SET @sql = CONCAT( 'ALTER TABLE logs_new MODIFY `created_at` bigint NOT NULL, DROP PRIMARY KEY, DROP INDEX `idx_created_at_id`, ADD PRIMARY KEY (`id`, `created_at`) PARTITION BY RANGE (`created_at`) ( ', @parts, ', PARTITION pmax VALUES LESS THAN MAXVALUE )' ); SELECT @sql; Step 4 执行分区语句 (Write) 执行上一步输出的 SQL,会将新的 logs_new 表调整为分区表 Step 5 导入旧的数据 (Write) 取决于您的数据量,这一步可能会花费一些时间 INSERT INTO logs_new SELECT * FROM logs; Step 6 校验数据已经导入完成 (Read) 如果您是停机更新,确保两条 SQL 输出的内容是一致的 如果您是在线更新,确保数据接近或一致 SELECT "logs" as `table`, COUNT(*), MIN(created_at), MAX(created_at) FROM logs UNION SELECT "logs_new" as `table`, COUNT(*), MIN(created_at), MAX(created_at) FROM logs_new; Step 7 确认分区 (Read) 下面的 SQL 会打印新表的所有分区,以及每个分区的数据量 SELECT PARTITION_NAME, PARTITION_DESCRIPTION, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'logs_new' ORDER BY PARTITION_ORDINAL_POSITION; Step 8 切表 (Write) 切换流量到新表,执行完成后请检查 NewAPI 各组件各页面是否能正常工作,特别是依赖日志的内容 RENAME TABLE logs TO logs_old, logs_new TO logs; Step 9 创建自动回收创建/分区任务 (Write) MySQL 不会自动创建或者删除分区,需要您创建定时任务来实现,下面会给出创建/删除分区的任务,您可以按需添加 Step 9.1 开启 MySQL Event Scheduler 在数据库中执行下面的命令,通常需要 root 用户,无需重启 SET GLOBAL event_scheduler = ON; SHOW VARIABLES LIKE 'event_scheduler'; 在配置文件的 mysqld 章节,增加下面的配置,无需重启 这一步是为了保证,即使后面重启数据库,Event Scheduler 仍然会是开启状态 [mysqld] event_scheduler=ON Step 9.2 创建新建分区任务 下面的两个 SQL 都需要执行 第一个 SQL 中的 SET time_zone = '+08:00'; 可按需修改为您的时区 第二个 SQL 中的时间您可以修改为适用于您的服务的时间,目前设置的是每天的 02:00,用于控制定时触发的时机 DELIMITER $$ DROP PROCEDURE IF EXISTS sp_logs_create_future_partitions$$ CREATE PROCEDURE sp_logs_create_future_partitions() BEGIN DECLARE v_i INT DEFAULT 0; DECLARE v_d DATE; DECLARE v_partition_name VARCHAR(32); DECLARE v_less_than BIGINT; DECLARE v_exists INT DEFAULT 0; DECLARE v_sql TEXT; SET time_zone = '+08:00'; WHILE v_i <= 7 DO SET v_d = DATE_ADD(CURDATE(), INTERVAL v_i DAY); SET v_partition_name = CONCAT('p', DATE_FORMAT(v_d, '%Y%m%d')); SET v_less_than = UNIX_TIMESTAMP(DATE_ADD(v_d, INTERVAL 1 DAY)); SELECT COUNT(*) INTO v_exists FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'logs' AND PARTITION_NAME = v_partition_name; IF v_exists = 0 THEN SET v_sql = CONCAT( 'ALTER TABLE logs REORGANIZE PARTITION pmax INTO (', 'PARTITION ', v_partition_name, ' VALUES LESS THAN (', v_less_than, '), ', 'PARTITION pmax VALUES LESS THAN MAXVALUE', ')' ); SET @sql = v_sql; PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; SET v_i = v_i + 1; END WHILE; END$$ DELIMITER ; DROP EVENT IF EXISTS ev_logs_create_future_partitions; CREATE EVENT ev_logs_create_future_partitions ON SCHEDULE EVERY 1 DAY STARTS TIMESTAMP(CURRENT_DATE, '02:00:00') DO CALL sp_logs_create_future_partitions(); Step 9.3 创建删除分区任务 (可选) 这个是用于替代 NewAPI 自带的删除数据任务,如果您有需要可以配置这里的自动删除 第一个 SQL 中的 INTERVAL 180 DAY 表示删除 180 天之前的数据,可以按需修改, SET time_zone = '+08:00'; 也可按需修改为您的时区 第二个 SQL 中的时间您可以修改为适用于您的服务的时间,目前设置的是每天的 03:00,用于控制定时触发的时机 DELIMITER $$ DROP PROCEDURE IF EXISTS sp_logs_drop_old_partitions$$ CREATE PROCEDURE sp_logs_drop_old_partitions() BEGIN DECLARE v_cutoff_date DATE; DECLARE v_cutoff_ts BIGINT; DECLARE v_drop_partitions TEXT; DECLARE v_sql TEXT; SET time_zone = '+08:00'; SET v_cutoff_date = DATE_SUB(CURDATE(), INTERVAL 180 DAY); SET v_cutoff_ts = UNIX_TIMESTAMP(v_cutoff_date); SELECT GROUP_CONCAT(PARTITION_NAME ORDER BY PARTITION_ORDINAL_POSITION) INTO v_drop_partitions FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'logs' AND PARTITION_NAME REGEXP '^p[0-9]{8}$' AND CAST(PARTITION_DESCRIPTION AS UNSIGNED) <= v_cutoff_ts; IF v_drop_partitions IS NOT NULL AND v_drop_partitions <> '' THEN SET v_sql = CONCAT( 'ALTER TABLE logs DROP PARTITION ', v_drop_partitions ); SET @sql = v_sql; PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; END$$ DELIMITER ; DROP EVENT IF EXISTS ev_logs_drop_old_partitions; CREATE EVENT ev_logs_drop_old_partitions ON SCHEDULE EVERY 1 DAY STARTS TIMESTAMP(CURRENT_DATE, '00:10:00') DO CALL sp_logs_drop_old_partitions(); Step 9.4 检查任务 show events; SHOW PROCEDURE STATUS WHERE Db = DATABASE(); Step 10 大功告成 一切已准备就绪,请使用吧!数据库将按照您的配置自动创建新的分片,回收旧的分片,后续如果有调整,也可以直接修改 SQL 配置再次执行。 您可以定期通过下面的 SQL 来检查分区任务的运行状态和分区的数据量,请检查 pmax 分区数据量为 0,且已经创建了 7 天后的分区 SELECT PARTITION_NAME, PARTITION_DESCRIPTION, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'logs' ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 15; 1 个帖子 - 1 位参与者 阅读完整话题
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
除了把 HomePod 放到 IoT VLAN ,还有什么更优雅的解决方案吗?
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
目前是虚拟机 win11 itunes+ios 旧应用下载,比较麻烦的是不晓得什么原因一段时间后 itunes 总会提示连接 appstore 出错,无法正常下载。
有没有使用lingma工具编程的好兄弟,你们如何优雅使用的,感觉除了上下文,好像其他方面也不错 1 个帖子 - 1 位参与者 阅读完整话题
大家都应该遇到过,国内网络访问ghcr.io的超时问题,经过网上学习加AI沟通,如下是本次处理的总结记录,希望可以帮到有需要的人。 ps:国内大厂不代理加速ghcr.io,说是因为流量和审核问题,所以基本上都是临时的,不知道是不是真这个理由。 一、 问题背景与痛点 在国内折腾 Homelab 或 NAS(如飞牛 OS)时,很多开源项目(例如 wg-easy )的 Docker 镜像都逐步迁移到了 GitHub 的容器注册表 ghcr.io (GitHub Container Registry)。 由于国内特殊的网络环境,直接在 NAS 上拉取 ghcr.io 镜像极易出现两种错误: 网络直接超时 :完全无法连接官方源。 公共加速站失效 :使用第三方或公益代拉加速站(如已经关停的域名),会遭遇 dial tcp: lookup xxx: no such host 报错。 为了彻底、稳定地解决这一“最后一公里”的分发难题,最完美的方案是利用自己拥有的 海外原生网络服务器(如美国 VPS) ,通过 1Panel 搭建一个专属的私有镜像反代通道。 二、 踩坑历程与底层原理分析 在折腾自建反代的过程中,通常会经历三个阶段的报错,其背后的底层网络逻辑非常值得记录: 坑 1:直接反代返回 Whoa there! Not Found 错误 现象 :浏览器访问或 Docker 拉取时返回 GitHub 标准的 404 网页。 原因 :Nginx 默认的反代配置非常老实,在转发时将请求头中的 Host 保持为了用户自己的域名。而 GitHub API 服务器极为严格,发现 Host 不是 ghcr.io 时,会直接将请求重定向到网页端的 404 错误页。 坑 2:拉取时遭遇 TLS handshake timeout 认证超时 现象 :修改了 Host 后,Docker 客户端在连接时依然卡死,报错提示 Get "https://ghcr.io/token?scope=..." net/http: TLS handshake timeout 。 原因 :Docker 注册表有一套特殊的 令牌(Token)鉴权机制 。当 NAS 找反代服务器下载镜像时,GitHub 会要求客户端先去拿一个临时 Token。因为没有拦截重定向,GitHub 直接把官方的 ghcr.io/token 地址甩给了国内的 NAS。结果 NAS 绕过了中转站,自己“肉身”去连官方拿 Token ,直接被大墙拦截导致超时。 三、 终极解决方案 步骤 1:域名解析准备 在域名服务商(如 Cloudflare)中添加一条 A 记录(例如 ghcr.xxx.com ),解析到你的海外服务器真实公网 IP。 注意 :如果使用 Cloudflare, 必须关闭小黄云(改为仅限 DNS / 灰色云朵) 。因为 Cloudflare 的 CDN 节点 IP 在国内经常遭到大面积封锁或干扰,开启会导致国内 NAS 报 no such host 错误。 步骤 2:在 1Panel 中配置高级反代 在 1Panel 中创建一个反向代理网站,主域名填写你的域名,后端代理地址填写 https://ghcr.io 。 申请并强制开启 HTTPS / SSL 证书 (Docker 客户端强制要求安全连接)。 打开该网站的 配置文件(Nginx 源码) ,将 location / 块完全替换为以下“瞒天过海”终极版配置: Nginx location / { proxy_pass https://ghcr.io; # 核心修复 1:强制将 Host 设为后端目标域名,欺骗 GitHub 放行 proxy_set_header Host ghcr.io; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 核心修复 2:拦截并改写 GitHub 返回的鉴权重定向 Location 头 # 强制让 Token 请求也走你自己的中转域名,闭环解决国内超时问题 proxy_redirect https://ghcr.io/ https://ghcr.xxx.com/; # 隐藏可能暴露源站域名的特定 Link 响应头 proxy_hide_header Link; # 穿透 Docker 认证头(Authorization) proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; # 核心修复 3:关闭缓冲区,开启流式传输,防止大容量镜像拉取时断开或 504 超时 proxy_buffering off; proxy_read_timeout 900s; proxy_send_timeout 900s; } 步骤 3:国内 NAS 客户端测试与使用 配置保存重载后,回到国内飞牛 OS 的 SSH 终端,直接在原镜像名前加上你的专属域名即可丝滑下载: Bash sudo docker pull ghcr.xxx.com/wg-easy/wg-easy:latest 四、 进阶安全建议 由于公开的反代接口极易被全网扫描器扫到并疯狂盗刷流量,建议在 1Panel 中为该反代站点开启 Basic Auth(用户密码认证) 或限制访问 IP。开启后,在 NAS 终端执行一次 docker login ghcr.xxx.com 输入账号密码,即可安全、专享地白嫖自己服务器的流量,不用担心月流量被黑客一夜薅秃。 2 个帖子 - 2 位参与者 阅读完整话题
音乐版块喜欢听音乐的怎么可以少好看的音乐播放器,分享二个 第一个 Folia一个全屏沉浸式歌词播放为核心的在线音乐播放器 第二个 BetterLyrics —— 曲中人心、词悦双眼,高颜值 Windows 歌词展示工具 二个缺点都是占用很大,尤其是第一个也效果好 自行考虑,喜欢简洁不花哨的,换其他的有很多 3 个帖子 - 3 位参与者 阅读完整话题
大家好,新入手一台 M4 芯片的 MacBook (24+512),准备用来做主力开发机。 想请教一下各位有经验的大佬:配置 Python 和 Node.js 最省心、最干净的方案是什么? 希望能抄一下大佬们的作业,感谢感谢! 23 个帖子 - 17 位参与者 阅读完整话题