简介

其实软件界最赚钱的不是写代码的,写代码的只能叫马龙,高级点的叫做程序员,都是苦力活。那么有没有高大上的职业呢?这个必须有,他们的名字就叫做咨询师。

咨询师就是去帮企业做方案、做架构、做优化的,有时候一个简单的代码改动、一个架构的调整都可以让软件或者流程更加高效的运行,从而为企业节省上亿的开支。

今天除了要给大家介绍一下如何在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/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:一个价值上亿的网站速度优化方案的更多相关文章

  1. 【网站管理6】_一个网站SEO优化方案

    首先,前端/页编人员主要负责站内优化,主要从四个方面入手: 第一个,站内结构优化 合理规划站点结构(1.扁平化结构 2.辅助导航.面包屑导航.次导航) 内容页结构设置(最新文章.推荐文章.热门文章.增 ...

  2. 一个网站SEO优化方案

    首先,前端/页编人员主要负责站内优化,主要从四个方面入手: 第一个,站内结构优化 合理规划站点结构(1.扁平化结构 2.辅助导航.面包屑导航.次导航) 内容页结构设置(最新文章.推荐文章.热门文章.增 ...

  3. netty系列之:搭建HTTP上传文件服务器

    目录 简介 GET方法上传数据 POST方法上传数据 POST方法上传文件 总结 简介 上一篇的文章中,我们讲到了如何从HTTP服务器中下载文件,和搭建下载文件服务器应该注意的问题,使用的GET方法. ...

  4. 一个网站完整详细的SEO优化方案

    根据自己的个人经验完成了这篇文章,希望对SEOer有点帮助,高手直接跳过,请勿喷水... 一个完整的SEO优化方案主要由四个小组组成: 一.前端/页编人员 二.内容编辑人员 三.推广人员 四.数据分析 ...

  5. 一个完整的SEO优化方案

    一个完整的SEO优化方案主要由四个小组组成: 一.前端/页编人员 二.内容编辑人员 三.推广人员 四.数据分析人员 接下来,我们就对这四个小组分配工作. 首先,前端/页编人员主要负责站内优化,主要从四 ...

  6. 应届生应聘阿里,腾讯,美团90%会被问到的Netty面试题!史上最全系列!

    1.BIO.NIO 和 AIO 的区别? BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理.线程开销大.伪异步 IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源 ...

  7. C#进阶系列——MEF实现设计上的“松耦合”(二)

    前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级 ...

  8. Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  9. 【netty】Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

随机推荐

  1. 带allow-create的el-select限制长度

    需求:给el-select添加新增字段长度限制且新增内容不能为空 1.首先给el-select绑定一个id(例如:selectSku),这个id会传到组件里面,绑定在那个input上面, <el ...

  2. [cf741C]Arpa’s overnight party and Mehrdad’s silent entering

    直接令2i-1和2i的位置不相同,相当于有2n条边,对其进行二分图染色即可(这张图一定不存在奇环). 假设给出的n条关系是A类边,2i-1和2i的边是B类边,可以发现一条路径一定是AB交替(因为A/B ...

  3. [atARC066F]Contest with Drinks Hard

    先不考虑修改,那么很明显即对于每一个极长的的区间,若其长度为$l$,有${l+1\choose 2}$的贡献 考虑dp去做,即$f_{i}$表示前$i$个数最大的答案,则$$f_{i}=\max(\m ...

  4. [hdu5245]Joyful

    很难考虑矩形覆盖的问题,但可以考虑每一个点被覆盖的概率/期望(把矩形分成九部分后容斥即可),sigma起来即答案 1 #include<bits/stdc++.h> 2 using nam ...

  5. [atAGC045E]Fragile Balls

    构造一张有向图$G=([1,n],\{(a_{i},b_{i})\})$(可以有重边和自环),定义其连通块为将其看作无向图(即边无向)后分为若干个连通块 记$in_{i}$为$i$的入度(即最终盒子中 ...

  6. [bzoj1863]皇帝的烦恼

    二分枚举答案,假设是ans,考虑判定答案从前往后计算,算出每一个将军与第一个将军最少和最多有多少个相同的奖牌,贪心转移即可 1 #include<bits/stdc++.h> 2 usin ...

  7. 【Golang】基于beego/orm实现相同表结构不同表名的分表方法实现

    一.背景 在业务场景开发的过程中, 随着数据量的增加,相同表结构不同表名的分表策略是常用的方案选择之一.如下以golang做为后端业务开发,尝试修改beego的orm库做一个相同表结构不同表名的分表实 ...

  8. Timer定时器的使用

    import java.util.Timer; import java.util.TimerTask; public class Demo2 { //执行时间,时间单位为毫秒,读者可自行设定,不得小于 ...

  9. 力扣 - 剑指 Offer 10- I. 斐波那契数列

    题目 剑指 Offer 10- I. 斐波那契数列 思路1(递归 / 自顶向下) 这题是很常见的一道入门递归题,可以采用自顶向下的递归方法,比如我们要求第n个位置的值,根据斐波那契数列的定义fib(n ...

  10. 常用的分布式ID生成器

    为何需要分布式ID生成器 **本人博客网站 **IT小神 www.itxiaoshen.com **拿我们系统常用Mysql数据库来说,在之前的单体架构基本是单库结构,每个业务表的ID一般从1增,通过 ...