经过再次重写之后,性能已经是 Nginx 的 1.76 倍 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
herozem
V2EX    分享创造

经过再次重写之后,性能已经是 Nginx 的 1.76 倍

  •  
  •   herozem 2018-01-25 16:12:47 +08:00 18888 次点击
    这是一个创建于 2824 天前的主题,其中的信息可能已经有所发展或是发生改变。

    guard 是一个高性能熔断器+代理

    RT。上周末发了 t/424778#reply14

    然后最近几天一直在迭代。从把锁丢掉,到重写 radix tree 和融合统计模块,到把 net/http 换成 fasthttp, 在我的笔记本上,QPS 从 7k 左右到了 22k,对比 Nginx,性能从 Nginx 的 0.55 到 1.76 倍。改写的过程非常 累,因为写好的测试需要一遍一遍推翻重写。数据结构也需要仔细设计。hot-path 需要非常注意避免性能问题。

    但是改写的过程也学到了很多东西,例如怎么去优化 Go 的性能,期间尝试了 prefork 模式,减少锁,缩小临界区,使用 CAS,调整 GOGC参数 等等等等。

    项目链接:

    https://github.com/jiajunhuang/guard

    核心模块的设计基本上已经稳定了,接下来要做的事情是:

    • 改写 time.Now,使用自己维护的粗略时间以减少性能损耗
    • 将 radix tree 中的 path 和索引改为[]byte,以便进一步降低 string 和[]byte 之间转换的损耗
    • 嵌入 viper,以便提供动态配置更改的功能
    • graceful restart

    欢迎大家关注和 star,以及提出意见,建议和 PR !

    第 1 条附言    2018-01-26 10:16:29 +08:00
    做了一下 Benchmark,不知道这样可以不。如果有不对的地方,麻烦指正出来然后可以再测。

    https://github.com/jiajunhuang/guard/blob/master/BENCHMARK.md
    第 2 条附言    2018-01-26 19:44:03 +08:00
    要说明的是,guard 最重要的功能,也是最初的目的,是熔断,做一个通用型熔断器。性能只是其中一个重要的功能,和 Nginx 对比,只是为了做对比,并不是要说“这个这个做的比 Nginx 更好”,我没有这个兴趣。

    Nginx 是我最喜欢的软件之一。
    45 条回复    2018-03-30 12:21:15 +08:00
    LuckCode
        1
    LuckCode  
       2018-01-25 16:35:54 +08:00 via iPhone
    不懂 bd,star 学习
    xwhxbg
        2
    xwhxbg  
       2018-01-25 16:41:56 +08:00
    厉害了,不知道有木有跟 traefik 对比一下性能,另外 string 和 byte 不是应该有相同的 underlying value 吗?这俩之间转换有什么特别大的消耗呀?
    herozem
        3
    herozem  
    OP
       2018-01-25 16:48:43 +08:00
    @LuckCode star 也是贡献~~鼓励开发者哈哈

    @xwhxbg 暂时还没有和 trafik 对比,trafik 说 [自己是 Nginx 的 85%]( https://docs.traefik.io/benchmarks/) 左右,起初我也是以这个为目标的。[]byte 是 mutable 的, string 是 immutable 的,如果底层共享的话,会发大乱子的。

    参考: https://syslog.ravelin.com/byte-vs-string-in-go-d645b67ca7ff
    xwhxbg
        4
    xwhxbg  
       2018-01-25 16:54:51 +08:00
    @herozem 学习了,厉害厉害,那已经是 traefik 的两倍了,看了下配置方式很新颖啊,是不是应该以后会有一个界面看 access log 和 register app
    herozem
        5
    herozem  
    OP
       2018-01-25 16:59:53 +08:00
    @xwhxbg 讲真,重写之后原来的配置方式被删掉了 :joy: 之后的话这些功能应该都可以慢慢加上的。不过当务之急是完善核心功能+继续压榨 Go 的性能。

    之前是有一个接口返回 app 和对应的统计数据的,不过如上所说,暂时被删掉了 :joy:

    欢迎贡献代码
    ryd994
        6
    ryd994  
       2018-01-25 17:24:50 +08:00 via Android
    希望能看到具体的测试场景和 nginx 配置,否则单凭 req/s 说服力不大
    xwhxbg
        7
    xwhxbg  
       2018-01-25 17:25:49 +08:00
    @herozem 我看了下代码,位运算好销魂。。。表示理解不能,超出了我的能力范围,贡献代码怕是不可能了
    bramblex
        8
    bramblex  
       2018-01-25 17:28:10 +08:00   2
    讲真 go 这种带着 runtime 的语言是怎么超越 nginx 那种 *****ptr 的优化的。nginx 在很多方面都已经是性能压榨的极限了。
    zhs227
        9
    zhs227  
       2018-01-25 17:31:55 +08:00
    初学者,怀着敬畏点评一下
    fasthttp 的头部都是在使用的时候才解析,之前都是一堆的 byte 地址传来传去。如果要逐个解析头部字段,速度就会明显慢下来。
    另外,fasthttp 前端目前不支持 http2。后面做一些 web 选型就没有再考虑这个。
    不过基于 traefik 的 benchmark 来看,大概 80%相当于 nginx 是靠谱的
    herozem
        10
    herozem  
    OP
       2018-01-25 17:35:13 +08:00
    @bramblex 尽可能的重复利用已经申请的对象,尽可能的避免锁。pprof,哪里耗时打哪里

    @xwhxbg 目前还在开发,变更比较大,等稳定了,注释多了就好读了 :)

    @ryd994 目前还只有简单的测试,等稳定了之后会把 benchmark 做的更详细更专业的 :) 目前是:Nginx 4 worker 返回默认的 index.html。Nginx 4 worker 监听 9999 做代理,guard 监听 23456 做代理。max fd 都是设置 2048000。

    因为都只能在自己的笔记本上跑跑,互相影响是肯定的,之后如果有机会的话,可以用强大的机器+虚拟机的模式来跑分
    herozem
        11
    herozem  
    OP
       2018-01-25 17:39:09 +08:00
    @zhs227 是的,原本我计划自己实现 proxy 也是这种思路。因为作为 proxy server,并不需要读 body。另外 net/http 实现里申请了太多的内存,相当的影响性能。 另外 guard 暂时也不会支持 http2。http/1.x 比 2 的工具等
    都成熟很多。更专业的 benchmark 我会在把功能做成熟做稳定之后再来,目前还只是一个粗略的跑分
        12
    caola  
       2018-01-25 17:50:49 +08:00
    不支持最新的 QUIC 就一切免谈,
    之前用 caddy 的 quic,最高只支持到 quic 38 版本,跟不上时代了
    果断放弃,改投 trafficserver 大法,可以支持到 quic 41 版本,爽。。
    zhujinliang
        13
    zhujinliang  
       2018-01-25 18:22:47 +08:00
    time.Now 这块能详细说一下么
    如何取当前时间的,精确度有多少?
    我想弄一个能精确到 1ms 或 0.5ms 的,但 linux 时间片好像就需要 10ms
    gouchaoer
        14
    gouchaoer  
       2018-01-25 18:25:10 +08:00 via Android
    你能跑个火焰图和 nginx 火焰图说明一下你哪里更厉害么?
    herozem
        15
    herozem  
    OP
       2018-01-25 18:56:28 +08:00
    est
        16
    est  
       2018-01-25 19:54:01 +08:00 via Android
    不太可能超过 nginx 贴配置看看? nginx worker 数量要等于 GOMAXPROC 才公平?
    miketeam
        17
    miketeam  
       2018-01-25 21:26:11 +08:00 via iPhone
    楼主,我搭你的车来了,已给 star
    6ufq0VLZn0DDkL80
        18
    6ufq0VLZn0DDkL80  
       2018-01-26 00:28:11 +08:00 via Android
    @zhujinliang 带 runtime 和调度器的语言就要求别太高了,1ms 的精度基本不可能的
    6ufq0VLZn0DDkL80
        19
    6ufq0VLZn0DDkL80  
       2018-01-26 00:32:07 +08:00 via Android
    @herozem 那位朋友想要高精度时钟,这个 coarseTime 精度应该比 time.Now 还低啊
    herozem
        20
    herozem  
    OP
       2018-01-26 00:42:54 +08:00 via iPad
    @cholerae 应该还是可以的,有写一个 benchmark,发现 time.Now 损耗大概在 40ns 左右,用 coarse 实现应该是可以控制到这位朋友要的精度的。毕竟 CPU 非常的快
    sagaxu
        21
    sagaxu  
       2018-01-26 01:56:55 +08:00
    能公布测试的细节吗? i5-3210M 是双核不是四核,nginx cpu affinity 怎么设置的?


    @herozem GC 卡顿都不敢保证 < 1ms,只能实现软高精度时间
    assad
        22
    assad  
       2018-01-26 07:38:45 +08:00 via Android
    要是能取代 nginx 就牛逼了
    herozem
        23
    herozem  
    OP
       2018-01-26 07:56:22 +08:00 via iPad
    @gouchaoer
    @est
    @sagaxu
    @assad 开发的时候都是用 wrk 粗略压测,CPU 是物理双核虚拟四核。GOMAXPROCS 默认是虚拟核心数(我 1.9 ),Nginx worker 是 4。我今天好好的做一次专业一些的压测,请大家耐心等候。
    herozem
        24
    herozem  
    OP
       2018-01-26 08:01:01 +08:00 via iPad
    @assad 没准备取代,设计的时候就没想过要取代。理想的方式是躲在 Nginx 之后作为一个中间件。因为 Nginx 非常的成熟非常的专业,第二 fasthttp 没有完全遵循 HTTP RFC,第三 guard 并不准备增加 Nginx 那么多可更改的配置和“脚本支持”。

    理想的方式是 Nginx 处理完规则,然后打到 guard,然后后面是应用
    sagaxu
        25
    sagaxu  
       2018-01-26 09:43:57 +08:00 via Android
    @herozem nginx 后面的中间件生存空间有限,一不留神就给 nginx 补丁或者模块取代了
    herozem
        26
    herozem  
    OP
       2018-01-26 10:18:52 +08:00
    @sagaxu :joy: 那可能是命数。。。要替代 Nginx,有太多太多的功能要开发和完善。其实这个项目起初也是为内网的一个需求设计的,不过目前还不够成熟所以还没有上生产。所以设计之初就是躲在 Nginx 后面工作的 (地下工作者
    KgM4gLtF0shViDH3
        27
    KgM4gLtF0shViDH3  
       2018-01-26 10:20:11 +08:00 via Android
    跟 caddy 一样吗
    herozem
        28
    herozem  
    OP
       2018-01-26 10:31:52 +08:00
    @bestkayle 我们不一样 :)
    VYSE
        29
    VYSE  
       2018-01-26 11:40:28 +08:00
    @zhujinliang #13 如果只是对 cpu 运转时间做比较操作,利用 time.Now()的 monotonic clock reading 精度是最高, 读的来源实际就是 cpu 开机至今的 cycle 数, 某些打印操作会导致读自然时间,这就依赖系统时间 api 误差(内核其实只是周期性 update 时间戳)
    zhicheng
        30
    zhicheng  
       2018-01-26 15:37:03 +08:00   8
    一般用非 C/C++ 写的基础软的生命周期:
    1, 写了个 demo 发现性能能接近 nginx,觉得有戏。
    2, 经过一番优化,性能已经完全超过 nginx,觉得非常有戏。
    3, 随着功能的完善,性能逐渐下降,完全无法匹敌 nginx。
    4, 继续经过一翻优化,性能勉强达到 nginx 水平,但代码已经不像高级语言,后悔没有直接用 C。
    5, 用 C 重写了一个 lib,给上层语言调用,性能很好,但 Bug 很多,很容易 Crash。
    6, 发现有人写了个 nginx 插件,很好用,项目被抛弃。
    feverzsj
        31
    feverzsj  
       2018-01-26 15:39:36 +08:00
    这是再测 fasthttp 吧
    herozem
        32
    herozem  
    OP
       2018-01-26 15:52:36 +08:00
    @feverzsj 绝大部分性能确实来自 fasthttp,但是也离不开其他组件的支持。


    @zhicheng 并不想取代 Nginx。在此只是压测时做对比和参照。Nginx 作为我最喜欢的软件之一,怎么能取代呢
    zhicheng
        33
    zhicheng  
       2018-01-26 16:17:21 +08:00
    @herozem
    并不是说要取代 nginx,而是不要把重点放在性能优化上,把重点放到需求上,性能只是一个功能。如果 “非性能” 部分的需求巨大,到时候哪怕再用 C 写一个,也不是问题。
    m939594960
        34
    m939594960  
       2018-01-26 16:25:58 +08:00
    benchmark nginx 的配置没关 log 啊
    0ZXYDDu796nVCFxq
        35
    0ZXYDDu796nVCFxq  
       2018-01-26 19:32:30 +08:00   1
    我优化一下 nginx 对比一下
    nginx 单进程,CPU 是虚拟机的 i5-4590 CPU @ 3.30GHz

    测试结果:
    1. 请求 nginx 默认首页
    wrk --latency -c 2048 -d 30 -t 2 http://127.0.0.1:32645/index.html

    Running 30s test @ http://127.0.0.1:32645/index.html
    2 threads and 2048 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 16.54ms 91.31ms 1.97s 96.19%
    Req/Sec 35.86k 14.09k 81.79k 66.50%
    Latency Distribution
    50% 1.55ms
    75% 2.86ms
    90% 4.47ms
    99% 406.41ms
    2140722 requests in 30.08s, 1.69GB read
    Socket errors: connect 1029, read 98, write 0, timeout 564
    Requests/sec: 71172.27
    Transfer/sec: 57.69MB

    2. 请求 nginx 直接 return 的 hello world
    wrk --latency -c 1000 -d 30 -t 2 http://127.0.0.1:32645/hello

    Running 30s test @ http://127.0.0.1:32645/hello
    2 threads and 1000 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 43.54ms 182.36ms 1.83s 94.93%
    Req/Sec 83.45k 12.45k 128.69k 74.58%
    Latency Distribution
    50% 0.99ms
    75% 1.75ms
    90% 50.98ms
    99% 1.12s
    4975705 requests in 30.04s, 749.51MB read
    Socket errors: connect 0, read 21, write 0, timeout 352
    Requests/sec: 165662.55
    Transfer/sec: 24.95MB


    测试配置和脚本见 github:
    https://gist.github.com/travislee8964/76e57bf013923eb9efe9f5cc6c5f9ce9
    0ZXYDDu796nVCFxq
        36
    0ZXYDDu796nVCFxq  
       2018-01-26 19:35:57 +08:00
    网络和内核没经过优化,所以有一些 socket errors
    优化后性能应该还能有提升
    0915240
        37
    0915240  
       2018-01-26 19:40:08 +08:00
    强烈关注。。
    herozem
        38
    herozem  
    OP
       2018-01-26 19:40:10 +08:00
    @zhicheng 嗯,这也是一种观点。过早优化是万恶之源没错,但是性能也是一个重要的功能。软件开发的过程并非要剑走偏锋,例如追着性能不放,而是在权衡之下取一个比较好的点。目前这边也没有完全追逐性能
    herozem
        39
    herozem  
    OP
       2018-01-26 19:41:09 +08:00
    @gstqc 如果可以的话,最好能把 guard 的测试一起贴上去。这样方便对比,哈哈~
    wzy44944
        40
    wzy44944  
       2018-01-26 23:05:03 +08:00
    压完看下火焰图更准确些,不然很容易被一些无所谓的配置掩盖掉,比如 nginx 的 accept 锁要去掉,reuseport 打开,而且随机请求压才有意义,只压一个请求会有内存缓存,这点和配置也有关系。既然不是替代 nginx 的,就不要和 nginx 对比了吧,和做同一个业务的软件对比才好
    sammo
        41
    sammo  
       2018-01-28 11:22:55 +08:00 via Android
    终于在 v 站上看到一个有性能追求的软件了
    xxdd
        42
    xxdd  
       2018-01-28 21:37:04 +08:00
    已 star
    从不吝啬 star QAQ
    xman99
        44
    xman99  
       2018-01-31 14:30:13 +08:00
    Mark, 膜拜中
    holulu
        45
    holulu  
       2018-03-30 12:21:15 +08:00
    @caola ATS 试试网上查到的配置,但开不了 QUIC。服务器能正常启动,日志也能看到 QUIC,但没见 UDP 端口有监听啊。
    Chrome stable 和 canary 也只支持 QUIC-39,QUIC-41 好像没有太大意义。
    关于     帮助文档   &nsp; 自助推广系统     博客     API     FAQ     Solana     2635 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 96ms UTC 09:26 PVG 17:26 LAX 02:26 JFK 05:26
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86