从HTTP性能基准测试谈Vert.x高性能的秘密:从JIT编译到网络优化 英文

2020-03-01 819浏览

  • 1.Real-world HTTP performance benchmarking, lessons learned Julien Viet QCon Shangai
  • 2.
  • 3.Once upon a time
  • 4.Round #8
  • 5.Every one was happy
  • 6.But one day...
  • 7.Round #14
  • 8.Round #14
  • 9.Round #14
  • 10.Round #14
  • 11.Round #14
  • 12.Real-world HTTP performance benchmarking, lessons learned
  • 13.Julien Viet Open source developer for 16+ years @vertx_project lead Principal software engineer at Marseille JUG Leader !https://www.julienviet.com/"http://github.com/vietj# @julienviet https://www.mixcloud.com/cooperdbi/
  • 14.Eclipse Vert.x Open source project started in 2012 Eclipse / Apache licensing A toolkit for building reactive applications for the JVM 8K ⋆ on " Built on top of !https://vertx.io# @vertx_project
  • 15.Techempower Framework Benchmark ✓ Performance of production grade deployments of real-world application frameworks and platforms ✓ 464 frameworks - 26 languages ✓ Community ✓ Physical of contributors on GitHub server or cloud (Azure)
  • 16.6 benchmarks ✓ "/plaintext", "/json" # ✓ "/db", ! "/queries", "/updates", "/fortunes" # ! "
  • 17.Things to remember ✓ Benchmarking is hard ✓ Benchmarking != load testing ✓ Measure ✓ Be critic don't guess
  • 18.The lab
  • 19.
  • 20.
  • 21.
  • 22./plaintext
  • 23.Benchmark ✓ Simple Hello World ✓ 16,384 concurrent connections ✓ HTTP ✓ No pipelining (16) back-end ✓ Heavily CPU bound
  • 24.Keep-alive GET OK PUT OK GET OK
  • 25.Head of line blocking
  • 26.Pipelining GET PUT GET OK OK OK
  • 27.Our weapons ✓ Async-profiler ✓ Jitwatch ✓ Wireshark + Flame graphs
  • 28.Code inlining
  • 29.process error process request process body
  • 30.process error process request process body
  • 31.process error process request process body reduce method size to favor inlining
  • 32.b2073fa091d64a1dfe06699bca1a8befddb5a805 process error process request process body $ 2. inline by hand
  • 33.Batch to amortise costs
  • 34.chctx.fireChannelRead(msg) // class VertxHandler void channelRead(Object msg) { Connection conn = getConnection(); Context ctx = conn.getContext(); context.executeFromIO(conn::startRead());channelRead(conn, msg); } // class VertxHttpHandler extends VertxHandler void startRead() { ... } void channelRead(Connection conn, Object msg) { conn.handleMessage(msg); } void handleMessage(Object msg) { ... }
  • 35.799df9e602eabcd51b56052e20cc7d05134!901 chctx.fireChannelRead(msg) Batch here // class VertxHandler public void channelRead(ChannelHandlerContext chctx, Object msg) { Connection conn = getConnection(); Context ctx = conn.getContext(); context.executeFromIO(() -> { conn.startRead(); conn.handleMessage(msg); }); } void startRead() { } void handleMessage(Object msg) { ... }
  • 36.The fastest code is the code that never runs
  • 37.Netty Vert.x Application req.response() .end("Hello World");
  • 38.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } Application req.response() .end("Hello World");
  • 39.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } void queueForWrite(Object msg) { needsFlush = true; channel.write(encode(obj)); } Application req.response() .end("Hello World");
  • 40.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } ChannelFuture write(Object msg) { return pipeline.write(msg); void queueForWrite(Object msg) { } needsFlush = true; channel.write(encode(obj)); } Application req.response() .end("Hello World");
  • 41.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } ChannelFuture write(Object msg) { return pipeline.write(msg); void queueForWrite(Object msg) { } needsFlush = true; channel.write(encode(obj)); } // default implementation (inherited) void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { ctx.write(msg, promise); } Application req.response() .end("Hello World");
  • 42.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } ChannelFuture write(Object msg) { return pipeline.write(msg); void queueForWrite(Object msg) { } needsFlush = true; channel.write(encode(obj)); } void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } // default implementation (inherited) void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { ctx.write(msg, promise); } Application req.response() .end("Hello World");
  • 43.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } ChannelFuture write(Object msg) { return pipeline.write(msg); void queueForWrite(Object msg) { } needsFlush = true; channel.write(encode(obj)); } void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } // default implementation (inherited) void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { ctx.write(msg, promise); } Application req.response() .end("Hello World");
  • 44.Netty the fastest code is the code that never runs void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } Application req.response() .end("Hello World"); void queueForWrite(Object msg) { needsFlush = true; chctx.write(encode(obj)); } 217b17c78cd54103ae98557510a7ac431e17c5ea
  • 45.Reduce object allocation
  • 46.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } void write(Object msg) { write(msg, newPromise()); } void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } void queueForWrite(Object msg) { needsFlush = true; chctx.write(encode(obj)); } Application req.response() .end("Hello World");
  • 47.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } void write(Object msg) { write(msg, newPromise()); } void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } void queueForWrite(Object msg) { needsFlush = true; chctx.write(encode(obj)); } Application req.response() .end("Hello World");
  • 48.Netty Vert.x void end(Bu!er bu!er) { FullHttpResponse msg = ... queueForWrite(msg); } void queueForWrite(Object msg) { needsFlush = true; chctx.write(obj, channel.voidPromise()); } void write(Object msg, ChannelPromise promise) { next.invoke(msg, promise) } Application req.response() .end("Hello World"); reduce GC allocation by using VoidPromise 6b9788dec6e1147782a3a7017ead067778095cba
  • 49.Cache expensive operations
  • 50.void setConnection(Connection conn) { this.conn = conn; } Vert.x void channelReadComplete(ChannelHandlerContext ctx) { Runnable task =conn::endReadAndFlush();// Need to use executeFromIO to avoid race conditions context.executeFromIO(task); } void endReadAndFlush() { if (needFlush) { needFlush = false; channel.flush(); } }
  • 51.void setConnection(Connection conn) { this.conn = conn; } Vert.x void channelReadComplete(ChannelHandlerContext ctx) { Runnable task =conn::endReadAndFlush();// Need to use executeFromIO to avoid race conditions context.executeFromIO(task); } void endReadAndFlush() { if (needFlush) { needFlush = false; channel.flush(); } } Called for every each flush
  • 52.void setConnection(Connection conn) { this.conn = conn; this.task =conn::endReadAndFlush();'>conn::endReadAndFlush();