简介其实软件行业最赚钱的人不是写代码的人,写代码的只能叫马龙,而那些更高级的叫程序员,都是苦力活。那么有没有高级职业呢?这个肯定是有的,他们的名字叫顾问。顾问在那里帮助公司制定计划、构建架构和进行优化。有时一个简单的代码改动或架构调整,就能让软件或流程运行得更高效,从而为公司节省数亿的开支。今天除了介绍netty如何同时支持http和https协议外,还要介绍一个价值上亿的网站数据优化方案。有了这个方案,年薪百万不是梦!本文的目标本文将向大家介绍如何在一个netty服务中同时支持http和http2协议。在这两个服务器中,都提供了对多张图片的访问支持。我们将介绍如何从服务器返回多张图片。图片。最后给大家介绍一个价值上亿的速度优化方案,一定会让大家受益匪浅。支持多种图片服务对于服务器端,服务是通过ServerBootstrap启动的。ServerBootstrap有一个group方法来指定接受器组和客户端组。publicServerBootstrapgroup(EventLoopGroupgroup)publicServerBootstrapgroup(EventLoopGroupparentGroup,EventLoopGroupchildGroup)当然可以指定两个不同的组,也可以指定同一个组。它提供了两种组方法,效果没有太大区别。这里我们在主服务器创建一个EventLoopGroup,然后传入ImageHttp1Server和ImageHttp2Server。然后在两台服务器分别调用group方法,然后配置handler。先看ImageHttp1Server的结构:ServerBootstrapb=newServerBootstrap();b.option(ChannelOption.SO_BACKLOG,1024);b.group(group).channel(NioServerSocketChannel.class).handler(newLoggingHandler(LogLevel.INFO)).childHandler(newChannelInitializer(){@OverrideprotectedvoidinitChannel(SocketChannelch){ch.pipeline()}.addLast(newHttpRequestDecoder(),newHttpResponseEncoder(),newHttpObjectAggregator(MAX_CONTENT_LENGtHandpler)(new);}});我们传入了netty自带的HttpRequestDecoder,HttpResponseEncoder和HttpObjectAggregator,还有一个自定义的Http1RequestHandler。再看一下ImageHttp2Server的结构:ServerBootstrapb=newServerBootstrap();b.option(ChannelOption.SO_BACKLOG,1024);b.group(group).channel(NioServerSocketChannel.class).childHandler(newChannelInitializer(){@OverrideprotectedvoidinitChannel(SocketChannelch){ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()),newCustProtocolNegotiationHandler());}});为了简单起见,我们默认如果从http访问,则使用http1服务,如果从https访问,则使用http2服务。所以在http2服务中,我们只需要自定义ProtocolNegotiationHandler,而不用去处理明文升级请求。在http2处理器的TLS环境中,我们自定义CustProtocolNegotiationHandler,继承自ApplicationProtocolNegotiationHandler,实现客户端和服务端协议的交互。对于http2协议,利用netty自带的InboundHttp2ToHttpAdapterBuilder和HttpToHttp2ConnectionHandlerBuilder将http2的帧转换为http1的FullHttpRequest对象。这样我们就可以直接处理http1格式的消息了。转换过程如下:DefaultHttp2Connectionconnection=newDefaultHttp2Connection(true);InboundHttp2ToHttpAdapterlistener=newInboundHttp2ToHttpAdapterBuilder(connection).propagateSettings(true).validateHttpHeaders(false).maxContentLength(MAX_CONTENT_LENGTH).build();ctx.pipeline().addLast(newHttpToHttp2ConnectionHandlerBuilder().frameListener(listener).connection(connection).build());ctx.pipeline().addLast(newHttp2RequestHandler());转换后的http2处理程序和普通的http1处理程序之间的唯一区别是为请求和响应标头额外设置了一个streamId属性。而且不需要处理http1-specific100-continue和KeepAlive。其余与http1处理程序相同。处理页面和图片因为我们使用转换器将http2的frame转换为http1的普通对象,所以请求相应页面和图片的处理与http1的处理没有太大区别。对于页面,我们需要获取返回的html,然后设置CONTENT_TYPE为“text/html;charset=UTF-8”并返回:privatevoidhandlePage(ChannelHandlerContextctx,StringstreamId,FullHttpRequestrequest)throwsIOException{ByteBuf内容=ImagePage.getContent();FullHttpResponse响应=newDefaultFullHttpResponse(HTTP_1_1,OK,content);response.headers().set(CONTENT_TYPE,"text/html;charset=UTF-8");sendResponse(ctx,streamId,响应,请求);对于图像,我们获取要返回的图像,将其转换为ByteBuf,然后将CONTENT_TYPE设置为“image/jpeg”并返回:privatevoidhandleImage(Stringid,ChannelHandlerContextctx,StringstreamId,FullHttpRequestrequest){ByteBufimage=ImagePage.getImage(parseInt(id));FullHttpResponse响应=newDefaultFullHttpResponse(HTTP_1_1,OK,image);response.headers().set(CONTENT_TYPE,"image/jpeg");sendResponse(ctx,streamId,响应,请求);这样我们就可以在netty服务器上同时处理页面请求和图片请求了。价值上亿的速度优化方案终于来到本文最精彩的部分了。价值数亿的速度优化方案是什么?在讲这个方案之前,先给大家讲一个抗洪抢险的故事。有两个县住在一条大河旁边。这条大河水势很不稳定,经常泛滥,但两县的县长却有着截然不同的做法。A县县令认真负责。他派人定期巡查自己所属的河段,筑堤、植树、巡查。B县县令从不巡逻。某条河水泛滥,B县县长组织群众抗洪。然后媒体都在报道B县县长抗洪的丰功伟绩。最终,B县县长因政绩显赫,被提拔为县长。好了,故事讲完了,接下来就是我们的优化了。不管用户请求的是页面还是图片,都需要调用ctx.writeAndFlush(response)方法写回response。如果放入定时任务定时执行,如下:.毫秒);然后服务器将在延迟指定的毫秒数后发送相应的响应。例如,这里我们将延迟的值设置为5秒。5秒当然不行,所以领导或者客户找到你,让你优化。你说这道性能题很难,涉及到麦克斯韦方程组和热力学第三定律,需要一个月的时间。领导说好,撸起袖子好好干,下个月工资涨50%。一个月后,您将延迟更改为2.5秒,性能提高了100%。这个优化值几亿?总结当然,上一节给大家开了个玩笑,但是netty响应中使用定时任务的技巧大家也应该牢牢掌握,道理你懂的!本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/34-netty-multiple-server/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!