V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
MagicCoder
V2EX  ›  程序员

拥抱 PostgreSQL 支持 UI 配置化

  •  
  •   MagicCoder · 1 天前 · 2532 次点击

    前言

    前阵子写的日志分析工具NginxPulse,自开源以来,已过去 2 周时间,目前 GitHub 已收获 1.5k 的 star 。收到了不少用户的反馈建议,花了点时间将这些问题都处理了下。

    本文就跟大家分享下新版本都解决了哪些问题,优化了哪些内容,欢迎各位感兴趣的开发者阅读本文。

    抛弃 SQLite

    有不少用户反馈说日志文件很大的时候( 10G+),解析速度非常慢,需要解析好几个小时,解析完成之后数据看板的查询也比较慢(接口响应在 5 秒左右)。

    于是,我重写了日志解析策略(解析阶段不做 IP 归属地查询,仅入库其他数据,将日志中 IP 记录起来),日志解析完毕后,将记录的 IP 做去重处理,随后去做归属地的查询处理(优先本地的 ip2region 库,远程的 API 调用查询做兜底),最后将解析到的归属地回填至对应的数据库表中,这样一套下来就可以大大提升日志的解析速度。

    数据库的数据量大了之后,SQLite 的表现就有点差强人意了,请教了一些后端朋友,他们给了我一些方案,结合我自身的实际场景后,最后选定了 PostgreSQL 作为新的数据库选型。

    这套方案落地后,用户群的好兄弟说:他原先需要解析 1 个小时的日志,新版只需要 10 多分钟。

    6c1c8781ddb810d57c9f508fdaf47025

    UI 配置可视化使用

    有一部分用户反馈说他非专业人士,这些晦涩的配置对他来说使用门槛太高了,希望能有一个 UI 配置页面,他只需要点一点、敲敲键盘,就能完成这些配置。

    我将整个配置流程做成了 4 步,同时也准备一个[演示视频](NginxPulse 支持 UI 配置化了) - https://www.bilibili.com/video/BV1hqzyBVEU9:

    • 配置站点
    • 配置数据库
    • 配置运行参数
    • 确认最终配置

    image-20260125235847464

    新增 wiki 文档

    因为配置过于庞大,仓库主页浏览 README.md 比较费劲,希望能整理一份 wiki 文档发上去。

    花了点时间,简化了下 README ,整理了一份: https://github.com/likaia/nginxpulse/wiki

    image-20260126000555725

    访问明细模块优化

    有部分用户反馈说希望增加更多的筛选条件以及导出 Excel 功能,现在它来了:

    image-20260126001010068

    概况模块优化

    概况页面的日期筛选之前放在趋势分析卡片的上方,但是他的切换影响的维度还包含了指标,于是我就调整了下它的位置,新版如下图所示:

    image-20260126001325265

    项目地址

    写在最后

    至此,文章就分享完毕了。

    我是神奇的程序员,一位前端开发工程师。

    如果你对我感兴趣,请移步我的个人网站,进一步了解。

    30 条回复    2026-01-27 10:47:09 +08:00
    yjhatfdu2
        1
    yjhatfdu2  
       1 天前   ❤️ 4
    为什么不用 duckdb 呢?和 sqlite 一样是进程内数据库,但是是列存分析型数据库性能超强,存储效率也会比 pg 和 sqlite 高很多,存储体积小,也基本支持 postgresql 的语法,估计时间可以进一步缩短好几倍。
    dog82
        2
    dog82  
       1 天前
    为啥把日志写到 DB 呢?
    yjhatfdu2
        3
    yjhatfdu2  
       1 天前   ❤️ 1
    @dog82 估计是便于分析聚合吧,不过存 pg 也确实是效率有点低了,我做的话可能会考虑存 parquet 文件用 duckdb 分析,这样文件可以存文件系统也可以存 s3 ,比较灵活,体积也非常小,10G 文件做到分钟级解析我也有信心
    MagicCoder
        4
    MagicCoder  
    OP
       1 天前
    @yjhatfdu2 好高级的词汇😂,我研究下 duckdb 之前没听过
    concernedz
        5
    concernedz  
       1 天前
    日志不是用 mongodb 么
    yjhatfdu2
        6
    yjhatfdu2  
       22 小时 20 分钟前
    试了下,使用 golang 并行解析 11G 的 nginx accesslog ,同样适用 ip2region 解析地理位置,解析 useragent 字段,8 个线程,写入 parquet 文件,在我 m1max 老机器上可以在 40 秒左右完成。然后使用 duckdb 直接查询,7000 多万条数据,根据状态码 group by count 聚合大概 0.11 秒,还是非常适合这个场景的,整个 dashboard 尤其是只分析时间段的,应该秒级全出。
    select count(*),status from 'parquet_out/*.parquet' group by status;
    ┌──────────────┬────────┐
    │ count_star() │ status │
    │ int64 │ int32 │
    ├──────────────┼────────┤
    │ 16455120 │ 200 │
    │ 420 │ 413 │
    │ 58349130 │ 404 │
    │ 261330 │ 400 │
    │ 8310 │ 500 │
    │ 60 │ 408 │
    │ 3540 │ 501 │
    │ 3537120 │ 405 │
    │ 90 │ 403 │
    │ 7230 │ 206 │
    │ 15630 │ 304 │
    │ 4980 │ 499 │
    ├──────────────┴────────┤
    │ 12 rows 2 columns │
    └───────────────────────┘
    Run Time (s): real 0.112 user 0.937740 sys 0.047321
    yjhatfdu2
        7
    yjhatfdu2  
       22 小时 10 分钟前
    然后使用 create table access_log as select * from 'parquet_out/*.parquet'; 创建 duckdb 的表并导入 parquet 的所有数据,耗时 20 秒,之后查询可以再快一倍,最终 duckdb 存储 7000 多万条记录占用硬盘 1.9G ,原始 access.log 一共 11G
    MagicCoder
        8
    MagicCoder  
    OP
       22 小时 9 分钟前
    @yjhatfdu2 卧槽 这性能可以
    yjhatfdu2
        9
    yjhatfdu2  
       21 小时 58 分钟前
    我看了下,你这里用了大量的维度表、预聚合、分表来提高性能,其实用 duckdb 性能足够,单机 10 亿条都用不着干这些事。可以极大的简化后端,减少存储占用和提高解析和写入速度
    MagicCoder
        10
    MagicCoder  
    OP
       21 小时 53 分钟前
    @yjhatfdu2 对的,我后端做了大量的优化工作提升性能,感觉 duckdb 确实可行😂
    MagicCoder
        11
    MagicCoder  
    OP
       21 小时 52 分钟前
    @yjhatfdu2 之前朋友还给我推荐过 clickhouse ,我就是看他太耗费资源了,我这个场景还用不到
    yjhatfdu2
        12
    yjhatfdu2  
       21 小时 37 分钟前
    @MagicCoder clickhouse 性能上也是可以的,但是部署维护复杂,稍微老点的版本对于 update/delete 效率非常低,资源消耗也是很高。duckdb 适合直接平替 sqlite ,单机模式下很适合。当然你这里如果需要初始化也做的非常快,还是需要做一些工程优化的,如果是 duckdb 直接使用 golang 的驱动,使用 appender 接口进行写入,这个场景也就 20-30w 行一秒,我是尝试了直接使用 go-parquet ,每个线程独立直接写入 parquet 文件,最后再用 duckdb 执行 sql 直接导入,后续再使用 go 的 database/sql 接口写入增量数据,这样才能做到初始化的极速、后续处理的方便。
    MagicCoder
        13
    MagicCoder  
    OP
       20 小时 58 分钟前
    @yjhatfdu2 懂了,非常感谢,我研究下你说的这个方案
    XyIsMy
        14
    XyIsMy  
       20 小时 46 分钟前
    @MagicCoder duckdb ,可以直接在 postgresql 上面装一个扩展,开启扩展,会自动转换成 duckdb ,也很方便
    MagicCoder
        15
    MagicCoder  
    OP
       20 小时 40 分钟前
    @XyIsMy 哦豁,这么高级,那就方便很多了
    goodryb
        16
    goodryb  
       19 小时 58 分钟前
    OP 这下又有活可以干了,等你下个稳定版出来了我试试
    Hermitist
        17
    Hermitist  
       19 小时 10 分钟前
    我也在等 OP 的更新, 冒昧问下, 用你的项目在一个暂时免费, 但以后商业化的软件有什么问题吗?
    MagicCoder
        18
    MagicCoder  
    OP
       18 小时 26 分钟前
    @Hermitist 没事,随便用
    MagicCoder
        19
    MagicCoder  
    OP
       18 小时 23 分钟前
    @goodryb 行 别忘了🤣
    yjhatfdu2
        20
    yjhatfdu2  
       18 小时 2 分钟前
    @MagicCoder duckdb 的 pg_duckdb 插件并不是很适合。首先,你还是需要 pg ,pg 需要单独部署,不能集成到应用里面,作为轻量化的,必然增加了部署的复杂度。第二,pg 需要部署 pg_duckdb 插件需要自行编译或者使用特定的发行版,还是有一定复杂度的。第三,pg_duckdb 主要是方便使用 pg 访问、查询外部 parquet 等文件,或者联合 pg 本地表进行分析查询。但是还是需要走 pg 的协议、parser 等,也没法直接写入 duckdb 自己的库,对于现在这个场景降低了性能,提高了复杂度。
    MagicCoder
        21
    MagicCoder  
    OP
       15 小时 27 分钟前
    @yjhatfdu2 好吧🤣 那看来还是得完整的用 duckdb
    mephisto
        22
    mephisto  
       13 小时 40 分钟前
    UI 部分 iPhone 和 iPad 端访问时各种错位,能适配下就好了
    MagicCoder
        23
    MagicCoder  
    OP
       13 小时 3 分钟前
    @mephisto 这周的计划就是写移动端
    xiaoz
        24
    xiaoz  
       4 小时 52 分钟前 via Android
    这个项目支持资源流量统计不?
    MagicCoder
        25
    MagicCoder  
    OP
       3 小时 6 分钟前
    @xiaoz 只要请求走 nginx ,有日志记录,就能统计到
    DLOG
        26
    DLOG  
       2 小时 58 分钟前
    ALL IN DORIS !
    apkapb
        27
    apkapb  
       2 小时 16 分钟前
    op 还是非常非常厉害的👍
    apkapb
        28
    apkapb  
       2 小时 14 分钟前
    format transform `{request>headers>X-Forwarded-For>[0]} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"`

    像我这个 caddy 日志格式,有现成的嘛😅
    MagicCoder
        29
    MagicCoder  
    OP
       1 小时 13 分钟前
    @apkapb 内置的 caddy 有试过能解析吗?
    MagicCoder
        30
    MagicCoder  
    OP
       1 小时 12 分钟前
    @DLOG 高级
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   4686 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 03:59 · PVG 11:59 · LAX 19:59 · JFK 22:59
    ♥ Do have faith in what you're doing.