

netty系列之:一个价值上亿的网站速度优化方案
source link: http://www.flydean.com/34-netty-multiple-server/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

其实软件界最赚钱的不是写代码的,写代码的只能叫马龙,高级点的叫做程序员,都是苦力活。那么有没有高大上的职业呢?这个必须有,他们的名字就叫做咨询师。
咨询师就是去帮企业做方案、做架构、做优化的,有时候一个简单的代码改动、一个架构的调整都可以让软件或者流程更加高效的运行,从而为企业节省上亿的开支。
今天除了要给大家介绍一下如何在netty中同时支持http和https协议之外,还给大家介绍一个价值上亿的网站数据优化方案,有了这个方案,年薪百万不是梦!
本文的目标
本文将会给大家介绍一下如何在一个netty服务中同时支持http和http2两种协议,在这两个服务器中,提供了对多图片的访问支持,我们介绍如何从服务器端返回多个图片。最后介绍一个价值上亿的速度优化方案,肯定大家会受益匪浅。
支持多个图片服务
对于服务器端来说,是通过ServerBootstrap来启动服务的,ServerBootstrap有一个group方法用来指定acceptor的group和client的group。
public ServerBootstrap group(EventLoopGroup group)
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup)
当然你可以指定两个不同的group,也可以指定同一个group,它提供了两个group方法,效果上没太大的区别。
这里我们现在主服务器中创建一个EventLoopGroup,然后将其传入到ImageHttp1Server和ImageHttp2Server中。然后分别在两个server中调用group方法,然后配置handler即可。
先看一下ImageHttp1Server的构造:
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(group).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch){
ch.pipeline().addLast(new HttpRequestDecoder(),
new HttpResponseEncoder(),
new HttpObjectAggregator(MAX_CONTENT_LENGTH),
new Http1RequestHandler());
}
});
我们传入了netty自带的HttpRequestDecoder、HttpResponseEncoder和HttpObjectAggregator。还有一个自定义的Http1RequestHandler。
再看一下ImageHttp2Server的构造:
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(group).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()), new CustProtocolNegotiationHandler());
}
});
为了简单起见,我们默认如果从http来访问的话,就使用http1服务,如果是从https来访问的话,就使用http2服务。
所以在http2服务中,我们只需要自定义ProtocolNegotiationHandler即可,而不用处理clear text升级的请求。
http2处理器
在TLS环境中,我们通过自定义CustProtocolNegotiationHandler,继承自ApplicationProtocolNegotiationHandler来进行客户端和服务器端协议的交互。
对于http2协议来说,使用了netty自带的InboundHttp2ToHttpAdapterBuilder和HttpToHttp2ConnectionHandlerBuilder将http2 frame转换成为http1的FullHttpRequest对象。这样我们直接处理http1格式的消息即可。
转换过程如下:
DefaultHttp2Connection connection = new DefaultHttp2Connection(true);
InboundHttp2ToHttpAdapter listener = new InboundHttp2ToHttpAdapterBuilder(connection)
.propagateSettings(true).validateHttpHeaders(false)
.maxContentLength(MAX_CONTENT_LENGTH).build();
ctx.pipeline().addLast(new HttpToHttp2ConnectionHandlerBuilder()
.frameListener(listener)
.connection(connection).build());
ctx.pipeline().addLast(new Http2RequestHandler());
转换转换的http2 handler和普通的http1的handler唯一不同的是需要额外设置一个streamId属性到请求头和响应头中。
并且不需要处理http1特有的100-continue和KeepAlive。其他的和http1 handler没什么两样。
处理页面和图像
因为我们使用转换器将http2的frame转换成了http1的普通对象,所以对请求相应的页面和图像来说,跟http1的处理没什么太大区别。
对于页面来说,我们需要获取要返回的html,然后设置CONTENT_TYPE为”text/html; charset=UTF-8″,返回即可:
private void handlePage(ChannelHandlerContext ctx, String streamId, FullHttpRequest request) throws IOException {
ByteBuf content =ImagePage.getContent();
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
sendResponse(ctx, streamId, response, request);
}
对于图像来说,我们获取到要返回的图像,将其转换成为ByteBuf,然后设置CONTENT_TYPE为”image/jpeg”,返回即可:
private void handleImage(String id, ChannelHandlerContext ctx, String streamId,
FullHttpRequest request) {
ByteBuf image = ImagePage.getImage(parseInt(id));
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, image);
response.headers().set(CONTENT_TYPE, "image/jpeg");
sendResponse(ctx, streamId, response, request);
}
这样,我们就能够在netty服务器端同时处理页面请求和图片请求了。
价值上亿的速度优化方案
终于要到本文中最精彩的部分了,价值上亿的速度优化方案是什么呢?
在讲这个方案之前,先给大家讲一个抗洪抢险的故事。有两个县都住在一条大河的旁边。这条大河很不安稳,经常会发洪灾,但是两个县的县长做法很不同。
A县的县长认真负责,派人定期巡逻检查所属的河段,筑堤、种树、巡视,一刻都放松,在他的任期平平安安,没有发生任何洪水溃堤的情况。
B县的县长从来不巡检,一道河水泛滥的时候,B县长就组织人抗洪抢险,然后媒体全都报道的是B县长抗洪的丰功伟绩,最后B县长由于政绩突出,升任市长。
好了,故事讲完了,接下来是我们的优化。不管是用户请求页面还是图片,最终都需要调用ctx.writeAndFlush(response)方法进行响应回写。
如果将其放入一个定时任务中,来定时执行,如下所示:
ctx.executor().schedule(new Runnable() {
@Override
public void run() {
ctx.writeAndFlush(response);
}
}, latency, TimeUnit.MILLISECONDS);
那么服务器在经过latency指定的毫秒之后,才会发送对应的响应。比如这里我们设置latency的值为5秒。
当然5秒是不能够让人满意的,于是领导或者客户找到你,说让你给优化一下。你说这个性能问题是很难的,涉及到了麦克斯韦方程组和热力学第三定律,需要一个月时间。领导说好,撸起袖子加油干,下个月给你工资涨50%。
一个月后,你把latency改成2.5秒,性能提升了100%,这个优化值不值几个亿?
当然,上一节给大家开个玩笑,不过在netty响应中使用定时任务的技巧,大家也应该牢牢掌握,原因你懂的!
本文的例子可以参考:learn-netty4
本文已收录于 http://www.flydean.com/34-netty-multiple-server/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
Recommend
-
9
WebView优化提升H5加载速度方案 WebView加载H5经历的过程图示
-
11
0 Comments 写 C/C++ 的同学都知道,项目稍大点,编译速度就开始拖后腿了,这对于我们来说是个又爱又恨的时候:急着改代码...
-
5
网站访问速度优化 作者: 张志强 , 发表于 2015...
-
9
学院网站访问速度测试 谢益辉 / 2006-04-13 对学院网站的访问速度进行了一下测试,分别找了三位朋友: 台湾 谢益辉 说 (16:34): 帮我个忙,看看你在台湾访问我们学院的新网站有没有...
-
10
Jager · 2月3日 · 2018年CDN · CDN加速 · 网站优化 9878次已读很...
-
8
本文出自于“「2021 友盟+ 移动应用性能挑战赛」” 中的参赛作品,该文章表述了作者如何借助
-
2
Mr.Feng BlogNLP、深度学习、机器学习、Python、Go优化算法系列(5):SGD改进之Adam一个综合方案和派生(更新)本文已经更新了Adam的派生方案。 梯度估...
-
7
动手点关注 干货不迷路 👆 一、背景和目标 作为 Android 开发者,相信大家都碰到过 Java OOM 问题,导致 OOM 的原因可能是应用存在内存泄漏,也可能是因为手机的 heapsize 比较小不能满足复杂应用对内存资源的大量需求。对...
-
7
前言:这是白杨SEO公众号原创第397篇。为什么想到写这个?一个星期前一个微信好友发了个站让我看看,如图。所以...
-
2
网站速度终极优化 – 土木坛子 好久没有折腾网站速度了。最近尝试再次优化提升网站的访问...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK